|  |  |  | import Photos | 
					
						
							|  |  |  | import PhotosUI | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public func requestCameraPermissionIfNeeded() -> Bool { | 
					
						
							|  |  |  |     switch AVCaptureDevice.authorizationStatus(for: .video) { | 
					
						
							|  |  |  |     case .authorized: return true | 
					
						
							|  |  |  |     case .denied, .restricted: | 
					
						
							|  |  |  |         let modal = PermissionMissingModal(permission: "camera") { } | 
					
						
							|  |  |  |         modal.modalPresentationStyle = .overFullScreen | 
					
						
							|  |  |  |         modal.modalTransitionStyle = .crossDissolve | 
					
						
							|  |  |  |         guard let presentingVC = CurrentAppContext().frontmostViewController() else { preconditionFailure() } | 
					
						
							|  |  |  |         presentingVC.present(modal, animated: true, completion: nil) | 
					
						
							|  |  |  |         return false | 
					
						
							|  |  |  |     case .notDetermined: | 
					
						
							|  |  |  |         AVCaptureDevice.requestAccess(for: .video, completionHandler: { _ in }) | 
					
						
							|  |  |  |         return false | 
					
						
							|  |  |  |     default: return false | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public func requestMicrophonePermissionIfNeeded(onNotGranted: @escaping () -> Void) { | 
					
						
							|  |  |  |     switch AVAudioSession.sharedInstance().recordPermission { | 
					
						
							|  |  |  |     case .granted: break | 
					
						
							|  |  |  |     case .denied: | 
					
						
							|  |  |  |         onNotGranted() | 
					
						
							|  |  |  |         let modal = PermissionMissingModal(permission: "microphone") { | 
					
						
							|  |  |  |             onNotGranted() | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         modal.modalPresentationStyle = .overFullScreen | 
					
						
							|  |  |  |         modal.modalTransitionStyle = .crossDissolve | 
					
						
							|  |  |  |         guard let presentingVC = CurrentAppContext().frontmostViewController() else { preconditionFailure() } | 
					
						
							|  |  |  |         presentingVC.present(modal, animated: true, completion: nil) | 
					
						
							|  |  |  |     case .undetermined: | 
					
						
							|  |  |  |         onNotGranted() | 
					
						
							|  |  |  |         AVAudioSession.sharedInstance().requestRecordPermission { _ in } | 
					
						
							|  |  |  |     default: break | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public func requestLibraryPermissionIfNeeded(onAuthorized: @escaping () -> Void) { | 
					
						
							|  |  |  |     let authorizationStatus: PHAuthorizationStatus | 
					
						
							|  |  |  |     if #available(iOS 14, *) { | 
					
						
							|  |  |  |         authorizationStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite) | 
					
						
							|  |  |  |         if authorizationStatus == .notDetermined { | 
					
						
							|  |  |  |             // When the user chooses to select photos (which is the .limit status), | 
					
						
							|  |  |  |             // the PHPhotoUI will present the picker view on the top of the front view. | 
					
						
							|  |  |  |             // Since we have the ScreenLockUI showing when we request premissions, | 
					
						
							|  |  |  |             // the picker view will be presented on the top of the ScreenLockUI. | 
					
						
							|  |  |  |             // However, the ScreenLockUI will dismiss with the permission request alert view, so | 
					
						
							|  |  |  |             // the picker view then will dismiss, too. The selection process cannot be finished | 
					
						
							|  |  |  |             // this way. So we add a flag (isRequestingPermission) to prevent the ScreenLockUI | 
					
						
							|  |  |  |             // from showing when we request the photo library permission. | 
					
						
							|  |  |  |             Environment.shared?.isRequestingPermission = true | 
					
						
							|  |  |  |             let appMode = AppModeManager.shared.currentAppMode | 
					
						
							|  |  |  |             // FIXME: Rather than setting the app mode to light and then to dark again once we're done, | 
					
						
							|  |  |  |             // it'd be better to just customize the appearance of the image picker. There doesn't currently | 
					
						
							|  |  |  |             // appear to be a good way to do so though... | 
					
						
							|  |  |  |             AppModeManager.shared.setCurrentAppMode(to: .light) | 
					
						
							|  |  |  |             PHPhotoLibrary.requestAuthorization(for: .readWrite) { status in | 
					
						
							|  |  |  |                 DispatchQueue.main.async { | 
					
						
							|  |  |  |                     AppModeManager.shared.setCurrentAppMode(to: appMode) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 Environment.shared?.isRequestingPermission = false | 
					
						
							|  |  |  |                 if [ PHAuthorizationStatus.authorized, PHAuthorizationStatus.limited ].contains(status) { | 
					
						
							|  |  |  |                     onAuthorized() | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         authorizationStatus = PHPhotoLibrary.authorizationStatus() | 
					
						
							|  |  |  |         if authorizationStatus == .notDetermined { | 
					
						
							|  |  |  |             PHPhotoLibrary.requestAuthorization { status in | 
					
						
							|  |  |  |                 if status == .authorized { | 
					
						
							|  |  |  |                     onAuthorized() | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     switch authorizationStatus { | 
					
						
							|  |  |  |     case .authorized, .limited: | 
					
						
							|  |  |  |         onAuthorized() | 
					
						
							|  |  |  |     case .denied, .restricted: | 
					
						
							|  |  |  |         let modal = PermissionMissingModal(permission: "library") { } | 
					
						
							|  |  |  |         modal.modalPresentationStyle = .overFullScreen | 
					
						
							|  |  |  |         modal.modalTransitionStyle = .crossDissolve | 
					
						
							|  |  |  |         guard let presentingVC = CurrentAppContext().frontmostViewController() else { preconditionFailure() } | 
					
						
							|  |  |  |         presentingVC.present(modal, animated: true, completion: nil) | 
					
						
							|  |  |  |     default: return | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |