178 lines
5.2 KiB
Swift
178 lines
5.2 KiB
Swift
//
|
|
// Swiftfin is subject to the terms of the Mozilla Public
|
|
// License, v2.0. If a copy of the MPL was not distributed with this
|
|
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
//
|
|
// Copyright (c) 2025 Jellyfin & Jellyfin Contributors
|
|
//
|
|
|
|
import Combine
|
|
import Foundation
|
|
import Logging
|
|
import SwiftUI
|
|
|
|
// TODO: figure out this directional response stuff
|
|
extension EnvironmentValues {
|
|
|
|
@Entry
|
|
var panGestureDirection: Direction = .all
|
|
}
|
|
|
|
struct GestureView: UIViewRepresentable {
|
|
|
|
func makeUIView(context: Context) -> UIView {
|
|
let view = UIView(frame: .zero)
|
|
|
|
view.addGestureRecognizer(context.coordinator.longPressGesture)
|
|
view.addGestureRecognizer(context.coordinator.panGesture)
|
|
view.addGestureRecognizer(context.coordinator.pinchGesture)
|
|
view.addGestureRecognizer(context.coordinator.tapGesture)
|
|
view.addGestureRecognizer(context.coordinator.doubleTouchGesture)
|
|
|
|
view.backgroundColor = .clear
|
|
return view
|
|
}
|
|
|
|
func updateUIView(_ uiView: UIView, context: Context) {
|
|
|
|
context.coordinator.longPressAction = context.environment.longPressAction
|
|
context.coordinator.panAction = context.environment.panAction
|
|
context.coordinator.pinchAction = context.environment.pinchAction
|
|
context.coordinator.tapAction = context.environment.tapGestureAction
|
|
|
|
context.coordinator.panGesture.direction = context.environment.panGestureDirection
|
|
}
|
|
|
|
func makeCoordinator() -> Coordinator {
|
|
Coordinator()
|
|
}
|
|
|
|
class Coordinator {
|
|
|
|
lazy var doubleTouchGesture: UITapGestureRecognizer! = {
|
|
let recognizer = UITapGestureRecognizer(
|
|
target: self,
|
|
action: #selector(handleTap)
|
|
)
|
|
recognizer.numberOfTouchesRequired = 2
|
|
return recognizer
|
|
}()
|
|
|
|
lazy var longPressGesture: UILongPressGestureRecognizer! = {
|
|
let recognizer = UILongPressGestureRecognizer(
|
|
target: self,
|
|
action: #selector(handleLongPress)
|
|
)
|
|
recognizer.minimumPressDuration = 1.2
|
|
return recognizer
|
|
}()
|
|
|
|
lazy var panGesture: DirectionalPanGestureRecognizer! = {
|
|
.init(
|
|
direction: .allButDown,
|
|
target: self,
|
|
action: #selector(handlePan)
|
|
)
|
|
}()
|
|
|
|
lazy var pinchGesture: UIPinchGestureRecognizer! = {
|
|
.init(
|
|
target: self,
|
|
action: #selector(handlePinch)
|
|
)
|
|
}()
|
|
|
|
lazy var tapGesture: UITapGestureRecognizer! = {
|
|
.init(
|
|
target: self,
|
|
action: #selector(handleTap)
|
|
)
|
|
}()
|
|
|
|
var longPressAction: LongPressAction? {
|
|
didSet { longPressGesture.isEnabled = longPressAction != nil }
|
|
}
|
|
|
|
var panAction: PanAction? {
|
|
didSet { panGesture.isEnabled = panAction != nil }
|
|
}
|
|
|
|
var pinchAction: PinchAction? {
|
|
didSet { pinchGesture.isEnabled = pinchAction != nil }
|
|
}
|
|
|
|
var tapAction: TapAction? {
|
|
didSet {
|
|
doubleTouchGesture.isEnabled = tapAction != nil
|
|
tapGesture.isEnabled = tapAction != nil
|
|
}
|
|
}
|
|
|
|
private var didSwipe = false
|
|
|
|
@objc
|
|
func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
|
|
guard let view = gesture.view else { return }
|
|
|
|
let location = gesture.location(in: view)
|
|
let unitPoint = UnitPoint(
|
|
x: location.x / view.bounds.width,
|
|
y: location.y / view.bounds.height
|
|
)
|
|
|
|
longPressAction?(
|
|
location: location,
|
|
unitPoint: unitPoint,
|
|
state: gesture.state
|
|
)
|
|
}
|
|
|
|
@objc
|
|
func handlePan(_ gesture: UIPanGestureRecognizer) {
|
|
guard let view = gesture.view else { return }
|
|
|
|
let translation = gesture.translation(in: view)
|
|
let velocity = gesture.velocity(in: view)
|
|
let location = gesture.location(in: view)
|
|
let unitPoint = UnitPoint(
|
|
x: location.x / view.bounds.width,
|
|
y: location.y / view.bounds.height
|
|
)
|
|
|
|
panAction?(
|
|
translation: translation,
|
|
velocity: velocity,
|
|
location: location,
|
|
unitPoint: unitPoint,
|
|
state: gesture.state
|
|
)
|
|
}
|
|
|
|
@objc
|
|
func handlePinch(_ gesture: UIPinchGestureRecognizer) {
|
|
pinchAction?(
|
|
scale: gesture.scale,
|
|
velocity: gesture.velocity,
|
|
state: gesture.state
|
|
)
|
|
}
|
|
|
|
@objc
|
|
func handleTap(_ gesture: UITapGestureRecognizer) {
|
|
guard let view = gesture.view else { return }
|
|
|
|
let location = gesture.location(in: gesture.view)
|
|
let unitPoint = UnitPoint(
|
|
x: location.x / view.bounds.width,
|
|
y: location.y / view.bounds.height
|
|
)
|
|
|
|
tapAction?(
|
|
location: location,
|
|
unitPoint: unitPoint,
|
|
count: gesture.numberOfTouches
|
|
)
|
|
}
|
|
}
|
|
}
|