Quellcode durchsuchen

Merge pull request #2078 from nextcloud/AutoUploadChunk

Upload
Marino Faggiana vor 3 Jahren
Ursprung
Commit
9731a8b05e

+ 4 - 1
Share/NCShareExtension.swift

@@ -339,7 +339,10 @@ extension NCShareExtension {
         guard uploadStarted else { return }
         guard uploadMetadata.count > counterUploaded else { return finishedUploading() }
         let metadata = uploadMetadata[counterUploaded]
-
+        let results = NCCommunicationCommon.shared.getInternalType(fileName: metadata.fileNameView, mimeType: metadata.contentType, directory: false)
+        metadata.contentType = results.mimeType
+        metadata.iconName = results.iconName
+        metadata.classFile = results.classFile
         // E2EE
         metadata.e2eEncrypted = CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase)
         // CHUNCK

+ 1 - 0
iOSClient/Data/NCDatabase.swift

@@ -385,6 +385,7 @@ class tableMetadata: Object, NCUserBaseUrl {
     @objc dynamic var hasPreview: Bool = false
     @objc dynamic var iconName = ""
     @objc dynamic var iconUrl = ""
+    @objc dynamic var isAutoupload: Bool = false
     @objc dynamic var livePhoto: Bool = false
     @objc dynamic var mountType = ""
     @objc dynamic var name = ""

+ 5 - 1
iOSClient/Data/NCManageDatabase+Metadata.swift

@@ -221,9 +221,11 @@ extension NCManageDatabase {
         return metadata
     }
 
-    @objc func addMetadata(_ metadata: tableMetadata) {
+    @discardableResult
+    @objc func addMetadata(_ metadata: tableMetadata) -> tableMetadata? {
 
         let realm = try! Realm()
+        let returnMetadata = tableMetadata.init(value: metadata)
 
         do {
             try realm.safeWrite {
@@ -231,7 +233,9 @@ extension NCManageDatabase {
             }
         } catch let error {
             NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
+            return nil
         }
+        return returnMetadata
     }
 
     @objc func addMetadatas(_ metadatas: [tableMetadata]) {

+ 1 - 0
iOSClient/Data/NCManageDatabase.swift

@@ -27,6 +27,7 @@ import RealmSwift
 import NCCommunication
 import SwiftyJSON
 import CoreMedia
+import Photos
 
 class NCManageDatabase: NSObject {
     @objc static let shared: NCManageDatabase = {

+ 10 - 3
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift

@@ -1418,13 +1418,20 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
         if !metadata.directory {
             if metadata.name == NCGlobal.shared.appName {
 
-                let imagePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
+                let filePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
                 let iconImagePath = CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)!
 
                 if FileManager().fileExists(atPath: iconImagePath) {
                     (cell as! NCCellProtocol).filePreviewImageView?.image =  UIImage(contentsOfFile: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag))
-                } else if metadata.status > NCGlobal.shared.metadataStatusNormal && FileManager().fileExists(atPath: imagePath) {
-                    if let image = UIImage(contentsOfFile: imagePath), let image = image.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon), isAspectRation: true), let data = image.jpegData(compressionQuality: 0.5) {
+                } else if metadata.status > NCGlobal.shared.metadataStatusNormal && metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue && FileManager().fileExists(atPath: filePath) {
+                    if let image = UIImage(contentsOfFile: filePath), let image = image.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon), isAspectRation: true), let data = image.jpegData(compressionQuality: 0.5) {
+                        do {
+                            try data.write(to: URL.init(fileURLWithPath: iconImagePath), options: .atomic)
+                            (cell as! NCCellProtocol).filePreviewImageView?.image = image
+                        } catch { }
+                    }
+                } else if metadata.status > NCGlobal.shared.metadataStatusNormal && metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue && FileManager().fileExists(atPath: filePath) {
+                    if let image = NCUtility.shared.imageFromVideo(url: URL(fileURLWithPath: filePath), at: 0), let image = image.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon), isAspectRation: true), let data = image.jpegData(compressionQuality: 0.5) {
                         do {
                             try data.write(to: URL.init(fileURLWithPath: iconImagePath), options: .atomic)
                             (cell as! NCCellProtocol).filePreviewImageView?.image = image

+ 3 - 41
iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift

@@ -362,16 +362,15 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate {
             let useFolderPhotoRow: XLFormRowDescriptor  = self.form.formRow(withTag: "useFolderAutoUpload")!
             let useSubFolderRow: XLFormRowDescriptor  = self.form.formRow(withTag: "useSubFolder")!
             var useSubFolder: Bool = false
-            var metadatasMOV: [tableMetadata] = []
             var metadatasNOConflict: [tableMetadata] = []
             var metadatasUploadInConflict: [tableMetadata] = []
+            let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: self.appDelegate.urlBase, account: self.appDelegate.account)
 
             if (useFolderPhotoRow.value! as AnyObject).boolValue == true {
                 self.serverUrl = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: self.appDelegate.urlBase, account: self.appDelegate.account)
                 useSubFolder = (useSubFolderRow.value! as AnyObject).boolValue
             }
 
-            let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: self.appDelegate.urlBase, account: self.appDelegate.account)
             if autoUploadPath == self.serverUrl {
                 if !NCNetworking.shared.createFolder(assets: self.assets, selector: NCGlobal.shared.selectorUploadFile, useSubFolder: useSubFolder, account: self.appDelegate.account, urlBase: self.appDelegate.urlBase) {
                     NCContentPresenter.shared.messageNotification("_error_", description: "_error_createsubfolders_upload_", delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: NCGlobal.shared.errorInternalError)
@@ -385,30 +384,23 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate {
                 var livePhoto: Bool = false
                 let fileName = CCUtility.createFileName(asset.value(forKey: "filename") as? String, fileDate: asset.creationDate, fileType: asset.mediaType, keyFileName: NCGlobal.shared.keyFileNameMask, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: false)!
                 let assetDate = asset.creationDate ?? Date()
-                let dateFormatter = DateFormatter()
 
-                // Detect LivePhoto Upload
                 if asset.mediaSubtypes.contains(.photoLive) && CCUtility.getLivePhoto() {
                     livePhoto = true
                 }
 
-                // Create serverUrl if use sub folder
                 if useSubFolder {
-
+                    let dateFormatter = DateFormatter()
                     dateFormatter.dateFormat = "yyyy"
                     let yearString = dateFormatter.string(from: assetDate)
-
                     dateFormatter.dateFormat = "MM"
                     let monthString = dateFormatter.string(from: assetDate)
-
                     serverUrl = autoUploadPath + "/" + yearString + "/" + monthString
                 }
 
                 // Check if is in upload
                 let isRecordInSessions = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@ AND session != ''", self.appDelegate.account, serverUrl, fileName), sorted: "fileName", ascending: false)
-                if isRecordInSessions.count > 0 {
-                    continue
-                }
+                if isRecordInSessions.count > 0 { continue }
 
                 let metadataForUpload = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: serverUrl, urlBase: self.appDelegate.urlBase, url: "", contentType: "", isLivePhoto: livePhoto)
 
@@ -417,34 +409,6 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate {
                 metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile
                 metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload
 
-                if livePhoto {
-
-                    let fileNameMove = (fileName as NSString).deletingPathExtension + ".mov"
-                    let ocId = NSUUID().uuidString
-                    let filePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameMove)!
-
-                    let semaphore = Semaphore()
-                    CCUtility.extractLivePhotoAsset(asset, filePath: filePath) { url in
-                        if let url = url {
-                            let fileSize = NCUtilityFileSystem.shared.getFileSize(filePath: url.path)
-                            let metadataMOVForUpload = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileNameMove, fileNameView: fileNameMove, ocId: ocId, serverUrl: serverUrl, urlBase: self.appDelegate.urlBase, url: "", contentType: "", isLivePhoto: livePhoto)
-
-                            metadataForUpload.livePhoto = true
-                            metadataMOVForUpload.livePhoto = true
-
-                            metadataMOVForUpload.session = self.session
-                            metadataMOVForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile
-                            metadataMOVForUpload.size = fileSize
-                            metadataMOVForUpload.status = NCGlobal.shared.metadataStatusWaitUpload
-                            metadataMOVForUpload.classFile = NCCommunicationCommon.typeClassFile.video.rawValue
-
-                            metadatasMOV.append(metadataMOVForUpload)
-                        }
-                        semaphore.continue()
-                    }
-                    semaphore.wait()
-                }
-
                 if NCManageDatabase.shared.getMetadataConflict(account: self.appDelegate.account, serverUrl: serverUrl, fileName: fileName) != nil {
                     metadatasUploadInConflict.append(metadataForUpload)
                 } else {
@@ -460,7 +424,6 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate {
 
                         conflict.serverUrl = self.serverUrl
                         conflict.metadatasNOConflict = metadatasNOConflict
-                        conflict.metadatasMOV = metadatasMOV
                         conflict.metadatasUploadInConflict = metadatasUploadInConflict
                         conflict.delegate = self.appDelegate
 
@@ -471,7 +434,6 @@ class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate {
             } else {
 
                 self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadatasNOConflict)
-                self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadatasMOV)
             }
 
             DispatchQueue.main.async {self.dismiss(animated: true, completion: nil)  }

+ 9 - 35
iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift

@@ -23,6 +23,7 @@
 
 import UIKit
 import NCCommunication
+import Photos
 
 @objc protocol NCCreateFormUploadConflictDelegate {
     @objc func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?)
@@ -52,7 +53,6 @@ extension NCCreateFormUploadConflictDelegate {
 
     @objc var metadatasNOConflict: [tableMetadata]
     @objc var metadatasUploadInConflict: [tableMetadata]
-    @objc var metadatasMOV: [tableMetadata]
     @objc var serverUrl: String?
     @objc weak var delegate: NCCreateFormUploadConflictDelegate?
     @objc var alwaysNewFileNameNumber: Bool = false
@@ -67,7 +67,6 @@ extension NCCreateFormUploadConflictDelegate {
 
     @objc required init?(coder aDecoder: NSCoder) {
         self.metadatasNOConflict = []
-        self.metadatasMOV = []
         self.metadatasUploadInConflict = []
         super.init(coder: aDecoder)
     }
@@ -99,13 +98,18 @@ extension NCCreateFormUploadConflictDelegate {
 
         buttonCancel.layer.cornerRadius = 20
         buttonCancel.layer.masksToBounds = true
+        buttonCancel.layer.borderWidth = 0.5
+        buttonCancel.layer.borderColor = UIColor.darkGray.cgColor
+        buttonCancel.backgroundColor = NCBrandColor.shared.systemGray5
         buttonCancel.setTitle(NSLocalizedString("_cancel_", comment: ""), for: .normal)
+        buttonCancel.setTitleColor(NCBrandColor.shared.label, for: .normal)
 
         buttonContinue.layer.cornerRadius = 20
         buttonContinue.layer.masksToBounds = true
+        buttonContinue.backgroundColor = NCBrandColor.shared.brand
         buttonContinue.setTitle(NSLocalizedString("_continue_", comment: ""), for: .normal)
         buttonContinue.isEnabled = false
-        buttonContinue.setTitleColor(NCBrandColor.shared.gray, for: .normal)
+        buttonContinue.setTitleColor(NCBrandColor.shared.brandText, for: .normal)
 
         let blurEffect = UIBlurEffect(style: .light)
         blurView = UIVisualEffectView(effect: blurEffect)
@@ -250,7 +254,6 @@ extension NCCreateFormUploadConflictDelegate {
             // keep both
             if metadatasConflictNewFiles.contains(metadata.ocId) && metadatasConflictAlreadyExistingFiles.contains(metadata.ocId) {
 
-                let fileNameMOV = (metadata.fileNameView as NSString).deletingPathExtension + ".mov"
                 var fileName = metadata.fileNameView
                 let fileNameExtension = (fileName as NSString).pathExtension.lowercased()
                 let fileNameWithoutExtension = (fileName as NSString).deletingPathExtension
@@ -272,46 +275,16 @@ extension NCCreateFormUploadConflictDelegate {
 
                 metadatasNOConflict.append(metadata)
 
-                // MOV (Live Photo)
-                if let metadataMOV = self.metadatasMOV.first(where: { $0.fileName == fileNameMOV }) {
-
-                    let oldPath = CCUtility.getDirectoryProviderStorageOcId(metadataMOV.ocId, fileNameView: metadataMOV.fileNameView)
-                    let newFileNameMOV = (newFileName as NSString).deletingPathExtension + ".mov"
-
-                    metadataMOV.ocId = UUID().uuidString
-                    metadataMOV.fileName = newFileNameMOV
-                    metadataMOV.fileNameView = newFileNameMOV
-
-                    let newPath = CCUtility.getDirectoryProviderStorageOcId(metadataMOV.ocId, fileNameView: newFileNameMOV)
-                    CCUtility.moveFile(atPath: oldPath, toPath: newPath)
-                }
-
             // overwrite
             } else if metadatasConflictNewFiles.contains(metadata.ocId) {
 
                 metadatasNOConflict.append(metadata)
 
-            // remove (MOV)
-            } else if metadatasConflictAlreadyExistingFiles.contains(metadata.ocId) {
-
-                let fileNameMOV = (metadata.fileNameView as NSString).deletingPathExtension + ".mov"
-                var index = 0
-
-                for metadataMOV in metadatasMOV {
-                    if metadataMOV.fileNameView == fileNameMOV {
-                        metadatasMOV.remove(at: index)
-                        break
-                    }
-                    index += 1
-                }
-
             } else {
                 // used UIAlert (replace all)
             }
         }
 
-        metadatasNOConflict.append(contentsOf: metadatasMOV)
-
         dismiss(animated: true) {
             self.delegate?.dismissCreateFormUploadConflict(metadatas: self.metadatasNOConflict)
         }
@@ -423,7 +396,8 @@ extension NCCreateFormUploadConflict: UITableViewDataSource {
 
                 } else {
 
-                    CCUtility.extractImageVideoFromAssetLocalIdentifier(forUpload: metadataNewFile) { metadataNew, fileNamePath in
+                    // PREVIEW
+                    CCUtility.extractImageVideoFromAssetLocalIdentifier(forUpload: metadataNewFile, queue: .main) { metadataNew, fileNamePath in
 
                         if metadataNew != nil {
                             self.fileNamesPath[metadataNewFile.fileNameView] = fileNamePath!

+ 1 - 0
iOSClient/Main/NCFunctionCenter.swift

@@ -26,6 +26,7 @@ import NCCommunication
 import Queuer
 import JGProgressHUD
 import SVGKit
+import Photos
 
 @objc class NCFunctionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelectDelegate {
     @objc public static let shared: NCFunctionCenter = {

+ 1 - 0
iOSClient/Main/NCPickerViewController.swift

@@ -24,6 +24,7 @@
 import UIKit
 import TLPhotoPicker
 import MobileCoreServices
+import Photos
 
 // MARK: - Photo Picker
 

+ 1 - 1
iOSClient/NCGlobal.swift

@@ -115,7 +115,7 @@ class NCGlobal: NSObject {
     // Database Realm
     //
     let databaseDefault                             = "nextcloud.realm"
-    let databaseSchemaVersion: UInt64               = 227
+    let databaseSchemaVersion: UInt64               = 228
 
     // Intro selector
     //

+ 104 - 162
iOSClient/Networking/NCAutoUpload.swift

@@ -24,6 +24,7 @@
 import UIKit
 import CoreLocation
 import NCCommunication
+import Photos
 
 class NCAutoUpload: NSObject {
     @objc static let shared: NCAutoUpload = {
@@ -37,38 +38,36 @@ class NCAutoUpload: NSObject {
     // MARK: -
 
     @objc func initAutoUpload(viewController: UIViewController?, completion: @escaping (_ items: Int) -> Void) {
-        if let activeAccount = NCManageDatabase.shared.getActiveAccount() {
-            if activeAccount.autoUpload {
-                NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in
-                    if hasPermission {
-                        self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUpload, log: "Init Auto Upload") { items in
-                            if items > 0 {
-                                self.appDelegate.networkingProcessUpload?.startProcess()
-                            }
-                            completion(items)
-                        }
+        guard let activeAccount = NCManageDatabase.shared.getActiveAccount(), activeAccount.autoUpload else {
+            completion(0)
+            return
+        }
 
-                    } else {
-                        NCManageDatabase.shared.setAccountAutoUploadProperty("autoUpload", state: false)
-                        completion(0)
-                    }
-                }
-            } else {
+        NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in
+            guard hasPermission else {
+                NCManageDatabase.shared.setAccountAutoUploadProperty("autoUpload", state: false)
                 completion(0)
+                return
+            }
+
+            self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUpload, log: "Init Auto Upload") { items in
+                if items > 0 {
+                    self.appDelegate.networkingProcessUpload?.startProcess()
+                }
+                completion(items)
             }
-        } else {
-            completion(0)
         }
     }
 
     @objc func autoUploadFullPhotos(viewController: UIViewController?, log: String) {
+
         NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: appDelegate.window?.rootViewController) { hasPermission in
-            if hasPermission {
-                NCContentPresenter.shared.messageNotification("_attention_", description: "_create_full_upload_", delay: NCGlobal.shared.dismissAfterSecondLong, type: .info, errorCode: NCGlobal.shared.errorNoError, priority: .max)
-                NCUtility.shared.startActivityIndicator(backgroundView: nil, blurEffect: true)
-                self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUploadAll, log: log) { _ in
-                    NCUtility.shared.stopActivityIndicator()
-                }
+            guard hasPermission else { return }
+
+            NCContentPresenter.shared.messageNotification("_attention_", description: "_create_full_upload_", delay: NCGlobal.shared.dismissAfterSecondLong, type: .info, errorCode: NCGlobal.shared.errorNoError, priority: .max)
+            NCUtility.shared.startActivityIndicator(backgroundView: nil, blurEffect: true)
+            self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUploadAll, log: log) { _ in
+                NCUtility.shared.stopActivityIndicator()
             }
         }
     }
@@ -78,35 +77,27 @@ class NCAutoUpload: NSObject {
             completion(0)
             return
         }
-
         guard let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", appDelegate.account)) else { return }
-        let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: account.urlBase, account: account.account)
-        var counterLivePhoto: Int = 0
-        var metadataFull: [tableMetadata] = []
-        var counterItemsUpload: Int = 0
+
         DispatchQueue.global(qos: .background).async {
 
-            self.getCameraRollAssets(viewController: viewController, account: account, selector: selector, alignPhotoLibrary: false) { assets in
+            let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: account.urlBase, account: account.account)
+            var metadatas: [tableMetadata] = []
 
-                if assets == nil || assets?.count == 0 {
+            self.getCameraRollAssets(viewController: viewController, account: account, selector: selector, alignPhotoLibrary: false) { assets in
+                guard let assets = assets, !assets.isEmpty else {
                     NCCommunicationCommon.shared.writeLog("Automatic upload, no new assets found [" + log + "]")
-                    DispatchQueue.main.async {
-                        completion(counterItemsUpload)
-                    }
+                    completion(0)
                     return
-                } else {
-                    NCCommunicationCommon.shared.writeLog("Automatic upload, new \(assets?.count ?? 0) assets found [" + log + "]")
                 }
-                guard let assets = assets else { return }
+                NCCommunicationCommon.shared.writeLog("Automatic upload, new \(assets.count) assets found [" + log + "]")
 
                 // Create the folder for auto upload & if request the subfolders
                 if !NCNetworking.shared.createFolder(assets: assets, selector: selector, useSubFolder: account.autoUploadCreateSubfolder, account: account.account, urlBase: account.urlBase) {
-                    DispatchQueue.main.async {
-                        if selector == NCGlobal.shared.selectorUploadAutoUploadAll {
-                            NCContentPresenter.shared.messageNotification("_error_", description: "_error_createsubfolders_upload_", delay: NCGlobal.shared.dismissAfterSecond, type: .error, errorCode: NCGlobal.shared.errorInternalError, priority: .max)
-                        }
-                        return completion(counterItemsUpload)
+                    if selector == NCGlobal.shared.selectorUploadAutoUploadAll {
+                        NCContentPresenter.shared.messageNotification("_error_", description: "_error_createsubfolders_upload_", delay: NCGlobal.shared.dismissAfterSecond, type: .error, errorCode: NCGlobal.shared.errorInternalError, priority: .max)
                     }
+                    return completion(0)
                 }
 
                 self.endForAssetToUpload = false
@@ -117,10 +108,13 @@ class NCAutoUpload: NSObject {
                     var session: String = ""
                     guard let assetDate = asset.creationDate else { continue }
                     let assetMediaType = asset.mediaType
-                    let formatter = DateFormatter()
                     var serverUrl: String = ""
-
                     let fileName = CCUtility.createFileName(asset.value(forKey: "filename") as? String, fileDate: assetDate, fileType: assetMediaType, keyFileName: NCGlobal.shared.keyFileNameAutoUploadMask, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false)!
+                    let formatter = DateFormatter()
+                    formatter.dateFormat = "yyyy"
+                    let yearString = formatter.string(from: assetDate)
+                    formatter.dateFormat = "MM"
+                    let monthString = formatter.string(from: assetDate)
 
                     if asset.mediaSubtypes.contains(.photoLive) && CCUtility.getLivePhoto() {
                         livePhoto = true
@@ -140,11 +134,6 @@ class NCAutoUpload: NSObject {
                         } else { session = NCNetworking.shared.sessionIdentifierBackground }
                     }
 
-                    formatter.dateFormat = "yyyy"
-                    let yearString = formatter.string(from: assetDate)
-                    formatter.dateFormat = "MM"
-                    let monthString = formatter.string(from: assetDate)
-
                     if account.autoUploadCreateSubfolder {
                         serverUrl = autoUploadPath + "/" + yearString + "/" + monthString
                     } else {
@@ -157,86 +146,39 @@ class NCAutoUpload: NSObject {
                     if ext == "HEIC" && CCUtility.getFormatCompatibility() {
                         fileNameSearchMetadata = (fileNameSearchMetadata as NSString).deletingPathExtension + ".jpg"
                     }
-
                     if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView == %@", account.account, serverUrl, fileNameSearchMetadata)) != nil {
-
                         if selector == NCGlobal.shared.selectorUploadAutoUpload {
                             NCManageDatabase.shared.addPhotoLibrary([asset], account: account.account)
                         }
-
                     } else {
-
-                        /* INSERT METADATA FOR UPLOAD */
-                        let metadataForUpload = NCManageDatabase.shared.createMetadata(account: account.account, user: account.user, userId: account.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: serverUrl, urlBase: account.urlBase, url: "", contentType: "", isLivePhoto: livePhoto)
-                        metadataForUpload.assetLocalIdentifier = asset.localIdentifier
-                        metadataForUpload.session = session
-                        metadataForUpload.sessionSelector = selector
-                        metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload
+                        let metadata = NCManageDatabase.shared.createMetadata(account: account.account, user: account.user, userId: account.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: serverUrl, urlBase: account.urlBase, url: "", contentType: "", isLivePhoto: livePhoto)
+                        metadata.assetLocalIdentifier = asset.localIdentifier
+                        metadata.session = session
+                        metadata.sessionSelector = selector
+                        if selector == NCGlobal.shared.selectorUploadAutoUpload {
+                            metadata.isAutoupload = true
+                        }
+                        metadata.status = NCGlobal.shared.metadataStatusWaitUpload
                         if assetMediaType == PHAssetMediaType.video {
-                            metadataForUpload.classFile = NCCommunicationCommon.typeClassFile.video.rawValue
+                            metadata.classFile = NCCommunicationCommon.typeClassFile.video.rawValue
                         } else if assetMediaType == PHAssetMediaType.image {
-                            metadataForUpload.classFile = NCCommunicationCommon.typeClassFile.image.rawValue
+                            metadata.classFile = NCCommunicationCommon.typeClassFile.image.rawValue
                         }
-
                         if selector == NCGlobal.shared.selectorUploadAutoUpload {
-                            NCCommunicationCommon.shared.writeLog("Automatic upload added \(metadataForUpload.fileNameView) with Identifier \(metadataForUpload.assetLocalIdentifier)")
-                            self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: [metadataForUpload], verifyAlreadyExists: true)
+                            NCCommunicationCommon.shared.writeLog("Automatic upload added \(metadata.fileNameView) with Identifier \(metadata.assetLocalIdentifier)")
                             NCManageDatabase.shared.addPhotoLibrary([asset], account: account.account)
-                        } else if selector == NCGlobal.shared.selectorUploadAutoUploadAll {
-                            metadataFull.append(metadataForUpload)
-                        }
-                        counterItemsUpload += 1
-
-                        /* INSERT METADATA MOV LIVE PHOTO FOR UPLOAD */
-                        if livePhoto {
-
-                            counterLivePhoto += 1
-                            let fileName = (fileName as NSString).deletingPathExtension + ".mov"
-                            let ocId = NSUUID().uuidString
-                            let filePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!
-
-                            CCUtility.extractLivePhotoAsset(asset, filePath: filePath) { url in
-                                if url != nil {
-                                    let metadataForUpload = NCManageDatabase.shared.createMetadata(account: account.account, user: account.user, userId: account.userId, fileName: fileName, fileNameView: fileName, ocId: ocId, serverUrl: serverUrl, urlBase: account.urlBase, url: "", contentType: "", isLivePhoto: livePhoto)
-                                    metadataForUpload.session = session
-                                    metadataForUpload.sessionSelector = selector
-                                    metadataForUpload.size = NCUtilityFileSystem.shared.getFileSize(filePath: filePath)
-                                    metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload
-                                    metadataForUpload.classFile = NCCommunicationCommon.typeClassFile.video.rawValue
-
-                                    if selector == NCGlobal.shared.selectorUploadAutoUpload {
-                                        NCCommunicationCommon.shared.writeLog("Automatic upload added Live Photo \(metadataForUpload.fileNameView) with Identifier \(metadataForUpload.assetLocalIdentifier)")
-                                        self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: [metadataForUpload], verifyAlreadyExists: true)
-
-                                    } else if selector == NCGlobal.shared.selectorUploadAutoUploadAll {
-                                        metadataFull.append(metadataForUpload)
-                                    }
-                                    counterItemsUpload += 1
-                                }
-                                counterLivePhoto -= 1
-                                if counterLivePhoto == 0 && self.endForAssetToUpload {
-                                    DispatchQueue.main.async {
-                                        if selector == NCGlobal.shared.selectorUploadAutoUploadAll {
-                                            self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadataFull)
-                                        }
-                                        completion(counterItemsUpload)
-                                    }
-                                }
-                            }
                         }
+                        metadatas.append(metadata)
                     }
                 }
 
                 self.endForAssetToUpload = true
-
-                if counterLivePhoto == 0 {
-                    DispatchQueue.main.async {
-                        if selector == NCGlobal.shared.selectorUploadAutoUploadAll {
-                            self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadataFull)
-                        }
-                        completion(counterItemsUpload)
-                    }
+                if selector == NCGlobal.shared.selectorUploadAutoUploadAll {
+                    self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadatas)
+                } else {
+                    self.appDelegate.networkingProcessUpload?.createProcessUploads(metadatas: metadatas, verifyAlreadyExists: true)
                 }
+                completion(metadatas.count)
             }
         }
     }
@@ -244,66 +186,66 @@ class NCAutoUpload: NSObject {
     // MARK: -
 
     @objc func alignPhotoLibrary(viewController: UIViewController?) {
-        if let activeAccount = NCManageDatabase.shared.getActiveAccount() {
-            getCameraRollAssets(viewController: viewController, account: activeAccount, selector: NCGlobal.shared.selectorUploadAutoUploadAll, alignPhotoLibrary: true) { assets in
-                NCManageDatabase.shared.clearTable(tablePhotoLibrary.self, account: activeAccount.account)
-                if let assets = assets {
-                    NCManageDatabase.shared.addPhotoLibrary(assets, account: activeAccount.account)
-                    NCCommunicationCommon.shared.writeLog("Align Photo Library \(assets.count)")
-                }
-            }
+        guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return }
+
+        getCameraRollAssets(viewController: viewController, account: activeAccount, selector: NCGlobal.shared.selectorUploadAutoUploadAll, alignPhotoLibrary: true) { assets in
+            NCManageDatabase.shared.clearTable(tablePhotoLibrary.self, account: activeAccount.account)
+            guard let assets = assets else { return }
+
+            NCManageDatabase.shared.addPhotoLibrary(assets, account: activeAccount.account)
+            NCCommunicationCommon.shared.writeLog("Align Photo Library \(assets.count)")
         }
     }
 
     private func getCameraRollAssets(viewController: UIViewController?, account: tableAccount, selector: String, alignPhotoLibrary: Bool, completion: @escaping (_ assets: [PHAsset]?) -> Void) {
 
         NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in
-            if hasPermission {
-                let assetCollection = PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.smartAlbum, subtype: PHAssetCollectionSubtype.smartAlbumUserLibrary, options: nil)
-                if assetCollection.count > 0 {
-
-                    let predicateImage = NSPredicate(format: "mediaType == %i", PHAssetMediaType.image.rawValue)
-                    let predicateVideo = NSPredicate(format: "mediaType == %i", PHAssetMediaType.video.rawValue)
-                    var predicate: NSPredicate?
-                    let fetchOptions = PHFetchOptions()
-                    var newAssets: [PHAsset] = []
-
-                    if alignPhotoLibrary || (account.autoUploadImage && account.autoUploadVideo) {
-                        predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicateImage, predicateVideo])
-                    } else if account.autoUploadImage {
-                        predicate = predicateImage
-                    } else if account.autoUploadVideo {
-                        predicate = predicateVideo
-                    } else {
-                        return completion(nil)
-                    }
+            guard hasPermission else {
+                completion(nil)
+                return
+            }
+            let assetCollection = PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.smartAlbum, subtype: PHAssetCollectionSubtype.smartAlbumUserLibrary, options: nil)
+            if assetCollection.count == 0 {
+                completion(nil)
+                return
+            }
 
-                    fetchOptions.predicate = predicate
-                    let assets: PHFetchResult<PHAsset> = PHAsset.fetchAssets(in: assetCollection.firstObject!, options: fetchOptions)
-
-                    if selector == NCGlobal.shared.selectorUploadAutoUpload {
-                        var creationDate = ""
-                        var idAsset = ""
-                        let idsAsset = NCManageDatabase.shared.getPhotoLibraryIdAsset(image: account.autoUploadImage, video: account.autoUploadVideo, account: account.account)
-                        assets.enumerateObjects { asset, _, _ in
-                            if asset.creationDate != nil { creationDate = String(describing: asset.creationDate!) }
-                            idAsset = account.account + asset.localIdentifier + creationDate
-                            if !(idsAsset?.contains(idAsset) ?? false) {
-                                newAssets.append(asset)
-                            }
-                        }
-                    } else {
-                        assets.enumerateObjects { asset, _, _ in
-                            newAssets.append(asset)
-                        }
+            let predicateImage = NSPredicate(format: "mediaType == %i", PHAssetMediaType.image.rawValue)
+            let predicateVideo = NSPredicate(format: "mediaType == %i", PHAssetMediaType.video.rawValue)
+            var predicate: NSPredicate?
+            let fetchOptions = PHFetchOptions()
+            var newAssets: [PHAsset] = []
+
+            if alignPhotoLibrary || (account.autoUploadImage && account.autoUploadVideo) {
+                predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicateImage, predicateVideo])
+            } else if account.autoUploadImage {
+                predicate = predicateImage
+            } else if account.autoUploadVideo {
+                predicate = predicateVideo
+            } else {
+                return completion(nil)
+            }
+
+            fetchOptions.predicate = predicate
+            let assets: PHFetchResult<PHAsset> = PHAsset.fetchAssets(in: assetCollection.firstObject!, options: fetchOptions)
+
+            if selector == NCGlobal.shared.selectorUploadAutoUpload {
+                var creationDate = ""
+                var idAsset = ""
+                let idsAsset = NCManageDatabase.shared.getPhotoLibraryIdAsset(image: account.autoUploadImage, video: account.autoUploadVideo, account: account.account)
+                assets.enumerateObjects { asset, _, _ in
+                    if asset.creationDate != nil { creationDate = String(describing: asset.creationDate!) }
+                    idAsset = account.account + asset.localIdentifier + creationDate
+                    if !(idsAsset?.contains(idAsset) ?? false) {
+                        newAssets.append(asset)
                     }
-                    completion(newAssets)
-                } else {
-                    completion(nil)
                 }
             } else {
-                completion(nil)
+                assets.enumerateObjects { asset, _, _ in
+                    newAssets.append(asset)
+                }
             }
+            completion(newAssets)
         }
     }
 }

+ 27 - 76
iOSClient/Networking/NCNetworking.swift

@@ -26,6 +26,7 @@ import OpenSSL
 import NCCommunication
 import Alamofire
 import Queuer
+import Photos
 
 @objc public protocol NCNetworkingDelegate {
     @objc optional func downloadProgress(_ progress: Float, totalBytes: Int64, totalBytesExpected: Int64, fileName: String, serverUrl: String, session: URLSession, task: URLSessionTask)
@@ -417,88 +418,38 @@ import Queuer
 
     // MARK: - Upload
 
-    @objc func upload(metadata: tableMetadata, start: @escaping () -> Void, completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> Void) {
+    @objc func upload(metadata: tableMetadata,
+                      start: @escaping () -> () = { },
+                      completion: @escaping (_ errorCode: Int, _ errorDescription: String) -> () = { errorCode, errorDescription in }) {
 
-        func uploadMetadata(_ metadata: tableMetadata) {
-
-            // DETECT IF CHUNCK
-            let chunckSize = CCUtility.getChunkSize() * 1000000
-            if chunckSize > 0 && metadata.size > chunckSize {
-                metadata.chunk = true
-                metadata.session = NCCommunicationCommon.shared.sessionIdentifierUpload
-            }
-
-            // DETECT IF E2EE
-            if CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) {
-                metadata.e2eEncrypted = true
-            }
-
-            NCManageDatabase.shared.addMetadata(metadata)
-            let metadata = tableMetadata.init(value: metadata)
-
-            NCCommunicationCommon.shared.writeLog("Upload file \(metadata.fileNameView) with Identifier \(metadata.assetLocalIdentifier) with size \(metadata.size) [CHUNCK \(metadata.chunk), E2EE \(metadata.e2eEncrypted)]")
+        let metadata = tableMetadata.init(value: metadata)
+        NCCommunicationCommon.shared.writeLog("Upload file \(metadata.fileNameView) with Identifier \(metadata.assetLocalIdentifier) with size \(metadata.size) [CHUNCK \(metadata.chunk), E2EE \(metadata.e2eEncrypted)]")
 
-            if metadata.e2eEncrypted {
-#if !EXTENSION_FILE_PROVIDER_EXTENSION
-                NCNetworkingE2EE.shared.upload(metadata: metadata, start: start) { errorCode, errorDescription in
-                    DispatchQueue.main.async {
-                        completion(errorCode, errorDescription)
-                    }
-                }
-#endif
-            } else if metadata.chunk {
-                uploadChunkedFile(metadata: metadata, start: start) { errorCode, errorDescription in
-                    DispatchQueue.main.async {
-                        completion(errorCode, errorDescription)
-                    }
-                }
-            } else if metadata.session == NCCommunicationCommon.shared.sessionIdentifierUpload {
-                uploadFile(metadata: metadata, start: start) { errorCode, errorDescription in
-                    DispatchQueue.main.async {
-                        completion(errorCode, errorDescription)
-                    }
-                }
-            } else {
-                uploadFileInBackground(metadata: metadata, start: start) { errorCode, errorDescription in
-                    DispatchQueue.main.async {
-                        completion(errorCode, errorDescription)
-                    }
+        if metadata.e2eEncrypted {
+            #if !EXTENSION_FILE_PROVIDER_EXTENSION
+            NCNetworkingE2EE.shared.upload(metadata: metadata, start: start) { errorCode, errorDescription in
+                DispatchQueue.main.async {
+                    completion(errorCode, errorDescription)
                 }
             }
-        }
-        
-        let metadata = tableMetadata.init(value: metadata)
-
-        if metadata.assetLocalIdentifier.isEmpty {
-
-            let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
-            let results = NCCommunicationCommon.shared.getInternalType(fileName: metadata.fileNameView, mimeType: metadata.contentType, directory: false)
-            metadata.contentType = results.mimeType
-            metadata.iconName = results.iconName
-            metadata.classFile = results.classFile
-            if let date = NCUtilityFileSystem.shared.getFileCreationDate(filePath: fileNameLocalPath) {
-                 metadata.creationDate = date
+            #endif
+        } else if metadata.chunk {
+            uploadChunkedFile(metadata: metadata, start: start) { errorCode, errorDescription in
+                DispatchQueue.main.async {
+                    completion(errorCode, errorDescription)
+                }
             }
-            if let date =  NCUtilityFileSystem.shared.getFileModificationDate(filePath: fileNameLocalPath) {
-                metadata.date = date
+        } else if metadata.session == NCCommunicationCommon.shared.sessionIdentifierUpload {
+            uploadFile(metadata: metadata, start: start) { errorCode, errorDescription in
+                DispatchQueue.main.async {
+                    completion(errorCode, errorDescription)
+                }
             }
-            metadata.size = NCUtilityFileSystem.shared.getFileSize(filePath: fileNameLocalPath)
-
-            uploadMetadata(metadata)
-
         } else {
-
-            CCUtility.extractImageVideoFromAssetLocalIdentifier(forUpload: metadata) { extractMetadata, fileNamePath in
-
-                guard let metadata = extractMetadata else {
-                    NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
-                    return completion(NCGlobal.shared.errorInternalError, "Internal error")
+            uploadFileInBackground(metadata: metadata, start: start) { errorCode, errorDescription in
+                DispatchQueue.main.async {
+                    completion(errorCode, errorDescription)
                 }
-
-                let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
-                NCUtilityFileSystem.shared.moveFileInBackground(atPath: fileNamePath!, toPath: fileNameLocalPath)
-
-                uploadMetadata(metadata)
             }
         }
     }
@@ -704,7 +655,7 @@ import Queuer
         }
     }
 
-    func getOcIdInBackgroundSession(completion: @escaping (_ listOcId: [String]) -> Void) {
+    func getOcIdInBackgroundSession(queue: DispatchQueue = .main, completion: @escaping (_ listOcId: [String]) -> Void) {
 
         var listOcId: [String] = []
 
@@ -716,7 +667,7 @@ import Queuer
                 for task in tasks {
                     listOcId.append(task.description)
                 }
-                completion(listOcId)
+                queue.async { completion(listOcId) }
             })
         })
     }

+ 87 - 97
iOSClient/Networking/NCNetworkingChunkedUpload.swift

@@ -37,11 +37,10 @@ extension NCNetworking {
 
         var uploadErrorCode: Int = 0
         var uploadErrorDescription: String = ""
+
         var filesNames = NCManageDatabase.shared.getChunks(account: metadata.account, ocId: metadata.ocId)
         if filesNames.count == 0 {
-
             filesNames = NCCommunicationCommon.shared.chunkedFile(inputDirectory: directoryProviderStorageOcId, outputDirectory: directoryProviderStorageOcId, fileName: metadata.fileName, chunkSizeMB: chunkSize)
-
             if filesNames.count > 0 {
                 NCManageDatabase.shared.addChunks(account: metadata.account, ocId: metadata.ocId, chunkFolder: chunkFolder, fileNames: filesNames)
             } else {
@@ -49,149 +48,140 @@ extension NCNetworking {
                 NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
                 return completion(uploadErrorCode, uploadErrorDescription)
             }
-
         } else {
-
             NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": metadata.serverUrl])
         }
-
         NCContentPresenter.shared.noteTop(text: NSLocalizedString("_upload_chunk_", comment: ""), image: nil, type: NCContentPresenter.messageType.info, delay: NCGlobal.shared.dismissAfterSecond, priority: .max)
 
         createChunkedFolder(chunkFolderPath: chunkFolderPath, account: metadata.account) { errorCode, errorDescription in
 
             start()
 
-            if errorCode == 0 {
-
-                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId": metadata.ocId])
-
-                for fileName in filesNames {
+            guard errorCode == 0 else {
+                self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, directoryProviderStorageOcId: directoryProviderStorageOcId, errorCode: errorCode, errorDescription: errorDescription)
+                completion(errorCode, errorDescription)
+                return
+            }
 
-                    let serverUrlFileName = chunkFolderPath + "/" + fileName
-                    let fileNameChunkLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: fileName)!
+            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId": metadata.ocId])
 
-                    var size: Int64?
-                    if let tableChunk = NCManageDatabase.shared.getChunk(account: metadata.account, fileName: fileName) {
-                        size = tableChunk.size - NCUtilityFileSystem.shared.getFileSize(filePath: fileNameChunkLocalPath)
-                    }
+            for fileName in filesNames {
 
-                    let semaphore = Semaphore()
+                let serverUrlFileName = chunkFolderPath + "/" + fileName
+                let fileNameChunkLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: fileName)!
 
-                    NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameChunkLocalPath, requestHandler: { request in
+                var size: Int64?
+                if let tableChunk = NCManageDatabase.shared.getChunk(account: metadata.account, fileName: fileName) {
+                    size = tableChunk.size - NCUtilityFileSystem.shared.getFileSize(filePath: fileNameChunkLocalPath)
+                }
 
-                        self.uploadRequest[fileNameLocalPath] = request
+                let semaphore = Semaphore()
 
-                    }, taskHandler: { task in
+                NCCommunication.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameChunkLocalPath, requestHandler: { request in
 
-                        NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, sessionError: "", sessionTaskIdentifier: task.taskIdentifier, status: NCGlobal.shared.metadataStatusUploading)
+                    self.uploadRequest[fileNameLocalPath] = request
 
-                        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId": metadata.ocId])
+                }, taskHandler: { task in
 
-                        NCCommunicationCommon.shared.writeLog("Upload chunk: " + fileName)
+                    NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, sessionError: "", sessionTaskIdentifier: task.taskIdentifier, status: NCGlobal.shared.metadataStatusUploading)
 
-                    }, progressHandler: { progress in
+                    NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadStartFile, userInfo: ["ocId": metadata.ocId])
 
-                        if let size = size {
+                    NCCommunicationCommon.shared.writeLog("Upload chunk: " + fileName)
 
-                            let totalBytesExpected = size + progress.completedUnitCount
-                            let totalBytes = metadata.size
-                            let fractionCompleted = Float(totalBytesExpected) / Float(totalBytes)
+                }, progressHandler: { progress in
 
-                            NotificationCenter.default.postOnMainThread(
-                                name: NCGlobal.shared.notificationCenterProgressTask,
-                                object: nil,
-                                userInfo: [
-                                    "account": metadata.account,
-                                    "ocId": metadata.ocId,
-                                    "fileName": metadata.fileName,
-                                    "serverUrl": metadata.serverUrl,
-                                    "status": NSNumber(value: NCGlobal.shared.metadataStatusInUpload),
-                                    "progress": NSNumber(value: fractionCompleted),
-                                    "totalBytes": NSNumber(value: totalBytes),
-                                    "totalBytesExpected": NSNumber(value: totalBytesExpected)])
-                        }
+                    if let size = size {
 
-                    }) { _, _, _, _, _, _, _, errorCode, errorDescription in
+                        let totalBytesExpected = size + progress.completedUnitCount
+                        let totalBytes = metadata.size
+                        let fractionCompleted = Float(totalBytesExpected) / Float(totalBytes)
 
-                        self.uploadRequest[fileNameLocalPath] = nil
-                        uploadErrorCode = errorCode
-                        uploadErrorDescription = errorDescription
-                        semaphore.continue()
+                        NotificationCenter.default.postOnMainThread(
+                            name: NCGlobal.shared.notificationCenterProgressTask,
+                            object: nil,
+                            userInfo: [
+                                "account": metadata.account,
+                                "ocId": metadata.ocId,
+                                "fileName": metadata.fileName,
+                                "serverUrl": metadata.serverUrl,
+                                "status": NSNumber(value: NCGlobal.shared.metadataStatusInUpload),
+                                "progress": NSNumber(value: fractionCompleted),
+                                "totalBytes": NSNumber(value: totalBytes),
+                                "totalBytesExpected": NSNumber(value: totalBytesExpected)])
                     }
 
-                    semaphore.wait()
+                }) { _, _, _, _, _, _, _, errorCode, errorDescription in
 
-                    if uploadErrorCode == 0 {
-                        NCManageDatabase.shared.deleteChunk(account: metadata.account, ocId: metadata.ocId, fileName: fileName)
-                    } else {
-                        break
-                    }
+                    self.uploadRequest[fileNameLocalPath] = nil
+                    uploadErrorCode = errorCode
+                    uploadErrorDescription = errorDescription
+                    semaphore.continue()
                 }
 
-                if uploadErrorCode == 0 {
-
-                    // Assembling the chunks
-                    let serverUrlFileNameSource = chunkFolderPath + "/.file"
-                    let pathServerUrl = CCUtility.returnPathfromServerUrl(metadata.serverUrl, urlBase: metadata.urlBase, account: metadata.account)!
-                    let serverUrlFileNameDestination = metadata.urlBase + "/" + NCUtilityFileSystem.shared.getWebDAV(account: metadata.account) + "/files/" + metadata.userId + pathServerUrl + "/" + metadata.fileName
+                semaphore.wait()
 
-                    var addCustomHeaders: [String: String] = [:]
-                    let creationDate = "\(metadata.creationDate.timeIntervalSince1970)"
-                    let modificationDate = "\(metadata.date.timeIntervalSince1970)"
+                if uploadErrorCode == 0 {
+                    NCManageDatabase.shared.deleteChunk(account: metadata.account, ocId: metadata.ocId, fileName: fileName)
+                } else {
+                    break
+                }
+            }
 
-                    addCustomHeaders["X-OC-CTime"] = creationDate
-                    addCustomHeaders["X-OC-MTime"] = modificationDate
+            guard uploadErrorCode == 0 else {
+                self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, directoryProviderStorageOcId: directoryProviderStorageOcId, errorCode: uploadErrorCode, errorDescription: uploadErrorDescription)
+                completion(errorCode, errorDescription)
+                return
+            }
 
-                    NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: true, addCustomHeaders: addCustomHeaders) { _, errorCode, errorDescription in
+            // Assembling the chunks
+            let serverUrlFileNameSource = chunkFolderPath + "/.file"
+            let pathServerUrl = CCUtility.returnPathfromServerUrl(metadata.serverUrl, urlBase: metadata.urlBase, account: metadata.account)!
+            let serverUrlFileNameDestination = metadata.urlBase + "/" + NCUtilityFileSystem.shared.getWebDAV(account: metadata.account) + "/files/" + metadata.userId + pathServerUrl + "/" + metadata.fileName
 
-                        NCCommunicationCommon.shared.writeLog("Assembling chunk with error code: \(errorCode)")
+            var addCustomHeaders: [String: String] = [:]
+            let creationDate = "\(metadata.creationDate.timeIntervalSince1970)"
+            let modificationDate = "\(metadata.date.timeIntervalSince1970)"
 
-                        if errorCode == 0 {
+            addCustomHeaders["X-OC-CTime"] = creationDate
+            addCustomHeaders["X-OC-MTime"] = modificationDate
 
-                            let serverUrl = metadata.serverUrl
-                            let assetLocalIdentifier = metadata.assetLocalIdentifier
+            NCCommunication.shared.moveFileOrFolder(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: true, addCustomHeaders: addCustomHeaders) { _, errorCode, errorDescription in
 
-                            NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
-                            NCManageDatabase.shared.deleteChunks(account: metadata.account, ocId: metadata.ocId)
-                            NCUtilityFileSystem.shared.deleteFile(filePath: directoryProviderStorageOcId)
+                NCCommunicationCommon.shared.writeLog("Assembling chunk with error code: \(errorCode)")
 
-                            self.readFile(serverUrlFileName: serverUrlFileNameDestination) { (_, metadata, _, _) in
+                guard uploadErrorCode == 0 else {
+                    self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, directoryProviderStorageOcId: directoryProviderStorageOcId, errorCode: errorCode, errorDescription: errorDescription)
+                    completion(errorCode, errorDescription)
+                    return
+                }
 
-                                if errorCode == 0, let metadata = metadata {
+                let serverUrl = metadata.serverUrl
+                let assetLocalIdentifier = metadata.assetLocalIdentifier
 
-                                    metadata.assetLocalIdentifier = assetLocalIdentifier
-                                    // Delete Asset on Photos album
-                                    if CCUtility.getRemovePhotoCameraRoll() && !metadata.assetLocalIdentifier.isEmpty {
-                                        metadata.deleteAssetLocalIdentifier = true
-                                    }
-                                    NCManageDatabase.shared.addMetadata(metadata)
-                                    NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": serverUrl])
+                NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
+                NCManageDatabase.shared.deleteChunks(account: metadata.account, ocId: metadata.ocId)
+                NCUtilityFileSystem.shared.deleteFile(filePath: directoryProviderStorageOcId)
 
-                                } else {
+                self.readFile(serverUrlFileName: serverUrlFileNameDestination) { (_, metadata, _, _) in
 
-                                    NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced, userInfo: ["serverUrl": serverUrl])
-                                }
+                    if errorCode == 0, let metadata = metadata {
 
-                                completion(errorCode, errorDescription)
-                            }
+                        metadata.assetLocalIdentifier = assetLocalIdentifier
+                        // Delete Asset on Photos album
+                        if CCUtility.getRemovePhotoCameraRoll() && !metadata.assetLocalIdentifier.isEmpty {
+                            metadata.deleteAssetLocalIdentifier = true
+                        }
+                        NCManageDatabase.shared.addMetadata(metadata)
+                        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": serverUrl])
 
-                        } else {
+                    } else {
 
-                            self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, directoryProviderStorageOcId: directoryProviderStorageOcId, errorCode: errorCode, errorDescription: errorDescription)
-                            completion(errorCode, errorDescription)
-                        }
+                        NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetworkForced, userInfo: ["serverUrl": serverUrl])
                     }
 
-                } else {
-
-                    self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, directoryProviderStorageOcId: directoryProviderStorageOcId, errorCode: uploadErrorCode, errorDescription: uploadErrorDescription)
                     completion(errorCode, errorDescription)
                 }
-
-            } else {
-
-                self.uploadChunkFileError(metadata: metadata, chunkFolderPath: chunkFolderPath, directoryProviderStorageOcId: directoryProviderStorageOcId, errorCode: errorCode, errorDescription: errorDescription)
-                completion(errorCode, errorDescription)
             }
         }
     }

