Eine misslungene Seite beendete das Nachladen für immer

Der Grund für „es sind wieder nicht alle Filme drin": im Fehlerfall stand
hier `page = nil`. Eine einzige misslungene Anfrage auf einer wackeligen
Leitung, und die Mediathek blieb endgültig bei sechzig Titeln stehen —
lautlos, ohne dass irgendetwas darauf hindeutete. Im Zug passiert das
zuverlässig.

Der Kommentar daneben begründete das Schweigen, und das war auch richtig:
ein Fehlerblatt mitten im Scrollen wäre störend. Nur hat er das
eigentliche Problem verdeckt — nicht die fehlende Meldung war schlimm,
sondern dass es danach keinen Weg zurück gab.

Jetzt bleibt die Seite erhalten, und unten erscheint eine Zeile zum
Weiterladen. Von selbst wird nach einem Fehlschlag **nicht** mehr
nachgefasst: sonst liefe bei jedem Scrollen eine Anfrage in dieselbe tote
Leitung.

Dazu der Knopf zum Neuladen in der Leiste, wie gewünscht. Ziehen von oben
gibt es auf dem Mac nicht, und in einem Raster ist es ohnehin kaum zu
treffen — wer den Verdacht hat, dass etwas fehlt, braucht einen Knopf
und keine Geste.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-27 18:40:53 +02:00
co-authored by Claude Opus 5
parent 24d7423f9c
commit 348ec96282
2 changed files with 117 additions and 8 deletions
+51
View File
@@ -2481,6 +2481,57 @@
}
}
},
"library.loadMore" : {
"extractionState" : "manual",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Weitere laden"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Load more"
}
}
}
},
"library.loadMoreFailed" : {
"extractionState" : "manual",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Der Nachschub ist hängen geblieben — es fehlen noch Titel."
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Loading more stalled — some titles are still missing."
}
}
}
},
"library.reload" : {
"extractionState" : "manual",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Neu laden"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Reload"
}
}
}
},
"library.scan" : {
"localizations" : {
"de" : {
+66 -8
View File
@@ -17,6 +17,12 @@ struct LibraryView: View {
@State private var state: LoadState<Void> = .loading
@State private var query = MediaQuery()
@State private var page: MediaPage?
/// Ob der letzte Nachschub misslungen ist.
///
/// Dann steht unten eine Zeile zum Weiterversuchen: von selbst passiert
/// nichts mehr, weil die Kacheln, die das Nachladen auslösen, längst
/// erschienen sind und kein zweites Mal erscheinen.
@State private var loadMoreFailed = false
@State private var isLoadingMore = false
@State private var showsFilters = false
@@ -101,6 +107,7 @@ struct LibraryView: View {
.padding(FlixySpacing.screenMargin)
if isLoadingMore { ProgressView().padding(.bottom, FlixySpacing.section) }
moreButton.padding(.bottom, FlixySpacing.section)
}
.flixyRevealsTopChrome()
}
@@ -120,10 +127,28 @@ struct LibraryView: View {
}
if isLoadingMore { ProgressView().padding(.vertical, FlixySpacing.section) }
moreButton.padding(.vertical, FlixySpacing.section)
}
.flixyRevealsTopChrome()
}
/// Der Weg weiter, wenn der Nachschub hängen geblieben ist.
@ViewBuilder
private var moreButton: some View {
if loadMoreFailed, let page, page.hasMore {
VStack(spacing: FlixySpacing.snug) {
Text("library.loadMoreFailed")
.font(.flixyCaption)
.foregroundStyle(Color.flixyTextMuted)
Button("library.loadMore") {
Task { await loadMore() }
}
.buttonStyle(.bordered)
}
.frame(maxWidth: .infinity)
}
}
@ToolbarContentBuilder
private var toolbar: some ToolbarContent {
// Nur auf schmalen Geräten: dort hat die Suche keinen eigenen Eintrag
@@ -139,6 +164,20 @@ struct LibraryView: View {
}
}
// **Neu laden.** Auf dem Mac und dem iPad gibt es kein Ziehen von
// oben, und selbst dort wo es das gibt, ist es in einem Raster kaum
// zu treffen. Wer den Verdacht hat, dass etwas fehlt, braucht einen
// Knopf und keine Geste.
ToolbarItem(placement: .flixyTrailing) {
Button {
Task { await reload() }
} label: {
Image(systemName: "arrow.clockwise")
}
.accessibilityLabel(Text("library.reload"))
.disabled(isLoadingMore)
}
ToolbarItem(placement: .flixyTrailing) {
Button {
showsFilters = true
@@ -182,16 +221,28 @@ struct LibraryView: View {
/// Lädt nach, sobald die Ansicht sich dem Ende der Liste nähert.
private func loadMoreIfNeeded(reaching item: MediaItem) async {
guard
// Fünf Einträge vor Schluss: früh genug, dass der Nachschub da
// ist, bevor jemand am Ende ankommt, und spät genug, dass nicht
// jedes Scrollen eine Anfrage auslöst.
items.suffix(5).contains(where: { $0.id == item.id }),
// Nach einem Fehlschlag **nicht** von selbst: sonst läuft bei
// jedem Scrollen eine Anfrage in dieselbe tote Leitung. Von dort
// übernimmt der Knopf.
!loadMoreFailed
else { return }
await loadMore()
}
/// Holt die nächste Seite — von selbst oder auf Knopfdruck.
private func loadMore() async {
guard let server = session.backend,
let page, page.hasMore,
!isLoadingMore,
// Fünf Einträge vor Schluss: früh genug, dass der Nachschub da
// ist, bevor jemand am Ende ankommt, und spät genug, dass nicht
// jedes Scrollen eine Anfrage auslöst.
items.suffix(5).contains(where: { $0.id == item.id })
!isLoadingMore
else { return }
isLoadingMore = true
loadMoreFailed = false
defer { isLoadingMore = false }
do {
@@ -208,9 +259,16 @@ struct LibraryView: View {
items.append(contentsOf: next.items.filter { !known.contains($0.id) })
self.page = next
} catch {
// Stillschweigend: die Liste steht bereits, ein Fehlerblatt mitten
// im Scrollen wäre störender als ein paar fehlende Einträge.
self.page = nil
// **Nicht `page = nil`.** Das stand hier, und es beendete das
// Nachladen **endgültig**: eine einzige misslungene Anfrage auf
// einer wackeligen Leitung, und die Mediathek blieb für immer bei
// sechzig Titeln stehen — lautlos, ohne dass irgendetwas darauf
// hindeutete. Genau so sieht „es sind nicht alle Filme drin" aus.
//
// Die Seite bleibt also, damit ein zweiter Versuch möglich ist.
// Ein Fehlerblatt mitten im Scrollen wäre trotzdem störend —
// stattdessen erscheint unten eine Zeile zum Weiterladen.
loadMoreFailed = true
}
}
}