Start, Suche, Mediathek, Detailseiten und Downloads arbeiten jetzt mit `MediaItem` und dem `MediaBackend`-Vertrag. Damit sind sie fertig für einen zweiten Server, ohne dass an ihnen noch etwas zu tun wäre. Dabei sind ein paar Namen ehrlicher geworden: aus `grandparentTitle` wurde `seriesTitle`, aus `viewedLeafCount` `playedEpisodeCount`. Und `TagStrip` nahm bisher Plex-Marken mit Kennung und Rolle entgegen, um davon nur den Namen anzuzeigen — Genres sind jetzt schlicht Zeichenketten. `Arrangement` ist aus PlexKit heraus und generisch: dieselbe Rechnung gilt für jede Liste, die jemand selbst zusammenstellt. Phase 3 baut die konfigurierbare Seitenleiste darauf, statt sie ein zweites Mal — und ein zweites Mal falsch — zu schreiben. Die Fehlerübersetzung gibt es nur noch einmal. Es waren zwei, und sie waren bereits auseinandergelaufen: derselbe Fehler bekam je nach Bildschirm eine andere Erklärung. Das Nachladen der Mediathek bleibt unangetastet: eine lange Liste, die fünf Einträge vor dem Ende nachlädt. `MediaPage` heißt zwar Seite, ist aber eine technische Portion — Blättern mit „weiter zu Seite 2" gehört nicht in eine Mediathek, in der man stöbert. Der Kommentar dort sagt das jetzt ausdrücklich, damit es niemand später „aufräumt". Player, Live-TV und die Download-Engine sprechen noch unmittelbar mit Plex. Sie folgen als Nächstes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
105 lines
4.5 KiB
Swift
105 lines
4.5 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import MediaKit
|
|
|
|
private func hub(_ identifier: String) -> MediaRowGroup {
|
|
MediaRowGroup(id: identifier, title: identifier.capitalized)
|
|
}
|
|
|
|
@Suite("Anordnung der Startseiten-Reihen")
|
|
struct ArrangementTests {
|
|
private let serverHubs = [hub("continue"), hub("recent"), hub("watchlist"), hub("collections")]
|
|
|
|
@Test("Ohne Einstellungen bleibt die Reihenfolge des Servers")
|
|
func defaultKeepsServerOrder() {
|
|
let result = Arrangement().apply(to: serverHubs)
|
|
#expect(result.map(\.id) == ["continue", "recent", "watchlist", "collections"])
|
|
}
|
|
|
|
@Test("Ausgeblendete Reihen verschwinden")
|
|
func hiddenRowsAreRemoved() {
|
|
let arrangement = Arrangement(hidden: ["watchlist", "collections"])
|
|
let result = arrangement.apply(to: serverHubs)
|
|
#expect(result.map(\.id) == ["continue", "recent"])
|
|
}
|
|
|
|
@Test("Die gespeicherte Reihenfolge wird angewendet")
|
|
func storedOrderIsApplied() {
|
|
let arrangement = Arrangement(order: ["watchlist", "continue", "recent", "collections"])
|
|
let result = arrangement.apply(to: serverHubs)
|
|
#expect(result.map(\.id) == ["watchlist", "continue", "recent", "collections"])
|
|
}
|
|
|
|
@Test("Neue Reihen vom Server landen am Ende statt zu verschwinden")
|
|
func unknownRowsAppearAtTheEnd() {
|
|
// Der Fall, der die einfachere Regel — nur Bekanntes anzeigen — zur
|
|
// Falle macht: ein neu angelegtes Regal auf dem Server wäre in der App
|
|
// nie aufgetaucht, ohne dass jemand den Grund gesehen hätte.
|
|
let arrangement = Arrangement(order: ["recent", "continue"])
|
|
let result = arrangement.apply(to: serverHubs)
|
|
#expect(result.map(\.id) == ["recent", "continue", "watchlist", "collections"])
|
|
}
|
|
|
|
@Test("Mehrere neue Reihen behalten die Reihenfolge des Servers")
|
|
func multipleUnknownRowsKeepServerOrder() {
|
|
// Ohne stabile Rückfalllinie wäre ihre Anordnung zufällig — und
|
|
// änderte sich bei jedem Start.
|
|
let arrangement = Arrangement(order: ["collections"])
|
|
let result = arrangement.apply(to: serverHubs)
|
|
#expect(result.map(\.id) == ["collections", "continue", "recent", "watchlist"])
|
|
}
|
|
|
|
@Test("Gespeicherte Reihen, die es nicht mehr gibt, stören nicht")
|
|
func staleOrderEntriesAreIgnored() {
|
|
// Entsteht beim Löschen einer Mediathek auf dem Server.
|
|
let arrangement = Arrangement(order: ["geloescht", "recent", "continue"])
|
|
let result = arrangement.apply(to: serverHubs)
|
|
#expect(result.map(\.id) == ["recent", "continue", "watchlist", "collections"])
|
|
}
|
|
|
|
@Test("Ein doppelter Eintrag in der Reihenfolge stürzt nicht ab")
|
|
func duplicateOrderEntriesAreTolerated() {
|
|
// Kann nach einem abgebrochenen Schreibvorgang entstehen. Ein
|
|
// Dictionary aus doppelten Schlüsseln wäre ein harter Absturz.
|
|
let arrangement = Arrangement(order: ["recent", "recent", "continue"])
|
|
let result = arrangement.apply(to: serverHubs)
|
|
#expect(result.first?.id == "recent")
|
|
#expect(result.count == 4)
|
|
}
|
|
|
|
@Test("Ausblenden und Sortieren greifen zusammen")
|
|
func hidingAndOrderingCombine() {
|
|
let arrangement = Arrangement(
|
|
hidden: ["recent"],
|
|
order: ["collections", "recent", "continue"]
|
|
)
|
|
let result = arrangement.apply(to: serverHubs)
|
|
#expect(result.map(\.id) == ["collections", "continue", "watchlist"])
|
|
}
|
|
|
|
// MARK: - Die Liste für die Einstellungen
|
|
|
|
@Test("Der Einstellungsbildschirm zeigt Gespeichertes zuerst")
|
|
func settingsListPutsStoredFirst() {
|
|
let arrangement = Arrangement(order: ["watchlist", "continue"])
|
|
let identifiers = arrangement.arrangedIdentifiers(from: serverHubs)
|
|
#expect(identifiers == ["watchlist", "continue", "recent", "collections"])
|
|
}
|
|
|
|
@Test("Der Einstellungsbildschirm zeigt auch ausgeblendete Reihen")
|
|
func settingsListIncludesHidden() {
|
|
// Sonst ließe sich eine einmal ausgeblendete Reihe nie wieder
|
|
// einschalten — eine Einbahnstraße.
|
|
let arrangement = Arrangement(hidden: ["recent"])
|
|
let identifiers = arrangement.arrangedIdentifiers(from: serverHubs)
|
|
#expect(identifiers.contains("recent"))
|
|
}
|
|
|
|
@Test("Verschwundene Reihen erscheinen nicht in den Einstellungen")
|
|
func settingsListDropsStaleEntries() {
|
|
let arrangement = Arrangement(order: ["geloescht", "recent"])
|
|
let identifiers = arrangement.arrangedIdentifiers(from: serverHubs)
|
|
#expect(!identifiers.contains("geloescht"))
|
|
}
|
|
}
|