Antippen spielt ab — und vier Dinge, die daneben lagen
**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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1fa8011094
commit
a665d79e6d
@@ -180,6 +180,7 @@ extension PlexHub {
|
||||
id: hubIdentifier,
|
||||
title: title,
|
||||
moreKey: more == true ? key : nil,
|
||||
libraryID: librarySectionID,
|
||||
items: items.map(\.asMediaItem)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -63,6 +63,17 @@ public struct PlexHub: Sendable, Equatable, Decodable, Identifiable {
|
||||
/// Ob es mehr Einträge gibt, als die Reihe zeigt — Grundlage für ein
|
||||
/// „Alle anzeigen" am Ende.
|
||||
public let more: Bool
|
||||
/// Aus welcher Mediathek diese Reihe stammt.
|
||||
///
|
||||
/// `nil` bei den übergreifenden Reihen — „Fortsetzen" geht quer durch
|
||||
/// alle, und Plex nennt dort keine Nummer.
|
||||
///
|
||||
/// **Warum es überhaupt gelesen wird.** Ohne diese Angabe kann die App
|
||||
/// eine Reihe keiner Mediathek zuordnen, und die Auswahl „welche
|
||||
/// Mediatheken speisen den Aufmacher" greift ins Leere: sie wirft dann
|
||||
/// jede Reihe weg, fällt auf „alles" zurück und sieht aus wie ein
|
||||
/// Schalter, der nichts tut. Genau so war es.
|
||||
public let librarySectionID: String?
|
||||
public let items: [PlexItem]
|
||||
|
||||
public var id: String { hubIdentifier }
|
||||
@@ -84,7 +95,7 @@ public struct PlexHub: Sendable, Equatable, Decodable, Identifiable {
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case hubIdentifier, title, type, key, size, more
|
||||
case hubIdentifier, title, type, key, size, more, librarySectionID
|
||||
case items = "Metadata"
|
||||
}
|
||||
|
||||
@@ -99,6 +110,15 @@ public struct PlexHub: Sendable, Equatable, Decodable, Identifiable {
|
||||
self.key = try values.decodeIfPresent(String.self, forKey: .key)
|
||||
self.size = try values.decodeIfPresent(Int.self, forKey: .size)
|
||||
self.more = try values.decodeIfPresent(Bool.self, forKey: .more) ?? false
|
||||
// **Zahl oder Zeichenkette.** Plex liefert die Abschnittsnummer je
|
||||
// nach Endpunkt mal als `3`, mal als `"3"`. Nur eines davon zu lesen
|
||||
// hiesse, dass es auf manchen Servern geht und auf anderen nicht —
|
||||
// und zwar lautlos, denn eine fehlende Nummer ist ein gültiger Fall.
|
||||
if let zahl = try? values.decodeIfPresent(Int.self, forKey: .librarySectionID) {
|
||||
self.librarySectionID = String(zahl)
|
||||
} else {
|
||||
self.librarySectionID = try values.decodeIfPresent(String.self, forKey: .librarySectionID)
|
||||
}
|
||||
self.items = try values.decodeIfPresent([PlexItem].self, forKey: .items) ?? []
|
||||
}
|
||||
|
||||
@@ -109,9 +129,11 @@ public struct PlexHub: Sendable, Equatable, Decodable, Identifiable {
|
||||
key: String? = nil,
|
||||
size: Int? = nil,
|
||||
more: Bool = false,
|
||||
librarySectionID: String? = nil,
|
||||
items: [PlexItem] = []
|
||||
) {
|
||||
self.hubIdentifier = hubIdentifier
|
||||
self.librarySectionID = librarySectionID
|
||||
self.title = title
|
||||
self.type = type
|
||||
self.key = key
|
||||
|
||||
@@ -45,3 +45,46 @@ struct HubShapeTests {
|
||||
#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")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user