Der Klick in den schwarzen Rand trifft jetzt den schwarzen Rand

Er hat weiterhin angehalten statt ein- und auszublenden, und der Grund
steckte in der Rechnung: der schwarze Rand wurde aus der Fenstergrösse
ausgerechnet, das Bild liegt aber in einer Fläche mit `ignoresSafeArea()`.
Auf dem Mac ist der Einzug der Fensterleiste genau der Unterschied
zwischen beiden — die Rechnung lag um diesen Betrag daneben.

Jetzt wird die Bildfläche gemessen statt angenommen, und beide Zahlen
stehen in einem gemeinsamen, benannten Koordinatenraum. Vor allem aber
wird zuerst `AVPlayerLayer.videoRect` gefragt: der Player weiss selbst,
wo Bild steht. Die eigene Rechnung bleibt für den Moment vor dem ersten
Bild und für VLC, das keine solche Ebene hat.

Dazu zwei Worte: „Nachschub" heisst jetzt „Nachladen", und „Blatt" heisst
wieder „Sheet" — das ist ein Fachbegriff und bleibt englisch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-28 06:49:15 +02:00
co-authored by Claude Opus 5
parent f47c6385e3
commit 18958aadbc
17 changed files with 4234 additions and 4190 deletions
@@ -46,14 +46,14 @@ extension View {
#endif
}
/// Ein Blatt, das die halbe Höhe einnimmt.
/// Ein Sheet, das die halbe Höhe einnimmt.
///
/// Auf dem Mac ist ein Blatt ein Fenster: dort zählt keine Rastung,
/// Auf dem Mac ist ein Sheet ein Fenster: dort zählt keine Rastung,
/// sondern eine vernünftige Mindestgröße.
public func flixyMediumSheet() -> some View {
// **Zur Laufzeit, nicht beim Übersetzen.** Der `#else`-Zweig für
// macOS griff nie: auf dem Mac läuft der iOS-Bau, und damit bekam ein
// grosses Fenster eine Blattkante in iPhone-Höhe — ein schmaler
// grosses Fenster eine Sheet-Kante in iPhone-Höhe — ein schmaler
// Streifen, der unten im Nichts klebt.
presentationDetents(FlixyPlatform.isMac ? [.large] : [.medium])
}
@@ -220,7 +220,7 @@ extension JellyfinBackend: LiveTVBackend {
channelID: channelID,
title: item.name ?? "—",
// `EpisodeTitle` und nicht `Name`: hier stand der Reihentitel ein
// zweites Mal, und im Blatt hätte derselbe Satz zweimal
// zweites Mal, und im Sheet hätte derselbe Satz zweimal
// untereinander gestanden.
subtitle: item.episodeTitle,
summary: item.overview,
@@ -60,7 +60,7 @@ public struct TranscodeSettings: Sendable, Equatable {
/// angegebene Bitrate bleibt dabei die **oberste** Sprosse; was darunter
/// liegt, erfindet der Server.
///
/// Nur bei `automatic` gesetzt. Wer im Blatt ausdrücklich „720p · 3 Mbps"
/// Nur bei `automatic` gesetzt. Wer im Sheet ausdrücklich „720p · 3 Mbps"
/// antippt, soll das bekommen und nicht „höchstens 3, meistens weniger"
/// unter unverändertem Etikett.
public let prefersAdaptive: Bool
@@ -94,7 +94,7 @@ public actor PlexAuthenticator {
do {
try await clock.sleep(for: pollInterval)
} catch {
// Abbruch durch die Oberfläche, etwa weil das Anmeldeblatt
// Abbruch durch die Oberfläche, etwa weil das Anmelde-Sheet
// geschlossen wurde. Kein Fehlerfall.
throw .transport(description: "Anmeldung abgebrochen")
}
@@ -77,14 +77,14 @@ struct LibraryQueryTests {
@Suite("Seitenweises Nachladen")
struct PlexPageTests {
@Test("Eine volle Seite kündigt Nachschub an")
@Test("Eine volle Seite kündigt weitere Titel an")
func fullPageHasMore() {
let page = PlexPage(items: Array(0..<60), offset: 0, totalSize: 250)
#expect(page.hasMore)
#expect(page.nextOffset == 60)
}
@Test("Die letzte Seite kündigt keinen Nachschub an")
@Test("Die letzte Seite kündigt keine weiteren Titel an")
func lastPageHasNoMore() {
// Genau die Bedingung, die sonst zu einer Endlosschleife führt: die
// Ansicht lädt nach, bekommt nichts, lädt wieder nach.