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:
Scarriffle
2026-10-01 10:39:45 +02:00
co-authored by Claude Opus 5
parent 1fa8011094
commit a665d79e6d
9 changed files with 219 additions and 39 deletions
@@ -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