From 2ab05ee8f63866c615c65d857d26eb6ef2da136d Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Thu, 1 Oct 2026 12:29:26 +0200 Subject: [PATCH] =?UTF-8?q?Der=20Schriftzug=20geh=C3=B6rte=20zum=20vorigen?= =?UTF-8?q?=20Film=20=E2=80=94=20ein=20Zustand=20ohne=20Adresse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit „Werner Beinhart" über dem Bild von John Wick. Von mir eingebaut, im Commit, der die Überblendung umgestellt hat. **Der Grund ist der Umbau selbst.** Vorher bekam der Aufmacher je Titel eine neue Identität; sein Zustand begann damit jedes Mal von vorn. Seit er bleibt und nur seine Angaben wechseln, überlebt auch der geladene Schriftzug den Wechsel — und `availableLogo` gab ihn heraus, ohne zu prüfen, ob er überhaupt zum aktuellen Titel gehört: if let logo { return logo } // ← zu irgendeinem Film Jetzt trägt der Zustand die Adresse mit, zu der er gehört, und wird nur herausgegeben, wenn sie zur aktuellen passt. Passt sie nicht, gilt der Zwischenspeicher — und wenn auch der nichts hat, der gesetzte Titel. Nie der falsche Schriftzug. **Dieselbe Falle steckte in `FlixyArtwork`**, nur unauffälliger: auch dort hielt `loaded` ein Bild ohne Angabe, wozu es gehört, und `load()` brach deswegen früh ab („ist ja schon eins da"). Solange jede Kachel ihre eigene Identität hat, fällt das nicht auf. Der Aufmacher hat seit dem Umbau keine mehr. Die Regel dahinter gilt allgemein: **ein Zustand, der etwas zwischenspeichert, muss sagen, wozu es gehört** — sonst gilt er für alles. Die Attrappe liefert jetzt Schriftzüge (`Logo`-Bildmarke). Ohne sie fällt der Aufmacher auf den gesetzten Titel zurück, und dieser ganze Weg wäre im Simulator gar nicht zu sehen — genau deshalb ist der Fehler erst beim Nutzer aufgefallen. iOS und tvOS bauen, 476 Tests grün. Co-Authored-By: Claude Opus 5 --- .../FlixyDesign/Components/FlixyArtwork.swift | 13 ++++++++++--- .../FlixyDesign/Components/HeroBanner.swift | 17 ++++++++++++++--- Tools/JellyfinStub/server.py | 7 ++++++- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/FlixyArtwork.swift b/Packages/FlixyKit/Sources/FlixyDesign/Components/FlixyArtwork.swift index 093f730..14700bd 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Components/FlixyArtwork.swift +++ b/Packages/FlixyKit/Sources/FlixyDesign/Components/FlixyArtwork.swift @@ -68,7 +68,14 @@ public struct FlixyArtwork: View { self.contentMode = contentMode } - @State private var loaded: PlatformImage? + /// Das geladene Bild — **mit den Adressen, zu denen es gehört**. + /// + /// **Ohne sie wird es falsch,** sobald eine Ansicht ihre Identität über + /// einen Inhaltswechsel hinweg behält: der Zustand überlebt den Wechsel, + /// und das alte Bild bliebe stehen, bis das neue geladen ist. Solange + /// jede Kachel ihre eigene Identität hatte, fiel das nicht auf — der + /// Aufmacher hat seit dem Umbau der Überblendung keine mehr. + @State private var loaded: (urls: [URL], image: PlatformImage)? @State private var hasFailed = false public var body: some View { @@ -96,7 +103,7 @@ public struct FlixyArtwork: View { /// ersten Bild und blitzt nicht kurz grau auf. Über ein `await` ginge das /// nicht — das kostet immer einen Durchlauf. private var available: PlatformImage? { - if let loaded { return loaded } + if let loaded, loaded.urls == urls { return loaded.image } // Die erste, die schon im Speicher liegt — in der Reihenfolge der // Vorlieben, nicht in der des Zufalls. for url in urls { @@ -147,7 +154,7 @@ public struct FlixyArtwork: View { let bild = await ArtworkLoader.shared.image(for: url) guard !Task.isCancelled else { return } if let bild { - withAnimation(.easeOut(duration: 0.2)) { loaded = bild } + withAnimation(.easeOut(duration: 0.2)) { loaded = (urls, bild) } return } } diff --git a/Packages/FlixyKit/Sources/FlixyDesign/Components/HeroBanner.swift b/Packages/FlixyKit/Sources/FlixyDesign/Components/HeroBanner.swift index 7947de8..f3a430c 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/Components/HeroBanner.swift +++ b/Packages/FlixyKit/Sources/FlixyDesign/Components/HeroBanner.swift @@ -53,7 +53,16 @@ public struct HeroBanner: View { private let fillsAvailableSpace: Bool private let actions: Actions - @State private var logo: PlatformImage? + /// Der geladene Schriftzug — **mit der Adresse, zu der er gehört**. + /// + /// **Ohne die Adresse wird er falsch.** Seit der Aufmacher seine + /// Identität über den Titelwechsel hinweg behält, überlebt auch dieser + /// Zustand ihn: der Schriftzug des vorigen Films stand dann über dem Bild + /// des neuen, bis der neue geladen war. „Werner Beinhart" über John Wick. + /// + /// Ein Zustand, der eine andere Angabe zwischenspeichert, muss sagen, + /// wozu er gehört — sonst gilt er für alles. + @State private var loadedLogo: (url: URL, image: PlatformImage)? public init( title: String, @@ -143,8 +152,8 @@ public struct HeroBanner: View { /// Bild des Übergangs da. Nur wenn nicht, wird nachgeladen — und dann /// steht bis dahin der gesetzte Titel. private var availableLogo: PlatformImage? { - if let logo { return logo } guard let logoURL else { return nil } + if let loadedLogo, loadedLogo.url == logoURL { return loadedLogo.image } return ArtworkLoader.cachedImage(for: logoURL) } @@ -224,7 +233,9 @@ public struct HeroBanner: View { } .task(id: logoURL) { guard let logoURL, ArtworkLoader.cachedImage(for: logoURL) == nil else { return } - logo = await ArtworkLoader.shared.image(for: logoURL) + if let bild = await ArtworkLoader.shared.image(for: logoURL) { + loadedLogo = (logoURL, bild) + } } } diff --git a/Tools/JellyfinStub/server.py b/Tools/JellyfinStub/server.py index 2d13c59..9f40233 100644 --- a/Tools/JellyfinStub/server.py +++ b/Tools/JellyfinStub/server.py @@ -60,7 +60,12 @@ def item(key, name, kind, overview, *, resume=None, series=None): "ProductionYear": 2021 + (len(name) % 4), "RunTimeTicks": (90 + len(name)) * 60 * 10_000_000, "OfficialRating": "12", - "ImageTags": {"Primary": "p-" + key}, + # `Logo` ist der freigestellte Schriftzug. Er steht hier, damit sich + # pruefen laesst, dass beim Wechsel im Aufmacher nicht der Schriftzug + # des vorigen Titels ueber dem neuen Bild stehenbleibt — ohne Logo + # faellt der Aufmacher auf den gesetzten Titel zurueck, und dieser + # Weg waere gar nicht zu sehen. + "ImageTags": {"Primary": "p-" + key, "Logo": "l-" + key}, "BackdropImageTags": ["b-" + key], "Genres": ["Drama"], "UserData": {"PlayCount": 0, "Played": False, "PlaybackPositionTicks": 0},