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.
128 lines
4.5 KiB
Swift
128 lines
4.5 KiB
Swift
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
import UIKit
|
|
import SignalUtilitiesKit
|
|
|
|
// 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
|
|
gesture.allowedScrollTypesMask = .continuous
|
|
|
|
view.addGestureRecognizer(gesture)
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private var fastEnoughToCompleteTransition = false
|
|
private var farEnoughToCompleteTransition = false
|
|
private var lastProgress: CGFloat = 0
|
|
private var lastIncreasedProgress: CGFloat = 0
|
|
|
|
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)
|
|
|
|
// If the user has reverted enough progress then we want to reset the velocity
|
|
// flag (don't want the user to start quickly, slowly drag it back end end up
|
|
// dismissing the screen)
|
|
if (lastIncreasedProgress - progress) > 0.2 || progress < 0.05 {
|
|
fastEnoughToCompleteTransition = false
|
|
}
|
|
|
|
update(progress)
|
|
|
|
lastIncreasedProgress = (progress > lastProgress ? progress : lastIncreasedProgress)
|
|
lastProgress = progress
|
|
|
|
interactiveDismissDelegate?.interactiveDismissUpdate(self, didChangeTouchOffset: offset)
|
|
|
|
case .cancelled:
|
|
interactiveDismissDelegate?.interactiveDismissDidFinish(self)
|
|
cancel()
|
|
|
|
interactionInProgress = false
|
|
farEnoughToCompleteTransition = false
|
|
fastEnoughToCompleteTransition = false
|
|
lastIncreasedProgress = 0
|
|
lastProgress = 0
|
|
|
|
case .ended:
|
|
if shouldCompleteTransition {
|
|
finish()
|
|
}
|
|
else {
|
|
cancel()
|
|
}
|
|
|
|
interactiveDismissDelegate?.interactiveDismissDidFinish(self)
|
|
|
|
interactionInProgress = false
|
|
farEnoughToCompleteTransition = false
|
|
fastEnoughToCompleteTransition = false
|
|
lastIncreasedProgress = 0
|
|
lastProgress = 0
|
|
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|