diff --git a/Flixy/Views/Player/PlayerView.swift b/Flixy/Views/Player/PlayerView.swift index 82c3ea6..90cf939 100644 --- a/Flixy/Views/Player/PlayerView.swift +++ b/Flixy/Views/Player/PlayerView.swift @@ -32,6 +32,8 @@ struct PlayerView: View { @State private var hintTask: Task? /// Ob die Tastatur bei diesem Bildschirm ankommt. Nur auf dem Mac gesetzt. @FocusState private var keyboardFocus: Bool + /// Ob Zeiger und Tastatur gelten. Einmal beim Start ermittelt. + private var isMac: Bool { FlixyPlatform.isMac } /// Wann der Zeiger zuletzt die Bedienelemente geholt hat. @State private var lastPointerReveal: Date = .distantPast @@ -124,36 +126,28 @@ struct PlayerView: View { // // Dort ist beides selbstverständlich: Leertaste hält an, die Pfeile // springen, und die Bedienelemente kommen von allein, sobald sich der - // Zeiger regt. Auf dem iPhone gibt es keines von beidem, und - // `focusable` legte dort nur einen Fokusrahmen über den Film. - #if targetEnvironment(macCatalyst) - .focusable() + // Zeiger regt. Auf dem iPhone gibt es keines von beidem. + // + // Zur Laufzeit entschieden, nicht beim Übersetzen: „für iPad + // angepasst" ist der iOS-Bau und läuft trotzdem auf dem Mac. Ein + // `#if` hätte das Ganze genau dort abgeschaltet. `focusable(_:)` + // nimmt den Schalter entgegen, die Tastenhandler geben sonst + // `.ignored` zurück — so bleibt es **eine** Ansicht, und der Player + // wird nicht neu aufgebaut, nur weil die Frage vom Gerät abhängt. + .focusable(isMac) .focusEffectDisabled() .focused($keyboardFocus) // Von Hand gesetzt, weil sonst niemand den Fokus hat: der Player // besteht aus Knöpfen, und solange keiner angeklickt wurde, ginge // jeder Tastendruck ins Leere. - .onAppear { keyboardFocus = true } - .onKeyPress(.space) { - model.togglePlayPause() - revealControls() - return .handled - } - .onKeyPress(.leftArrow) { - seek(by: -Double(settings.rewindSeconds)) - revealControls() - return .handled - } - .onKeyPress(.rightArrow) { - seek(by: Double(settings.forwardSeconds)) - revealControls() - return .handled - } + .onAppear { if isMac { keyboardFocus = true } } + .onKeyPress(.space) { onMac { model.togglePlayPause() } } + .onKeyPress(.leftArrow) { onMac { seek(by: -Double(settings.rewindSeconds)) } } + .onKeyPress(.rightArrow) { onMac { seek(by: Double(settings.forwardSeconds)) } } .onContinuousHover { phase in - guard case .active = phase else { return } + guard isMac, case .active = phase else { return } pointerMoved() } - #endif .sheet(item: $trackPicker) { kind in TrackPickerSheet(model: model, kind: kind) } @@ -602,12 +596,20 @@ struct PlayerView: View { /// ein Tipp, der sofort anhält, nähme den einzigen Weg zu Scrubber, /// Tonspur und Qualität. private func primaryTap() { - #if targetEnvironment(macCatalyst) + guard isMac else { + toggleControls() + return + } model.togglePlayPause() revealControls() - #else - toggleControls() - #endif + } + + /// Führt eine Tastenaktion aus — aber nur dort, wo es eine Tastatur gibt. + private func onMac(_ action: () -> Void) -> KeyPress.Result { + guard isMac else { return .ignored } + action() + revealControls() + return .handled } private func toggleControls() { diff --git a/Packages/FlixyKit/Sources/FlixyDesign/PlatformShims.swift b/Packages/FlixyKit/Sources/FlixyDesign/PlatformShims.swift index 33cf720..1c62d49 100644 --- a/Packages/FlixyKit/Sources/FlixyDesign/PlatformShims.swift +++ b/Packages/FlixyKit/Sources/FlixyDesign/PlatformShims.swift @@ -12,6 +12,30 @@ import AppKit /// Systeme verschiedene Namen dafür haben, steht der Unterschied hier und /// nirgends sonst. Sonst wandert er in zwanzig Dateien und wird beim /// nächsten Bildschirm vergessen. +/// Auf was für einem Gerät läuft das hier gerade? +public enum FlixyPlatform { + /// Läuft die App auf einem Mac? + /// + /// **Zwei Wege führen dorthin, und für den Übersetzer sehen sie + /// verschieden aus.** Catalyst ist ein eigener Bau und meldet sich als + /// `targetEnvironment(macCatalyst)`. „Für iPad angepasst" ist dagegen + /// buchstäblich der iOS-Bau, der auf Apple Silicon startet — dort ist + /// dieselbe Abfrage schlicht falsch. + /// + /// Wer nur die erste Hälfte prüft, schreibt Code für den Mac, der auf dem + /// Mac nicht läuft: übersetzt sauber, ist aber genau dort abgeschaltet, + /// wo er gebraucht wird. Deshalb hier beide Wege, an einer Stelle. + public static let isMac: Bool = { + #if targetEnvironment(macCatalyst) + true + #elseif os(iOS) + ProcessInfo.processInfo.isiOSAppOnMac + #else + true + #endif + }() +} + extension View { /// Eine schmale Titelzeile — auf dem Mac gibt es sie nicht. public func flixyInlineTitle() -> some View {