diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index a18f369f3..fa0ffdb84 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -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() { @@ -726,19 +729,46 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc } } - func requestLibraryPermissionIfNeeded() -> Bool { - switch PHPhotoLibrary.authorizationStatus() { - case .authorized, .limited: return true + func requestLibraryPermissionIfNeeded(handler: @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 this ScreenLockUI showing when we request premissions, + // the picker view will be presented on the top of ScreenLockUI. + // However, the ScreenLockUI will dismiss with the permission request alert view, + // the picker view then will dissmiss, 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 + PHPhotoLibrary.requestAuthorization(for: .readWrite) { status in + Environment.shared.isRequestingPermission = false + if ([PHAuthorizationStatus.authorized, PHAuthorizationStatus.limited].contains(status)) { + handler() + } + } + } + } else { + authorizationStatus = PHPhotoLibrary.authorizationStatus() + if (authorizationStatus == .notDetermined) { + PHPhotoLibrary.requestAuthorization { status in + if (status == .authorized) { + handler() + } + } + } + } + switch authorizationStatus { + case .authorized, .limited: + handler() 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 } } diff --git a/Session/Meta/Session-Info.plist b/Session/Meta/Session-Info.plist index 727fb665f..875ffe05b 100644 --- a/Session/Meta/Session-Info.plist +++ b/Session/Meta/Session-Info.plist @@ -2,6 +2,8 @@ + PHPhotoLibraryPreventAutomaticLimitedAccessAlert + BuildDetails CarthageVersion @@ -80,7 +82,7 @@ NSContactsUsageDescription Signal uses your contacts to find users you know. We do not store your contacts on the server. NSFaceIDUsageDescription - Session's Screen Lock feature uses Face ID. + Session's Screen Lock feature uses Face ID. NSMicrophoneUsageDescription Session needs access to your microphone to record media. NSPhotoLibraryAddUsageDescription diff --git a/Session/Shared/OWSScreenLockUI.m b/Session/Shared/OWSScreenLockUI.m index 65bf6f28e..e7cb44121 100644 --- a/Session/Shared/OWSScreenLockUI.m +++ b/Session/Shared/OWSScreenLockUI.m @@ -347,6 +347,10 @@ NS_ASSUME_NONNULL_BEGIN OWSLogVerbose(@"desiredUIState: none 3."); return ScreenLockUIStateNone; } + + if (Environment.shared.isRequestingPermission) { + return ScreenLockUIStateNone; + } if (Environment.shared.preferences.screenSecurityIsEnabled) { OWSLogVerbose(@"desiredUIState: screen protection 4."); diff --git a/SessionMessagingKit/Utilities/Environment.h b/SessionMessagingKit/Utilities/Environment.h index 64d7ddc61..edbd77376 100644 --- a/SessionMessagingKit/Utilities/Environment.h +++ b/SessionMessagingKit/Utilities/Environment.h @@ -29,6 +29,8 @@ @property (nonatomic, readonly) OWSPreferences *preferences; @property (nonatomic, readonly) OWSSounds *sounds; @property (nonatomic, readonly) OWSWindowManager *windowManager; +// We don't want to cover the window when we request the photo library permission +@property (nonatomic, readwrite) BOOL isRequestingPermission; @property (class, nonatomic) Environment *shared; diff --git a/SessionMessagingKit/Utilities/Environment.m b/SessionMessagingKit/Utilities/Environment.m index e4abb4602..81a39ccf2 100644 --- a/SessionMessagingKit/Utilities/Environment.m +++ b/SessionMessagingKit/Utilities/Environment.m @@ -58,6 +58,7 @@ static Environment *sharedEnvironment = nil; _proximityMonitoringManager = proximityMonitoringManager; _sounds = sounds; _windowManager = windowManager; + _isRequestingPermission = false; return self; }