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.6 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			128 lines
		
	
	
		
			4.6 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
 | 
						|
        if #available(iOS 13.4, *) { 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
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |