Phase 5: Nachladen, Startseiten-Layout
Nachladen - DownloadRefiller wählt aus, WELCHE Folgen fehlen; wie viele, rechnet die Regel-Engine. Getrennt, weil das Rechnen ohne Server auskommt und damit prüfbar ist. - In Ausstrahlungsreihenfolge, Specials in Staffel 0 bleiben außen vor. - Läuft nach dem Ansehen und beim Start, nicht auf einem Zeitgeber: eine App, die im Hintergrund unaufgefordert Gigabytes lädt, wäre eine unangenehme Überraschung auf der Mobilfunkrechnung. Startseiten-Layout - Reihen ein-/ausblenden und per Bearbeiten-Modus umsortieren. - Die Anordnungslogik liegt als HubArrangement in PlexKit statt im App-Target — dort ist sie ohne Simulator testbar, und dort sitzen die unangenehmen Fälle: neue Reihen vom Server landen am Ende statt zu verschwinden, verschwundene aus der gespeicherten Liste stören nicht, ein doppelter Eintrag stürzt nicht ab. 11 Tests. 126 Tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import SwiftUI
|
||||
import FlixyDesign
|
||||
import PlexKit
|
||||
|
||||
/// Reihen der Startseite ein- und ausblenden und umsortieren.
|
||||
struct HomeLayoutView: View {
|
||||
@Environment(FlixySession.self) private var session
|
||||
@Environment(HomeLayoutSettings.self) private var layout
|
||||
|
||||
@State private var rows: [HomeRow] = []
|
||||
@State private var isLoading = true
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if isLoading {
|
||||
ProgressView().frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
} else if rows.isEmpty {
|
||||
ContentUnavailableView {
|
||||
Label("home.empty.title", systemImage: "rectangle.stack")
|
||||
} description: {
|
||||
Text("homeLayout.empty")
|
||||
}
|
||||
} else {
|
||||
list
|
||||
}
|
||||
}
|
||||
.background(Color.flixyCanvas)
|
||||
.navigationTitle(Text("homeLayout.title"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar { EditButton() }
|
||||
.task { await load() }
|
||||
}
|
||||
|
||||
private var list: some View {
|
||||
List {
|
||||
Section {
|
||||
ForEach($rows) { $row in
|
||||
Toggle(isOn: Binding(
|
||||
get: { !row.isHidden },
|
||||
set: {
|
||||
row.isHidden = !$0
|
||||
layout.setHidden(!$0, for: row.id)
|
||||
}
|
||||
)) {
|
||||
Text(row.title)
|
||||
.foregroundStyle(Color.flixyTextPrimary)
|
||||
}
|
||||
.listRowBackground(Color.flixySurface)
|
||||
}
|
||||
.onMove { indices, destination in
|
||||
rows.move(fromOffsets: indices, toOffset: destination)
|
||||
layout.setOrder(rows.map(\.id))
|
||||
}
|
||||
} footer: {
|
||||
Text("homeLayout.explanation")
|
||||
}
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
}
|
||||
|
||||
private func load() async {
|
||||
defer { isLoading = false }
|
||||
guard let server = session.server else { return }
|
||||
// Die Reihen kommen vom Server — es gibt keine feste Liste, die sich
|
||||
// vorweg anzeigen ließe. Was hier steht, hängt davon ab, welche
|
||||
// Mediatheken und Sammlungen angelegt sind.
|
||||
let hubs = (try? await server.homeHubs()) ?? []
|
||||
rows = layout.rows(from: hubs)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user