diff --git a/Flixy/Views/Player/PlayerView.swift b/Flixy/Views/Player/PlayerView.swift index 36211ae..e00f1b9 100644 --- a/Flixy/Views/Player/PlayerView.swift +++ b/Flixy/Views/Player/PlayerView.swift @@ -242,6 +242,17 @@ struct PlayerView: View { safeArea = ScreenSafeArea.current } .onAppear { safeArea = ScreenSafeArea.current } + // **Auch beim Zurückholen der App.** Eine Drehung im Hintergrund + // ändert die Fläche, ohne dass `onGeometryChange` hier feuert — die + // Ansicht ist dann gar nicht sichtbar. Wer die App danach quer + // wiederfindet, hätte sonst die Ränder von vorhin. + .onReceive( + NotificationCenter.default.publisher( + for: UIApplication.didBecomeActiveNotification + ) + ) { _ in + safeArea = ScreenSafeArea.current + } .animation(.easeInOut(duration: 0.2), value: model.isBuffering) // **Herein sanft, hinaus zügig.** Das Einblenden begleitet eine // Bewegung und soll der Hand entgegenkommen; das Ausblenden ist ein @@ -353,6 +364,7 @@ struct PlayerView: View { transport(for: model) Spacer() scrubber(for: model) + diagnose(for: model) } .padding(FlixySpacing.loose) // **Zusätzlich zum Polster, nicht statt.** Der Sicherheitsrand sagt, @@ -377,6 +389,27 @@ struct PlayerView: View { } } + /// Was der Player über seinen Platz weiss. + /// + /// **Nur im Entwicklerbau, und nur, weil zweimal Raten nicht gereicht + /// hat.** Sitzen die Knöpfe ausserhalb des Bildschirms, gibt es genau + /// drei Möglichkeiten: die Ränder kommen als null an, sie kommen falsch + /// an, oder sie stimmen und der Rahmen ist grösser als der Schirm. Von + /// aussen sehen alle drei gleich aus. Diese Zeile unterscheidet sie. + /// + /// Die Schirmgrösse daneben ist dabei der Schlüssel: steht dort etwas + /// anderes als die Fläche, auf der die Knöpfe liegen, liegt es nicht an + /// den Rändern. + @ViewBuilder + private func diagnose(for model: PlayerModel) -> some View { + #if DEBUG + let schirm = ScreenSafeArea.screenSize + Text(verbatim: "SA \(Int(safeArea.top)),\(Int(safeArea.leading)),\(Int(safeArea.trailing)),\(Int(safeArea.bottom)) Schirm \(Int(schirm.width))×\(Int(schirm.height)) \(model.videoFit == .fill ? "füllen" : "einpassen")") + .font(.system(size: 11).monospaced()) + .foregroundStyle(.yellow) + #endif + } + private func topBar(for model: PlayerModel) -> some View { HStack(alignment: .top, spacing: FlixySpacing.regular) { // Der Pfeil verkleinert, er beendet nicht. Das ist der ganze diff --git a/Flixy/Views/Player/ScreenSafeArea.swift b/Flixy/Views/Player/ScreenSafeArea.swift index 54340f1..5801031 100644 --- a/Flixy/Views/Player/ScreenSafeArea.swift +++ b/Flixy/Views/Player/ScreenSafeArea.swift @@ -38,9 +38,7 @@ enum ScreenSafeArea { // Bildschirmseiten, SwiftUI in Leserichtung. Bei einer Sprache, die // von rechts nach links läuft, wären sie vertauscht — deshalb hier // ausdrücklich in die Leserichtung übersetzt. - let vonLinks = UIApplication.shared.connectedScenes - .compactMap { $0 as? UIWindowScene } - .first?.keyWindow?.effectiveUserInterfaceLayoutDirection != .rightToLeft + let vonLinks = fenster?.effectiveUserInterfaceLayoutDirection != .rightToLeft return EdgeInsets( top: i.top, leading: vonLinks ? i.left : i.right, @@ -49,10 +47,33 @@ enum ScreenSafeArea { ) } - private static var windowInsets: UIEdgeInsets { - UIApplication.shared.connectedScenes - .compactMap { $0 as? UIWindowScene } - .first { $0.activationState == .foregroundActive }? - .keyWindow?.safeAreaInsets ?? .zero + /// Wie gross der Bildschirm gerade ist. + /// + /// Nur für die Diagnose: sie beantwortet die Frage, ob der Player grösser + /// gezeichnet wird als der Schirm — und die lässt sich von innen sonst + /// nicht stellen. + static var screenSize: CGSize { fenster?.bounds.size ?? .zero } + + private static var windowInsets: UIEdgeInsets { fenster?.safeAreaInsets ?? .zero } + + /// Das Fenster, das gerade zählt. + /// + /// **Mit Rückfall, und das ist der Punkt.** Zuerst stand hier nur + /// „die Szene, die `foregroundActive` ist" — und genau die gibt es in + /// zwei Momenten nicht: während einer Drehung und kurz nach dem + /// Zurückholen der App. Wer dann fragt, bekommt `nil`, daraus werden + /// Ränder von null, und die bleiben stehen, bis sich die Fläche wieder + /// ändert. Die Knöpfe sitzen dann im Home-Indikator, und zwar dauerhaft, + /// obwohl die Rechnung stimmt. + /// + /// Ein Fenster, das die richtigen Ränder kennt, ist in dem Moment + /// trotzdem da — es ist nur nicht „aktiv". Also der Reihe nach: aktiv, + /// sonst sichtbar, sonst irgendeines. + private static var fenster: UIWindow? { + let szenen = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene } + let gewählt = szenen.first { $0.activationState == .foregroundActive } + ?? szenen.first { $0.activationState == .foregroundInactive } + ?? szenen.first + return gewählt?.keyWindow ?? gewählt?.windows.first { $0.isKeyWindow } ?? gewählt?.windows.first } }