Files
Flaro/Flixy/Views/Home/HeroArtwork.swift
T
ScarriffleandClaude Opus 5 2a2afa8573 Der Aufmacher bleibt stehen, und Folgen bekommen ein Bild
Drei Sachen am Karussell.

Die Vorschlaege wechselten bei jedem Start, obwohl es dafuer laengst ein
Zeitfenster von sechs Stunden gab. Der Grund: das Los hing an der Position
in der Liste, nicht am Titel. Kam einer dazu, verschwand einer, oder
aenderte sich ein Fortschritt, bekamen alle dahinter ein anderes Los — und
„Weiterschauen\" waechst und schrumpft staendig. Jetzt haengt das Los an der
Kennung; wer dazukommt, stoert niemanden. Als eigener Typ mit elf Tests,
weil „es wechselt zu oft\" kein Befund ist, den man debuggen kann.

Folgen zeigten kein Bild. Die Kette Folge → Serie gab es zwar, aber sie
hoerte beim ersten Glied auf, das sich **zusammensetzen** liess — und ob es
das Bild dahinter gibt, stellt sich erst beim Abruf heraus. Die Reihenfolge
wandert deshalb ins Laden: Folge, Staffel, Serie, der Reihe nach, bis eine
Adresse antwortet.

Und auf dem Mac gibt es jetzt Pfeile links und rechts, sobald der Zeiger
ueber dem Aufmacher liegt, sowie Punkte, die unter dem Zeiger wachsen und
auf die man springen kann. Nur dort: auf dem iPad und dem iPhone wischt man
ohnehin, und zwei Knoepfe staenden nur im Bild.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-28 20:46:34 +02:00

82 lines
3.7 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
import FlixyDesign
import MediaKit
/// Woher der Aufmacher seine Bilder nimmt.
///
/// An **einer** Stelle, weil zwei Stellen es schon zweimal falsch gemacht
/// haben:
///
/// Erstens wurde das Hintergrundbild in 900×1200 angefordert — hochkant — und
/// dann in einem 16:9-Rahmen gezeigt. Zu sehen war davon ein schmaler Streifen
/// aus der Mitte; vom Bild fehlte oben und unten je ein Drittel. Die Maße
/// richten sich jetzt nach dem Rahmen, in dem das Bild landet.
///
/// Zweitens holt das Karussell das nächste Bild vor, solange das aktuelle noch
/// steht. Weicht dessen Adresse auch nur in einer Zahl ab, ist es eine andere
/// Adresse, der Zwischenspeicher trifft daneben und der Aufmacher blendet auf
/// eine graue Fläche über.
enum HeroArtwork {
/// Die Maße, in denen das Bild angefordert wird.
///
/// Im Seitenverhältnis des Rahmens, in dem es landet — sonst schneidet der
/// Server zu, und man sieht einen Streifen aus der Mitte.
static func size(compact: Bool) -> (width: Int, height: Int) {
compact ? (600, 900) : (1920, 1080)
}
static func aspectRatio(compact: Bool) -> CGFloat {
compact ? FlixyAspectRatio.poster : FlixyAspectRatio.hero
}
/// Auf einem schmalen Bildschirm das **Plakat**, sonst das Hintergrundbild.
///
/// Ein Hintergrundbild ist 16:9. Hochkant gezeigt fehlen ihm links und
/// rechts je ein Viertel, und zu sehen ist ein Ausschnitt aus der Mitte —
/// vom Bild bleibt wenig übrig. Ein Plakat ist von vornherein hochkant;
/// es passt in den Rahmen, ohne dass etwas weggeschnitten werden muss.
static func backdropURL(for item: MediaItem, backend: any MediaBackend, compact: Bool) -> URL? {
backdropURLs(for: item, backend: backend, compact: compact).first
}
/// Alle Kandidaten, vom besten zum schlechtesten.
///
/// **Warum mehrere und nicht einer.** Eine Folge hat selten ein eigenes
/// Querformatbild, die Staffel manchmal, die Serie fast immer. Bisher
/// wurde die erste Adresse genommen, die sich **zusammensetzen** liess —
/// und ob es das Bild dahinter gibt, stellt sich erst beim Abruf heraus.
/// Gab es keines, blieb die Fläche grau, obwohl eine Ebene höher eines
/// gelegen hätte. Genau so sahen Folgen im Aufmacher aus.
///
/// Die Reihenfolge steht hier, ausprobiert wird sie beim Laden.
static func backdropURLs(
for item: MediaItem,
backend: any MediaBackend,
compact: Bool
) -> [URL] {
let size = size(compact: compact)
let pfade: [String?] = compact
// Hochkant: das Plakat der Folge, dann das der Staffel, dann das
// der Serie. Ein Hintergrundbild kommt hier zuletzt — es ist
// quer und verliert hochkant die Hälfte.
? [item.posterArtworkPath, item.thumb, item.parentThumb, item.seriesThumb, item.art]
// Quer: das eigene Hintergrundbild, dann das der Staffel, dann
// das der Serie — und erst danach das Vorschaubild der Folge.
: [item.art, item.parentThumb, item.seriesArt, item.seriesThumb, item.thumb]
var gesehen = Set<String>()
return pfade
.compactMap(\.self)
.filter { gesehen.insert($0).inserted }
.compactMap { backend.artworkURL(path: $0, width: size.width, height: size.height) }
}
/// Der freigestellte Schriftzug — ohne Bild-Transcoder.
///
/// Er ist ein PNG mit durchsichtigem Grund, und der Transcoder liefert
/// JPEG. Aus dem Schriftzug würde sonst ein schwarzer Kasten.
static func logoURL(for item: MediaItem, backend: any MediaBackend) -> URL? {
backend.rawImageURL(path: item.clearLogoPath)
}
}