#if os(iOS) import SwiftUI import UIKit /// Bestimmt, in welche Richtungen sich die App drehen darf. /// /// In reinem SwiftUI gibt es dafür keinen Weg: `requestGeometryUpdate` dreht /// zwar, aber das System dreht sofort zurück, wenn der Bildschirm es nicht /// auch erlaubt. Erlaubt wird es über /// `application(_:supportedInterfaceOrientationsFor:)` — und das gibt es nur /// am klassischen App-Delegaten. Diese Klasse ist die Brücke dazwischen. @MainActor final class OrientationLock { static let shared = OrientationLock() private(set) var mask: UIInterfaceOrientationMask = .portrait private init() { // Auf dem iPad bleibt alles erlaubt: dort ist das Querformat beim // Blättern der Normalfall, nicht die Ausnahme. if UIDevice.current.userInterfaceIdiom == .pad { mask = .all } } /// Dreht ins Querformat und hält es dort. func lockLandscape() { guard UIDevice.current.userInterfaceIdiom != .pad else { return } apply(.landscape, rotatingTo: .landscape) } /// Gibt die Ausrichtung wieder frei und dreht zurück ins Hochformat. func releaseLandscape() { guard UIDevice.current.userInterfaceIdiom != .pad else { return } apply(.portrait, rotatingTo: .portrait) } private func apply( _ newMask: UIInterfaceOrientationMask, rotatingTo target: UIInterfaceOrientationMask ) { mask = newMask guard let scene = UIApplication.shared.connectedScenes .compactMap({ $0 as? UIWindowScene }) .first(where: { $0.activationState == .foregroundActive }) else { return } // Erst die neue Erlaubnis bekanntgeben, dann drehen. In der anderen // Reihenfolge lehnt das System die Drehung ab, weil die alte Maske // noch gilt — und das sah aus wie „dreht sich nicht richtig". scene.keyWindow?.rootViewController?.setNeedsUpdateOfSupportedInterfaceOrientations() scene.requestGeometryUpdate(.iOS(interfaceOrientations: target)) } } /// Dreht beim Erscheinen ins Querformat und beim Verschwinden zurück. struct LandscapeWhileVisible: ViewModifier { /// Ob überhaupt gesperrt wird. /// /// Für die allermeisten Filme ist das Querformat richtig — und für den, /// der im Bett auf der Seite liegt, das Gegenteil davon. let isEnabled: Bool func body(content: Content) -> some View { content .onAppear { if isEnabled { OrientationLock.shared.lockLandscape() } } .onDisappear { OrientationLock.shared.releaseLandscape() } } } extension View { /// Für den Vollbildplayer: Film ist Querformat. func landscapeWhileVisible(_ isEnabled: Bool = true) -> some View { modifier(LandscapeWhileVisible(isEnabled: isEnabled)) } } #else import SwiftUI /// Auf dem Mac dreht sich nichts. /// /// Ein Fenster hat keine Ausrichtung, die sich sperren ließe — der Nutzer /// bestimmt seine Größe. Die Stelle bleibt trotzdem bestehen, damit der /// Player auf beiden Plattformen dieselbe Zeile schreiben kann. extension View { func landscapeWhileVisible(_ isEnabled: Bool = true) -> some View { self } } #endif