Seek settings

This commit is contained in:
Arkadiusz Fal 2022-12-19 12:08:27 +01:00
parent 5d4983d6d2
commit 8631389b8f
7 changed files with 113 additions and 11 deletions

View File

@ -162,6 +162,7 @@ final class PlayerModel: ObservableObject {
@Default(.closePiPOnOpeningPlayer) var closePiPOnOpeningPlayer @Default(.closePiPOnOpeningPlayer) var closePiPOnOpeningPlayer
@Default(.resetWatchedStatusOnPlaying) var resetWatchedStatusOnPlaying @Default(.resetWatchedStatusOnPlaying) var resetWatchedStatusOnPlaying
@Default(.playerRate) var playerRate @Default(.playerRate) var playerRate
@Default(.systemControlsSeekDuration) var systemControlsSeekDuration
#if !os(macOS) #if !os(macOS)
@Default(.closePiPAndOpenPlayerOnEnteringForeground) var closePiPAndOpenPlayerOnEnteringForeground @Default(.closePiPAndOpenPlayerOnEnteringForeground) var closePiPAndOpenPlayerOnEnteringForeground
@ -746,18 +747,19 @@ final class PlayerModel: ObservableObject {
UIApplication.shared.beginReceivingRemoteControlEvents() UIApplication.shared.beginReceivingRemoteControlEvents()
#endif #endif
let preferredIntervals = [NSNumber(10)] let interval = TimeInterval(systemControlsSeekDuration) ?? 10
let preferredIntervals = [NSNumber(value: interval)]
skipForwardCommand.preferredIntervals = preferredIntervals skipForwardCommand.preferredIntervals = preferredIntervals
skipBackwardCommand.preferredIntervals = preferredIntervals skipBackwardCommand.preferredIntervals = preferredIntervals
skipForwardCommand.addTarget { [weak self] _ in skipForwardCommand.addTarget { [weak self] _ in
self?.backend.seek(relative: .secondsInDefaultTimescale(10), seekType: .userInteracted) self?.backend.seek(relative: .secondsInDefaultTimescale(interval), seekType: .userInteracted)
return .success return .success
} }
skipBackwardCommand.addTarget { [weak self] _ in skipBackwardCommand.addTarget { [weak self] _ in
self?.backend.seek(relative: .secondsInDefaultTimescale(-10), seekType: .userInteracted) self?.backend.seek(relative: .secondsInDefaultTimescale(-interval), seekType: .userInteracted)
return .success return .success
} }

View File

@ -1,3 +1,4 @@
import Defaults
import Foundation import Foundation
import SwiftUI import SwiftUI
@ -51,4 +52,25 @@ struct Constants {
return "list.and.film" return "list.and.film"
} }
} }
static func seekIcon(_ type: String, _ interval: TimeInterval) -> String {
let interval = Int(interval)
let allVersions = [10, 15, 30, 45, 60, 75, 90]
let iOS15 = [5]
let iconName = "go\(type).\(interval)"
if #available(iOS 15, macOS 12, *) {
if iOS15.contains(interval) {
return iconName
}
}
if allVersions.contains(interval) {
return iconName
}
let sign = type == "forward" ? "plus" : "minus"
return "go\(type).\(sign)"
}
} }

View File

@ -188,6 +188,12 @@ extension Defaults.Keys {
static let playerActionsButtonLabelStyle = Key<ButtonLabelStyle>("playerActionsButtonLabelStyle", default: .iconAndText) static let playerActionsButtonLabelStyle = Key<ButtonLabelStyle>("playerActionsButtonLabelStyle", default: .iconAndText)
static let systemControlsCommands = Key<SystemControlsCommands>("systemControlsCommands", default: .restartAndAdvanceToNext) static let systemControlsCommands = Key<SystemControlsCommands>("systemControlsCommands", default: .restartAndAdvanceToNext)
static let buttonBackwardSeekDuration = Key<String>("buttonBackwardSeekDuration", default: "10")
static let buttonForwardSeekDuration = Key<String>("buttonForwardSeekDuration", default: "10")
static let gestureBackwardSeekDuration = Key<String>("gestureBackwardSeekDuration", default: "10")
static let gestureForwardSeekDuration = Key<String>("gestureForwardSeekDuration", default: "10")
static let systemControlsSeekDuration = Key<String>("systemControlsBackwardSeekDuration", default: "10")
static let actionButtonShareEnabled = Key<Bool>("actionButtonShareEnabled", default: true) static let actionButtonShareEnabled = Key<Bool>("actionButtonShareEnabled", default: true)
static let actionButtonAddToPlaylistEnabled = Key<Bool>("actionButtonAddToPlaylistEnabled", default: true) static let actionButtonAddToPlaylistEnabled = Key<Bool>("actionButtonAddToPlaylistEnabled", default: true)
static let actionButtonSubscribeEnabled = Key<Bool>("actionButtonSubscribeEnabled", default: false) static let actionButtonSubscribeEnabled = Key<Bool>("actionButtonSubscribeEnabled", default: false)

View File

@ -29,6 +29,8 @@ struct PlayerControls: View {
@Default(.playerControlsLayout) private var regularPlayerControlsLayout @Default(.playerControlsLayout) private var regularPlayerControlsLayout
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout @Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
@Default(.openWatchNextOnClose) private var openWatchNextOnClose @Default(.openWatchNextOnClose) private var openWatchNextOnClose
@Default(.buttonBackwardSeekDuration) private var buttonBackwardSeekDuration
@Default(.buttonForwardSeekDuration) private var buttonForwardSeekDuration
private let controlsOverlayModel = ControlOverlaysModel.shared private let controlsOverlayModel = ControlOverlaysModel.shared
@ -398,8 +400,14 @@ struct PlayerControls: View {
size = playerControlsLayout.bigButtonSize size = playerControlsLayout.bigButtonSize
#endif #endif
return button("Seek Backward", systemImage: "gobackward.10", fontSize: fontSize, size: size, cornerRadius: 5, background: false, foregroundColor: foregroundColor) { let interval = TimeInterval(buttonBackwardSeekDuration) ?? 10
player.backend.seek(relative: .secondsInDefaultTimescale(-10), seekType: .userInteracted)
return button(
"Seek Backward",
systemImage: Constants.seekIcon("backward", interval),
fontSize: fontSize, size: size, cornerRadius: 5, background: false, foregroundColor: foregroundColor
) {
player.backend.seek(relative: .secondsInDefaultTimescale(-interval), seekType: .userInteracted)
} }
.disabled(player.liveStreamInAVPlayer) .disabled(player.liveStreamInAVPlayer)
#if os(tvOS) #if os(tvOS)
@ -420,8 +428,14 @@ struct PlayerControls: View {
size = playerControlsLayout.bigButtonSize size = playerControlsLayout.bigButtonSize
#endif #endif
return button("Seek Forward", systemImage: "goforward.10", fontSize: fontSize, size: size, cornerRadius: 5, background: false, foregroundColor: foregroundColor) { let interval = TimeInterval(buttonForwardSeekDuration) ?? 10
player.backend.seek(relative: .secondsInDefaultTimescale(10), seekType: .userInteracted)
return button(
"Seek Forward",
systemImage: Constants.seekIcon("forward", interval),
fontSize: fontSize, size: size, cornerRadius: 5, background: false, foregroundColor: foregroundColor
) {
player.backend.seek(relative: .secondsInDefaultTimescale(interval), seekType: .userInteracted)
} }
.disabled(player.liveStreamInAVPlayer) .disabled(player.liveStreamInAVPlayer)
#if os(tvOS) #if os(tvOS)

View File

@ -1,9 +1,13 @@
import Defaults
import SwiftUI import SwiftUI
struct PlayerGestures: View { struct PlayerGestures: View {
private var player = PlayerModel.shared private var player = PlayerModel.shared
@ObservedObject private var model = PlayerControlsModel.shared @ObservedObject private var model = PlayerControlsModel.shared
@Default(.gestureBackwardSeekDuration) private var gestureBackwardSeekDuration
@Default(.gestureForwardSeekDuration) private var gestureForwardSeekDuration
var body: some View { var body: some View {
HStack(spacing: 0) { HStack(spacing: 0) {
gestureRectangle gestureRectangle
@ -11,7 +15,8 @@ struct PlayerGestures: View {
tapSensitivity: 0.2, tapSensitivity: 0.2,
singleTapAction: { singleTapAction() }, singleTapAction: { singleTapAction() },
doubleTapAction: { doubleTapAction: {
player.backend.seek(relative: .secondsInDefaultTimescale(-10), seekType: .userInteracted) let interval = TimeInterval(gestureBackwardSeekDuration) ?? 10
player.backend.seek(relative: .secondsInDefaultTimescale(-interval), seekType: .userInteracted)
}, },
anyTapAction: { anyTapAction: {
model.update() model.update()
@ -32,7 +37,8 @@ struct PlayerGestures: View {
tapSensitivity: 0.2, tapSensitivity: 0.2,
singleTapAction: { singleTapAction() }, singleTapAction: { singleTapAction() },
doubleTapAction: { doubleTapAction: {
player.backend.seek(relative: .secondsInDefaultTimescale(10), seekType: .userInteracted) let interval = TimeInterval(gestureForwardSeekDuration) ?? 10
player.backend.seek(relative: .secondsInDefaultTimescale(interval), seekType: .userInteracted)
} }
) )
} }

View File

@ -66,6 +66,8 @@ struct VideoPlayerView: View {
@Default(.seekGestureSpeed) var seekGestureSpeed @Default(.seekGestureSpeed) var seekGestureSpeed
@Default(.seekGestureSensitivity) var seekGestureSensitivity @Default(.seekGestureSensitivity) var seekGestureSensitivity
@Default(.playerSidebar) var playerSidebar @Default(.playerSidebar) var playerSidebar
@Default(.gestureBackwardSeekDuration) private var gestureBackwardSeekDuration
@Default(.gestureForwardSeekDuration) private var gestureForwardSeekDuration
@ObservedObject internal var controlsOverlayModel = ControlOverlaysModel.shared @ObservedObject internal var controlsOverlayModel = ControlOverlaysModel.shared
@ -371,10 +373,12 @@ struct VideoPlayerView: View {
guard !player.controls.presentingControls else { return } guard !player.controls.presentingControls else { return }
if direction == .left { if direction == .left {
player.backend.seek(relative: .secondsInDefaultTimescale(-10), seekType: .userInteracted) let interval = TimeInterval(gestureBackwardSeekDuration) ?? 10
player.backend.seek(relative: .secondsInDefaultTimescale(-interval), seekType: .userInteracted)
} }
if direction == .right { if direction == .right {
player.backend.seek(relative: .secondsInDefaultTimescale(10), seekType: .userInteracted) let interval = TimeInterval(gestureForwardSeekDuration) ?? 10
player.backend.seek(relative: .secondsInDefaultTimescale(interval), seekType: .userInteracted)
} }
} }
.onPlayPauseCommand { .onPlayPauseCommand {

View File

@ -33,6 +33,12 @@ struct PlayerSettings: View {
@Default(.openWatchNextOnFinishedWatching) private var openWatchNextOnFinishedWatching @Default(.openWatchNextOnFinishedWatching) private var openWatchNextOnFinishedWatching
@Default(.openWatchNextOnFinishedWatchingDelay) private var openWatchNextOnFinishedWatchingDelay @Default(.openWatchNextOnFinishedWatchingDelay) private var openWatchNextOnFinishedWatchingDelay
@Default(.buttonBackwardSeekDuration) private var buttonBackwardSeekDuration
@Default(.buttonForwardSeekDuration) private var buttonForwardSeekDuration
@Default(.gestureBackwardSeekDuration) private var gestureBackwardSeekDuration
@Default(.gestureForwardSeekDuration) private var gestureForwardSeekDuration
@Default(.systemControlsSeekDuration) private var systemControlsSeekDuration
@Default(.actionButtonShareEnabled) private var actionButtonShareEnabled @Default(.actionButtonShareEnabled) private var actionButtonShareEnabled
@Default(.actionButtonSubscribeEnabled) private var actionButtonSubscribeEnabled @Default(.actionButtonSubscribeEnabled) private var actionButtonSubscribeEnabled
@Default(.actionButtonNextEnabled) private var actionButtonNextEnabled @Default(.actionButtonNextEnabled) private var actionButtonNextEnabled
@ -41,6 +47,7 @@ struct PlayerSettings: View {
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled @Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled @Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
@Default(.actionButtonNextQueueCountEnabled) private var actionButtonNextQueueCountEnabled @Default(.actionButtonNextQueueCountEnabled) private var actionButtonNextQueueCountEnabled
@ObservedObject private var accounts = AccountsModel.shared @ObservedObject private var accounts = AccountsModel.shared
private var player = PlayerModel.shared private var player = PlayerModel.shared
@ -83,6 +90,10 @@ struct PlayerSettings: View {
systemControlsCommandsPicker systemControlsCommandsPicker
} }
Section(header: SettingsHeader(text: "Seeking"), footer: seekingGestureSection) {
seekingSection
}
#if !os(tvOS) #if !os(tvOS)
Section(header: SettingsHeader(text: "Actions Buttons")) { Section(header: SettingsHeader(text: "Actions Buttons")) {
actionButtonToggles actionButtonToggles
@ -225,6 +236,43 @@ struct PlayerSettings: View {
.multilineTextAlignment(.trailing) .multilineTextAlignment(.trailing)
} }
@ViewBuilder private var seekingSection: some View {
seekingDurationSetting("System controls", $systemControlsSeekDuration)
.foregroundColor(systemControlsCommands == .restartAndAdvanceToNext ? .secondary : .primary)
.disabled(systemControlsCommands == .restartAndAdvanceToNext)
seekingDurationSetting("Controls button: backwards", $buttonBackwardSeekDuration)
seekingDurationSetting("Controls button: forwards", $buttonForwardSeekDuration)
seekingDurationSetting("Gesture: backwards", $gestureBackwardSeekDuration)
seekingDurationSetting("Gesture: fowards", $gestureForwardSeekDuration)
}
private var seekingGestureSection: some View {
#if os(iOS)
Text("Gesture settings control skipping interval for double tap gesture on left/right side of the player. Changing system controls settings requires restart.")
#elseif os(macOS)
Text("Gesture settings control skipping interval for double click on left/right side of the player. Changing system controls settings requires restart.")
#else
Text("Gesture settings control skipping interval for remote arrow buttons (for 2nd generation Siri Remote or newer). Changing system controls settings requires restart.")
#endif
}
private func seekingDurationSetting(_ name: String, _ value: Binding<String>) -> some View {
HStack {
Text(name)
.frame(minWidth: 140, alignment: .leading)
Spacer()
TextField("Duration", text: value)
.frame(maxWidth: 50, alignment: .trailing)
.multilineTextAlignment(.trailing)
.labelsHidden()
#if !os(macOS)
.keyboardType(.numberPad)
#endif
}
}
@ViewBuilder private var actionButtonToggles: some View { @ViewBuilder private var actionButtonToggles: some View {
actionButtonToggle("Share", $actionButtonShareEnabled) actionButtonToggle("Share", $actionButtonShareEnabled)
actionButtonToggle("Add to Playlist", $actionButtonAddToPlaylistEnabled) actionButtonToggle("Add to Playlist", $actionButtonAddToPlaylistEnabled)