diff --git a/Flixy/Resources/Localizable.xcstrings b/Flixy/Resources/Localizable.xcstrings index 4a0976d..2fc362a 100644 --- a/Flixy/Resources/Localizable.xcstrings +++ b/Flixy/Resources/Localizable.xcstrings @@ -2124,6 +2124,23 @@ } } }, + "home.heroLibrariesNoMatch": { + "extractionState": "manual", + "localizations": { + "de": { + "stringUnit": { + "state": "translated", + "value": "Für die gewählten Mediatheken gibt es derzeit keine eigene Reihe auf der Startseite. Die Auswahl greift deshalb nicht — der Aufmacher zeigt alles." + } + }, + "en": { + "stringUnit": { + "state": "translated", + "value": "The selected libraries currently have no row of their own on the home screen, so the selection has no effect — the hero shows everything." + } + } + } + }, "home.heroSource": { "extractionState": "stale", "localizations": { @@ -2912,6 +2929,7 @@ } }, "libraryHub.empty": { + "extractionState": "stale", "localizations": { "de": { "stringUnit": { @@ -6036,6 +6054,7 @@ } }, "sidebar.library": { + "extractionState": "stale", "localizations": { "de": { "stringUnit": { diff --git a/Flixy/Views/Settings/HomeLayoutView.swift b/Flixy/Views/Settings/HomeLayoutView.swift index 4d54225..a3b569d 100644 --- a/Flixy/Views/Settings/HomeLayoutView.swift +++ b/Flixy/Views/Settings/HomeLayoutView.swift @@ -9,6 +9,14 @@ struct HomeLayoutView: View { @Environment(HomeLayoutSettings.self) private var layout @State private var rows: [HomeRow] = [] + /// Welche Mediatheken überhaupt eine Reihe auf der Startseite stellen. + /// + /// **Gemessen, nicht angenommen.** Nur Reihen, die der Server einer + /// Mediathek zuordnet, kann der Aufmacher auseinanderhalten — bei + /// Jellyfin sind das die „Neu in …"-Reihen. Gibt es für eine angehakte + /// Mediathek keine, greift die Auswahl ins Leere, und das sieht aus wie + /// ein kaputter Schalter. + @State private var libraryBackedRows: Set = [] @State private var isLoading = true var body: some View { @@ -91,7 +99,17 @@ struct HomeLayoutView: View { } header: { Text("home.heroLibraries") } footer: { - Text("home.heroLibrariesExplanation") + VStack(alignment: .leading, spacing: FlixySpacing.snug) { + Text("home.heroLibrariesExplanation") + // Lieber eine Erklärung als ein Aufmacher, der + // heimlich etwas anderes zeigt: trifft die Auswahl + // keine einzige Reihe, gilt sie als wirkungslos — und + // dann muss dastehen, warum. + if greiftInsLeere { + Text("home.heroLibrariesNoMatch") + .foregroundStyle(Color.flixyDestructive) + } + } } .listRowBackground(Color.flixySurface) } @@ -163,6 +181,13 @@ struct HomeLayoutView: View { .scrollContentBackground(.hidden) } + /// Ob die Auswahl keine einzige Reihe trifft. + private var greiftInsLeere: Bool { + !layout.heroLibraries.isEmpty + && !libraryBackedRows.isEmpty + && layout.heroLibraries.isDisjoint(with: libraryBackedRows) + } + /// Kreuzt eine Mediathek für den Aufmacher an oder ab. private func toggleHeroLibrary(_ identifier: String) { if layout.heroLibraries.contains(identifier) { @@ -198,6 +223,7 @@ struct HomeLayoutView: View { // Mediatheken und Sammlungen angelegt sind. let hubs = (try? await backend.homeRows()) ?? [] rows = layout.rows(from: hubs) + libraryBackedRows = Set(hubs.compactMap(\.libraryID)) } } diff --git a/Tools/JellyfinStub/server.py b/Tools/JellyfinStub/server.py index 7c9082f..2d13c59 100644 --- a/Tools/JellyfinStub/server.py +++ b/Tools/JellyfinStub/server.py @@ -43,7 +43,16 @@ TITLES = [ ("s2", "Hinter dem Deich", "Series", "Eine Familie, ein Hof, drei Staffeln."), ("m4", "Letzter Sommer", "Movie", "Zwei Wochen, die alles ändern."), ("m5", "Kalte Küste", "Movie", "Ein Leuchtturm und eine Frage zu viel."), + # Nur in „Gemischtes". Ohne einen Titel, den es ausschliesslich dort + # gibt, laesst sich gar nicht pruefen, ob eine abgewaehlte Mediathek + # wirklich aus dem Aufmacher verschwindet: steht ueberall dasselbe, + # sieht ein wirkungsloser Filter wie ein wirksamer aus. + ("x1", "Zwischen den Zeilen", "Movie", "Nur in Gemischtes zu finden."), + ("x2", "Randnotiz", "Movie", "Ebenfalls nur in Gemischtes."), ] +# Welche Titel in welcher Mediathek liegen. Was hier nicht steht, liegt +# ueberall — so war es vorher, und fuer die uebrigen Pruefungen reicht das. +NUR_IN = {"x1": "lib-mixed", "x2": "lib-mixed"} def item(key, name, kind, overview, *, resume=None, series=None): d = { @@ -192,7 +201,12 @@ class Handler(BaseHTTPRequestHandler): "lib-movies": {"Movie"}, "lib-shows": {"Series"}, }.get(eltern) - gewaehlt = [t for t in TITLES if erlaubt is None or t[2] in erlaubt] + gewaehlt = [ + t for t in TITLES + if (erlaubt is None or t[2] in erlaubt) + and NUR_IN.get(t[0], eltern) == eltern + ] + gewaehlt.sort(key=lambda t: t[0] not in NUR_IN) return self.reply([item(*t) for t in gewaehlt[:6]]) if p == f"/Users/{USER_ID}/Items/Resume": # Wie bei Jellyfin: hier steht, was eine gemerkte Stelle groesser