session-ios/Session/Media Viewing & Editing/Transitions/MediaInteractiveDismiss.swift
Morgan Pretty aabf656d89 Finished off the MediaGallery logic
Updated the config message generation for GRDB
Migrated more preferences into GRDB
Added paging to the MediaTileViewController and sorted out the various animations/transitions
Fixed an issue where the 'recipientState' for the 'baseQuery' on the ConversationCell.ViewModel wasn't grouping correctly
Fixed an issue where the MediaZoomAnimationController could fail if the contextual info wasn't available
Fixed an issue where the MediaZoomAnimationController bounce looked odd when returning to the detail screen from the tile screen
Fixed an issue where the MediaZoomAnimationController didn't work for videos
Fixed a bug where the YDB to GRDB migration wasn't properly handling video files
Fixed a number of minor UI bugs with the GalleryRailView
Deleted a bunch of legacy code
2022-05-20 17:58:39 +10:00

126 lines
4.5 KiB
Swift

// 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 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
}
}
}