Fix Current Key Commands (#991)

This commit is contained in:
Ethan Pippin 2024-03-12 20:26:26 -06:00 committed by GitHub
parent e28805a5cf
commit 3efe899250
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 169 additions and 231 deletions

View File

@ -8,7 +8,7 @@
import Foundation
extension Float {
extension Double {
var rateLabel: String {
String(format: "%.2f", self).appending("x")

View File

@ -32,7 +32,7 @@ extension EnvironmentValues {
}
struct PlaybackSpeedKey: EnvironmentKey {
static let defaultValue: Binding<Float> = .constant(1)
static let defaultValue: Binding<Double> = .constant(1)
}
// TODO: does this actually do anything useful?

View File

@ -40,7 +40,7 @@ extension EnvironmentValues {
set { self[IsScrubbingKey.self] = newValue }
}
var playbackSpeed: Binding<Float> {
var playbackSpeed: Binding<Double> {
get { self[PlaybackSpeedKey.self] }
set { self[PlaybackSpeedKey.self] = newValue }
}

View File

@ -362,7 +362,7 @@
E154967E296CCB6C00C4EF88 /* BasicNavigationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E154967D296CCB6C00C4EF88 /* BasicNavigationCoordinator.swift */; };
E1559A76294D960C00C1FFBC /* MainOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1559A75294D960C00C1FFBC /* MainOverlay.swift */; };
E157563029355B7900976E1F /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E157562F29355B7900976E1F /* UpdateView.swift */; };
E15756322935642A00976E1F /* Float.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15756312935642A00976E1F /* Float.swift */; };
E15756322935642A00976E1F /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15756312935642A00976E1F /* Double.swift */; };
E15756342936851D00976E1F /* NativeVideoPlayerSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15756332936851D00976E1F /* NativeVideoPlayerSettingsView.swift */; };
E15756362936856700976E1F /* VideoPlayerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15756352936856700976E1F /* VideoPlayerType.swift */; };
E1575E3C293C6B15001665B1 /* Files in Frameworks */ = {isa = PBXBuildFile; productRef = E1575E3B293C6B15001665B1 /* Files */; };
@ -405,7 +405,7 @@
E1575E90293E7B1E001665B1 /* EdgeInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = E12F038B28F8B0B100976CC3 /* EdgeInsets.swift */; };
E1575E91293E7B1E001665B1 /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E1DCC2273CE19800C9AE76 /* URL.swift */; };
E1575E92293E7B1E001665B1 /* CGSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10EAA4E277BBCC4000269ED /* CGSize.swift */; };
E1575E93293E7B1E001665B1 /* Float.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15756312935642A00976E1F /* Float.swift */; };
E1575E93293E7B1E001665B1 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15756312935642A00976E1F /* Double.swift */; };
E1575E94293E7B1E001665B1 /* VerticalAlignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A1528128FD126C00600579 /* VerticalAlignment.swift */; };
E1575E95293E7B1E001665B1 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11CEB8C28999B4A003E74C7 /* Font.swift */; };
E1575E98293E7B1E001665B1 /* UIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A2C153279A7D5A005EC829 /* UIApplication.swift */; };
@ -1040,7 +1040,7 @@
E154967D296CCB6C00C4EF88 /* BasicNavigationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicNavigationCoordinator.swift; sourceTree = "<group>"; };
E1559A75294D960C00C1FFBC /* MainOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainOverlay.swift; sourceTree = "<group>"; };
E157562F29355B7900976E1F /* UpdateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateView.swift; sourceTree = "<group>"; };
E15756312935642A00976E1F /* Float.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Float.swift; sourceTree = "<group>"; };
E15756312935642A00976E1F /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
E15756332936851D00976E1F /* NativeVideoPlayerSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeVideoPlayerSettingsView.swift; sourceTree = "<group>"; };
E15756352936856700976E1F /* VideoPlayerType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerType.swift; sourceTree = "<group>"; };
E1575EA5293E7D40001665B1 /* VideoPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayer.swift; sourceTree = "<group>"; };
@ -1820,12 +1820,12 @@
6267B3D526710B8900A7371D /* Collection.swift */,
E173DA5126D04AAF00CC4EB7 /* Color.swift */,
E1B490462967E2E500D3EDCE /* CoreStore.swift */,
E15756312935642A00976E1F /* Double.swift */,
E15D4F092B1BD88900442DB8 /* Edge.swift */,
E12F038B28F8B0B100976CC3 /* EdgeInsets.swift */,
E187F7652B8E6A08005400FE /* EnvironmentValue */,
E1B33EAF28EA890D0073B0FD /* Equatable.swift */,
E133328729538D8D00EE76AB /* Files.swift */,
E15756312935642A00976E1F /* Float.swift */,
E11CEB8C28999B4A003E74C7 /* Font.swift */,
E1E6C44A29AED2B70064123F /* HorizontalAlignment.swift */,
E139CC1E28EC83E400688DE2 /* Int.swift */,
@ -3255,7 +3255,7 @@
E1575E5F293E77B5001665B1 /* StreamType.swift in Sources */,
E1388A42293F0AAD009721B1 /* PreferenceUIHostingSwizzling.swift in Sources */,
E13DD3E227176BD3009D4DAF /* ServerListViewModel.swift in Sources */,
E1575E93293E7B1E001665B1 /* Float.swift in Sources */,
E1575E93293E7B1E001665B1 /* Double.swift in Sources */,
E1B5784228F8AFCB00D42911 /* WrappedView.swift in Sources */,
E11895AA289383BC0042947B /* ScrollViewOffsetModifier.swift in Sources */,
E1575E76293E77B5001665B1 /* VideoPlayerType.swift in Sources */,
@ -3568,7 +3568,7 @@
E18ACA922A15A32F00BB4F35 /* (null) in Sources */,
E1E1E24D28DF8A2E000DF5FD /* PreferenceKeys.swift in Sources */,
E1C812BC277A8E5D00918266 /* PlaybackSpeed.swift in Sources */,
E15756322935642A00976E1F /* Float.swift in Sources */,
E15756322935642A00976E1F /* Double.swift in Sources */,
E139CC1D28EC836F00688DE2 /* ChapterOverlay.swift in Sources */,
E168BD14289A4162001A6922 /* LatestInLibraryView.swift in Sources */,
E1E6C45029B104840064123F /* Button.swift in Sources */,