+ 120 - 57
iOSClient/Networking/NCNetworkingProcessUpload.swift

@@ -24,6 +24,7 @@
 import UIKit
 import NCCommunication
 import Photos
+import Queuer
 
 class NCNetworkingProcessUpload: NSObject {
 
@@ -39,7 +40,7 @@ class NCNetworkingProcessUpload: NSObject {
 
     @objc func startProcess() {
         if timerProcess?.isValid ?? false {
-            process()
+            DispatchQueue.main.async { self.process() }
         }
     }
 
@@ -55,9 +56,10 @@ class NCNetworkingProcessUpload: NSObject {
     @objc private func process() {
         guard !appDelegate.account.isEmpty else { return }
 
+        let queue = DispatchQueue.global(qos: .background)
+        let applicationState = UIApplication.shared.applicationState
         var counterUpload: Int = 0
         let sessionSelectors = [NCGlobal.shared.selectorUploadFile, NCGlobal.shared.selectorUploadAutoUpload, NCGlobal.shared.selectorUploadAutoUploadAll]
-
         let metadatasUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status == %d OR status == %d", NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading))
         counterUpload = metadatasUpload.count
 
@@ -65,19 +67,13 @@ class NCNetworkingProcessUpload: NSObject {
 
         print("[LOG] PROCESS-UPLOAD \(counterUpload)")
 
-        NCNetworking.shared.getOcIdInBackgroundSession { listOcId in
+        NCNetworking.shared.getOcIdInBackgroundSession(queue: queue, completion: { listOcId in
 
             for sessionSelector in sessionSelectors {
                 if counterUpload < self.maxConcurrentOperationUpload {
 
                     let limit = self.maxConcurrentOperationUpload - counterUpload
-                    var predicate = NSPredicate()
-                    if UIApplication.shared.applicationState == .background {
-                        predicate = NSPredicate(format: "sessionSelector == %@ AND status == %d AND (classFile != %@ || livePhoto == true)", sessionSelector, NCGlobal.shared.metadataStatusWaitUpload, NCCommunicationCommon.typeClassFile.video.rawValue)
-                    } else {
-                        predicate = NSPredicate(format: "sessionSelector == %@ AND status == %d", sessionSelector, NCGlobal.shared.metadataStatusWaitUpload)
-                    }
-                    let metadatas = NCManageDatabase.shared.getAdvancedMetadatas(predicate: predicate, page: 1, limit: limit, sorted: "date", ascending: true)
+                    let metadatas = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "sessionSelector == %@ AND status == %d", sessionSelector, NCGlobal.shared.metadataStatusWaitUpload), page: 1, limit: limit, sorted: "date", ascending: true)
                     if metadatas.count > 0 {
                         NCCommunicationCommon.shared.writeLog("PROCESS-UPLOAD find \(metadatas.count) items")
                     }
@@ -104,56 +100,39 @@ class NCNetworkingProcessUpload: NSObject {
                         // Is already in upload E2EE / CHUNK ? exit [ ONLY ONE IN QUEUE ]
                         for metadata in metadatasUpload {
                             if metadata.chunk || metadata.e2eEncrypted {
-                                self.startTimer()
-                                return
+                                counterUpload = self.maxConcurrentOperationUpload
+                                continue
                             }
                         }
 
-                        // Chunk 
-                        if metadata.chunk && UIApplication.shared.applicationState == .active {
+                        let (metadataForUpload, metadataLivePhotoForUpload) = self.extractFiles(from: metadata, queue: queue)
+
+                        // Upload
+                        if let metadata = metadataForUpload {
+                            if (metadata.e2eEncrypted || metadata.chunk) && applicationState != .active { continue }
                             if let metadata = NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusInUpload) {
-                                NCNetworking.shared.upload(metadata: metadata) {
-                                    // start
-                                } completion: { _, _ in
-                                    DispatchQueue.main.async {
-                                        self.startTimer()
-                                    }
-                                }
+                                NCNetworking.shared.upload(metadata: metadata)
+                            }
+                            if metadata.e2eEncrypted || metadata.chunk {
+                                counterUpload = self.maxConcurrentOperationUpload
                             } else {
-                                self.startTimer()
+                                counterUpload += 1
                             }
-                            return
                         }
 
-                        // E2EE
-                        if metadata.e2eEncrypted && UIApplication.shared.applicationState == .active {
+                        // Upload Live photo
+                        if let metadata = metadataLivePhotoForUpload {
+                            if (metadata.e2eEncrypted || metadata.chunk) && applicationState != .active { continue }
                             if let metadata = NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusInUpload) {
-                                NCNetworking.shared.upload(metadata: metadata) {
-                                    // start
-                                } completion: { _, _ in
-                                    DispatchQueue.main.async {
-                                        self.startTimer()
-                                    }
-                                }
-                            } else {
-                                self.startTimer()
+                                NCNetworking.shared.upload(metadata: metadata)
                             }
-                            return
-                        }
-
-                        counterUpload += 1
-                        if let metadata = NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusInUpload) {
-                            NCNetworking.shared.upload(metadata: metadata) {
-                                // start
-                            } completion: { _, _ in
-                                // completion
+                            if metadata.e2eEncrypted || metadata.chunk {
+                                counterUpload = self.maxConcurrentOperationUpload
+                            } else {
+                                counterUpload += 1
                             }
                         }
                     }
-
-                } else {
-                    self.startTimer()
-                    return
                 }
             }
 
@@ -166,14 +145,16 @@ class NCNetworkingProcessUpload: NSObject {
             }
              
             // verify delete Asset Local Identifiers in auto upload (DELETE Photos album)
-            if (counterUpload == 0 && !self.appDelegate.isPasscodePresented()) {
-                self.deleteAssetLocalIdentifiers(account: self.appDelegate.account) {
+            DispatchQueue.main.async {
+                if (counterUpload == 0 && !self.appDelegate.isPasscodePresented()) {
+                    self.deleteAssetLocalIdentifiers(account: self.appDelegate.account) {
+                        self.startTimer()
+                    }
+                } else {
                     self.startTimer()
                 }
-            } else {
-                self.startTimer()
             }
-        }
+        })
     }
 
     private func deleteAssetLocalIdentifiers(account: String, completition: @escaping () -> Void) {
@@ -206,23 +187,105 @@ class NCNetworkingProcessUpload: NSObject {
 
     // MARK: -
 
+    func extractFiles(from metadata: tableMetadata, queue: DispatchQueue) -> (metadataForUpload: tableMetadata?, metadataLivePhotoForUpload: tableMetadata?) {
+
+        var metadataForUpload: tableMetadata?
+        var metadataLivePhotoForUpload: tableMetadata?
+        let chunckSize = CCUtility.getChunkSize() * 1000000
+        let semaphore = Semaphore()
+
+        guard queue != .main else { return(nil, nil) }
+        guard !metadata.assetLocalIdentifier.isEmpty else {
+            let filePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileName)!
+            metadata.size = NCUtilityFileSystem.shared.getFileSize(filePath: filePath)
+            let results = NCCommunicationCommon.shared.getInternalType(fileName: metadata.fileNameView, mimeType: metadata.contentType, directory: false)
+            metadata.contentType = results.mimeType
+            metadata.iconName = results.iconName
+            metadata.classFile = results.classFile
+            if let date = NCUtilityFileSystem.shared.getFileCreationDate(filePath: filePath) { metadata.creationDate = date }
+            if let date =  NCUtilityFileSystem.shared.getFileModificationDate(filePath: filePath) { metadata.date = date }
+            // DETECT IF CHUNCK
+            if chunckSize > 0 && metadata.size > chunckSize {
+                metadata.chunk = true
+                metadata.session = NCCommunicationCommon.shared.sessionIdentifierUpload
+            }
+            // DETECT IF E2EE
+            if CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) {
+                metadata.e2eEncrypted = true
+            }
+            let metadata = NCManageDatabase.shared.addMetadata(metadata)
+            return (metadata, nil)
+        }
+
+        CCUtility.extractImageVideoFromAssetLocalIdentifier(forUpload: metadata, queue: queue) { extractMetadata, fileNamePath in
+            if let metadata = extractMetadata {
+                let toPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
+                NCUtilityFileSystem.shared.moveFile(atPath: fileNamePath!, toPath: toPath)
+                metadata.size = NCUtilityFileSystem.shared.getFileSize(filePath: toPath)
+                // DETECT IF CHUNCK
+                if chunckSize > 0 && metadata.size > chunckSize {
+                    metadata.chunk = true
+                    metadata.session = NCCommunicationCommon.shared.sessionIdentifierUpload
+                }
+                // DETECT IF E2EE
+                if CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) {
+                    metadata.e2eEncrypted = true
+                }
+                // update
+                metadataForUpload = NCManageDatabase.shared.addMetadata(metadata)
+            }
+            semaphore.continue()
+        }
+        semaphore.wait()
+
+        if metadataForUpload == nil {
+            NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
+            return (nil, nil)
+        }
+
+        let fetchAssets = PHAsset.fetchAssets(withLocalIdentifiers: [metadata.assetLocalIdentifier], options: nil)
+        if metadata.livePhoto, fetchAssets.count > 0  {
+            let ocId = NSUUID().uuidString
+            let fileName = (metadata.fileName as NSString).deletingPathExtension + ".mov"
+            let filePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!
+            CCUtility.extractLivePhotoAsset(fetchAssets.firstObject, filePath: filePath, queue: queue) { url in
+                if url != nil {
+                    let metadataLivePhoto = NCManageDatabase.shared.createMetadata(account: metadata.account, user: metadata.user, userId: metadata.userId, fileName: fileName, fileNameView: fileName, ocId: ocId, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, url: "", contentType: "", isLivePhoto: true)
+                    metadataLivePhoto.classFile = NCCommunicationCommon.typeClassFile.video.rawValue
+                    metadataLivePhoto.e2eEncrypted = metadata.e2eEncrypted
+                    metadataLivePhoto.isAutoupload = metadata.isAutoupload
+                    metadataLivePhoto.session = metadata.session
+                    metadataLivePhoto.sessionSelector = metadata.sessionSelector
+                    metadataLivePhoto.size = NCUtilityFileSystem.shared.getFileSize(filePath: filePath)
+                    metadataLivePhoto.status = metadata.status
+                    if chunckSize > 0 && metadataLivePhoto.size > chunckSize {
+                        metadataLivePhoto.chunk = true
+                        metadataLivePhoto.session = NCCommunicationCommon.shared.sessionIdentifierUpload
+                    }
+                    metadataLivePhotoForUpload = NCManageDatabase.shared.addMetadata(metadataLivePhoto)
+                }
+                semaphore.continue()
+            }
+            semaphore.wait()
+        }
+
+        return(metadataForUpload, metadataLivePhotoForUpload)
+    }
+
+    // MARK: -
+
     @objc func createProcessUploads(metadatas: [tableMetadata], verifyAlreadyExists: Bool = false) {
 
         var metadatasForUpload: [tableMetadata] = []
-
         for metadata in metadatas {
-
             if verifyAlreadyExists {
                 if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ && serverUrl == %@ && fileName == %@ && session != ''", metadata.account, metadata.serverUrl, metadata.fileName)) != nil {
                     continue
                 }
             }
-
             metadatasForUpload.append(metadata)
         }
-
         NCManageDatabase.shared.addMetadatas(metadatasForUpload)
-
         startProcess()
     }
 

+ 1 - 0
iOSClient/ScanDocument/NCScan.swift

@@ -22,6 +22,7 @@
 //
 
 import UIKit
+import Photos
 
 @available(iOS 13.0, *)
 class NCScan: UIViewController, NCScanCellCellDelegate {

+ 1 - 0
iOSClient/Settings/NCManageAutoUploadFileName.swift

@@ -22,6 +22,7 @@
 //
 
 import UIKit
+import Photos
 
 class NCManageAutoUploadFileName: XLFormViewController {
 

+ 27 - 7
iOSClient/Transfers/NCTransfers.swift

@@ -127,12 +127,20 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate {
     @objc func startTask(_ notification: Any) {
 
         guard let metadata = metadataTemp else { return }
+        guard appDelegate.account == metadata.account else { return }
+        guard let networkingProcessUpload = appDelegate.networkingProcessUpload else { return }
 
-        metadata.status = NCGlobal.shared.metadataStatusInUpload
-        metadata.session = NCCommunicationCommon.shared.sessionIdentifierUpload
+        let (metadataForUpload, metadataLivePhotoForUpload) = networkingProcessUpload.extractFiles(from: metadata, queue: DispatchQueue.global(qos: .background))
 
-        NCManageDatabase.shared.addMetadata(metadata)
-        NCNetworking.shared.upload(metadata: metadata) { } completion: { _, _ in }
+        // Upload
+        if let metadata = metadataForUpload, let metadata = NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusInUpload) {
+            NCNetworking.shared.upload(metadata: metadata)
+        }
+
+        // Upload Live photo
+        if let metadata = metadataLivePhotoForUpload, let metadata = NCManageDatabase.shared.setMetadataStatus(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusInUpload) {
+            NCNetworking.shared.upload(metadata: metadata)
+        }
     }
 
     override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
@@ -150,6 +158,11 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate {
 
     // MARK: - Collection View
 
+    @available(iOS 13.0, *)
+    override func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
+        return nil
+    }
+
     override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
         // nothing
     }
@@ -182,13 +195,20 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate {
 
         cell.progressView.progress = 0.0
 
-        let imagePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
+        let filePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
         let iconImagePath = CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)!
 
         if FileManager().fileExists(atPath: iconImagePath) {
             cell.imageItem.image =  UIImage(contentsOfFile:iconImagePath)
-        } else if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue, FileManager().fileExists(atPath: imagePath) {
-            if let image = UIImage(contentsOfFile: imagePath), let image = image.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon), isAspectRation: true), let data = image.jpegData(compressionQuality: 0.5) {
+        } else if metadata.classFile == NCCommunicationCommon.typeClassFile.image.rawValue, FileManager().fileExists(atPath: filePath) {
+            if let image = UIImage(contentsOfFile: filePath), let image = image.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon), isAspectRation: true), let data = image.jpegData(compressionQuality: 0.5) {
+                do {
+                    try data.write(to: URL.init(fileURLWithPath: iconImagePath), options: .atomic)
+                    cell.imageItem.image = image
+                } catch { }
+            }
+        } else if metadata.classFile == NCCommunicationCommon.typeClassFile.video.rawValue, FileManager().fileExists(atPath: filePath) {
+            if let image = NCUtility.shared.imageFromVideo(url: URL(fileURLWithPath: filePath), at: 0), let image = image.resizeImage(size: CGSize(width: NCGlobal.shared.sizeIcon, height: NCGlobal.shared.sizeIcon), isAspectRation: true), let data = image.jpegData(compressionQuality: 0.5) {
                 do {
                     try data.write(to: URL.init(fileURLWithPath: iconImagePath), options: .atomic)
                     cell.imageItem.image = image

+ 2 - 2
iOSClient/Utility/CCUtility.h

@@ -243,8 +243,8 @@
 
 + (NSString *)getMimeType:(NSString *)fileNameView;
 
-+ (void)extractImageVideoFromAssetLocalIdentifierForUpload:(tableMetadata *)metadataForUpload completion:(void(^)(tableMetadata *newMetadata, NSString* fileNamePath))completion;
-+ (void)extractLivePhotoAsset:(PHAsset*)asset filePath:(NSString *)filePath withCompletion:(void (^)(NSURL* url))completion;
++ (void)extractImageVideoFromAssetLocalIdentifierForUpload:(tableMetadata *)metadataForUpload queue:(dispatch_queue_t)queue completion:(void(^)(tableMetadata *newMetadata, NSString* fileNamePath))completion;
++ (void)extractLivePhotoAsset:(PHAsset*)asset filePath:(NSString *)filePath queue:(dispatch_queue_t)queue withCompletion:(void (^)(NSURL* url))completion;
 
 // ===== E2E Encrypted =====
 

+ 131 - 113
iOSClient/Utility/CCUtility.m

@@ -1352,136 +1352,142 @@
     return path;
 }
 
-+ (void)extractImageVideoFromAssetLocalIdentifierForUpload:(tableMetadata *)metadataForUpload completion:(void(^)(tableMetadata *metadata, NSString* fileNamePath))completion
++ (void)extractImageVideoFromAssetLocalIdentifierForUpload:(tableMetadata *)metadataForUpload queue:(dispatch_queue_t)queue completion:(void(^)(tableMetadata *metadata, NSString* fileNamePath))completion
 {
     if (metadataForUpload == nil) {
-        return completion(nil, nil);
+        dispatch_async(queue, ^{
+            completion(nil, nil);
+        });
+        return;
     }
     
     tableMetadata *metadata = [[NCManageDatabase shared] copyObjectWithMetadata:metadataForUpload];
     
     PHFetchResult *result = [PHAsset fetchAssetsWithLocalIdentifiers:@[metadata.assetLocalIdentifier] options:nil];
     if (!result.count) {
-        return completion(nil, nil);
+        dispatch_async(queue, ^{
+            completion(nil, nil);
+        });
+        return;
     }
     
     PHAsset *asset = result[0];
     NSDate *creationDate = asset.creationDate;
     NSDate *modificationDate = asset.modificationDate;
 
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-    
-        // IMAGE
-        if (asset.mediaType == PHAssetMediaTypeImage) {
-            
-            PHImageRequestOptions *options = [PHImageRequestOptions new];
-            options.networkAccessAllowed = YES;
-            options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
-            options.synchronous = YES;
-            options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
-                
-                NSLog(@"cacheAsset: %f", progress);
-                
-                if (error) {
-                    [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCGlobal.shared.notificationCenterUploadedFile object:nil userInfo:@{@"ocId": metadata.ocId, @"errorCode": @(error.code), @"errorDescription": [NSString stringWithFormat:@"Image request iCloud failed [%@]", error.description]}];
-                    return completion(nil, nil);
-                }
-            };
-            
-            NSString *extensionAsset = [[[asset valueForKey:@"filename"] pathExtension] uppercaseString];
-            
-            //raw image will always ignore any edits made to the photo if compatibility is false
-            if ([extensionAsset isEqualToString:@"DNG"]) {
-                options.version = PHImageRequestOptionsVersionOriginal;
-            }
-            
-            [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
-                
-                NSError *error = nil;
-                NSString *fileName = metadata.fileNameView;
+    // IMAGE
+    if (asset.mediaType == PHAssetMediaTypeImage) {
 
-                if (([extensionAsset isEqualToString:@"HEIC"] || [extensionAsset isEqualToString:@"DNG"]) && [CCUtility getFormatCompatibility]) {
-                    
-                    CIImage *ciImage = [CIImage imageWithData:imageData];
-                    CIContext *context = [CIContext context];
-                    imageData = [context JPEGRepresentationOfImage:ciImage colorSpace:ciImage.colorSpace options:@{}];
-                    
-                    NSString *fileNameJPEG = [[metadata.fileName lastPathComponent] stringByDeletingPathExtension];
-                    fileName = [fileNameJPEG stringByAppendingString:@".jpg"];
-                    metadata.contentType = @"image/jpeg";
-                    metadata.ext = @"jpg";
-                }
-                
-                NSString *fileNamePath = [NSTemporaryDirectory() stringByAppendingString:fileName];
-                
-                [[NSFileManager defaultManager]removeItemAtPath:fileNamePath error:nil];
-                [imageData writeToFile:fileNamePath options:NSDataWritingAtomic error:&error];
-                
-                if (metadata.e2eEncrypted) {
-                    metadata.fileNameView = fileName;
-                } else {
-                    metadata.fileNameView = fileName;
-                    metadata.fileName = fileName;
-                }
-                     
-                metadata.creationDate = creationDate;
-                metadata.date = modificationDate;
-                metadata.size = [[NCUtilityFileSystem shared] getFileSizeWithFilePath:fileNamePath];
-                
-                dispatch_async(dispatch_get_main_queue(), ^{
-                    completion(metadata, fileNamePath);
+        PHImageRequestOptions *options = [PHImageRequestOptions new];
+        options.networkAccessAllowed = YES;
+        options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
+        options.synchronous = YES;
+        options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
+
+            NSLog(@"cacheAsset: %f", progress);
+
+            if (error) {
+                [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCGlobal.shared.notificationCenterUploadedFile object:nil userInfo:@{@"ocId": metadata.ocId, @"errorCode": @(error.code), @"errorDescription": [NSString stringWithFormat:@"Image request iCloud failed [%@]", error.description]}];
+                dispatch_async(queue, ^{
+                    completion(nil, nil);
                 });
-            }];
+                return;
+            }
+        };
+
+        NSString *extensionAsset = [[[asset valueForKey:@"filename"] pathExtension] uppercaseString];
+
+        //raw image will always ignore any edits made to the photo if compatibility is false
+        if ([extensionAsset isEqualToString:@"DNG"]) {
+            options.version = PHImageRequestOptionsVersionOriginal;
         }
-    
-        // VIDEO
-        if (asset.mediaType == PHAssetMediaTypeVideo) {
-            
-            PHVideoRequestOptions *options = [PHVideoRequestOptions new];
-            options.networkAccessAllowed = YES;
-            options.version = PHVideoRequestOptionsVersionOriginal;
-            options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
-                
-                NSLog(@"cacheAsset: %f", progress);
-                
-                if (error) {
-                    [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCGlobal.shared.notificationCenterUploadedFile object:nil userInfo:@{@"ocId": metadata.ocId, @"errorCode": @(error.code), @"errorDescription": [NSString stringWithFormat:@"Video request iCloud failed [%@]", error.description]}];
+
+        [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
+
+            NSError *error = nil;
+            NSString *fileName = metadata.fileNameView;
+
+            if (([extensionAsset isEqualToString:@"HEIC"] || [extensionAsset isEqualToString:@"DNG"]) && [CCUtility getFormatCompatibility]) {
+
+                CIImage *ciImage = [CIImage imageWithData:imageData];
+                CIContext *context = [CIContext context];
+                imageData = [context JPEGRepresentationOfImage:ciImage colorSpace:ciImage.colorSpace options:@{}];
+
+                NSString *fileNameJPEG = [[metadata.fileName lastPathComponent] stringByDeletingPathExtension];
+                fileName = [fileNameJPEG stringByAppendingString:@".jpg"];
+                metadata.contentType = @"image/jpeg";
+                metadata.ext = @"jpg";
+            }
+
+            NSString *fileNamePath = [NSTemporaryDirectory() stringByAppendingString:fileName];
+
+            [[NSFileManager defaultManager]removeItemAtPath:fileNamePath error:nil];
+            [imageData writeToFile:fileNamePath options:NSDataWritingAtomic error:&error];
+
+            if (metadata.e2eEncrypted) {
+                metadata.fileNameView = fileName;
+            } else {
+                metadata.fileNameView = fileName;
+                metadata.fileName = fileName;
+            }
+
+            metadata.creationDate = creationDate;
+            metadata.date = modificationDate;
+            metadata.size = [[NCUtilityFileSystem shared] getFileSizeWithFilePath:fileNamePath];
+
+            dispatch_async(queue, ^{
+                completion(metadata, fileNamePath);
+            });
+        }];
+    }
+
+    // VIDEO
+    if (asset.mediaType == PHAssetMediaTypeVideo) {
+
+        PHVideoRequestOptions *options = [PHVideoRequestOptions new];
+        options.networkAccessAllowed = YES;
+        options.version = PHVideoRequestOptionsVersionOriginal;
+        options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
+
+            NSLog(@"cacheAsset: %f", progress);
+
+            if (error) {
+                [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCGlobal.shared.notificationCenterUploadedFile object:nil userInfo:@{@"ocId": metadata.ocId, @"errorCode": @(error.code), @"errorDescription": [NSString stringWithFormat:@"Video request iCloud failed [%@]", error.description]}];
+                dispatch_async(queue, ^{
                     completion(nil, nil);
-                }
-            };
-            
-            [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
-                
-                if ([asset isKindOfClass:[AVURLAsset class]]) {
-                    
-                    NSString *fileNamePath = [NSTemporaryDirectory() stringByAppendingString:metadata.fileNameView];
-                    NSURL *fileNamePathURL = [[NSURL alloc] initFileURLWithPath:fileNamePath];
-                    NSError *error = nil;
-                    //NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys: modificationDate, NSFileModificationDate, creationDate, NSFileCreationDate, NULL];
+                });
+                return;
+            }
+        };
 
-                    [[NSFileManager defaultManager] removeItemAtURL:fileNamePathURL error:nil];
-                    [[NSFileManager defaultManager] copyItemAtURL:[(AVURLAsset *)asset URL] toURL:fileNamePathURL error:&error];
-                    //[[NSFileManager defaultManager] setAttributes: attributes ofItemAtPath:fileNamePath error:nil];
+        [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
 
-                    dispatch_async(dispatch_get_main_queue(), ^{
-                        
-                        if (error) {
-                            [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCGlobal.shared.notificationCenterUploadedFile object:nil userInfo:@{@"ocId": metadata.ocId, @"errorCode": @(error.code), @"errorDescription": [NSString stringWithFormat:@"Video request iCloud failed [%@]", error.description]}];
-                            completion(nil, nil);
-                        } else {
-                            metadata.creationDate = creationDate;
-                            metadata.date = modificationDate;
-                            metadata.size = [[NCUtilityFileSystem shared] getFileSizeWithFilePath:fileNamePath];
-                            completion(metadata, fileNamePath);
-                        }
-                    });
-                }
-            }];
-        }
-    });
+            if ([asset isKindOfClass:[AVURLAsset class]]) {
+
+                NSString *fileNamePath = [NSTemporaryDirectory() stringByAppendingString:metadata.fileNameView];
+                NSURL *fileNamePathURL = [[NSURL alloc] initFileURLWithPath:fileNamePath];
+                NSError *error = nil;
+
+                [[NSFileManager defaultManager] removeItemAtURL:fileNamePathURL error:nil];
+                [[NSFileManager defaultManager] copyItemAtURL:[(AVURLAsset *)asset URL] toURL:fileNamePathURL error:&error];
+
+                dispatch_async(queue, ^{
+                    if (error) {
+                        [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCGlobal.shared.notificationCenterUploadedFile object:nil userInfo:@{@"ocId": metadata.ocId, @"errorCode": @(error.code), @"errorDescription": [NSString stringWithFormat:@"Video request iCloud failed [%@]", error.description]}];
+                        completion(nil, nil);
+                    } else {
+                        metadata.creationDate = creationDate;
+                        metadata.date = modificationDate;
+                        metadata.size = [[NCUtilityFileSystem shared] getFileSizeWithFilePath:fileNamePath];
+                        completion(metadata, fileNamePath);
+                    }
+                });
+            }
+        }];
+    }
 }
 
