Der Schriftzug gehörte zum vorigen Film — ein Zustand ohne Adresse
„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 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
37bb153dd8
commit
2ab05ee8f6
@@ -68,7 +68,14 @@ public struct FlixyArtwork: View {
|
|||||||
self.contentMode = contentMode
|
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
|
@State private var hasFailed = false
|
||||||
|
|
||||||
public var body: some View {
|
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
|
/// ersten Bild und blitzt nicht kurz grau auf. Über ein `await` ginge das
|
||||||
/// nicht — das kostet immer einen Durchlauf.
|
/// nicht — das kostet immer einen Durchlauf.
|
||||||
private var available: PlatformImage? {
|
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
|
// Die erste, die schon im Speicher liegt — in der Reihenfolge der
|
||||||
// Vorlieben, nicht in der des Zufalls.
|
// Vorlieben, nicht in der des Zufalls.
|
||||||
for url in urls {
|
for url in urls {
|
||||||
@@ -147,7 +154,7 @@ public struct FlixyArtwork: View {
|
|||||||
let bild = await ArtworkLoader.shared.image(for: url)
|
let bild = await ArtworkLoader.shared.image(for: url)
|
||||||
guard !Task.isCancelled else { return }
|
guard !Task.isCancelled else { return }
|
||||||
if let bild {
|
if let bild {
|
||||||
withAnimation(.easeOut(duration: 0.2)) { loaded = bild }
|
withAnimation(.easeOut(duration: 0.2)) { loaded = (urls, bild) }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,16 @@ public struct HeroBanner<Actions: View>: View {
|
|||||||
private let fillsAvailableSpace: Bool
|
private let fillsAvailableSpace: Bool
|
||||||
private let actions: Actions
|
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(
|
public init(
|
||||||
title: String,
|
title: String,
|
||||||
@@ -143,8 +152,8 @@ public struct HeroBanner<Actions: View>: View {
|
|||||||
/// Bild des Übergangs da. Nur wenn nicht, wird nachgeladen — und dann
|
/// Bild des Übergangs da. Nur wenn nicht, wird nachgeladen — und dann
|
||||||
/// steht bis dahin der gesetzte Titel.
|
/// steht bis dahin der gesetzte Titel.
|
||||||
private var availableLogo: PlatformImage? {
|
private var availableLogo: PlatformImage? {
|
||||||
if let logo { return logo }
|
|
||||||
guard let logoURL else { return nil }
|
guard let logoURL else { return nil }
|
||||||
|
if let loadedLogo, loadedLogo.url == logoURL { return loadedLogo.image }
|
||||||
return ArtworkLoader.cachedImage(for: logoURL)
|
return ArtworkLoader.cachedImage(for: logoURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +233,9 @@ public struct HeroBanner<Actions: View>: View {
|
|||||||
}
|
}
|
||||||
.task(id: logoURL) {
|
.task(id: logoURL) {
|
||||||
guard let logoURL, ArtworkLoader.cachedImage(for: logoURL) == nil else { return }
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,12 @@ def item(key, name, kind, overview, *, resume=None, series=None):
|
|||||||
"ProductionYear": 2021 + (len(name) % 4),
|
"ProductionYear": 2021 + (len(name) % 4),
|
||||||
"RunTimeTicks": (90 + len(name)) * 60 * 10_000_000,
|
"RunTimeTicks": (90 + len(name)) * 60 * 10_000_000,
|
||||||
"OfficialRating": "12",
|
"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],
|
"BackdropImageTags": ["b-" + key],
|
||||||
"Genres": ["Drama"],
|
"Genres": ["Drama"],
|
||||||
"UserData": {"PlayCount": 0, "Played": False, "PlaybackPositionTicks": 0},
|
"UserData": {"PlayCount": 0, "Played": False, "PlaybackPositionTicks": 0},
|
||||||
|
|||||||
Reference in New Issue
Block a user