mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.7 KiB
Swift
109 lines
3.7 KiB
Swift
3 years ago
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||
|
|
||
|
import UIKit
|
||
|
|
||
|
// MARK: - InteractivelyDismissableViewController
|
||
|
|
||
|
protocol InteractivelyDismissableViewController: UIViewController {
|
||
|
func performInteractiveDismissal(animated: Bool)
|
||
|
}
|
||
|
|
||
|
// MARK: - InteractiveDismissDelegate
|
||
|
|
||
|
protocol InteractiveDismissDelegate: AnyObject {
|
||
|
func interactiveDismissUpdate(_ interactiveDismiss: UIPercentDrivenInteractiveTransition, didChangeTouchOffset offset: CGPoint)
|
||
|
func interactiveDismissDidFinish(_ interactiveDismiss: UIPercentDrivenInteractiveTransition)
|
||
|
}
|
||
|
|
||
|
// MARK: - MediaInteractiveDismiss
|
||
|
|
||
|
class MediaInteractiveDismiss: UIPercentDrivenInteractiveTransition {
|
||
|
var interactionInProgress = false
|
||
|
|
||
|
weak var interactiveDismissDelegate: InteractiveDismissDelegate?
|
||
|
private weak var targetViewController: InteractivelyDismissableViewController?
|
||
|
|
||
|
init(targetViewController: InteractivelyDismissableViewController) {
|
||
|
super.init()
|
||
|
|
||
|
self.targetViewController = targetViewController
|
||
|
}
|
||
|
|
||
|
public func addGestureRecognizer(to view: UIView) {
|
||
|
let gesture: DirectionalPanGestureRecognizer = DirectionalPanGestureRecognizer(direction: .vertical, target: self, action: #selector(handleGesture(_:)))
|
||
|
|
||
|
// Allow panning with trackpad
|
||
|
if #available(iOS 13.4, *) { gesture.allowedScrollTypesMask = .continuous }
|
||
|
|
||
|
view.addGestureRecognizer(gesture)
|
||
|
}
|
||
|
|
||
|
// MARK: - Private
|
||
|
|
||
|
private var fastEnoughToCompleteTransition = false
|
||
|
private var farEnoughToCompleteTransition = false
|
||
|
|
||
|
private var shouldCompleteTransition: Bool {
|
||
|
if farEnoughToCompleteTransition { return true }
|
||
|
if fastEnoughToCompleteTransition { return true }
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
@objc private func handleGesture(_ gestureRecognizer: UIScreenEdgePanGestureRecognizer) {
|
||
|
guard let coordinateSpace = gestureRecognizer.view?.superview else { return }
|
||
|
|
||
|
if case .began = gestureRecognizer.state {
|
||
|
gestureRecognizer.setTranslation(.zero, in: coordinateSpace)
|
||
|
}
|
||
|
|
||
|
let totalDistance: CGFloat = 100
|
||
|
let velocityThreshold: CGFloat = 500
|
||
|
|
||
|
switch gestureRecognizer.state {
|
||
|
case .began:
|
||
|
interactionInProgress = true
|
||
|
targetViewController?.performInteractiveDismissal(animated: true)
|
||
|
|
||
|
case .changed:
|
||
|
let velocity = abs(gestureRecognizer.velocity(in: coordinateSpace).y)
|
||
|
if velocity > velocityThreshold {
|
||
|
fastEnoughToCompleteTransition = true
|
||
|
}
|
||
|
|
||
|
let offset = gestureRecognizer.translation(in: coordinateSpace)
|
||
|
let progress = abs(offset.y) / totalDistance
|
||
|
// `farEnoughToCompleteTransition` is cancelable if the user reverses direction
|
||
|
farEnoughToCompleteTransition = progress >= 0.5
|
||
|
update(progress)
|
||
|
|
||
|
interactiveDismissDelegate?.interactiveDismissUpdate(self, didChangeTouchOffset: offset)
|
||
|
|
||
|
case .cancelled:
|
||
|
interactiveDismissDelegate?.interactiveDismissDidFinish(self)
|
||
|
cancel()
|
||
|
|
||
|
interactionInProgress = false
|
||
|
farEnoughToCompleteTransition = false
|
||
|
fastEnoughToCompleteTransition = false
|
||
|
|
||
|
case .ended:
|
||
|
if shouldCompleteTransition {
|
||
|
finish()
|
||
|
}
|
||
|
else {
|
||
|
cancel()
|
||
|
}
|
||
|
|
||
|
interactiveDismissDelegate?.interactiveDismissDidFinish(self)
|
||
|
|
||
|
interactionInProgress = false
|
||
|
farEnoughToCompleteTransition = false
|
||
|
fastEnoughToCompleteTransition = false
|
||
|
|
||
|
default:
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|