Merge pull request #820 from yattee/video-details-gestures

add drag gestures to video details
This commit is contained in:
Arkadiusz Fal 2024-11-08 15:03:07 +01:00 committed by GitHub
commit 9ca5d292ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 56 additions and 7 deletions

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.controls.presentingOverlays) { _ in player.playerSize = proxy.size } .onChange(of: player.currentItem?.id) { _ in player.playerSize = proxy.size }
}) })
#if !os(tvOS) #if !os(tvOS)

View File

@ -56,7 +56,6 @@ 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
@ -80,6 +79,54 @@ 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
@ -108,7 +155,6 @@ 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,13 +24,12 @@ struct VideoPlayerView: View {
#if os(macOS) #if os(macOS)
335 335
#else #else
200 140
#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
@ -51,12 +50,14 @@ 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
@ -308,6 +309,8 @@ 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 {}
} }