Bei VLC sass das Bild nie richtig — und der Knopf wirkte nie

Zwei Fehler, die dieselbe Ursache haben: alles, was über VLC läuft, ging
an der Bildebene vorbei, an der die App gedreht hat.

**Das Bild sass nicht mittig.** Nicht ein paar Punkte daneben — gemessen
eine Anzeigefläche von 1200×480 Punkt in einer Zeichenfläche von 711×400,
unten rechts angeschlagen, im falschen Seitenverhältnis. Der Grund steht
im Vertrag von `VLCDrawable`: VLCKit fragt die Grösse **einmal** beim
Anlegen ab und überlässt seine Anzeigefläche danach der
Autoresizing-Maske. Eine Maske hält aber den Unterschied fest, nicht das
Verhältnis — was beim Anlegen zu gross war, bleibt für immer um denselben
Betrag zu gross. Und angelegt wird sie mitten in der Drehung ins
Querformat, während SwiftUI sie einblendet: also regelmässig falsch.

Die Zeichenfläche ist jetzt eine eigene Klasse, die ihrer Anzeigefläche
bei jedem Layout wieder die eigene Grösse gibt. Danach gemessen: 695,7 ×
400 Punkt, Rand links 130,0, rechts 130,3 — mittig.

**Der Knopf für einpassen/füllen tat nichts.** Er schrieb `videoGravity`
auf eine `AVPlayerLayer`, die bei VLC gar nicht im Baum hängt. Die
Einstellung geht deshalb jetzt durch die Engine: `setVideoFit` am
Protokoll, beim Systemplayer eine Voreinstellung, die nichts tut — dort
macht es die Bildebene —, bei VLC `videoFitMode`. `smaller` heisst bei
libvlc „fit inside", `larger` „fit outside".

Gemessen, im Querformat auf einem Pro Max, über VLC:

    eingepasst   695,7 × 400 pt   Rand l/r 130,0/130,3   o/u 20,0/20,0
    füllend      935,3 × 440 pt   Rand l/r  10,3/ 10,3   o/u  0,0/ 0,0

**Zurückgenommen:** im Kommentar an `videoFit` stand, ein `didSet` auf
einer `@Observable`-Klasse werde nicht gemeldet. Das stimmt nicht —
`HomeLayoutSettings` lebt davon. Ein Kommentar, der einen falschen
Mechanismus behauptet, schickt den nächsten in die falsche Richtung;
jetzt steht der belegte Grund dort.

Dazu, damit dieser Weg überhaupt prüfbar ist: die Attrappe meldet mit
`--vlc` DTS-Ton. AVFoundation kann das nicht, also fällt die App auf
VLCKit zurück. Die Beispieldatei bleibt dieselbe — geprüft wird der Weg,
nicht der Ton. Ohne diesen Schalter ist der VLC-Zweig im Simulator gar
nicht zu erreichen, und genau deshalb lagen beide Fehler so lange da.

Ebenfalls dabei: `EdgeInsets.symmetrical` mit fünf Tests und das Polster
im Player, das damit nicht mehr verschiebt statt einrückt.

iOS und tvOS bauen, 465 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-30 21:05:57 +02:00
co-authored by Claude Opus 5
parent 51abcabb27
commit b0db4f8f5f
8 changed files with 229 additions and 15 deletions
@@ -0,0 +1,58 @@
import SwiftUI
import Testing
@testable import FlixyDesign
@Suite("Ränder gleichmachen")
struct SymmetricInsetsTests {
/// **Der Fall aus dem Querformat.** Notch links, nichts rechts — mit den
/// rohen Werten stünde das Bild einunddreissig Punkte zu weit rechts.
@Test("Die Notch-Seite bestimmt beide Seiten")
func landscapeNotch() {
let roh = EdgeInsets(top: 0, leading: 62, bottom: 21, trailing: 0)
let gleich = roh.symmetrical
#expect(gleich.leading == 62)
#expect(gleich.trailing == 62)
#expect(gleich.top == 21)
#expect(gleich.bottom == 21)
}
/// Und aus dem Hochformat: oben zweiundsechzig, unten vierunddreissig.
@Test("Oben und unten wird der grössere genommen")
func portrait() {
let gleich = EdgeInsets(top: 62, leading: 0, bottom: 34, trailing: 0).symmetrical
#expect(gleich.top == 62)
#expect(gleich.bottom == 62)
#expect(gleich.leading == 0)
#expect(gleich.trailing == 0)
}
/// Was schon gleich ist, bleibt gleich — sonst würde die Rechnung auf
/// einem iPad ohne Notch Balken erfinden, wo keine hingehören.
@Test("Symmetrisches bleibt unverändert")
func alreadySymmetric() {
let roh = EdgeInsets(top: 20, leading: 50, bottom: 20, trailing: 50)
#expect(roh.symmetrical == roh)
}
@Test("Ohne Ränder bleibt es ohne")
func zero() {
let gleich = EdgeInsets().symmetrical
#expect(gleich == EdgeInsets())
}
/// **Die Zusage, auf die es ankommt.** Egal wie schief der Rand ankommt —
/// danach ist die Mitte des verbleibenden Platzes die Mitte des Schirms.
@Test("Die Mitte bleibt die Mitte")
func centreStaysCentred() {
for roh in [
EdgeInsets(top: 0, leading: 62, bottom: 21, trailing: 0),
EdgeInsets(top: 62, leading: 0, bottom: 34, trailing: 0),
EdgeInsets(top: 5, leading: 1, bottom: 99, trailing: 40),
] {
let g = roh.symmetrical
#expect(g.leading - g.trailing == 0)
#expect(g.top - g.bottom == 0)
}
}
}