Zwei Fehler um dieselbe Bildfläche

**Die Wiedergabe sprang von selbst wieder an.** Auf dem Mac pausiert ein
Klick ins Bild — und der Klick, mit dem man ein Fenster nach vorn holt,
kommt ebenfalls dort an. Man aktiviert das Fenster und drückt dabei auf
Play. Klicks innerhalb einer Viertelsekunde nach dem Aktivieren zählen
deshalb nicht: länger braucht niemand bis zum ersten gemeinten Klick,
kürzer erwischt den Fall nicht.

**Schwarzbild mit Ton nach dem Vergrössern.** Kachel und Vollbild
bestehen beim Wechsel kurz gleichzeitig, und beide holten sich dieselbe
Bildfläche in ihre Hülle. Eine Ansicht hat aber nur einen Vorgesetzten —
wer zuletzt aktualisiert, gewinnt, und das war nicht verlässlich die
richtige. Blieb die Fläche bei der Kachel, die gleich darauf verschwand,
lief im Vollbild der Ton weiter und das Bild blieb schwarz.

Die Hülle allein genügte nicht: sie verhindert, dass das Abräumen der
einen Ansicht der anderen etwas wegnimmt, entscheidet aber nicht, wer
die Fläche bekommen **soll**. Das sagt jetzt `isActive` — abgeleitet aus
`playback.presentation`, also aus derselben Quelle, die auch bestimmt,
welche Ansicht überhaupt zu sehen ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-27 18:44:20 +02:00
co-authored by Claude Opus 5
parent 348ec96282
commit 279d8e36ae
3 changed files with 59 additions and 9 deletions
+26 -7
View File
@@ -38,18 +38,32 @@ struct VideoSurface: View {
/// hier ist es jetzt derselbe Weg.
let surface: PlayerLayerView
/// Ob **diese** Ansicht die Bildfläche gerade haben soll.
///
/// **Der Kern des Schwarzbilds.** Kachel und Vollbild bestehen beim
/// Wechsel kurz gleichzeitig, und beide holen sich die Fläche in ihre
/// Hülle. Eine Ansicht hat aber nur einen Vorgesetzten — wer zuletzt
/// aktualisiert, gewinnt, und das war nicht verlässlich die richtige.
/// Blieb die Fläche bei der Kachel, die gleich darauf verschwand, lief
/// im Vollbild der Ton weiter und das Bild blieb schwarz.
///
/// Die Hülle allein genügte dagegen nicht: sie verhindert, dass das
/// Abräumen der einen der anderen etwas wegnimmt, entscheidet aber
/// nicht, wer sie bekommen **soll**. Das steht hier.
var isActive = true
var body: some View {
#if canImport(FlixyVLC)
if let vlcEngine = engine as? VLCPlayerEngine {
SurfaceContainer(view: vlcEngine.videoView)
SurfaceContainer(view: vlcEngine.videoView, isActive: isActive)
} else if engine is AVPlayerEngine {
SurfaceContainer(view: surface)
SurfaceContainer(view: surface, isActive: isActive)
} else {
Color.black
}
#else
if engine is AVPlayerEngine {
SurfaceContainer(view: surface)
SurfaceContainer(view: surface, isActive: isActive)
} else {
Color.black
}
@@ -106,33 +120,38 @@ final class PlayerLayerView: NSView {
#if canImport(UIKit)
private struct SurfaceContainer: UIViewRepresentable {
let view: PlatformView
let isActive: Bool
func makeUIView(context: Context) -> PlatformView {
let host = UIView()
host.backgroundColor = .black
adopt(view, into: host)
if isActive { adopt(view, into: host) }
return host
}
func updateUIView(_ host: PlatformView, context: Context) {
guard view.superview !== host else { return }
// Wer nicht dran ist, greift auch nicht zu. Ohne diese Zeile holen
// sich beide Ansichten dieselbe Fläche, und die Reihenfolge
// entscheidet — mal richtig, mal schwarz.
guard isActive, view.superview !== host else { return }
adopt(view, into: host)
}
}
#else
private struct SurfaceContainer: NSViewRepresentable {
let view: PlatformView
let isActive: Bool
func makeNSView(context: Context) -> PlatformView {
let host = NSView()
host.wantsLayer = true
host.layer?.backgroundColor = NSColor.black.cgColor
adopt(view, into: host)
if isActive { adopt(view, into: host) }
return host
}
func updateNSView(_ host: PlatformView, context: Context) {
guard view.superview !== host else { return }
guard isActive, view.superview !== host else { return }
adopt(view, into: host)
}
}