-+ (void)extractLivePhotoAsset:(PHAsset*)asset filePath:(NSString *)filePath withCompletion:(void (^)(NSURL* url))completion
++ (void)extractLivePhotoAsset:(PHAsset*)asset filePath:(NSString *)filePath queue:(dispatch_queue_t)queue withCompletion:(void (^)(NSURL* url))completion
 {    
     [CCUtility removeFileAtPath:filePath];
     NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
@@ -1501,12 +1507,24 @@
             }
             if(videoResource){
                 [[PHAssetResourceManager defaultManager] writeDataForAssetResource:videoResource toFile:fileUrl options:nil completionHandler:^(NSError * _Nullable error) {
-                    if (!error) {
-                        completion(fileUrl);
-                    } else { completion(nil); }
+                    dispatch_async(queue, ^{
+                        if (!error) {
+                            completion(fileUrl);
+                        } else {
+                            completion(nil);
+                        }
+                    });
                 }];
-            } else { completion(nil); }
-        } else { completion(nil); }
+            } else {
+                dispatch_async(queue, ^{
+                    completion(nil);
+                });
+            }
+        } else {
+            dispatch_async(queue, ^{
+                completion(nil);
+            });
+        }
     }];
 }
 

+ 24 - 22
iOSClient/Utility/NCContentPresenter.swift

