**Antippen startet, langes Drücken führt auf die Detailseite.** Am Telefon und am iPad; am Mac bleibt der Klick die Seite, denn dort gibt es den Abspielknopf beim Überfahren und langes Drücken ist keine übliche Geste. Die Hürde war nicht die Geste, sondern das Schieben: ein `NavigationLink` schiebt selbst, ein Menüeintrag kann es nicht. Der Stapel ist deshalb ein eigener Typ mit Pfad (`MediaStack`) und reicht eine Schiebefunktion über die Umgebung nach innen — denselben Weg nimmt schon die Meldung, dass sich am Server etwas geändert hat. **Zwei Knöpfe übereinander auf der Detailseite.** Das Monogramm hing als Überzug an `mediaStack` — also über **jedem** Bildschirm dieses Stapels, auch den geschobenen, und dort über deren Drei-Punkte-Menü. Es gilt jetzt für die Startseite und endet mit ihr. **Der Kopf der Detailseite war viel zu flach.** Dort stand kein Seitenverhältnis, also galt die Vorgabe 16∶9 — während `HeroArtwork` auf einem schmalen Gerät ein **Plakat** anfordert, also hochkant. Zu sehen war ein Streifen aus der Mitte. Der Aufmacher auf der Startseite macht es seit Langem richtig; die beiden Detailseiten nicht. **Die Mediathekenleiste stand linksbündig in einer halbleeren Kapsel.** Jetzt ist sie so breit wie ihr Inhalt und mittig. `ViewThatFits` nimmt die ungescrollte Reihe, solange sie passt, sonst die scrollbare — damit steht nirgends eine Zahl, ab wann es kippt. **Und der Grund, warum die Mediathekenauswahl beim Nutzer nie griff:** Plex. Dessen Hubs sagten nicht, aus welcher Mediathek sie stammen, also warf der Filter jede Reihe weg und fiel auf „alles" zurück — ein Schalter, der nichts tut. `PlexHub` liest jetzt `librarySectionID`, als Zahl oder als Zeichenkette, je nachdem was der Server liefert. Vier Tests dazu. Das ist **kein** Wiederaufnehmen der Plex-Arbeit: es repariert eine Funktion, die dort gelogen hat. Neues kommt weiterhin nicht dazu. iOS und tvOS bauen, 476 Tests grün. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
91 lines
3.7 KiB
Swift
91 lines
3.7 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import PlexKit
|
|
|
|
/// Welche Reihe welche Kachelform bekommt.
|
|
///
|
|
/// Weiterschauen lebt vom Szenenbild — man erkennt die Stelle wieder, an der
|
|
/// man aufgehört hat. Überall sonst ist das Plakat richtig, denn danach sucht
|
|
/// man einen Film aus.
|
|
@Suite("Form der Reihen")
|
|
struct HubShapeTests {
|
|
|
|
@Test(
|
|
"Angefangenes wird als Szenenbild gezeigt",
|
|
arguments: ["home.continue", "continueWatching", "tv.ondeck", "home.ondeck"]
|
|
)
|
|
func continueWatchingUsesLandscape(identifier: String) {
|
|
#expect(PlexHub(hubIdentifier: identifier, title: "Weiterschauen").isContinueWatching)
|
|
}
|
|
|
|
@Test(
|
|
"Alles andere bekommt Plakate",
|
|
arguments: ["home.movies.recent", "movie.recentlyadded", "home.watchlist",
|
|
"movie.collection", "tv.recentlyaired"]
|
|
)
|
|
func everythingElseUsesPosters(identifier: String) {
|
|
#expect(!PlexHub(hubIdentifier: identifier, title: "Irgendeine Reihe").isContinueWatching)
|
|
}
|
|
|
|
@Test("Die Entscheidung hängt nicht am übersetzten Titel")
|
|
func titleDoesNotDecide() {
|
|
// Der Titel kommt in der Sprache des Servers. Würde er die Form
|
|
// bestimmen, sähe die Startseite auf Englisch anders aus als auf
|
|
// Deutsch — und niemand käme auf die Ursache.
|
|
let english = PlexHub(hubIdentifier: "home.continue", title: "Continue Watching")
|
|
let german = PlexHub(hubIdentifier: "home.continue", title: "Weiterschauen")
|
|
#expect(english.isContinueWatching == german.isContinueWatching)
|
|
|
|
let misleading = PlexHub(hubIdentifier: "home.movies.recent", title: "Weiterschauen")
|
|
#expect(!misleading.isContinueWatching)
|
|
}
|
|
|
|
@Test("Groß- und Kleinschreibung spielt keine Rolle")
|
|
func caseInsensitive() {
|
|
#expect(PlexHub(hubIdentifier: "Home.ContinueWatching", title: "x").isContinueWatching)
|
|
}
|
|
}
|
|
|
|
/// Aus welcher Mediathek eine Reihe stammt.
|
|
///
|
|
/// **Der Fehler, der es hierher gebracht hat.** Ohne diese Angabe kann die
|
|
/// App eine Reihe keiner Mediathek zuordnen — und die Einstellung „welche
|
|
/// Mediatheken speisen den Aufmacher" wirft dann jede Reihe weg, fällt auf
|
|
/// „alles" zurück und sieht aus wie ein Schalter, der nichts tut.
|
|
@Suite("Mediathek einer Reihe")
|
|
struct HubLibraryTests {
|
|
|
|
private func hub(_ json: String) throws -> PlexHub {
|
|
try JSONDecoder().decode(PlexHub.self, from: Data(json.utf8))
|
|
}
|
|
|
|
/// Plex liefert die Abschnittsnummer je nach Endpunkt als Zahl oder als
|
|
/// Zeichenkette. Nur eines zu lesen hiesse: geht auf manchen Servern und
|
|
/// auf anderen nicht, und zwar lautlos.
|
|
@Test("Die Nummer kommt als Zahl")
|
|
func readsNumber() throws {
|
|
let reihe = try hub(#"{"hubIdentifier":"movie.recentlyadded","title":"Neu","librarySectionID":3}"#)
|
|
#expect(reihe.librarySectionID == "3")
|
|
}
|
|
|
|
@Test("Die Nummer kommt als Zeichenkette")
|
|
func readsString() throws {
|
|
let reihe = try hub(#"{"hubIdentifier":"movie.recentlyadded","title":"Neu","librarySectionID":"3"}"#)
|
|
#expect(reihe.librarySectionID == "3")
|
|
}
|
|
|
|
/// „Fortsetzen" geht quer durch alle Mediatheken; Plex nennt dort keine
|
|
/// Nummer. Das ist kein Fehler, sondern die richtige Auskunft.
|
|
@Test("Übergreifende Reihen nennen keine")
|
|
func crossLibraryHasNone() throws {
|
|
let reihe = try hub(#"{"hubIdentifier":"home.continue","title":"Fortsetzen"}"#)
|
|
#expect(reihe.librarySectionID == nil)
|
|
}
|
|
|
|
@Test("Die Reihe reicht sie weiter")
|
|
func rowCarriesIt() throws {
|
|
let reihe = try hub(#"{"hubIdentifier":"movie.recentlyadded","title":"Neu","librarySectionID":7}"#)
|
|
#expect(reihe.asMediaRowGroup.libraryID == "7")
|
|
}
|
|
}
|