import SwiftUI import FlixyDesign import MediaKit /// Eine waagerechte Reihe von Titeln auf dem Fernseher. /// /// Dieselben Daten wie `MediaRow` am Telefon, aber eine andere Bedienung: es /// gibt keinen Finger, der die Reihe schiebt, sondern einen Fokus, der von /// Karte zu Karte springt und die Reihe hinter sich herzieht. struct TVMediaRow: View { let row: MediaRowGroup let onSelect: (MediaItem) -> Void /// Wer gerade dran ist — damit der Aufmacher oben mitwandert. var onFocus: (MediaItem) -> Void = { _ in } @Environment(FlixySession.self) private var session /// Breit genug, dass die übernächste Karte angeschnitten ist — das zeigt, /// dass es weitergeht, ohne einen Pfeil dafür zu brauchen. private var breite: CGFloat { row.isContinueWatching ? 500 : 280 } var body: some View { VStack(alignment: .leading, spacing: FlixySpacing.regular) { Text(row.title) .font(.flixyRowHeader) .foregroundStyle(Color.flixyTextPrimary) .padding(.horizontal, FlixySpacing.screenMargin) ScrollView(.horizontal) { LazyHStack(spacing: FlixySpacing.regular) { ForEach(row.items) { item in karte(for: item).frame(width: breite) } } .padding(.horizontal, FlixySpacing.screenMargin) // **Platz zum Anheben.** Eine fokussierte Karte wächst über // ihren Rahmen hinaus, und eine ScrollView beschneidet am // Rand. Ohne Polster und ohne das abgeschaltete Beschneiden // fehlt der obersten Reihe die Anhebung — und zwar nur ihr, // was wie ein Zufall aussieht statt wie ein Fehler. .padding(.vertical, FlixySpacing.regular) } .scrollClipDisabled() .scrollIndicators(.never) } } /// Szenenbild beim Weiterschauen, sonst das Plakat. @ViewBuilder private func karte(for item: MediaItem) -> some View { if row.isContinueWatching { TVLandscapeCard( title: item.rowTitle, subtitle: item.cardSubtitle, artworkURL: session.backend?.artworkURL( path: item.rowArtworkPath, width: 880, height: 496 ), progress: item.watchProgress, onFocusChange: { if $0 { onFocus(item) } } ) { onSelect(item) } } else { TVPosterCard( title: item.rowTitle, subtitle: item.cardSubtitle, artworkURL: session.backend?.artworkURL( path: item.thumb, width: 560, height: 840 ), progress: item.watchProgress, onFocusChange: { if $0 { onFocus(item) } } ) { onSelect(item) } } } }