@@ -137,29 +137,31 @@ class NCContentPresenter: NSObject {
 
         if SwiftEntryKit.isCurrentlyDisplaying(entryNamed: text) { return }
 
-        var attributes = EKAttributes.topNote
-
-        attributes.windowLevel = .normal
-        attributes.displayDuration = delay
-        attributes.name = text
-        if let color = color {
-            attributes.entryBackground = .color(color: EKColor(color))
-        }
-        if let type = type {
-            attributes.entryBackground = .color(color: EKColor(getBackgroundColorFromType(type)))
-        }
-        attributes.precedence = .override(priority: priority, dropEnqueuedEntries: dropEnqueuedEntries)
-
-        let style = EKProperty.LabelStyle(font: MainFont.light.with(size: 14), color: .white, alignment: .center)
-        let labelContent = EKProperty.LabelContent(text: text, style: style)
+        DispatchQueue.main.async {
+            var attributes = EKAttributes.topNote
 
-        if let image = image {
-            let imageContent = EKProperty.ImageContent(image: image, size: CGSize(width: 17, height: 17))
-            let contentView = EKImageNoteMessageView(with: labelContent, imageContent: imageContent)
-            DispatchQueue.main.async { SwiftEntryKit.display(entry: contentView, using: attributes) }
-        } else {
-            let contentView = EKNoteMessageView(with: labelContent)
-            DispatchQueue.main.async { SwiftEntryKit.display(entry: contentView, using: attributes) }
+            attributes.windowLevel = .normal
+            attributes.displayDuration = delay
+            attributes.name = text
+            if let color = color {
+                attributes.entryBackground = .color(color: EKColor(color))
+            }
+            if let type = type {
+                attributes.entryBackground = .color(color: EKColor(self.getBackgroundColorFromType(type)))
+            }
+            attributes.precedence = .override(priority: priority, dropEnqueuedEntries: dropEnqueuedEntries)
+
+            let style = EKProperty.LabelStyle(font: MainFont.light.with(size: 14), color: .white, alignment: .center)
+            let labelContent = EKProperty.LabelContent(text: text, style: style)
+
+            if let image = image {
+                let imageContent = EKProperty.ImageContent(image: image, size: CGSize(width: 17, height: 17))
+                let contentView = EKImageNoteMessageView(with: labelContent, imageContent: imageContent)
+                SwiftEntryKit.display(entry: contentView, using: attributes)
+            } else {
+                let contentView = EKNoteMessageView(with: labelContent)
+                SwiftEntryKit.display(entry: contentView, using: attributes)
+            }
         }
     }