Nach Folge 8 kam wieder Folge 1, und nichts sagte warum
Der Server liefert die Folgen einer Serie am Stück. Auf der Seite stand unter „Staffeln" eine durchgehende Liste, in der nach der achten Folge wieder eine erste kam — die der zweiten Staffel, aber das stand nirgends. Jetzt wählt ein Menü die Staffel, dort wo vorher nur „Folgen" stand. Bei einer einzigen Staffel bleibt es beim Wort: ein Menü mit einem Eintrag ist keine Wahl. Kein `Picker`: diese Seite ist eine `ScrollView`, kein `Form`, und dort hat ein `Picker` kein Aussehen, auf das man sich verlassen kann — dieselbe Begründung wie beim Sprachmenü darüber. „Alle auswählen" meint jetzt die gezeigte Staffel. Vorher hätte ein Griff sechzehn Folgen heruntergeladen statt acht. Beim Wechsel der Staffel fällt eine bestehende Auswahl weg: stehen zu lassen, was man nicht mehr sieht, lädt unsichtbare Folgen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fa31adf3d1
commit
ab43656f71
@@ -33,6 +33,13 @@ struct SeriesDetailView: View {
|
||||
@State private var isWorking = false
|
||||
@State private var summary: String?
|
||||
|
||||
/// Welche Staffel die Liste zeigt — `nil` heisst: die erste.
|
||||
///
|
||||
/// **Weil der Server die Folgen am Stück liefert.** Eine Serie mit zwei
|
||||
/// Staffeln ergab eine Liste, in der nach Folge 8 wieder eine Folge 1
|
||||
/// kam, ohne dass irgendwo stünde, dass dazwischen eine Staffel endet.
|
||||
@State private var gewaehlteStaffel: Int?
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: FlaroSpacing.section) {
|
||||
@@ -172,23 +179,33 @@ struct SeriesDetailView: View {
|
||||
.padding(.horizontal, FlaroSpacing.screenMargin)
|
||||
|
||||
case .loaded(let entries):
|
||||
let nummern = staffelnummern(in: entries)
|
||||
let sichtbar = sichtbareFolgen(in: entries, staffeln: nummern)
|
||||
|
||||
VStack(alignment: .leading, spacing: FlaroSpacing.regular) {
|
||||
// **Der Auswählen-Knopf steht bei dem, was er auswählt.**
|
||||
// Oben in der Werkzeugleiste wäre er weiter weg von der Liste
|
||||
// als von allem anderen auf dieser Seite.
|
||||
HStack {
|
||||
if nummern.count > 1 {
|
||||
staffelwahl(nummern)
|
||||
} else {
|
||||
Text(item.kind == .show ? "detail.seasons" : "detail.episodes")
|
||||
.font(.flaroRowHeader)
|
||||
.foregroundStyle(Color.flaroTextPrimary)
|
||||
}
|
||||
Spacer()
|
||||
if entries.contains(where: { $0.kind == .episode }) {
|
||||
selectionControls(for: entries)
|
||||
if sichtbar.contains(where: { $0.kind == .episode }) {
|
||||
// **Nur die gezeigte Staffel.** „Alle auswählen" soll
|
||||
// das meinen, was dasteht — sonst lädt ein Griff
|
||||
// sechzehn Folgen herunter statt acht.
|
||||
selectionControls(for: sichtbar)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, FlaroSpacing.screenMargin)
|
||||
|
||||
LazyVStack(spacing: 0) {
|
||||
ForEach(entries) { entry in
|
||||
ForEach(sichtbar) { entry in
|
||||
row(for: entry)
|
||||
Divider().overlay(Color.flaroSeparator)
|
||||
}
|
||||
@@ -197,6 +214,55 @@ struct SeriesDetailView: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// Welche Staffeln in dieser Liste vorkommen.
|
||||
///
|
||||
/// Leer, wenn die Einträge selbst Staffeln sind — dann gibt es nichts zu
|
||||
/// wählen, die Liste **ist** die Wahl.
|
||||
private func staffelnummern(in entries: [MediaItem]) -> [Int] {
|
||||
Set(entries.compactMap { $0.kind == .episode ? $0.parentIndex : nil }).sorted()
|
||||
}
|
||||
|
||||
private func sichtbareFolgen(in entries: [MediaItem], staffeln: [Int]) -> [MediaItem] {
|
||||
guard staffeln.count > 1 else { return entries }
|
||||
let gewaehlt = gewaehlteStaffel ?? staffeln[0]
|
||||
return entries.filter { $0.kind != .episode || $0.parentIndex == gewaehlt }
|
||||
}
|
||||
|
||||
/// Die Staffel als Menü — an der Stelle, an der sonst „Folgen" steht.
|
||||
///
|
||||
/// **Kein `Picker`.** Diese Seite ist eine `ScrollView`, kein `Form`;
|
||||
/// dort hat ein `Picker` kein Aussehen, auf das man sich verlassen kann.
|
||||
/// Dieselbe Begründung wie bei `AudioLanguagePicker`.
|
||||
private func staffelwahl(_ nummern: [Int]) -> some View {
|
||||
let gewaehlt = gewaehlteStaffel ?? nummern[0]
|
||||
|
||||
return Menu {
|
||||
ForEach(nummern, id: \.self) { nummer in
|
||||
Button {
|
||||
gewaehlteStaffel = nummer
|
||||
// Eine Auswahl aus der vorigen Staffel meint hier nichts
|
||||
// mehr — stehen zu lassen, was man nicht mehr sieht,
|
||||
// lädt unsichtbare Folgen herunter.
|
||||
selection.removeAll()
|
||||
} label: {
|
||||
Label(
|
||||
String(localized: "season.short \(nummer)"),
|
||||
systemImage: nummer == gewaehlt ? "checkmark" : ""
|
||||
)
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
HStack(spacing: FlaroSpacing.tight) {
|
||||
Text("season.short \(gewaehlt)")
|
||||
.font(.flaroRowHeader)
|
||||
.foregroundStyle(Color.flaroTextPrimary)
|
||||
Image(systemName: "chevron.up.chevron.down")
|
||||
.font(.flaroCaption)
|
||||
.foregroundStyle(accent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Eine Zeile — als Weg zur Folge oder als Kreuz zum Ankreuzen.
|
||||
@ViewBuilder
|
||||
private func row(for entry: MediaItem) -> some View {
|
||||
|
||||
Reference in New Issue
Block a user