diff --git a/ownCloud/Client/Actions/Actions+Extensions/UploadMediaAction.swift b/ownCloud/Client/Actions/Actions+Extensions/UploadMediaAction.swift
index 8afefc687..730428a81 100644
--- a/ownCloud/Client/Actions/Actions+Extensions/UploadMediaAction.swift
+++ b/ownCloud/Client/Actions/Actions+Extensions/UploadMediaAction.swift
@@ -20,8 +20,116 @@ import UIKit
import ownCloudSDK
import ownCloudAppShared
import Photos
+import PhotosUI
+
+@available(iOS 14, *)
+class PhotoPickerPresenter: NSObject, PHPickerViewControllerDelegate, PHPhotoLibraryChangeObserver {
+
+ typealias AssetSelectionHandler = ([PHAsset]) -> Void
+
+ var completionHandler: AssetSelectionHandler?
+ var parentViewController: UIViewController?
+
+ private var assetIdentifiers = [String]()
+
+ override init() {
+ super.init()
+ PHPhotoLibrary.shared().register(self)
+ }
+
+ var pickerViewController: UIViewController {
+ var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
+ configuration.preferredAssetRepresentationMode = .automatic
+ configuration.selectionLimit = 0
+ let pickerViewController = PHPickerViewController(configuration: configuration)
+ pickerViewController.delegate = self
+
+ return pickerViewController
+ }
+
+ // MARK: - PHPickerViewControllerDelegate
+
+ func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
+
+ picker.dismiss(animated: true)
+
+ OnBackgroundQueue {
+
+ // Get asset identifiers
+ for result in results {
+ if let identifier = result.assetIdentifier {
+ self.assetIdentifiers.append(identifier)
+ }
+ }
+
+ // Fetch corresponding assets
+ let assets = self.attemptAssetsFetch()
+
+ OnMainThread {
+ if results.count == assets.count{
+ self.completionHandler?(assets)
+ } else {
+ self.presentLimitedLibraryPicker()
+ }
+ }
+ }
+ }
+
+ private func presentLimitedLibraryPicker() {
+ guard let viewController = self.parentViewController else { return }
+ let library = PHPhotoLibrary.shared()
+
+ let alert = ThemedAlertController(title: "Limited Photo Access".localized, message: "Access for the media selected for upload is limited".localized, preferredStyle: .alert)
+
+ alert.addAction(UIAlertAction(title: "Change".localized, style: .default, handler: {_ in
+ library.presentLimitedLibraryPicker(from: viewController)
+ }))
+ alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in
+ self.assetIdentifiers.removeAll()
+ }))
+
+ self.parentViewController?.present(alert, animated: true)
+
+ }
+
+ private func attemptAssetsFetch() -> [PHAsset] {
+ // Fetch corresponding assets
+ var assets = [PHAsset]()
+
+ let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: assetIdentifiers, options: nil)
+ fetchResult.enumerateObjects({ (asset, _, _) in
+ assets.append(asset)
+ })
+
+ return assets
+ }
+
+ func present(in viewController:UIViewController, with completion:@escaping AssetSelectionHandler) {
+ self.parentViewController = viewController
+ self.completionHandler = completion
+ viewController.present(self.pickerViewController, animated: true)
+ }
+
+ // MARK: - PHPhotoLibraryChangeObserver
+
+ func photoLibraryDidChange(_ changeInstance: PHChange) {
+ OnMainThread {
+ let assets = self.attemptAssetsFetch()
+ if assets.count > 0 {
+ self.completionHandler?(assets)
+ } else {
+ let alert = ThemedAlertController(title: "Limited Photo Access".localized, message: "No Access to the media selected for upload".localized, preferredStyle: .alert)
+
+ alert.addAction(UIAlertAction(title: "OK".localized, style: .default, handler: nil))
+
+ self.parentViewController?.present(alert, animated: true)
+ }
+ }
+ }
+}
class UploadMediaAction: UploadBaseAction {
+
override class var identifier : OCExtensionIdentifier? { return OCExtensionIdentifier("com.owncloud.action.uploadphotos") }
override class var category : ActionCategory? { return .normal }
override class var name : String { return "Upload from your photo library".localized }
@@ -29,6 +137,9 @@ class UploadMediaAction: UploadBaseAction {
override class var keyCommand : String? { return "M" }
override class var keyModifierFlags: UIKeyModifierFlags? { return [.command] }
+ // We need this to keep PhotoPickerPresenter alive in iOS14. Type is 'Any' since it is iOS14 only and you can't add @available() to stored properties
+ private var picker: Any?
+
private struct AssociatedKeys {
static var actionKey = "action"
}
@@ -52,20 +163,33 @@ class UploadMediaAction: UploadBaseAction {
}
private func presentImageGalleryPicker() {
- if let viewController = self.context.viewController {
- let photoAlbumViewController = PhotoAlbumTableViewController()
- photoAlbumViewController.selectionCallback = {(assets) in
- self.completed()
- guard let path = self.context.items.first?.path else { return }
+ func addAssetsToQueue(assets:[PHAsset]) {
+ guard let path = self.context.items.first?.path else { return }
+ guard let bookmark = self.core?.bookmark else { return }
- guard let bookmark = self.core?.bookmark else { return }
+ MediaUploadQueue.shared.addUploads(assets, for: bookmark, at: path)
+ }
- MediaUploadQueue.shared.addUploads(assets, for: bookmark, at: path)
- }
- let navigationController = ThemeNavigationController(rootViewController: photoAlbumViewController)
+ if let viewController = self.context.viewController {
- viewController.present(navigationController, animated: true)
+ if #available(iOS 14, *) {
+ picker = PhotoPickerPresenter()
+ (picker as? PhotoPickerPresenter)?.present(in: viewController, with: { [weak self] (assets) in
+ self?.completed()
+ addAssetsToQueue(assets: assets)
+ self?.picker = nil
+ })
+ } else {
+ let photoAlbumViewController = PhotoAlbumTableViewController()
+ photoAlbumViewController.selectionCallback = {(assets) in
+ self.completed()
+ addAssetsToQueue(assets: assets)
+ }
+ let navigationController = ThemeNavigationController(rootViewController: photoAlbumViewController)
+
+ viewController.present(navigationController, animated: true)
+ }
} else {
self.completed(with: NSError(ocError: .internal))
}
diff --git a/ownCloud/Resources/Info.plist b/ownCloud/Resources/Info.plist
index b913def72..ae0143ed5 100644
--- a/ownCloud/Resources/Info.plist
+++ b/ownCloud/Resources/Info.plist
@@ -153,5 +153,7 @@
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
+ PHPhotoLibraryPreventAutomaticLimitedAccessAlert
+
diff --git a/ownCloud/Resources/en.lproj/Localizable.strings b/ownCloud/Resources/en.lproj/Localizable.strings
index 7927155c2..908b62837 100644
--- a/ownCloud/Resources/en.lproj/Localizable.strings
+++ b/ownCloud/Resources/en.lproj/Localizable.strings
@@ -836,3 +836,8 @@
"Prefer unedited photos" = "Prefer unedited photos";
"Prefer RAW photos" = "Prefer RAW photos";
"Prefer original videos" = "Prefer original videos";
+
+/* Limited photo library access */
+"Limited Photo Access" = "Limited Photo Access";
+"Access for the media selected for upload is limited" = "Access for the media selected for upload is limited";
+"No Access to the media selected for upload" = "No Access to the media selected for upload";
diff --git a/ownCloudAppFramework/Licensing/Providers/App Store/OCLicenseAppStoreProvider.m b/ownCloudAppFramework/Licensing/Providers/App Store/OCLicenseAppStoreProvider.m
index 178e8461f..e2eb9535a 100644
--- a/ownCloudAppFramework/Licensing/Providers/App Store/OCLicenseAppStoreProvider.m
+++ b/ownCloudAppFramework/Licensing/Providers/App Store/OCLicenseAppStoreProvider.m
@@ -68,7 +68,7 @@ - (instancetype)initWithItems:(NSArray *)items
__weak OCLicenseAppStoreProvider *weakSelf = self;
[OCIPNotificationCenter.sharedNotificationCenter addObserver:self forName:OCIPCNotificationNameLicenseAppStoreProviderDataChanged withHandler:^(OCIPNotificationCenter * _Nonnull notificationCenter, id _Nonnull observer, OCIPCNotificationName _Nonnull notificationName) {
- OCWLogDebug(@"Received AppStoreProviderDataChanged notification");
+ OCLogDebug(@"Received AppStoreProviderDataChanged notification");
[weakSelf loadReceipt];
}];
}