Die Attrappe unterscheidet die Mediatheken — und der Aufmacher sagt, wenn eine Auswahl ins Leere greift
Gemessen, weil „es tut nichts" und „es tut etwas anderes" von aussen
gleich aussehen. Gegen die Attrappe, mit laufendem Mitschnitt:
Auswahl ["lib-shows","lib-movies"] → übrig [latest.lib-movies, latest.lib-shows]
Auswahl ["lib-shows"] → übrig [latest.lib-shows]
Und der Aufmacher wechselte dabei **sofort** von „Nachtzug nach Genf"
(Film) zu „Küstenwache" (Serie) — ohne Neustart, mit offener App. Der
Weg stimmt also; was gemeldet wurde, muss eine andere Ursache haben.
Zwei Dinge, die diese Messung erst möglich gemacht haben:
**Die Attrappe hatte in jeder Mediathek dasselbe stehen.** „Neu in Filme",
„Neu in Serien" und „Neu in Gemischtes" lieferten dieselben Titel — damit
sieht ein wirkungsloser Filter genauso aus wie ein wirksamer. Jetzt gibt
es zwei Titel, die es **nur** in „Gemischtes" gibt, und jede Mediathek
führt, was zu ihr gehört.
**Ein Zwischenergebnis, das ich fast für den Fehler gehalten hätte:** ein
Neuinstallieren über `simctl install` löscht die Voreinstellungen nicht.
Die vermeintlich frische Auswahl war in Wahrheit die alte plus die neue —
zwei Messungen lang.
**Und der Punkt, der dem gemeldeten Verhalten am nächsten kommt:** trifft
die Auswahl keine einzige Reihe, gilt sie seit gestern als wirkungslos und
der Aufmacher zeigt alles. Das verhindert einen leeren Aufmacher, sieht
aber genau aus wie ein Schalter, der nichts tut. Jetzt steht es dort, wo
man es einstellt: ein Hinweis unter der Auswahl, sobald für die
angehakten Mediatheken keine eigene Reihe auf der Startseite existiert.
Welche Mediatheken überhaupt eine Reihe stellen, wird dafür aus den
geladenen Reihen gelesen, nicht angenommen.
iOS und tvOS bauen, 469 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7f380e5f4d
commit
0a59b8e82b
@@ -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": {
|
"home.heroSource": {
|
||||||
"extractionState": "stale",
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
@@ -2912,6 +2929,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"libraryHub.empty": {
|
"libraryHub.empty": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
@@ -6036,6 +6054,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sidebar.library": {
|
"sidebar.library": {
|
||||||
|
"extractionState": "stale",
|
||||||
"localizations": {
|
"localizations": {
|
||||||
"de": {
|
"de": {
|
||||||
"stringUnit": {
|
"stringUnit": {
|
||||||
|
|||||||
@@ -9,6 +9,14 @@ struct HomeLayoutView: View {
|
|||||||
@Environment(HomeLayoutSettings.self) private var layout
|
@Environment(HomeLayoutSettings.self) private var layout
|
||||||
|
|
||||||
@State private var rows: [HomeRow] = []
|
@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<String> = []
|
||||||
@State private var isLoading = true
|
@State private var isLoading = true
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -91,7 +99,17 @@ struct HomeLayoutView: View {
|
|||||||
} header: {
|
} header: {
|
||||||
Text("home.heroLibraries")
|
Text("home.heroLibraries")
|
||||||
} footer: {
|
} footer: {
|
||||||
|
VStack(alignment: .leading, spacing: FlixySpacing.snug) {
|
||||||
Text("home.heroLibrariesExplanation")
|
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)
|
.listRowBackground(Color.flixySurface)
|
||||||
}
|
}
|
||||||
@@ -163,6 +181,13 @@ struct HomeLayoutView: View {
|
|||||||
.scrollContentBackground(.hidden)
|
.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.
|
/// Kreuzt eine Mediathek für den Aufmacher an oder ab.
|
||||||
private func toggleHeroLibrary(_ identifier: String) {
|
private func toggleHeroLibrary(_ identifier: String) {
|
||||||
if layout.heroLibraries.contains(identifier) {
|
if layout.heroLibraries.contains(identifier) {
|
||||||
@@ -198,6 +223,7 @@ struct HomeLayoutView: View {
|
|||||||
// Mediatheken und Sammlungen angelegt sind.
|
// Mediatheken und Sammlungen angelegt sind.
|
||||||
let hubs = (try? await backend.homeRows()) ?? []
|
let hubs = (try? await backend.homeRows()) ?? []
|
||||||
rows = layout.rows(from: hubs)
|
rows = layout.rows(from: hubs)
|
||||||
|
libraryBackedRows = Set(hubs.compactMap(\.libraryID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,16 @@ TITLES = [
|
|||||||
("s2", "Hinter dem Deich", "Series", "Eine Familie, ein Hof, drei Staffeln."),
|
("s2", "Hinter dem Deich", "Series", "Eine Familie, ein Hof, drei Staffeln."),
|
||||||
("m4", "Letzter Sommer", "Movie", "Zwei Wochen, die alles ändern."),
|
("m4", "Letzter Sommer", "Movie", "Zwei Wochen, die alles ändern."),
|
||||||
("m5", "Kalte Küste", "Movie", "Ein Leuchtturm und eine Frage zu viel."),
|
("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):
|
def item(key, name, kind, overview, *, resume=None, series=None):
|
||||||
d = {
|
d = {
|
||||||
@@ -192,7 +201,12 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
"lib-movies": {"Movie"},
|
"lib-movies": {"Movie"},
|
||||||
"lib-shows": {"Series"},
|
"lib-shows": {"Series"},
|
||||||
}.get(eltern)
|
}.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]])
|
return self.reply([item(*t) for t in gewaehlt[:6]])
|
||||||
if p == f"/Users/{USER_ID}/Items/Resume":
|
if p == f"/Users/{USER_ID}/Items/Resume":
|
||||||
# Wie bei Jellyfin: hier steht, was eine gemerkte Stelle groesser
|
# Wie bei Jellyfin: hier steht, was eine gemerkte Stelle groesser
|
||||||
|
|||||||
Reference in New Issue
Block a user