|  |  |  | @ -1,5 +1,6 @@ | 
		
	
		
			
				|  |  |  |  | import CoreServices | 
		
	
		
			
				|  |  |  |  | import Photos | 
		
	
		
			
				|  |  |  |  | import PhotosUI | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuActionDelegate, ScrollToBottomButtonDelegate, | 
		
	
		
			
				|  |  |  |  |     SendMediaNavDelegate, UIDocumentPickerDelegate, AttachmentApprovalViewControllerDelegate, GifPickerViewControllerDelegate, | 
		
	
	
		
			
				
					|  |  |  | @ -91,12 +92,14 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |     func handleLibraryButtonTapped() { | 
		
	
		
			
				|  |  |  |  |         // FIXME: We're not yet handling the case where the user only gives access to selected photos/videos | 
		
	
		
			
				|  |  |  |  |         guard requestLibraryPermissionIfNeeded() else { return } | 
		
	
		
			
				|  |  |  |  |         let sendMediaNavController = SendMediaNavigationController.showingMediaLibraryFirst() | 
		
	
		
			
				|  |  |  |  |         sendMediaNavController.sendMediaNavDelegate = self | 
		
	
		
			
				|  |  |  |  |         sendMediaNavController.modalPresentationStyle = .fullScreen | 
		
	
		
			
				|  |  |  |  |         present(sendMediaNavController, animated: true, completion: nil) | 
		
	
		
			
				|  |  |  |  |         requestLibraryPermissionIfNeeded { [weak self] in | 
		
	
		
			
				|  |  |  |  |             DispatchQueue.main.async { | 
		
	
		
			
				|  |  |  |  |                 let sendMediaNavController = SendMediaNavigationController.showingMediaLibraryFirst() | 
		
	
		
			
				|  |  |  |  |                 sendMediaNavController.sendMediaNavDelegate = self | 
		
	
		
			
				|  |  |  |  |                 sendMediaNavController.modalPresentationStyle = .fullScreen | 
		
	
		
			
				|  |  |  |  |                 self?.present(sendMediaNavController, animated: true, completion: nil) | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |     func handleGIFButtonTapped() { | 
		
	
	
		
			
				
					|  |  |  | @ -752,19 +755,54 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     func requestLibraryPermissionIfNeeded() -> Bool { | 
		
	
		
			
				|  |  |  |  |         switch PHPhotoLibrary.authorizationStatus() { | 
		
	
		
			
				|  |  |  |  |         case .authorized, .limited: return true | 
		
	
		
			
				|  |  |  |  |     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 | 
		
	
		
			
				|  |  |  |  |             present(modal, animated: true, completion: nil) | 
		
	
		
			
				|  |  |  |  |             return false | 
		
	
		
			
				|  |  |  |  |         case .notDetermined: | 
		
	
		
			
				|  |  |  |  |             PHPhotoLibrary.requestAuthorization { _ in } | 
		
	
		
			
				|  |  |  |  |             return false | 
		
	
		
			
				|  |  |  |  |         default: return false | 
		
	
		
			
				|  |  |  |  |         default: return | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | 
 |