Compare commits

..

1 Commits

Author SHA1 Message Date
Toni Förster
72dcbe4515 allow user to disable fullscreen swipe gesture
furthermore, some rewording

Signed-off-by: Toni Förster <toni.foerster@gmail.com>
2024-09-12 16:57:48 +02:00
8 changed files with 26 additions and 62 deletions

View File

@@ -5,6 +5,7 @@ final class ConstrolsSettingsGroupExporter: SettingsGroupExporter {
override var globalJSON: JSON { override var globalJSON: JSON {
[ [
"avPlayerUsesSystemControls": Defaults[.avPlayerUsesSystemControls], "avPlayerUsesSystemControls": Defaults[.avPlayerUsesSystemControls],
"fullscreenPlayerGestureEnabled": Defaults[.fullscreenPlayerGestureEnabled],
"horizontalPlayerGestureEnabled": Defaults[.horizontalPlayerGestureEnabled], "horizontalPlayerGestureEnabled": Defaults[.horizontalPlayerGestureEnabled],
"seekGestureSensitivity": Defaults[.seekGestureSensitivity], "seekGestureSensitivity": Defaults[.seekGestureSensitivity],
"seekGestureSpeed": Defaults[.seekGestureSpeed], "seekGestureSpeed": Defaults[.seekGestureSpeed],

View File

@@ -9,6 +9,10 @@ struct ConstrolsSettingsGroupImporter {
Defaults[.avPlayerUsesSystemControls] = avPlayerUsesSystemControls Defaults[.avPlayerUsesSystemControls] = avPlayerUsesSystemControls
} }
if let fullscreenPlayerGestureEnabled = json["fullscreenPlayerGestureEnabled"].bool {
Defaults[.fullscreenPlayerGestureEnabled] = fullscreenPlayerGestureEnabled
}
if let horizontalPlayerGestureEnabled = json["horizontalPlayerGestureEnabled"].bool { if let horizontalPlayerGestureEnabled = json["horizontalPlayerGestureEnabled"].bool {
Defaults[.horizontalPlayerGestureEnabled] = horizontalPlayerGestureEnabled Defaults[.horizontalPlayerGestureEnabled] = horizontalPlayerGestureEnabled
} }

View File

@@ -116,6 +116,7 @@ extension Defaults.Keys {
static let avPlayerUsesSystemControls = Key<Bool>("avPlayerUsesSystemControls", default: Constants.isTvOS) static let avPlayerUsesSystemControls = Key<Bool>("avPlayerUsesSystemControls", default: Constants.isTvOS)
static let horizontalPlayerGestureEnabled = Key<Bool>("horizontalPlayerGestureEnabled", default: true) static let horizontalPlayerGestureEnabled = Key<Bool>("horizontalPlayerGestureEnabled", default: true)
static let fullscreenPlayerGestureEnabled = Key<Bool>("fullscreenPlayerGestureEnabled", default: true)
static let seekGestureSensitivity = Key<Double>("seekGestureSensitivity", default: 30.0) static let seekGestureSensitivity = Key<Double>("seekGestureSensitivity", default: 30.0)
static let seekGestureSpeed = Key<Double>("seekGestureSpeed", default: 0.5) static let seekGestureSpeed = Key<Double>("seekGestureSpeed", default: 0.5)

View File

@@ -43,7 +43,7 @@ struct PlayerBackendView: View {
Color.clear Color.clear
.onAppear { player.playerSize = proxy.size } .onAppear { player.playerSize = proxy.size }
.onChange(of: proxy.size) { _ in player.playerSize = proxy.size } .onChange(of: proxy.size) { _ in player.playerSize = proxy.size }
.onChange(of: player.currentItem?.id) { _ in player.playerSize = proxy.size } .onChange(of: player.controls.presentingOverlays) { _ in player.playerSize = proxy.size }
}) })
#if !os(tvOS) #if !os(tvOS)

View File

@@ -56,13 +56,14 @@ extension VideoPlayerView {
player.seek.gestureStart = time player.seek.gestureStart = time
} }
let timeSeek = (time / player.playerSize.width) * horizontalDrag * seekGestureSpeed let timeSeek = (time / player.playerSize.width) * horizontalDrag * seekGestureSpeed
player.seek.gestureSeek = timeSeek player.seek.gestureSeek = timeSeek
} }
return return
} }
// Toggle fullscreen on upward drag only when not disabled // Toggle fullscreen on upward drag only when not disabled
if verticalDrag < -50 { if fullscreenPlayerGestureEnabled, verticalDrag < -50 {
player.toggleFullScreenAction() player.toggleFullScreenAction()
disableGestureTemporarily() disableGestureTemporarily()
return return
@@ -79,54 +80,6 @@ extension VideoPlayerView {
} }
} }
var detailsDragGesture: some Gesture {
DragGesture(minimumDistance: 30)
.onChanged { value in
handleDetailsDragChange(value)
}
.onEnded { value in
handleDetailsDragEnd(value)
}
}
private func handleDetailsDragChange(_ value: DragGesture.Value) {
let maxOffset = -player.playerSize.height
// Continuous drag update for smooth movement of VideoDetails
if fullScreenDetails {
// Allow only downward dragging when in fullscreen
if value.translation.height > 0 {
detailViewDragOffset = min(value.translation.height, abs(maxOffset))
}
} else {
// Allow only upward dragging when not in fullscreen
if value.translation.height < 0 {
detailViewDragOffset = max(value.translation.height, maxOffset)
}
}
}
private func handleDetailsDragEnd(_ value: DragGesture.Value) {
if value.translation.height < -50, !fullScreenDetails {
// Swipe up to enter fullscreen
withAnimation(Constants.overlayAnimation) {
fullScreenDetails = true
detailViewDragOffset = 0
}
} else if value.translation.height > 50, fullScreenDetails {
// Swipe down to exit fullscreen
withAnimation(Constants.overlayAnimation) {
fullScreenDetails = false
detailViewDragOffset = 0
}
} else {
// Reset offset if drag was not significant
withAnimation(Constants.overlayAnimation) {
detailViewDragOffset = 0
}
}
}
func onPlayerDragGestureEnded() { func onPlayerDragGestureEnded() {
if horizontalPlayerGestureEnabled, isHorizontalDrag { if horizontalPlayerGestureEnabled, isHorizontalDrag {
isHorizontalDrag = false isHorizontalDrag = false
@@ -155,6 +108,7 @@ extension VideoPlayerView {
} }
} }
// Function to temporarily disable the toggle gesture after a fullscreen change
private func disableGestureTemporarily() { private func disableGestureTemporarily() {
disableToggleGesture = true disableToggleGesture = true
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {

View File

@@ -223,7 +223,7 @@ struct VideoDetails: View {
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
.contentShape(Rectangle()) .contentShape(Rectangle())
.padding(.horizontal, 16) .padding(.horizontal, 16)
// swiftlint:disable trailing_closure
// TODO: when setting tvOS minimum to 16, the platform modifier can be removed // TODO: when setting tvOS minimum to 16, the platform modifier can be removed
#if !os(tvOS) #if !os(tvOS)
.simultaneousGesture( // Simultaneous gesture to prioritize button tap .simultaneousGesture( // Simultaneous gesture to prioritize button tap
@@ -234,7 +234,7 @@ struct VideoDetails: View {
} }
) )
#endif #endif
// swiftlint:enable trailing_closure
if VideoActions().isAnyActionVisible() { if VideoActions().isAnyActionVisible() {
VideoActions(video: player.videoForDisplay) VideoActions(video: player.videoForDisplay)
.padding(.vertical, 5) .padding(.vertical, 5)

View File

@@ -24,12 +24,13 @@ struct VideoPlayerView: View {
#if os(macOS) #if os(macOS)
335 335
#else #else
140 200
#endif #endif
} }
@State private var playerSize: CGSize = .zero { didSet { updateSidebarQueue() } } @State private var playerSize: CGSize = .zero { didSet { updateSidebarQueue() } }
@State private var hoveringPlayer = false @State private var hoveringPlayer = false
@State private var fullScreenDetails = false
@State private var sidebarQueue = defaultSidebarQueueValue @State private var sidebarQueue = defaultSidebarQueueValue
@Environment(\.colorScheme) private var colorScheme @Environment(\.colorScheme) private var colorScheme
@@ -50,14 +51,12 @@ struct VideoPlayerView: View {
@State var isHorizontalDrag = false @State var isHorizontalDrag = false
@State var isVerticalDrag = false @State var isVerticalDrag = false
@State var viewDragOffset = Self.hiddenOffset @State var viewDragOffset = Self.hiddenOffset
@State var detailViewDragOffset: Double = 0
// swiftlint:enable private_swiftui_state // swiftlint:enable private_swiftui_state
#endif #endif
// swiftlint:disable private_swiftui_state // swiftlint:disable private_swiftui_state
@State var disableToggleGesture = false @State var disableToggleGesture = false
@State var fullScreenDetails = false
// swiftlint:enable private_swiftui_state // swiftlint:enable private_swiftui_state
@ObservedObject var player = PlayerModel.shared // swiftlint:disable:this swiftui_state_private @ObservedObject var player = PlayerModel.shared // swiftlint:disable:this swiftui_state_private
@@ -67,6 +66,7 @@ struct VideoPlayerView: View {
#endif #endif
@Default(.horizontalPlayerGestureEnabled) var horizontalPlayerGestureEnabled @Default(.horizontalPlayerGestureEnabled) var horizontalPlayerGestureEnabled
@Default(.fullscreenPlayerGestureEnabled) var fullscreenPlayerGestureEnabled
@Default(.seekGestureSpeed) var seekGestureSpeed @Default(.seekGestureSpeed) var seekGestureSpeed
@Default(.seekGestureSensitivity) var seekGestureSensitivity @Default(.seekGestureSensitivity) var seekGestureSensitivity
@Default(.playerSidebar) var playerSidebar @Default(.playerSidebar) var playerSidebar
@@ -308,8 +308,6 @@ struct VideoPlayerView: View {
#endif #endif
.id(player.currentVideo?.cacheKey) .id(player.currentVideo?.cacheKey)
.transition(.opacity) .transition(.opacity)
.offset(y: detailViewDragOffset)
.gesture(detailsDragGesture)
} else { } else {
VStack {} VStack {}
} }

View File

@@ -8,6 +8,7 @@ struct PlayerControlsSettings: View {
@Default(.playerControlsLayout) private var playerControlsLayout @Default(.playerControlsLayout) private var playerControlsLayout
@Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout @Default(.fullScreenPlayerControlsLayout) private var fullScreenPlayerControlsLayout
@Default(.horizontalPlayerGestureEnabled) private var horizontalPlayerGestureEnabled @Default(.horizontalPlayerGestureEnabled) private var horizontalPlayerGestureEnabled
@Default(.fullscreenPlayerGestureEnabled) private var fullscreenPlayerGestureEnabled
@Default(.seekGestureSpeed) private var seekGestureSpeed @Default(.seekGestureSpeed) private var seekGestureSpeed
@Default(.seekGestureSensitivity) private var seekGestureSensitivity @Default(.seekGestureSensitivity) private var seekGestureSensitivity
@Default(.buttonBackwardSeekDuration) private var buttonBackwardSeekDuration @Default(.buttonBackwardSeekDuration) private var buttonBackwardSeekDuration
@@ -64,9 +65,10 @@ struct PlayerControlsSettings: View {
@ViewBuilder var sections: some View { @ViewBuilder var sections: some View {
#if !os(tvOS) #if !os(tvOS)
Section(header: SettingsHeader(text: "Controls".localized()), footer: controlsLayoutFooter) { Section(header: SettingsHeader(text: "Player Controls".localized()), footer: controlsLayoutFooter) {
#if !os(tvOS)
avPlayerUsesSystemControlsToggle avPlayerUsesSystemControlsToggle
#if os(iOS)
fullscreenPlayerGestureEnabledToggle
#endif #endif
horizontalPlayerGestureEnabledToggle horizontalPlayerGestureEnabledToggle
SettingsHeader(text: "Seek gesture sensitivity".localized(), secondary: true) SettingsHeader(text: "Seek gesture sensitivity".localized(), secondary: true)
@@ -112,7 +114,7 @@ struct PlayerControlsSettings: View {
} }
var controlsButtonsSection: some View { var controlsButtonsSection: some View {
Section(header: SettingsHeader(text: "Controls Buttons".localized())) { Section(header: SettingsHeader(text: "Player Control Buttons".localized())) {
controlButtonToggles controlButtonToggles
} }
} }
@@ -157,8 +159,12 @@ struct PlayerControlsSettings: View {
#endif #endif
} }
private var fullscreenPlayerGestureEnabledToggle: some View {
Toggle("Swipe up toggles fullscreen", isOn: $fullscreenPlayerGestureEnabled)
}
private var horizontalPlayerGestureEnabledToggle: some View { private var horizontalPlayerGestureEnabledToggle: some View {
Toggle("Seek with horizontal swipe on video", isOn: $horizontalPlayerGestureEnabled) Toggle("Seek with horizontal swipe", isOn: $horizontalPlayerGestureEnabled)
} }
private var avPlayerUsesSystemControlsToggle: some View { private var avPlayerUsesSystemControlsToggle: some View {