1 // Copyright 2022-present 650 Industries. All rights reserved. 2 3 import PhotosUI 4 5 /** 6 Protocol that describes scenarios we care about while the user is picking media. 7 */ 8 protocol OnMediaPickingResultHandler { 9 @available(iOS 14, *) didPickMultipleMedianull10 func didPickMultipleMedia(selection: [PHPickerResult]) 11 func didPickMedia(mediaInfo: MediaInfo) 12 func didCancelPicking() 13 } 14 15 /** 16 This class is responsible for responding to any events that are happening in `UIImagePickerController`. 17 It then forwards them back in unified way via `OnMediaPickingResultHandler`. 18 19 The functionality of this delegate is separated from the main module class for two reasons: 20 1) main module cannot inherit from `NSObject` (and that's required by three protocols we must conform to), 21 because it already inherits from `Module` class and Swift language does not allow multiple inheritance, 22 2) it separates some logic from the main module class and hopefully makes it cleaner. 23 */ 24 internal class ImagePickerHandler: NSObject, 25 PHPickerViewControllerDelegate, 26 UINavigationControllerDelegate, 27 UIImagePickerControllerDelegate, 28 UIAdaptivePresentationControllerDelegate { 29 private let onMediaPickingResultHandler: OnMediaPickingResultHandler 30 private let hideStatusBarWhenPresented: Bool 31 private var statusBarVisibilityController = StatusBarVisibilityController() 32 33 init(onMediaPickingResultHandler: OnMediaPickingResultHandler, hideStatusBarWhenPresented: Bool) { 34 self.onMediaPickingResultHandler = onMediaPickingResultHandler 35 self.hideStatusBarWhenPresented = hideStatusBarWhenPresented 36 } 37 38 private func handlePickedMedia(mediaInfo: MediaInfo) { 39 statusBarVisibilityController.maybeRestoreStatusBarVisibility() 40 onMediaPickingResultHandler.didPickMedia(mediaInfo: mediaInfo) 41 } 42 43 @available(iOS 14, *) 44 private func handlePickedMedia(selection: [PHPickerResult]) { 45 statusBarVisibilityController.maybeRestoreStatusBarVisibility() 46 onMediaPickingResultHandler.didPickMultipleMedia(selection: selection) 47 } 48 49 private func handlePickingCancellation() { 50 statusBarVisibilityController.maybeRestoreStatusBarVisibility() 51 onMediaPickingResultHandler.didCancelPicking() 52 } 53 54 // MARK: - UIImagePickerControllerDelegate 55 56 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: MediaInfo) { 57 DispatchQueue.main.async { 58 picker.dismiss(animated: true) { [weak self] in 59 self?.handlePickedMedia(mediaInfo: info) 60 } 61 } 62 } 63 64 func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { 65 DispatchQueue.main.async { 66 picker.dismiss(animated: true) { [weak self] in 67 self?.handlePickingCancellation() 68 } 69 } 70 } 71 72 // MARK: - PHPickerViewControllerDelegate 73 74 @available(iOS 14, *) 75 func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { 76 DispatchQueue.main.async { 77 picker.dismiss(animated: true) { [weak self] in 78 // The PHPickerViewController returns empty collection when canceled 79 if results.isEmpty { 80 self?.handlePickingCancellation() 81 } else { 82 self?.handlePickedMedia(selection: results) 83 } 84 } 85 } 86 } 87 88 // MARK: - UIAdaptivePresentationControllerDelegate 89 90 func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { 91 handlePickingCancellation() 92 } 93 94 // MARK: - UINavigationControllerDelegate 95 96 func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { 97 statusBarVisibilityController.maybePreserveVisibilityAndHideStatusBar(hideStatusBarWhenPresented) 98 } 99 } 100 101 /** 102 Protocol that is a common type for supported picker controllers. 103 */ 104 internal protocol PickerUIController: UIViewController { setResultHandlernull105 func setResultHandler(_ handler: ImagePickerHandler) 106 } 107 108 extension UIImagePickerController: PickerUIController { 109 func setResultHandler(_ handler: ImagePickerHandler) { 110 self.delegate = handler 111 self.presentationController?.delegate = handler 112 } 113 } 114 115 @available(iOS 14, *) 116 extension PHPickerViewController: PickerUIController { setResultHandlernull117 func setResultHandler(_ handler: ImagePickerHandler) { 118 self.delegate = handler 119 self.presentationController?.delegate = handler 120 } 121 } 122