// // GalleryDismissInteraction.swift // GalleryVC // // Created by Shadowfacts on 3/1/24. // import UIKit @MainActor class GalleryDismissInteraction: NSObject { private unowned let viewController: GalleryViewController private var content: GalleryContentViewController? private var origContentFrameInGallery: CGRect? private var origControlsVisible: Bool? private(set) var isActive = false private(set) var dismissVelocity: CGPoint? private(set) var dismissTranslation: CGPoint? init(viewController: GalleryViewController) { self.viewController = viewController super.init() let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panRecognized)) panRecognizer.delegate = self panRecognizer.allowedScrollTypesMask = .continuous viewController.view.addGestureRecognizer(panRecognizer) } @objc private func panRecognized(_ recognizer: UIPanGestureRecognizer) { switch recognizer.state { case .began: isActive = true origContentFrameInGallery = viewController.view.convert(viewController.currentItemViewController.content.view.bounds, from: viewController.currentItemViewController.content.view) content = viewController.currentItemViewController.takeContent() content!.view.translatesAutoresizingMaskIntoConstraints = true content!.view.frame = origContentFrameInGallery! viewController.view.addSubview(content!.view) origControlsVisible = viewController.currentItemViewController.controlsVisible if origControlsVisible! { viewController.currentItemViewController.setControlsVisible(false, animated: true) } case .changed: let translation = recognizer.translation(in: viewController.view) content!.view.frame = origContentFrameInGallery!.offsetBy(dx: translation.x, dy: translation.y) case .ended: let translation = recognizer.translation(in: viewController.view) let velocity = recognizer.velocity(in: viewController.view) dismissVelocity = velocity dismissTranslation = translation viewController.dismiss(animated: true) // don't unset this until after dismiss is called, so that the dismiss animation controller can read it isActive = false default: break } } } extension GalleryDismissInteraction: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { let itemVC = viewController.currentItemViewController if viewController.galleryDataSource.galleryContentTransitionSourceView(forItemAt: itemVC.itemIndex) == nil { return false } else if itemVC.scrollView.zoomScale > itemVC.scrollView.minimumZoomScale { return false } else if !itemVC.scrollAndZoomEnabled { return false } else { return true } } }