View File

@ -6,18 +6,46 @@
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
//
import Defaults
import PreferencesView
import SwiftUI
import VLCUI
extension View {
func videoPlayerKeyCommands(
isAspectFilled: Binding<Bool>,
gestureStateHandler: VideoPlayer.GestureStateHandler,
videoPlayerManager: VideoPlayerManager,
updateViewProxy: UpdateViewProxy
) -> some View {
keyCommands {
modifier(
VideoPlayerKeyCommandsModifier(
gestureStateHandler: gestureStateHandler,
updateViewProxy: updateViewProxy
)
)
}
}
struct VideoPlayerKeyCommandsModifier: ViewModifier {
@Default(.VideoPlayer.jumpBackwardLength)
private var jumpBackwardLength
@Default(.VideoPlayer.jumpForwardLength)
private var jumpForwardLength
@Environment(\.aspectFilled)
private var isAspectFilled
@EnvironmentObject
private var videoPlayerManager: VideoPlayerManager
@EnvironmentObject
private var videoPlayerProxy: VLCVideoPlayer.Proxy
let gestureStateHandler: VideoPlayer.GestureStateHandler
let updateViewProxy: UpdateViewProxy
func body(content: Content) -> some View {
content.keyCommands {
// MARK: play/pause
@ -44,6 +72,8 @@ extension View {
gestureStateHandler.jumpForwardKeyPressAmount += 1
gestureStateHandler.jumpForwardKeyPressWorkItem?.cancel()
videoPlayerProxy.jumpForward(Int(jumpForwardLength.rawValue))
let task = DispatchWorkItem {
gestureStateHandler.jumpForwardKeyPressActive = false
gestureStateHandler.jumpForwardKeyPressAmount = 0
@ -56,6 +86,8 @@ extension View {
gestureStateHandler.jumpForwardKeyPressActive = true
gestureStateHandler.jumpForwardKeyPressAmount += 1
videoPlayerProxy.jumpForward(Int(jumpForwardLength.rawValue))
let task = DispatchWorkItem {
gestureStateHandler.jumpForwardKeyPressActive = false
gestureStateHandler.jumpForwardKeyPressAmount = 0
@ -67,6 +99,43 @@ extension View {
}
}
// MARK: jump backward
KeyCommandAction(
title: L10n.jumpBackward,
input: UIKeyCommand.inputLeftArrow
) {
if gestureStateHandler.jumpBackwardKeyPressActive {
gestureStateHandler.jumpBackwardKeyPressAmount += 1
gestureStateHandler.jumpBackwardKeyPressWorkItem?.cancel()
videoPlayerProxy.jumpBackward(Int(jumpBackwardLength.rawValue))
let task = DispatchWorkItem {
gestureStateHandler.jumpBackwardKeyPressActive = false
gestureStateHandler.jumpBackwardKeyPressAmount = 0
}
gestureStateHandler.jumpBackwardKeyPressWorkItem = task
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: task)
} else {
gestureStateHandler.jumpBackwardKeyPressActive = true
gestureStateHandler.jumpBackwardKeyPressAmount += 1
videoPlayerProxy.jumpBackward(Int(jumpBackwardLength.rawValue))
let task = DispatchWorkItem {
gestureStateHandler.jumpBackwardKeyPressActive = false
gestureStateHandler.jumpBackwardKeyPressAmount = 0
}
gestureStateHandler.jumpBackwardKeyPressWorkItem = task
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: task)
}
}
// MARK: aspect fill
KeyCommandAction(
@ -78,210 +147,81 @@ extension View {
isAspectFilled.wrappedValue.toggle()
}
}
// MARK: decrease playback speed
KeyCommandAction(
title: "Decrease Playback Speed",
input: "[",
modifierFlags: .command
) {
let clampedPlaybackSpeed = clamp(
videoPlayerManager.playbackSpeed.rawValue - 0.25,
min: 0.25,
max: 2.0
)
let newPlaybackSpeed = PlaybackSpeed(rawValue: clampedPlaybackSpeed) ?? .one
videoPlayerManager.playbackSpeed = newPlaybackSpeed
videoPlayerManager.proxy.setRate(.absolute(Float(newPlaybackSpeed.rawValue)))
updateViewProxy.present(systemName: "speedometer", title: newPlaybackSpeed.rawValue.rateLabel)
}
// MARK: increase playback speed
KeyCommandAction(
title: "Increase Playback Speed",
input: "]",
modifierFlags: .command
) {
let clampedPlaybackSpeed = clamp(
videoPlayerManager.playbackSpeed.rawValue + 0.25,
min: 0.25,
max: 2.0
)
let newPlaybackSpeed = PlaybackSpeed(rawValue: clampedPlaybackSpeed) ?? .one
videoPlayerManager.playbackSpeed = newPlaybackSpeed
videoPlayerManager.proxy.setRate(.absolute(Float(newPlaybackSpeed.rawValue)))
updateViewProxy.present(systemName: "speedometer", title: newPlaybackSpeed.rawValue.rateLabel)
}
// MARK: reset playback speed
KeyCommandAction(
title: "Reset Playback Speed",
input: "\\",
modifierFlags: .command
) {
let newPlaybackSpeed = PlaybackSpeed.one
videoPlayerManager.playbackSpeed = newPlaybackSpeed
videoPlayerManager.proxy.setRate(.absolute(Float(newPlaybackSpeed.rawValue)))
updateViewProxy.present(systemName: "speedometer", title: newPlaybackSpeed.rawValue.rateLabel)
}
// MARK: next item
KeyCommandAction(
title: L10n.nextItem,
input: UIKeyCommand.inputRightArrow,
modifierFlags: .command
) {
videoPlayerManager.selectNextViewModel()
}
// MARK: previous item
KeyCommandAction(
title: L10n.previousItem,
input: UIKeyCommand.inputLeftArrow,
modifierFlags: .command
) {
videoPlayerManager.selectPreviousViewModel()
}
}
// .addingKeyCommand(
// title: L10n.jumpForward,
// input: UIKeyCommand.inputRightArrow
// ) {
// if gestureStateHandler.jumpForwardKeyPressActive {
// gestureStateHandler.jumpForwardKeyPressAmount += 1
// gestureStateHandler.jumpForwardKeyPressWorkItem?.cancel()
//
// let task = DispatchWorkItem {
// gestureStateHandler.jumpForwardKeyPressActive = false
// gestureStateHandler.jumpForwardKeyPressAmount = 0
// }
//
// gestureStateHandler.jumpForwardKeyPressWorkItem = task
//
// DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: task)
// } else {
// gestureStateHandler.jumpForwardKeyPressActive = true
// gestureStateHandler.jumpForwardKeyPressAmount += 1
//
// let task = DispatchWorkItem {
// gestureStateHandler.jumpForwardKeyPressActive = false
// gestureStateHandler.jumpForwardKeyPressAmount = 0
// }
//
// gestureStateHandler.jumpForwardKeyPressWorkItem = task
//
// DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: task)
// }
//
// jumpAction(unitPoint: .init(x: 1, y: 0), amount: gestureStateHandler.jumpForwardKeyPressAmount)
// }
// .addingKeyCommand(
// title: L10n.jumpBackward,
// input: UIKeyCommand.inputLeftArrow
// ) {
// if gestureStateHandler.jumpBackwardKeyPressActive {
// gestureStateHandler.jumpBackwardKeyPressAmount += 1
// gestureStateHandler.jumpBackwardKeyPressWorkItem?.cancel()
//
// let task = DispatchWorkItem {
// gestureStateHandler.jumpBackwardKeyPressActive = false
// gestureStateHandler.jumpBackwardKeyPressAmount = 0
// }
//
// gestureStateHandler.jumpBackwardKeyPressWorkItem = task
//
// DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: task)
// } else {
// gestureStateHandler.jumpBackwardKeyPressActive = true
// gestureStateHandler.jumpBackwardKeyPressAmount += 1
//
// let task = DispatchWorkItem {
// gestureStateHandler.jumpBackwardKeyPressActive = false
// gestureStateHandler.jumpBackwardKeyPressAmount = 0
// }
//
// gestureStateHandler.jumpBackwardKeyPressWorkItem = task
//
// DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: task)
// }
//
//// jumpAction(unitPoint: .init(x: 0, y: 0), amount: gestureStateHandler.jumpBackwardKeyPressAmount)
// }
// self.keyCommands([
// .init(
// title: L10n.playAndPause,
// input: " ",
// action: {
// if videoPlayerManager.state == .playing {
// videoPlayerManager.proxy.pause()
// updateViewProxy.present(systemName: "pause.fill", title: "Pause")
// } else {
// videoPlayerManager.proxy.play()
// updateViewProxy.present(systemName: "play.fill", title: "Play")
// }
// }
// ),
// .init(
// title: L10n.jumpForward,
// input: UIKeyCommand.inputRightArrow,
// action: {
// if gestureStateHandler.jumpForwardKeyPressActive {
// gestureStateHandler.jumpForwardKeyPressAmount += 1
// gestureStateHandler.jumpForwardKeyPressWorkItem?.cancel()
//
// let task = DispatchWorkItem {
// gestureStateHandler.jumpForwardKeyPressActive = false
// gestureStateHandler.jumpForwardKeyPressAmount = 0
// }
//
// gestureStateHandler.jumpForwardKeyPressWorkItem = task
//
// DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: task)
// } else {
// gestureStateHandler.jumpForwardKeyPressActive = true
// gestureStateHandler.jumpForwardKeyPressAmount += 1
//
// let task = DispatchWorkItem {
// gestureStateHandler.jumpForwardKeyPressActive = false
// gestureStateHandler.jumpForwardKeyPressAmount = 0
// }
//
// gestureStateHandler.jumpForwardKeyPressWorkItem = task
//
// DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: task)
// }
//
//// jumpAction(unitPoint: .init(x: 1, y: 0), amount: gestureStateHandler.jumpForwardKeyPressAmount)
// }
// ),
// .init(
// title: L10n.jumpBackward,
// input: UIKeyCommand.inputLeftArrow,
// action: {
// if gestureStateHandler.jumpBackwardKeyPressActive {
// gestureStateHandler.jumpBackwardKeyPressAmount += 1
// gestureStateHandler.jumpBackwardKeyPressWorkItem?.cancel()
//
// let task = DispatchWorkItem {
// gestureStateHandler.jumpBackwardKeyPressActive = false
// gestureStateHandler.jumpBackwardKeyPressAmount = 0
// }
//
// gestureStateHandler.jumpBackwardKeyPressWorkItem = task
//
// DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: task)
// } else {
// gestureStateHandler.jumpBackwardKeyPressActive = true
// gestureStateHandler.jumpBackwardKeyPressAmount += 1
//
// let task = DispatchWorkItem {
// gestureStateHandler.jumpBackwardKeyPressActive = false
// gestureStateHandler.jumpBackwardKeyPressAmount = 0
// }
//
// gestureStateHandler.jumpBackwardKeyPressWorkItem = task
//
// DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: task)
// }
//
//// jumpAction(unitPoint: .init(x: 0, y: 0), amount: gestureStateHandler.jumpBackwardKeyPressAmount)
// }
// ),
// .init(
// title: "Decrease Playback Speed",
// input: "[",
// modifierFlags: .command,
// action: {
// let clampedPlaybackSpeed = clamp(
// videoPlayerManager.playbackSpeed - 0.25,
// min: 0.25,
// max: 5.0
// )
//
// updateViewProxy.present(systemName: "speedometer", title: clampedPlaybackSpeed.rateLabel)
// videoPlayerManager.proxy.setRate(.absolute(clampedPlaybackSpeed))
// }
// ),
// .init(
// title: "Increase Playback Speed",
// input: "]",
// modifierFlags: .command,
// action: {
// let clampedPlaybackSpeed = clamp(
// videoPlayerManager.playbackSpeed + 0.25,
// min: 0.25,
// max: 5.0
// )
//
// updateViewProxy.present(systemName: "speedometer", title: clampedPlaybackSpeed.rateLabel)
// videoPlayerManager.proxy.setRate(.absolute(clampedPlaybackSpeed))
// }
// ),
// .init(
// title: "Reset Playback Speed",
// input: "\\",
// modifierFlags: .command,
// action: {
// let clampedPlaybackSpeed: Float = 1
//
// updateViewProxy.present(systemName: "speedometer", title: clampedPlaybackSpeed.rateLabel)
// videoPlayerManager.proxy.setRate(.absolute(clampedPlaybackSpeed))
// }
// ),
// .init(
// title: L10n.nextItem,
// input: UIKeyCommand.inputRightArrow,
// modifierFlags: .command,
// action: {
// videoPlayerManager.selectNextViewModel()
// }
// ),
// .init(
// title: L10n.nextItem,
// input: UIKeyCommand.inputLeftArrow,
// modifierFlags: .command,
// action: {
// videoPlayerManager.selectPreviousViewModel()
// }
// ),
// ])
}
}

View File

@ -35,7 +35,7 @@ struct VideoPlayer: View {
var beginningAudioOffset: Int = 0
var beginningBrightnessValue: CGFloat = 0
var beginningPlaybackSpeed: Float = 0
var beginningPlaybackSpeed: Double = 0
var beginningSubtitleOffset: Int = 0
var beginningVolumeValue: Float = 0
@ -98,7 +98,7 @@ struct VideoPlayer: View {
@State
private var isScrubbing: Bool = false
@State
private var playbackSpeed: Float = 1
private var playbackSpeed: Double = 1
@State
private var subtitleOffset: Int = 0
@ -156,15 +156,6 @@ struct VideoPlayer: View {
}
VideoPlayer.Overlay()
.environmentObject(splitContentViewProxy)
.environmentObject(videoPlayerManager)
.environmentObject(videoPlayerManager.currentProgressHandler)
.environmentObject(videoPlayerManager.currentViewModel!)
.environmentObject(videoPlayerManager.proxy)
.environment(\.aspectFilled, $isAspectFilled)
.environment(\.isPresentingOverlay, $isPresentingOverlay)
.environment(\.isScrubbing, $isScrubbing)
.environment(\.playbackSpeed, $playbackSpeed)
}
}
.splitContent {
@ -190,11 +181,18 @@ struct VideoPlayer: View {
.padding(.top)
}
.videoPlayerKeyCommands(
isAspectFilled: $isAspectFilled,
gestureStateHandler: gestureStateHandler,
videoPlayerManager: videoPlayerManager,
updateViewProxy: updateViewProxy
)
.environmentObject(splitContentViewProxy)
.environmentObject(videoPlayerManager)
.environmentObject(videoPlayerManager.currentProgressHandler)
.environmentObject(videoPlayerManager.currentViewModel!)
.environmentObject(videoPlayerManager.proxy)
.environment(\.aspectFilled, $isAspectFilled)
.environment(\.isPresentingOverlay, $isPresentingOverlay)
.environment(\.isScrubbing, $isScrubbing)
.environment(\.playbackSpeed, $playbackSpeed)
}
var body: some View {
@ -485,7 +483,7 @@ extension VideoPlayer {
}
let newPlaybackSpeed = round(
gestureStateHandler.beginningPlaybackSpeed - Float(gestureStateHandler.beginningHorizontalPanUnit - point) * 2,
gestureStateHandler.beginningPlaybackSpeed - Double(gestureStateHandler.beginningHorizontalPanUnit - point) * 2,
toNearest: 0.25
)
let clampedPlaybackSpeed = clamp(newPlaybackSpeed, min: 0.25, max: 5.0)
@ -493,7 +491,7 @@ extension VideoPlayer {
updateViewProxy.present(systemName: "speedometer", title: clampedPlaybackSpeed.rateLabel)
playbackSpeed = clampedPlaybackSpeed
videoPlayerManager.proxy.setRate(.absolute(clampedPlaybackSpeed))
videoPlayerManager.proxy.setRate(.absolute(Float(clampedPlaybackSpeed)))
}
private func scrubAction(