Der dritte Modus neben Raster und Senderliste — und der einzige, den es
nicht überall gibt. Bei Plex fehlt schlicht der Schalter dorthin, denn
supportsRecordings fragt die eigene Fähigkeit ab.
Vormerken sitzt im Blatt, das eine angetippte Sendung ohnehin schon
öffnet, statt in einem zweiten Kontextmenü daneben. Trägt die Sendung
bereits einen Serien-Timer, steht dort das statt der Knöpfe: zweimal
vormerken ist kein Wunsch, sondern ein Versehen.
Aufnahmen führen über die Detailseite statt unmittelbar in den Player.
Eine Aufnahme ist auf dem Server ein gewöhnlicher Eintrag, und erst dort
steht, in welchen Fassungen sie vorliegt — von der Liste aus zu starten
hieße, das zu raten.
Zwölf Schlüssel in DE und EN. Die Übersetzungsdatei ist dabei auf das
Format zurückgeschrieben worden, das auch im letzten Commit steht;
inhaltlich ist sie HEAD plus diese zwölf, nachgerechnet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Keine Datei unter Views/LiveTV importiert noch PlexKit. Sender, Programm
und Einschalten laufen über den neutralen Vertrag, und supportsLiveTV
fragt endlich die Fähigkeit ab statt "server != nil" — womit die Zusage
in JellyfinBackend.capabilities zum ersten Mal stimmt.
Der Player holt die laufende Sendung jetzt für genau einen Sender nach.
Vorher ging dafür das Raster über alle Sender hinaus, weil der Plex-Weg
keinen schmaleren kannte; im neutralen Vertrag ist die Senderliste ein
Parameter.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drei Gründe, warum der Mac anders aussah, und keiner davon war Geschmack.
**Die Schrift.** macOS rendert dieselben Textstile deutlich kleiner als iOS:
`largeTitle` misst dort 26 Punkt statt 34, Fließtext 13 statt 17. Eine
Oberfläche, die auf dem iPad stimmt, wirkt damit zusammengeschrumpft. Auf dem
Mac stehen jetzt feste Größen — die von iOS. Das kostet dort Dynamic Type;
vertretbar, weil macOS keine systemweite Textgröße kennt und man ein Fenster
stattdessen größer ziehen kann.
**Der Aufmacher wächst mit.** Das war der zweite, größere Teil: das Bild ist so
breit wie das Fenster, die Schrift darauf war es nicht. Bei 1280 Punkt Breite
wirkt ein 34-Punkt-Titel verloren, bei 834 auf dem iPad genau richtig. Titel,
Schriftzug, Angaben und Abstände richten sich jetzt nach der Breite des
Aufmachers — mit dem iPad als Bezug und einem Deckel, damit ein Fenster über
die ganze Wand nicht in Plakatschrift endet. Die Beschreibung bekommt
außerdem eine Zeilenbreite: ein Satz über 1280 Punkt ist unlesbar, das Auge
verliert die Zeile.
**Die Seitenleiste.** Sie richtet sich nach ihrem Inhalt, und bei Wörtern wie
„Start" fällt sie auf eine Breite zusammen, in der schon der Kontoname darunter
nicht mehr Platz hatte — daher das „S…". Die Beschriftungen haben jetzt eine
Mindestbreite.
**Die Formulare.** Auf dem Mac nahm SwiftUI den Spalten-Stil: Beschriftungen
rechts ausgerichtet, keine abgesetzten Abschnitte. Jetzt derselbe gruppierte
Stil wie auf iOS.
Dazu: Scrollbalken sind weg. Der graue Streifen unter dem Aufmacher kam daher,
dass in den Systemeinstellungen „Scrollbalken immer einblenden" steht —
dagegen reicht `.hidden` nicht, `.never` schon. Und das Fenster öffnet mit
1280 × 820 statt in Notizzettelgröße, ohne graue Titelleiste.
263 Tests grün, iOS baut unverändert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Und dein Argument dafür war das beste: auf dem Mac kann ich selbst hinsehen.
Kein Simulator-Tunnel, der mitten im Prüfen abstürzt — `screencapture` auf das
Fenster der App, und zwar nur auf ihres, nicht auf den Bildschirm.
**Ein eigenes Ziel, nicht ein gemeinsames.** Die Info.plist der iOS-App ist
voller iOS-Angaben: Startbildschirm, erlaubte Ausrichtungen, Live Activities.
Die alle bedingt zu machen hieße, dass jede spätere Änderung an der iOS-Seite
über eine Stelle geht, die auch den Mac betrifft. Zwei Ziele sind ein paar
Zeilen mehr und eine Sorge weniger.
**Was den Unterschied ausmacht, steht an einer Stelle.** Ein neuer
`PlatformShims` in FlixyDesign übersetzt, was auf beiden Seiten verschieden
heißt: schmale Titelzeile, halbhohes Blatt, Eingabefelder ohne
Großschreibung, die Plätze in der Werkzeugleiste, die Zwischenablage. Zwanzig
Ansichten benutzen ihn, statt zwanzigmal `#if os(iOS)` zu tragen — sonst
wandert die Fallunterscheidung in jede neue Datei und wird beim übernächsten
Bildschirm vergessen.
Wirklich verschieden sind nur fünf Stellen: die Bildfläche (`UIView` gegen
`NSView`), der AirPlay-Knopf, die Ausrichtungssperre (auf dem Mac gibt es
nichts zu sperren), der App-Delegat für Hintergrund-Downloads und das
Anmeldefenster, das ein anderes Fenster als Anker braucht.
**Das Karussell blättert jetzt mit einem einrastenden Streifen** statt mit
`TabView(.page)` — den Seitenstil gibt es auf dem Mac nicht. Das ist nebenbei
die bessere Lösung: das verschachtelte TabView hatte die Eigenschaft, beim
Wechsel kurz zwei Seiten gleichzeitig zu zeigen.
**Was auf dem Mac fehlt und warum:** VLC. Das Binärpaket ist auf iOS
festgelegt; sein xcframework enthält zwar Mac-Teile, aber das ist eine eigene
Runde. Solange fällt die Wiedergabe dort auf den Systemplayer zurück — MKV und
DTS gehen also noch nicht. Live Activities gibt es auf dem Mac nicht, Bild-in-
Bild startet von Hand statt beim Verlassen der App.
Gesehen: die App startet, der Anmeldebildschirm steht, beide Wege sind da.
Angemeldet habe ich mich auf dem Mac **nicht** — das ginge nur, indem ich
einen Token in deinen Schlüsselbund schreibe, und dann fragt macOS dich beim
ersten Zugriff nach dem Passwort. Das machst du mit einem Klick selbst.
iOS baut unverändert, 263 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drei Fehler, alle im eigenen Code.
Die Sendezeiten stehen beim Programmanbieter im Medien-Block, nicht am
Eintrag darüber. Ich habe sie oben gesucht, nicht gefunden und jede
Sendung verworfen — übrig blieb „Kein Programm verfügbar" auf jedem
Sender, und ohne Sendungen fiel auch die Senderliste auf die Tunerliste
zurück.
Die Senderspalte im Raster fehlte ganz. Die Zeitachse ist mehrere tausend
Punkte breit, und der HStack hat den Nachbarn dafür auf null gedrückt.
Jetzt hat die Spalte Vorrang, und die Achse liegt als Auflage über einer
durchsichtigen Fläche — eine Auflage zählt bei der Größenrechnung nicht
mit. Der Abstand der Achsenbeschriftung gehört in die Spaltenbreite
hinein statt daneben, sonst steht die ganze Achse acht Punkte neben dem
Programm darunter.
Und das Einschalten: die Adresse wurde berechnet und verworfen, dann
bekam der Player eine Senderkennung, zu der er einen Film in der
Mediathek suchte. Den gibt es nicht. Jetzt reicht die Anfrage die fertige
Adresse durch, der Player spielt sie ohne Umweg, und meldet weder
Fortschritt noch sucht er Metadaten. Scheitert es doch, steht ab jetzt
eine Meldung da statt gar nichts.
Geprüft wurde das Raster diesmal mit den Augen: ein Gerüst im Simulator
zeichnet es mit erfundenen Sendern. Dafür bekommt es die Bildadresse als
Abschluss übergeben, statt sie aus der Sitzung zu lesen.
Dazu: Downloads zeigen jetzt an, wenn sie auf WLAN warten. Die
Hintergrund-Sitzung wartet in dem Fall von sich aus — kein Fehler, nur
Stillstand, und das sah bisher aus wie ein hängender Download.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Abzug vom Server zeigt beides schwarz auf weiß.
Erstens: /media/grabbers/devices/1/channels antwortet mit 278 Sendern —
unter dem Sammelnamen `DeviceChannel`. Die Hülle kannte nur `Channel` und
hat die vollständige Liste als leer verworfen.
Zweitens: das Programmraster antwortet, aber nicht auf `type=1`. Die 1
steht bei Plex für Film, und im Programm laufen auch Folgen, Sport und
Nachrichten — der Filter hat das Raster geleert. Ohne ihn kommen die
Sendungen samt Sendername, Nummer, Logo und Kennung.
Das Raster hat jetzt Vorrang vor der Tunerliste, auch wenn beide
antworten: nur dort gehören Sender und Programm zusammen, es enthält
ohnehin nur die eingeschalteten Sender, und die Tunerliste führt alle 278.
Einschalten läuft über die Adresse der laufenden Sendung beim
Programmanbieter — Plex behandelt eine laufende Sendung wie einen Film.
Die Adresse wird einmal entpackt, bevor sie in die Anfrage geht: sonst
kodiert URLComponents ein zweites Mal, und aus %3A wird %253A.
Die Tests stehen jetzt auf den echten Antworten aus dem Abzug, nicht auf
erfundenen: DeviceChannel mit `name` und `key`, Rastereinträge mit
channelVcn, channelID und einer Folge neben einem Film.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drei geratene Adressen für die Senderliste antworteten auf einem echten
Server alle mit 404. Statt ein viertes Mal zu raten, liest die App jetzt
zwei Dinge: was /media/providers an Endpunkten angibt, und das
Programmraster selbst — die Weboberfläche von Plex zeichnet ihren Guide
daraus, und jeder Rastereintrag trägt Sendername, Nummer, Logo und
Einschaltweg mit sich.
Damit kommen Sender und Programm aus einer Abfrage, und ihre Kennungen
passen zueinander. Getrennt geholt taten sie das nicht: das Programm
landete in keiner Zeile.
Dazu die Ansicht, für die das alles da ist — ein Programmraster mit
stehender Senderspalte, mitlaufender Zeitachse und einer Jetzt-Linie.
Antippen öffnet die Sendung; läuft sie gerade, schaltet ein Knopf um.
Die Geometrie steht in GuideLayout und ist geprüft: in einer View wäre
sie unsichtbar falsch. Die Trennlinien gehören in die Zeile statt
zwischen die Zeilen — Divider ist auf 3x-Schirmen keinen ganzen Punkt
hoch, und der Bruchteil summiert sich, bis die angetippte Zeile zum
Nachbarsender gehört.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>