浏览代码

Merge branch 'nextcloud:develop' into develop

Valdnet 3 年之前
父节点
当前提交
9dba172bd5
共有 100 个文件被更改,包括 997 次插入818 次删除
  1. 3 76
      File Provider Extension/FileProviderEnumerator.swift
  2. 4 6
      Nextcloud.xcodeproj/project.pbxproj
  3. 5 5
      Nextcloud.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
  4. 14 23
      Share/NCShareExtension.swift
  5. 5 4
      iOSClient/Activity/NCActivity.swift
  6. 14 3
      iOSClient/AppDelegate.swift
  7. 19 4
      iOSClient/Brand/Intro/NCIntro.storyboard
  8. 32 19
      iOSClient/Brand/Intro/NCIntroViewController.swift
  9. 16 1
      iOSClient/Data/NCDatabase.swift
  10. 0 1
      iOSClient/Data/NCElementsJSON.swift
  11. 132 4
      iOSClient/Data/NCManageDatabase.swift
  12. 3 2
      iOSClient/FileViewInFolder/NCFileViewInFolder.swift
  13. 12 0
      iOSClient/Images.xcassets/arrow.right.imageset/Contents.json
  14. 1 0
      iOSClient/Images.xcassets/arrow.right.imageset/arrow-right.svg
  15. 15 0
      iOSClient/Images.xcassets/note.text.imageset/Contents.json
  16. 1 0
      iOSClient/Images.xcassets/note.text.imageset/note.text.svg
  17. 41 134
      iOSClient/Login/NCLogin.storyboard
  18. 43 143
      iOSClient/Login/NCLogin.swift
  19. 3 1
      iOSClient/Login/NCLoginWeb.swift
  20. 6 5
      iOSClient/Main/Account Request/NCAccountRequest.swift
  21. 164 177
      iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
  22. 2 2
      iOSClient/Main/NCFunctionCenter.swift
  23. 5 9
      iOSClient/Media/NCMedia.swift
  24. 4 4
      iOSClient/Menu/NCCollectionViewCommon+Menu.swift
  25. 3 2
      iOSClient/Menu/NCLoginWeb+Menu.swift
  26. 6 6
      iOSClient/Menu/NCMedia+Menu.swift
  27. 1 1
      iOSClient/Menu/NCViewer+Menu.swift
  28. 6 6
      iOSClient/More/NCMore.swift
  29. 6 3
      iOSClient/More/NCMoreUserCell.xib
  30. 16 16
      iOSClient/NCGlobal.swift
  31. 72 14
      iOSClient/Networking/NCNetworking.swift
  32. 8 2
      iOSClient/Networking/NCNetworkingCheckRemoteUser.swift
  33. 58 38
      iOSClient/Networking/NCOperationQueue.swift
  34. 22 13
      iOSClient/Networking/NCService.swift
  35. 14 13
      iOSClient/Notification/NCNotification.swift
  36. 2 2
      iOSClient/Select/NCSelect.swift
  37. 1 1
      iOSClient/Settings/CCAdvanced.m
  38. 2 2
      iOSClient/Settings/CCManageAccount.m
  39. 61 29
      iOSClient/Share/NCShare.storyboard
  40. 67 17
      iOSClient/Share/NCShare.swift
  41. 8 8
      iOSClient/Share/NCShareComments.swift
  42. 2 2
      iOSClient/Share/NCShareCommentsCell.xib
  43. 39 1
      iOSClient/Share/NCShareLinkMenuView.swift
  44. 21 4
      iOSClient/Share/NCShareQuickStatusMenu.swift
  45. 36 1
      iOSClient/Share/NCShareUserMenuView.swift
  46. 二进制
      iOSClient/Supporting Files/af.lproj/Localizable.strings
  47. 二进制
      iOSClient/Supporting Files/ar.lproj/Localizable.strings
  48. 二进制
      iOSClient/Supporting Files/ast.lproj/Localizable.strings
  49. 二进制
      iOSClient/Supporting Files/az.lproj/Localizable.strings
  50. 二进制
      iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings
  51. 二进制
      iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings
  52. 二进制
      iOSClient/Supporting Files/br.lproj/Localizable.strings
  53. 二进制
      iOSClient/Supporting Files/bs.lproj/Localizable.strings
  54. 二进制
      iOSClient/Supporting Files/ca.lproj/Localizable.strings
  55. 二进制
      iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings
  56. 二进制
      iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings
  57. 二进制
      iOSClient/Supporting Files/da.lproj/Localizable.strings
  58. 二进制
      iOSClient/Supporting Files/de.lproj/Localizable.strings
  59. 二进制
      iOSClient/Supporting Files/el.lproj/Localizable.strings
  60. 二进制
      iOSClient/Supporting Files/en-GB.lproj/Localizable.strings
  61. 2 14
      iOSClient/Supporting Files/en.lproj/Localizable.strings
  62. 二进制
      iOSClient/Supporting Files/eo.lproj/Localizable.strings
  63. 二进制
      iOSClient/Supporting Files/es-419.lproj/Localizable.strings
  64. 二进制
      iOSClient/Supporting Files/es-AR.lproj/Localizable.strings
  65. 二进制
      iOSClient/Supporting Files/es-CL.lproj/Localizable.strings
  66. 二进制
      iOSClient/Supporting Files/es-CO.lproj/Localizable.strings
  67. 二进制
      iOSClient/Supporting Files/es-CR.lproj/Localizable.strings
  68. 二进制
      iOSClient/Supporting Files/es-DO.lproj/Localizable.strings
  69. 二进制
      iOSClient/Supporting Files/es-EC.lproj/Localizable.strings
  70. 二进制
      iOSClient/Supporting Files/es-GT.lproj/Localizable.strings
  71. 二进制
      iOSClient/Supporting Files/es-HN.lproj/Localizable.strings
  72. 二进制
      iOSClient/Supporting Files/es-MX.lproj/Localizable.strings
  73. 二进制
      iOSClient/Supporting Files/es-NI.lproj/Localizable.strings
  74. 二进制
      iOSClient/Supporting Files/es-PA.lproj/Localizable.strings
  75. 二进制
      iOSClient/Supporting Files/es-PE.lproj/Localizable.strings
  76. 二进制
      iOSClient/Supporting Files/es-PR.lproj/Localizable.strings
  77. 二进制
      iOSClient/Supporting Files/es-PY.lproj/Localizable.strings
  78. 二进制
      iOSClient/Supporting Files/es-SV.lproj/Localizable.strings
  79. 二进制
      iOSClient/Supporting Files/es-UY.lproj/Localizable.strings
  80. 二进制
      iOSClient/Supporting Files/es.lproj/Localizable.strings
  81. 二进制
      iOSClient/Supporting Files/et_EE.lproj/Localizable.strings
  82. 二进制
      iOSClient/Supporting Files/eu.lproj/Localizable.strings
  83. 二进制
      iOSClient/Supporting Files/fa.lproj/Localizable.strings
  84. 二进制
      iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings
  85. 二进制
      iOSClient/Supporting Files/fr.lproj/Localizable.strings
  86. 二进制
      iOSClient/Supporting Files/gl.lproj/Localizable.strings
  87. 二进制
      iOSClient/Supporting Files/he.lproj/Localizable.strings
  88. 二进制
      iOSClient/Supporting Files/hr.lproj/Localizable.strings
  89. 二进制
      iOSClient/Supporting Files/hu.lproj/Localizable.strings
  90. 二进制
      iOSClient/Supporting Files/hy.lproj/Localizable.strings
  91. 二进制
      iOSClient/Supporting Files/ia.lproj/Localizable.strings
  92. 二进制
      iOSClient/Supporting Files/id.lproj/Localizable.strings
  93. 二进制
      iOSClient/Supporting Files/is.lproj/Localizable.strings
  94. 二进制
      iOSClient/Supporting Files/it.lproj/Localizable.strings
  95. 二进制
      iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings
  96. 二进制
      iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings
  97. 二进制
      iOSClient/Supporting Files/km.lproj/Localizable.strings
  98. 二进制
      iOSClient/Supporting Files/ko.lproj/Localizable.strings
  99. 二进制
      iOSClient/Supporting Files/lb.lproj/Localizable.strings
  100. 二进制
      iOSClient/Supporting Files/lo.lproj/Localizable.strings

+ 3 - 76
File Provider Extension/FileProviderEnumerator.swift

@@ -96,8 +96,6 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
         
         /*** ServerUrl ***/
                 
-            let paginationEndpoint = NCManageDatabase.shared.getCapabilitiesServerString(account: fileProviderData.shared.account, elements: NCElementsJSON.shared.capabilitiesPaginationEndpoint)
-            
             guard let serverUrl = serverUrl else {
                 observer.finishEnumerating(upTo: nil)
                 return
@@ -105,33 +103,14 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
             
             if (page == NSFileProviderPage.initialPageSortedByDate as NSFileProviderPage || page == NSFileProviderPage.initialPageSortedByName as NSFileProviderPage) {
                 
-                if paginationEndpoint != nil {
-                                    
-                    self.getPagination(endpoint: paginationEndpoint!, serverUrl: serverUrl, page: 1, limit: fileProviderData.shared.itemForPage) { (metadatas) in
-                        self.completeObserver(observer, numPage: 1, metadatas: metadatas)
-                    }
-                    
-                } else {
-                    
-                    self.readFileOrFolder(serverUrl: serverUrl) { (metadatas) in
-                        self.completeObserver(observer, numPage: 1, metadatas: metadatas)
-                    }                    
+                self.readFileOrFolder(serverUrl: serverUrl) { (metadatas) in
+                    self.completeObserver(observer, numPage: 1, metadatas: metadatas)
                 }
                 
             } else {
                 
                 let numPage = Int(String(data: page.rawValue, encoding: .utf8)!)!
-
-                if paginationEndpoint != nil {
-
-                    self.getPagination(endpoint: paginationEndpoint!, serverUrl: serverUrl, page: numPage, limit: fileProviderData.shared.itemForPage) { (metadatas) in
-                        self.completeObserver(observer, numPage: numPage, metadatas: metadatas)
-                    }
-                    
-                } else {
-
-                    completeObserver(observer, numPage: numPage, metadatas: nil)
-                }
+                completeObserver(observer, numPage: numPage, metadatas: nil)
             }
         }
     }
@@ -254,56 +233,4 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
             }
         }
     }
-    
-    func getPagination(endpoint:String, serverUrl: String, page: Int, limit: Int, completionHandler: @escaping (_ metadatas: [tableMetadata]?) -> Void) {
-        
-        let offset = (page - 1) * limit
-        var fileNamePath = CCUtility.returnPathfromServerUrl(serverUrl, urlBase: fileProviderData.shared.accountUrlBase, account: fileProviderData.shared.account)!
-        if fileNamePath == "" {
-            fileNamePath = "/"
-        }
-        var directoryEtag: String?
-        
-        if let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", fileProviderData.shared.account, serverUrl)) {
-            if page == 1 {
-                directoryEtag = tableDirectory.etag
-            }
-        }
-        
-        NCCommunication.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "0", showHiddenFiles: CCUtility.getShowHiddenFiles()) { (account, files, responseData, errorCode, errorDescription) in
-        
-            if errorCode == 0 && files.count == 1 && directoryEtag != files.first?.etag {
-                
-                if page == 1 {
-                    let metadataFolder = NCManageDatabase.shared.convertNCFileToMetadata(files[0], isEncrypted: false, account: account)
-                    NCManageDatabase.shared.addMetadata(metadataFolder)
-                    NCManageDatabase.shared.addDirectory(encrypted: metadataFolder.e2eEncrypted, favorite: metadataFolder.favorite, ocId: metadataFolder.ocId, fileId: metadataFolder.fileId, etag: metadataFolder.etag, permissions: metadataFolder.permissions, serverUrl: serverUrl, account: metadataFolder.account)
-                }
-                                
-                NCCommunication.shared.iosHelper(fileNamePath: fileNamePath, serverUrl: serverUrl, offset: offset, limit: limit) { (account, files, errorCode, errorDescription) in
-                     
-                    if errorCode == 0 {
-                        DispatchQueue.global().async {
-                            NCManageDatabase.shared.convertNCCommunicationFilesToMetadatas(files, useMetadataFolder: false, account: account) { (metadataFolder, metadatasFolder, metadatas) in
-                                let metadatasResult = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND status == %d", fileProviderData.shared.account, serverUrl, NCGlobal.shared.metadataStatusNormal), page: page, limit: fileProviderData.shared.itemForPage, sorted: "fileName", ascending: true)
-                                NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult)
-                                for metadata in metadatasFolder {
-                                    let serverUrl = metadata.serverUrl + "/" + metadata.fileNameView
-                                    NCManageDatabase.shared.addDirectory(encrypted: metadata.e2eEncrypted, favorite: metadata.favorite, ocId: metadata.ocId, fileId: metadata.fileId, etag: nil, permissions: metadata.permissions, serverUrl: serverUrl, account: metadata.account)
-                                }
-                                let metadatas = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", fileProviderData.shared.account, serverUrl), page: page, limit: fileProviderData.shared.itemForPage, sorted: "fileName", ascending: true)
-                                completionHandler(metadatas)
-                            }
-                        }
-                    } else {
-                        let metadatas = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", fileProviderData.shared.account, serverUrl), page: page, limit: fileProviderData.shared.itemForPage, sorted: "fileName", ascending: true)
-                        completionHandler(metadatas)
-                    }
-                }
-            } else {
-                let metadatas = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", fileProviderData.shared.account, serverUrl), sorted: "fileName", ascending: true)
-                completionHandler(metadatas)
-            }
-        }
-    }
 }

+ 4 - 6
Nextcloud.xcodeproj/project.pbxproj

@@ -321,7 +321,6 @@
 		F7DFB7F0219C5B8000680748 /* NCCreateFormUploadAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7DFB7EF219C5B8000680748 /* NCCreateFormUploadAssets.swift */; };
 		F7DFB7F4219C5CA800680748 /* NCCreateFormUploadScanDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7DFB7F3219C5CA800680748 /* NCCreateFormUploadScanDocument.swift */; };
 		F7E0CDCF265CE8610044854E /* NCUserStatus.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7E0CDCE265CE8610044854E /* NCUserStatus.storyboard */; };
-		F7E17F4726C40AFA000AB7DD /* NCOperationQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A47EB2487B06B005AD489 /* NCOperationQueue.swift */; };
 		F7E4D9C422ED929B003675FD /* NCShareComments.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E4D9C322ED929B003675FD /* NCShareComments.swift */; };
 		F7ED547C25EEA65400956C55 /* QRCodeReader in Frameworks */ = {isa = PBXBuildFile; productRef = F7ED547B25EEA65400956C55 /* QRCodeReader */; };
 		F7EDE4CC262D7B6F00414FE6 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7239870253D86B600257F49 /* NCEmptyDataSet.swift */; };
@@ -2049,7 +2048,6 @@
 				F70460532499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F70BFC7520E0FA7D00C67599 /* NCUtility.swift in Sources */,
 				F79B646126CA661600838ACA /* UIControl+Extensions.swift in Sources */,
-				F7E17F4726C40AFA000AB7DD /* NCOperationQueue.swift in Sources */,
 				F7EDE4CC262D7B6F00414FE6 /* NCEmptyDataSet.swift in Sources */,
 				F798F0E225880608000DAFFD /* UIColor+Extensions.swift in Sources */,
 				F78295311F962EFA00A572F5 /* NCEndToEndEncryption.m in Sources */,
@@ -2614,7 +2612,7 @@
 		F77B0F9B1D118A16002130FE /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
 				CLANG_ENABLE_MODULES = YES;
@@ -2660,7 +2658,7 @@
 		F77B0F9C1D118A16002130FE /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
 				CLANG_ENABLE_MODULES = YES;
@@ -2931,7 +2929,7 @@
 			repositoryURL = "https://github.com/realm/realm-cocoa";
 			requirement = {
 				kind = exactVersion;
-				version = 10.12.0;
+				version = 10.14.0;
 			};
 		};
 		F786D58B253454BF00E3DD7B /* XCRemoteSwiftPackageReference "ios-communication-library" */ = {
@@ -2939,7 +2937,7 @@
 			repositoryURL = "https://github.com/nextcloud/ios-communication-library/";
 			requirement = {
 				kind = revision;
-				revision = 4b2b71daf4dea7b66d68cac5af67ec4aaf7d9281;
+				revision = 191b69d74ed12acc76a3d291542f0c587c43c7c0;
 			};
 		};
 		F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = {

+ 5 - 5
Nextcloud.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -105,7 +105,7 @@
         "repositoryURL": "https://github.com/nextcloud/ios-communication-library/",
         "state": {
           "branch": null,
-          "revision": "4b2b71daf4dea7b66d68cac5af67ec4aaf7d9281",
+          "revision": "191b69d74ed12acc76a3d291542f0c587c43c7c0",
           "version": null
         }
       },
@@ -186,8 +186,8 @@
         "repositoryURL": "https://github.com/realm/realm-cocoa",
         "state": {
           "branch": null,
-          "revision": "83a07f6a508c3427058d9e2c466208d0b6a960fa",
-          "version": "10.12.0"
+          "revision": "e7e7f072a1571435049683ca43c51501de2612fd",
+          "version": "10.14.0"
         }
       },
       {
@@ -195,8 +195,8 @@
         "repositoryURL": "https://github.com/realm/realm-core",
         "state": {
           "branch": null,
-          "revision": "e72b3078bfc5c3f69a0b18f7a220be27e28c463f",
-          "version": "11.2.0"
+          "revision": "fdb2157346dcdf0c2677b3608d9a4c30315fa7f0",
+          "version": "11.3.1"
         }
       },
       {

+ 14 - 23
Share/NCShareExtension.swift

@@ -240,19 +240,25 @@ class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDele
         
         // PROFILE BUTTON
                 
-        var image = NCUtility.shared.loadImage(named: "person.crop.circle")
-        let fileNamePath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(activeAccount.user, urlBase: activeAccount.urlBase)) + "-" + activeAccount.user + ".png"
-        if let userImage = UIImage(contentsOfFile: fileNamePath) {
-            image = userImage
+        var image: UIImage?
+        
+        if #available(iOS 13.0, *) {
+            let config = UIImage.SymbolConfiguration(pointSize: 30)
+            image = NCUtility.shared.loadImage(named: "person.crop.circle", symbolConfiguration: config)
+        } else {
+            image = NCUtility.shared.loadImage(named: "person.crop.circle", size: 30)
         }
-            
-        image = NCUtility.shared.createAvatar(image: image, size: 30)
-            
+        
+        let fileName = String(CCUtility.getUserUrlBase(activeAccount.user, urlBase: activeAccount.urlBase)) + "-" + activeAccount.user + "-original.png"
+        let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+        if let imageUser = UIImage(contentsOfFile: fileNameLocalPath) {
+            image = NCUtility.shared.createAvatar(image: imageUser, size: 30)
+        }
+        
         let profileButton = UIButton(type: .custom)
         profileButton.setImage(image, for: .normal)
             
         if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account) {
-             
 
             var title = "  "
             if activeAccount?.alias == "" {
@@ -572,21 +578,6 @@ extension NCShareExtension: UICollectionViewDataSource {
             cell.imageFavorite.image = NCBrandColor.cacheImages.favorite
         }
         
-        // Share image
-        if (isShare) {
-            cell.imageShared.image = NCBrandColor.cacheImages.shared
-        } else if (tableShare != nil && tableShare?.shareType == 3) {
-            cell.imageShared.image = NCBrandColor.cacheImages.shareByLink
-        } else if (tableShare != nil && tableShare?.shareType != 3) {
-            cell.imageShared.image = NCBrandColor.cacheImages.shared
-        } else {
-            cell.imageShared.image = NCBrandColor.cacheImages.canShare
-        }
-        if metadata.ownerId.count > 0 && metadata.ownerId != activeAccount.userId {
-            let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(activeAccount.user, urlBase: activeAccount.urlBase)) + "-" + metadata.ownerId + ".png"
-            NCOperationQueue.shared.downloadAvatar(user: metadata.ownerId, fileNameLocalPath: fileNameLocalPath, placeholder: nil, cell: cell, view: collectionView)
-        }
-        
         cell.imageSelect.isHidden = true
         cell.backgroundView = nil
         cell.hideButtonMore(true)

+ 5 - 4
iOSClient/Activity/NCActivity.swift

@@ -254,8 +254,9 @@ extension NCActivity: UITableViewDataSource {
                 cell.avatar.isHidden = false
                 cell.fileUser = activity.user
                 
-                let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + activity.user + ".png"
-                NCOperationQueue.shared.downloadAvatar(user: activity.user, fileNameLocalPath: fileNameLocalPath, placeholder: UIImage(named: "avatar"), cell: cell, view: tableView)
+                let fileName = String(CCUtility.getUserUrlBase(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + activity.user + ".png"
+
+                NCOperationQueue.shared.downloadAvatar(user: activity.user, fileName: fileName, placeholder: UIImage(named: "avatar"), cell: cell, view: tableView)
             }
             
             // subject
@@ -519,7 +520,7 @@ extension activityTableViewCell: UICollectionViewDataSource {
                         
                     } else {
                         
-                        NCCommunication.shared.downloadPreview(fileNamePathOrFileId: activityPreview.source, fileNamePreviewLocalPath: fileNamePath, widthPreview: 0, heightPreview: 0, useInternalEndpoint: false) { (account, imagePreview, imageIcon, errorCode, errorDescription) in
+                        NCCommunication.shared.downloadPreview(fileNamePathOrFileId: activityPreview.source, fileNamePreviewLocalPath: fileNamePath, widthPreview: 0, heightPreview: 0, etag: nil, useInternalEndpoint: false) { (account, imagePreview, imageIcon, imageOriginal, etag, errorCode, errorDescription) in
                             if errorCode == 0 && imagePreview != nil {
                                 self.collectionView.reloadData()
                             }
@@ -611,7 +612,7 @@ extension NCActivity {
             
             NCUtility.shared.stopActivityIndicator()
             
-            if errorCode == 304 {
+            if errorCode == NCGlobal.shared.errorNotModified {
                 self.canFetchActivity = false
             } else {
                 self.canFetchActivity = true

+ 14 - 3
iOSClient/AppDelegate.swift

@@ -64,7 +64,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     var pasteboardOcIds: [String] = []
     var shares: [tableShare] = []
     var timerErrorNetworking: Timer?
-    var avatars: [String:UIImage] = [:]
 
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
         
@@ -229,7 +228,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
                 
         // Required unsubscribing / subscribing
         NCPushNotification.shared().pushNotification()
-        
+            
         // Request Service Server Nextcloud
         NCService.shared.startRequestServicesServer()
         
@@ -480,7 +479,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         }
         
         // Nextcloud standard login
-        if NCBrandOptions.shared.disable_intro && NCBrandOptions.shared.disable_request_login_url {
+        if selector == NCGlobal.shared.introSignup {
+            
+            if activeLoginWeb?.view.window == nil {
+                activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb
+                if selector == NCGlobal.shared.introSignup {
+                    activeLoginWeb?.urlBase = NCBrandOptions.shared.linkloginPreferredProviders
+                } else {
+                    activeLoginWeb?.urlBase = self.urlBase
+                }
+                showLoginViewController(activeLoginWeb, contextViewController: viewController)
+            }
+            
+        } else if NCBrandOptions.shared.disable_intro && NCBrandOptions.shared.disable_request_login_url {
             
             if activeLoginWeb?.view.window == nil {
                 activeLoginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb

+ 19 - 4
iOSClient/Brand/Intro/NCIntro.storyboard

@@ -38,7 +38,7 @@
                                 </constraints>
                             </pageControl>
                             <button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Yyc-bK-mqW">
-                                <rect key="frame" x="72" y="584" width="270" height="40"/>
+                                <rect key="frame" x="72" y="550" width="270" height="40"/>
                                 <constraints>
                                     <constraint firstAttribute="height" constant="40" id="h0h-Pp-A9q"/>
                                     <constraint firstAttribute="width" constant="270" id="mXS-9b-u5o"/>
@@ -49,8 +49,20 @@
                                     <action selector="login:" destination="QS9-pa-PcE" eventType="touchUpInside" id="Lb4-EV-uT9"/>
                                 </connections>
                             </button>
+                            <button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="N4X-JQ-1c1">
+                                <rect key="frame" x="72" y="600" width="270" height="40"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="40" id="Z1i-8h-Kkj"/>
+                                    <constraint firstAttribute="width" constant="270" id="ski-k5-xeL"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                <state key="normal" title="Signup"/>
+                                <connections>
+                                    <action selector="signup:" destination="QS9-pa-PcE" eventType="touchUpInside" id="wKo-W5-MBd"/>
+                                </connections>
+                            </button>
                             <button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Z5d-gx-rTR">
-                                <rect key="frame" x="72" y="832" width="270" height="30"/>
+                                <rect key="frame" x="72" y="655" width="270" height="30"/>
                                 <constraints>
                                     <constraint firstAttribute="width" constant="270" id="rtc-VW-fLA"/>
                                     <constraint firstAttribute="height" constant="30" id="wPA-Ly-uB0"/>
@@ -71,19 +83,22 @@
                             <constraint firstItem="Eu1-Gv-7Jx" firstAttribute="top" secondItem="o6I-qu-IDh" secondAttribute="bottom" constant="8" id="Eeu-jq-3mJ"/>
                             <constraint firstItem="Yku-CN-snD" firstAttribute="trailing" secondItem="o6I-qu-IDh" secondAttribute="trailing" constant="8" id="Hc4-PE-nDo"/>
                             <constraint firstItem="o6I-qu-IDh" firstAttribute="centerX" secondItem="Xnz-EW-9gg" secondAttribute="centerX" id="XgO-Ht-bat"/>
-                            <constraint firstItem="Yyc-bK-mqW" firstAttribute="top" secondItem="Eu1-Gv-7Jx" secondAttribute="bottom" priority="250" constant="64" id="avi-Qq-NVJ"/>
+                            <constraint firstItem="Yyc-bK-mqW" firstAttribute="top" secondItem="Eu1-Gv-7Jx" secondAttribute="bottom" priority="250" constant="30" id="avi-Qq-NVJ"/>
+                            <constraint firstItem="N4X-JQ-1c1" firstAttribute="top" secondItem="Yyc-bK-mqW" secondAttribute="bottom" constant="10" id="g2S-FI-zsd"/>
+                            <constraint firstItem="N4X-JQ-1c1" firstAttribute="centerX" secondItem="Xnz-EW-9gg" secondAttribute="centerX" id="pyF-TA-FZv"/>
                             <constraint firstItem="Yyc-bK-mqW" firstAttribute="top" relation="greaterThanOrEqual" secondItem="Eu1-Gv-7Jx" secondAttribute="bottom" constant="8" id="qO4-JO-SuY"/>
-                            <constraint firstItem="Yku-CN-snD" firstAttribute="bottom" secondItem="Z5d-gx-rTR" secondAttribute="bottom" id="qo7-hg-l1p"/>
                             <constraint firstItem="o6I-qu-IDh" firstAttribute="top" secondItem="Xnz-EW-9gg" secondAttribute="topMargin" constant="60" id="qoE-U2-Ogf">
                                 <variation key="heightClass=compact" constant="8"/>
                             </constraint>
                             <constraint firstItem="Eu1-Gv-7Jx" firstAttribute="centerX" secondItem="Xnz-EW-9gg" secondAttribute="centerX" id="rML-gL-iXA"/>
                             <constraint firstItem="o6I-qu-IDh" firstAttribute="width" secondItem="o6I-qu-IDh" secondAttribute="height" multiplier="1:1" priority="750" id="tPF-eA-Pcb"/>
+                            <constraint firstItem="Z5d-gx-rTR" firstAttribute="top" secondItem="N4X-JQ-1c1" secondAttribute="bottom" constant="15" id="yH4-yF-95f"/>
                         </constraints>
                     </view>
                     <connections>
                         <outlet property="buttonHost" destination="Z5d-gx-rTR" id="Ngu-DS-yLh"/>
                         <outlet property="buttonLogin" destination="Yyc-bK-mqW" id="LPF-TP-LmK"/>
+                        <outlet property="buttonSignUp" destination="N4X-JQ-1c1" id="jz0-6S-IxP"/>
                         <outlet property="introCollectionView" destination="o6I-qu-IDh" id="DVx-Rt-VE8"/>
                         <outlet property="pageControl" destination="Eu1-Gv-7Jx" id="brQ-v9-knr"/>
                     </connections>

+ 32 - 19
iOSClient/Brand/Intro/NCIntroViewController.swift

@@ -28,6 +28,7 @@ import UIKit
 class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
 
     @IBOutlet weak var buttonLogin: UIButton!
+    @IBOutlet weak var buttonSignUp: UIButton!
     @IBOutlet weak var buttonHost: UIButton!
     @IBOutlet weak var introCollectionView: UICollectionView!
     @IBOutlet weak var pageControl: UIPageControl!
@@ -75,25 +76,33 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol
         self.navigationController?.navigationBar.tintColor = textColor
 
         
-        self.pageControl.currentPageIndicatorTintColor = textColor
-        self.pageControl.pageIndicatorTintColor = .lightGray
-
-        self.buttonLogin.layer.cornerRadius = 20
-        self.buttonLogin.setTitleColor(textColorOpponent, for: .normal)
-        self.buttonLogin.backgroundColor = textColor
-        self.buttonLogin.setTitle(NSLocalizedString("_log_in_", comment: ""), for: .normal)
-
-        self.buttonHost.layer.cornerRadius = 20
-        self.buttonHost.setTitle(NSLocalizedString("_host_your_own_server", comment: ""), for: .normal)
-        self.buttonHost.setTitleColor(textColor.withAlphaComponent(0.5), for: .normal)
-
-        self.introCollectionView.register(UINib(nibName: "NCIntroCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "introCell")
-        self.introCollectionView.dataSource = self
-        self.introCollectionView.delegate = self
-        self.introCollectionView.backgroundColor = NCBrandColor.shared.customer
-        self.pageControl.numberOfPages = self.titles.count
-        self.view.backgroundColor = NCBrandColor.shared.customer
-        self.timerAutoScroll = Timer.scheduledTimer(timeInterval: 5, target: self, selector: (#selector(NCIntroViewController.autoScroll)), userInfo: nil, repeats: true)
+        pageControl.currentPageIndicatorTintColor = textColor
+        pageControl.pageIndicatorTintColor = .lightGray
+
+        buttonLogin.layer.cornerRadius = 20
+        buttonLogin.setTitleColor(NCBrandColor.shared.customer, for: .normal)
+        buttonLogin.backgroundColor = textColor
+        buttonLogin.setTitle(NSLocalizedString("_log_in_", comment: ""), for: .normal)
+
+        buttonSignUp.layer.cornerRadius = 20
+        buttonSignUp.layer.borderColor = textColor.cgColor
+        buttonSignUp.layer.borderWidth = 1.0
+        buttonSignUp.setTitleColor(textColor, for: .normal)
+        buttonSignUp.backgroundColor = NCBrandColor.shared.customer
+        buttonSignUp.setTitle(NSLocalizedString("_sign_up_", comment: ""), for: .normal)
+
+        buttonHost.layer.cornerRadius = 20
+        buttonHost.setTitle(NSLocalizedString("_host_your_own_server", comment: ""), for: .normal)
+        buttonHost.setTitleColor(textColor.withAlphaComponent(0.5), for: .normal)
+
+        introCollectionView.register(UINib(nibName: "NCIntroCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "introCell")
+        introCollectionView.dataSource = self
+        introCollectionView.delegate = self
+        introCollectionView.backgroundColor = NCBrandColor.shared.customer
+        pageControl.numberOfPages = self.titles.count
+        
+        view.backgroundColor = NCBrandColor.shared.customer
+        timerAutoScroll = Timer.scheduledTimer(timeInterval: 5, target: self, selector: (#selector(NCIntroViewController.autoScroll)), userInfo: nil, repeats: true)
     }
     
     override var preferredStatusBarStyle: UIStatusBarStyle {
@@ -163,6 +172,10 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol
         appDelegate.openLogin(viewController: navigationController, selector: NCGlobal.shared.introLogin, openLoginWeb: false)
     }
 
+    @IBAction func signup(_ sender: Any) {
+        appDelegate.openLogin(viewController: navigationController, selector: NCGlobal.shared.introSignup, openLoginWeb: false)
+    }
+
     @IBAction func host(_ sender: Any) {
         guard let url = URL(string: NCBrandOptions.shared.linkLoginHost) else { return }
         UIApplication.shared.open(url)

+ 16 - 1
iOSClient/Data/NCDatabase.swift

@@ -166,6 +166,18 @@ class tableActivitySubjectRich: Object {
     }
 }
 
+class tableAvatar: Object {
+    
+    @objc dynamic var date = NSDate()
+    @objc dynamic var etag = ""
+    @objc dynamic var fileName = ""
+    @objc dynamic var loaded: Bool = false
+
+    override static func primaryKey() -> String {
+        return "fileName"
+    }
+}
+
 class tableCapabilities: Object {
     
     @objc dynamic var account = ""
@@ -341,6 +353,7 @@ class tableMetadata: Object {
     @objc dynamic var e2eEncrypted: Bool = false
     @objc dynamic var edited: Bool = false
     @objc dynamic var etag = ""
+    @objc dynamic var etagResource = ""
     @objc dynamic var ext = ""
     @objc dynamic var favorite: Bool = false
     @objc dynamic var fileId = ""
@@ -366,7 +379,9 @@ class tableMetadata: Object {
     @objc dynamic var sessionError = ""
     @objc dynamic var sessionSelector = ""
     @objc dynamic var sessionTaskIdentifier: Int = 0
-    @objc dynamic var sharePermissions = ""
+    @objc dynamic var sharePermissionsCollaborationServices: Int = 0
+    let sharePermissionsCloudMesh = List<String>()
+    let shareType = List<Int>()
     @objc dynamic var size: Int64 = 0
     @objc dynamic var status: Int = 0
     @objc dynamic var trashbinFileName = ""

+ 0 - 1
iOSClient/Data/NCElementsJSON.swift

@@ -56,7 +56,6 @@ import UIKit
 
     @objc public let capabilitiesFilesUndelete:                 Array = ["ocs","data","capabilities","files","undelete"]
     @objc public let capabilitiesFilesComments:                 Array = ["ocs","data","capabilities","files","comments"]                                            // NC 20
-    @objc public let capabilitiesPaginationEndpoint:            Array = ["ocs","data","capabilities","files","pagination","endpoint"]
 
     @objc public let capabilitiesHWCEnabled:                    Array = ["ocs","data","capabilities","handwerkcloud","enabled"]
     

+ 132 - 4
iOSClient/Data/NCManageDatabase.swift

@@ -116,13 +116,23 @@ class NCManageDatabase: NSObject {
                         }
                     }
                     
-                    if oldSchemaVersion < 196 {
+                    if oldSchemaVersion < 207 {
                         migration.deleteData(forType: tableDirectory.className())
                         migration.deleteData(forType: tableE2eEncryption.className())
                         migration.deleteData(forType: tableE2eEncryptionLock.className())
                         migration.deleteData(forType: tableMetadata.className())
                         migration.deleteData(forType: tableShare.className())
                         migration.deleteData(forType: tableTrash.className())
+                        // Delete OLD avatar image
+                        if var pathUrl = CCUtility.getDirectoryGroup() {
+                            pathUrl.appendPathComponent(NCGlobal.shared.appUserData)
+                            do {
+                                let fileURLs = try FileManager.default.contentsOfDirectory(at: pathUrl, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
+                                for fileURL in fileURLs {
+                                    try FileManager.default.removeItem(at: fileURL)
+                                }
+                            } catch { }
+                        }
                     }
                     
                 }, shouldCompactOnLaunch: { totalBytes, usedBytes in
@@ -178,7 +188,7 @@ class NCManageDatabase: NSObject {
     //MARK: -
     //MARK: Utility Database
 
-    @objc func clearTable(_ table : Object.Type, account: String?) {
+    @objc func clearTable(_ table : Object.Type, account: String? = nil) {
         
         let realm = try! Realm()
 
@@ -204,6 +214,7 @@ class NCManageDatabase: NSObject {
         self.clearTable(tableActivity.self, account: account)
         self.clearTable(tableActivityPreview.self, account: account)
         self.clearTable(tableActivitySubjectRich.self, account: account)
+        self.clearTable(tableAvatar.self)
         self.clearTable(tableCapabilities.self, account: account)
         self.clearTable(tableChunk.self, account: account)
         self.clearTable(tableComments.self, account: account)
@@ -894,6 +905,101 @@ class NCManageDatabase: NSObject {
         return 0
     }
     
+    //MARK: -
+    //MARK: Table Avatar
+    
+    @objc func addAvatar(fileName: String, etag: String) {
+        
+        let realm = try! Realm()
+        
+        do {
+            try realm.safeWrite {
+                
+                // Add new
+                let addObject = tableAvatar()
+                    
+                addObject.date = NSDate()
+                addObject.etag = etag
+                addObject.fileName = fileName
+                addObject.loaded = true
+
+                realm.add(addObject, update: .all)
+            }
+        } catch let error {
+            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
+        }
+    }
+    
+    func getTableAvatar(fileName: String) -> tableAvatar? {
+        
+        let realm = try! Realm()
+        
+        guard let result = realm.objects(tableAvatar.self).filter("fileName == %@", fileName).first else {
+            return nil
+        }
+        
+        return tableAvatar.init(value: result)
+    }
+
+    func clearAllAvatarLoaded() {
+        
+        let realm = try! Realm()
+        
+        do {
+            try realm.safeWrite {
+                
+                let results = realm.objects(tableAvatar.self)
+                for result in results {
+                    result.loaded = false
+                    realm.add(result, update: .all)
+                }
+            }
+        } catch let error {
+            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
+        }
+    }
+    
+    @discardableResult
+    func setAvatarLoaded(fileName: String) -> UIImage? {
+     
+        let realm = try! Realm()
+        let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+        var image: UIImage?
+        
+        do {
+            try realm.safeWrite {
+                if let result = realm.objects(tableAvatar.self).filter("fileName == %@", fileName).first {
+                    if let imageAvatar = UIImage(contentsOfFile: fileNameLocalPath) {
+                        result.loaded = true
+                        image = imageAvatar
+                    } else {
+                        realm.delete(result)
+                    }
+                }
+            }
+        } catch let error {
+            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
+        }
+        
+        return image
+    }
+    
+    func getImageAvatarLoaded(fileName: String) -> UIImage? {
+        
+        let realm = try! Realm()
+        let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+
+        let result = realm.objects(tableAvatar.self).filter("fileName == %@", fileName).first
+        if result == nil {
+            NCUtilityFileSystem.shared.deleteFile(filePath: fileNameLocalPath)
+            return nil
+        } else if result?.loaded == false {
+            return nil
+        }
+        
+        return UIImage(contentsOfFile: fileNameLocalPath)
+    }
+    
     //MARK: -
     //MARK: Table Capabilities
     
@@ -1862,7 +1968,13 @@ class NCManageDatabase: NSObject {
         metadata.richWorkspace = file.richWorkspace
         metadata.resourceType = file.resourceType
         metadata.serverUrl = file.serverUrl
-        metadata.sharePermissions = file.sharePermissions
+        metadata.sharePermissionsCollaborationServices = file.sharePermissionsCollaborationServices
+        for element in file.sharePermissionsCloudMesh {
+            metadata.sharePermissionsCloudMesh.append(element)
+        }
+        for element in file.shareType {
+            metadata.shareType.append(element)
+        }
         metadata.size = file.size
         metadata.classFile = file.classFile
         if let date = file.uploadDate {
@@ -2098,7 +2210,7 @@ class NCManageDatabase: NSObject {
                     
                     if let result = metadatasResult.first(where: { $0.ocId == metadata.ocId }) {
                         // update
-                        if result.status == NCGlobal.shared.metadataStatusNormal && (result.etag != metadata.etag || result.fileNameView != metadata.fileNameView || result.date != metadata.date || result.permissions != metadata.permissions || result.hasPreview != metadata.hasPreview) {
+                        if result.status == NCGlobal.shared.metadataStatusNormal && (result.etag != metadata.etag || result.fileNameView != metadata.fileNameView || result.date != metadata.date || result.permissions != metadata.permissions || result.hasPreview != metadata.hasPreview || result.note != metadata.note) {
                             ocIdsUdate.append(metadata.ocId)
                             realm.add(metadata, update: .all)
                         } else if result.status == NCGlobal.shared.metadataStatusNormal && addCompareLivePhoto && result.livePhoto != metadata.livePhoto {
@@ -2203,6 +2315,22 @@ class NCManageDatabase: NSObject {
         }
     }
     
+    func setMetadataEtagResource(ocId: String, etagResource: String?) {
+        
+        let realm = try! Realm()
+        var result: tableMetadata?
+        guard let etagResource = etagResource else { return }
+        
+        do {
+            try realm.safeWrite {
+                result = realm.objects(tableMetadata.self).filter("ocId == %@", ocId).first
+                result?.etagResource = etagResource
+            }
+        } catch let error {
+            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
+        }
+    }
+    
     @objc func setMetadataFavorite(ocId: String, favorite: Bool) {
         
         let realm = try! Realm()

+ 3 - 2
iOSClient/FileViewInFolder/NCFileViewInFolder.swift

@@ -24,7 +24,7 @@
 import UIKit
 import NCCommunication
 
-class NCFileViewInFolder: NCCollectionViewCommon  {
+class NCFileViewInFolder: NCCollectionViewCommon {
     
     internal var fileName: String?
 
@@ -43,7 +43,8 @@ class NCFileViewInFolder: NCCollectionViewCommon  {
     }
     
     override func viewWillAppear(_ animated: Bool) {
-
+        super.viewWillAppear(animated)
+        
         appDelegate.activeViewController = self
         
         if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: appDelegate.account) {

+ 12 - 0
iOSClient/Images.xcassets/arrow.right.imageset/Contents.json

@@ -0,0 +1,12 @@
+{
+  "images" : [
+    {
+      "filename" : "arrow-right.svg",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 1 - 0
iOSClient/Images.xcassets/arrow.right.imageset/arrow-right.svg

@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" /></svg>

+ 15 - 0
iOSClient/Images.xcassets/note.text.imageset/Contents.json

@@ -0,0 +1,15 @@
+{
+  "images" : [
+    {
+      "filename" : "note.text.svg",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "preserves-vector-representation" : true
+  }
+}

+ 1 - 0
iOSClient/Images.xcassets/note.text.imageset/note.text.svg

@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M21,6V8H3V6H21M3,18H12V16H3V18M3,13H21V11H3V13Z" /></svg>

+ 41 - 134
iOSClient/Login/NCLogin.storyboard

@@ -17,14 +17,14 @@
                         <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                         <subviews>
                             <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="BpI-xK-1SU">
-                                <rect key="frame" x="87" y="44" width="240" height="120"/>
+                                <rect key="frame" x="87" y="226.5" width="240" height="120"/>
                                 <constraints>
                                     <constraint firstAttribute="height" constant="120" id="E9d-5O-bto"/>
                                     <constraint firstAttribute="width" constant="240" id="xwH-mh-yDU"/>
                                 </constraints>
                             </imageView>
-                            <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" layoutMarginsFollowReadableWidth="YES" insetsLayoutMarginsFromSafeArea="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Server address https://…" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="szn-G7-5sK">
-                                <rect key="frame" x="45" y="164" width="326" height="44"/>
+                            <textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" layoutMarginsFollowReadableWidth="YES" insetsLayoutMarginsFromSafeArea="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="  Server address https://…" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="szn-G7-5sK">
+                                <rect key="frame" x="50" y="376.5" width="314" height="44"/>
                                 <constraints>
                                     <constraint firstAttribute="height" constant="44" id="I2v-Zr-IWf"/>
                                 </constraints>
@@ -32,97 +32,36 @@
                                 <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                 <textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL" returnKeyType="done"/>
                             </textField>
-                            <textField opaque="NO" clipsSubviews="YES" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="1Gf-Bw-Nim">
-                                <rect key="frame" x="45" y="208" width="319" height="44"/>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HQd-pF-3cE">
+                                <rect key="frame" x="324" y="378.5" width="40" height="40"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <constraints>
-                                    <constraint firstAttribute="height" constant="44" id="JYC-15-QFZ"/>
+                                    <constraint firstAttribute="height" constant="40" id="3yh-bo-Bzr"/>
+                                    <constraint firstAttribute="width" constant="40" id="yLC-Ai-3Ob"/>
                                 </constraints>
-                                <color key="textColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                <textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done"/>
-                            </textField>
-                            <textField opaque="NO" clipsSubviews="YES" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="jU7-Iw-XfU">
-                                <rect key="frame" x="45" y="252" width="324" height="44"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" constant="44" id="SHB-pM-p1U"/>
-                                </constraints>
-                                <color key="textColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                <textInputTraits key="textInputTraits" returnKeyType="done" secureTextEntry="YES"/>
-                            </textField>
-                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="loginUser" translatesAutoresizingMaskIntoConstraints="NO" id="4OF-5u-Hd1">
-                                <rect key="frame" x="10" y="217.5" width="25" height="25"/>
-                                <constraints>
-                                    <constraint firstAttribute="width" constant="25" id="FlR-Hd-bH5"/>
-                                    <constraint firstAttribute="height" constant="25" id="ViZ-ks-cWQ"/>
-                                </constraints>
-                            </imageView>
-                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="loginURL" translatesAutoresizingMaskIntoConstraints="NO" id="s9o-RX-XeS">
-                                <rect key="frame" x="10" y="173.5" width="25" height="25"/>
-                                <constraints>
-                                    <constraint firstAttribute="width" constant="25" id="fh1-RS-gPF"/>
-                                    <constraint firstAttribute="height" constant="25" id="rDO-8n-TTv"/>
-                                </constraints>
-                            </imageView>
-                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="loginPassword" translatesAutoresizingMaskIntoConstraints="NO" id="7q8-rl-x2M">
-                                <rect key="frame" x="10" y="261.5" width="25" height="25"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" constant="25" id="P8q-8P-IZg"/>
-                                    <constraint firstAttribute="width" constant="25" id="glL-CW-aF0"/>
-                                </constraints>
-                            </imageView>
-                            <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fhk-o9-J0l">
-                                <rect key="frame" x="379" y="261.5" width="25" height="25"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" constant="25" id="Tme-Lb-bhd"/>
-                                    <constraint firstAttribute="width" constant="25" id="uVC-Cm-7w6"/>
-                                </constraints>
-                                <state key="normal" image="visiblePassword" backgroundImage="visiblePassword"/>
-                                <connections>
-                                    <action selector="actionToggleVisiblePassword:" destination="yj9-jo-WIn" eventType="touchUpInside" id="n5I-x0-ngr"/>
-                                </connections>
-                            </button>
-                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HQd-pF-3cE">
-                                <rect key="frame" x="50" y="308" width="314" height="40"/>
-                                <color key="backgroundColor" red="0.2196078431372549" green="0.50196078431372548" blue="0.76470588235294112" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" constant="40" id="S6Y-YG-g6O"/>
-                                </constraints>
-                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                 <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                <state key="normal" title="Accedi">
+                                <state key="normal">
                                     <color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                 </state>
                                 <connections>
                                     <action selector="actionButtonLogin:" destination="yj9-jo-WIn" eventType="touchUpInside" id="vFP-SJ-rFq"/>
                                 </connections>
                             </button>
-                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="owR-PS-F32" userLabel="loginTypeView">
-                                <rect key="frame" x="159.5" y="822" width="95" height="40"/>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Al0-LA-Ndt">
+                                <rect key="frame" x="334" y="388.5" width="20" height="20"/>
                                 <constraints>
-                                    <constraint firstAttribute="height" constant="40" id="PaU-7J-gkn"/>
+                                    <constraint firstAttribute="height" constant="20" id="IQA-ga-jx5"/>
+                                    <constraint firstAttribute="width" constant="20" id="hVA-N5-u88"/>
                                 </constraints>
-                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                <state key="normal" title="Login type view"/>
-                                <connections>
-                                    <action selector="actionLoginModeButton:" destination="yj9-jo-WIn" eventType="touchUpInside" id="bqY-ne-nbT"/>
-                                </connections>
-                            </button>
-                            <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="Kfq-Bg-a0E">
-                                <rect key="frame" x="381" y="176" width="20" height="20"/>
-                            </activityIndicatorView>
-                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5lM-dt-8fM">
-                                <rect key="frame" x="182" y="548" width="50" height="50"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" constant="50" id="0RD-Gi-CTv"/>
-                                    <constraint firstAttribute="width" constant="50" id="NuK-Yo-LoT"/>
-                                </constraints>
-                                <connections>
-                                    <action selector="actionCertificate:" destination="yj9-jo-WIn" eventType="touchUpInside" id="Ibx-wC-iEY"/>
-                                </connections>
-                            </button>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="The link to your Nextcloud web interface when you open it in the browser." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PJH-5i-Tkf">
+                                <rect key="frame" x="60" y="438.5" width="294" height="29"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                                <nil key="textColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
                             <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6tp-bh-Z9k" userLabel="QRCode">
-                                <rect key="frame" x="182" y="448" width="50" height="50"/>
+                                <rect key="frame" x="182" y="567.5" width="50" height="50"/>
                                 <constraints>
                                     <constraint firstAttribute="width" constant="50" id="3hb-Ez-hOz"/>
                                     <constraint firstAttribute="height" constant="50" id="OLT-tb-4Qb"/>
@@ -131,76 +70,48 @@
                                     <action selector="actionQRCode:" destination="yj9-jo-WIn" eventType="touchUpInside" id="qwL-rG-ead"/>
                                 </connections>
                             </button>
-                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Mb1-fw-4Hf">
-                                <rect key="frame" x="50" y="363" width="314" height="40"/>
-                                <color key="backgroundColor" red="0.21960784310000001" green="0.50196078430000002" blue="0.76470588240000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5lM-dt-8fM">
+                                <rect key="frame" x="182" y="667.5" width="50" height="50"/>
                                 <constraints>
-                                    <constraint firstAttribute="height" constant="40" id="8C4-ay-ZVq"/>
+                                    <constraint firstAttribute="height" constant="50" id="0RD-Gi-CTv"/>
+                                    <constraint firstAttribute="width" constant="50" id="NuK-Yo-LoT"/>
                                 </constraints>
-                                <fontDescription key="fontDescription" type="system" pointSize="13"/>
-                                <color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                <state key="normal" title="Sign up">
-                                    <color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                </state>
                                 <connections>
-                                    <action selector="actionButtonSignup:" destination="yj9-jo-WIn" eventType="touchUpInside" id="CSW-BM-PsZ"/>
+                                    <action selector="actionCertificate:" destination="yj9-jo-WIn" eventType="touchUpInside" id="Ibx-wC-iEY"/>
                                 </connections>
                             </button>
                         </subviews>
                         <viewLayoutGuide key="safeArea" id="8lf-3Y-f5R"/>
                         <color key="backgroundColor" white="0.9023259132753424" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                         <constraints>
-                            <constraint firstItem="8lf-3Y-f5R" firstAttribute="trailing" secondItem="Kfq-Bg-a0E" secondAttribute="trailing" constant="13" id="3Rl-VS-3Op"/>
-                            <constraint firstItem="1Gf-Bw-Nim" firstAttribute="leading" secondItem="4OF-5u-Hd1" secondAttribute="trailing" constant="10" id="4CC-7B-dkI"/>
-                            <constraint firstItem="8lf-3Y-f5R" firstAttribute="trailing" secondItem="Mb1-fw-4Hf" secondAttribute="trailing" constant="50" id="8tC-US-hKm"/>
-                            <constraint firstItem="HQd-pF-3cE" firstAttribute="top" secondItem="8lf-3Y-f5R" secondAttribute="top" constant="264" id="9hf-b4-BDZ"/>
+                            <constraint firstItem="8lf-3Y-f5R" firstAttribute="trailing" secondItem="szn-G7-5sK" secondAttribute="trailing" constant="50" id="24L-p4-zOF"/>
+                            <constraint firstItem="PJH-5i-Tkf" firstAttribute="leading" secondItem="8lf-3Y-f5R" secondAttribute="leading" constant="60" id="3aW-cF-rdF"/>
+                            <constraint firstItem="8lf-3Y-f5R" firstAttribute="trailing" secondItem="HQd-pF-3cE" secondAttribute="trailing" constant="50" id="94K-sw-8AT"/>
                             <constraint firstItem="6tp-bh-Z9k" firstAttribute="centerX" secondItem="8lf-3Y-f5R" secondAttribute="centerX" id="Apc-1U-CwU"/>
-                            <constraint firstItem="BpI-xK-1SU" firstAttribute="top" secondItem="8lf-3Y-f5R" secondAttribute="top" id="Fep-pw-QEQ"/>
-                            <constraint firstItem="fhk-o9-J0l" firstAttribute="leading" secondItem="jU7-Iw-XfU" secondAttribute="trailing" constant="10" id="FmL-e8-YKk"/>
+                            <constraint firstItem="BpI-xK-1SU" firstAttribute="top" secondItem="Bv6-g3-l0M" secondAttribute="centerY" multiplier="0.5" constant="2.5" id="Gkg-up-7eW"/>
                             <constraint firstItem="8lf-3Y-f5R" firstAttribute="centerX" secondItem="BpI-xK-1SU" secondAttribute="centerX" id="IxG-UI-0vq"/>
-                            <constraint firstItem="Kfq-Bg-a0E" firstAttribute="centerY" secondItem="szn-G7-5sK" secondAttribute="centerY" id="Ldo-FD-LNp"/>
-                            <constraint firstItem="6tp-bh-Z9k" firstAttribute="top" secondItem="HQd-pF-3cE" secondAttribute="bottom" constant="100" id="NCo-gF-R4d"/>
-                            <constraint firstItem="jU7-Iw-XfU" firstAttribute="top" secondItem="1Gf-Bw-Nim" secondAttribute="bottom" id="QHr-T7-zbl"/>
-                            <constraint firstItem="6tp-bh-Z9k" firstAttribute="top" secondItem="Mb1-fw-4Hf" secondAttribute="bottom" constant="45" id="QOD-6T-3Sf"/>
-                            <constraint firstItem="owR-PS-F32" firstAttribute="centerX" secondItem="8lf-3Y-f5R" secondAttribute="centerX" id="VSS-Pz-f7g"/>
-                            <constraint firstItem="4OF-5u-Hd1" firstAttribute="centerY" secondItem="1Gf-Bw-Nim" secondAttribute="centerY" id="Wkl-Is-Ay0"/>
-                            <constraint firstItem="jU7-Iw-XfU" firstAttribute="leading" secondItem="7q8-rl-x2M" secondAttribute="trailing" constant="10" id="a3y-yQ-wa8"/>
-                            <constraint firstItem="7q8-rl-x2M" firstAttribute="leading" secondItem="8lf-3Y-f5R" secondAttribute="leading" constant="10" id="bf8-6l-dfs"/>
-                            <constraint firstItem="4OF-5u-Hd1" firstAttribute="leading" secondItem="8lf-3Y-f5R" secondAttribute="leading" constant="10" id="e7p-K8-Tt3"/>
-                            <constraint firstItem="s9o-RX-XeS" firstAttribute="leading" secondItem="8lf-3Y-f5R" secondAttribute="leading" constant="10" id="gYr-20-hOQ"/>
+                            <constraint firstItem="6tp-bh-Z9k" firstAttribute="top" secondItem="PJH-5i-Tkf" secondAttribute="bottom" constant="100" id="MZQ-GT-XSM"/>
+                            <constraint firstItem="PJH-5i-Tkf" firstAttribute="top" secondItem="szn-G7-5sK" secondAttribute="bottom" constant="18" id="Vfj-lG-7wT"/>
+                            <constraint firstItem="Al0-LA-Ndt" firstAttribute="centerX" secondItem="HQd-pF-3cE" secondAttribute="centerX" id="Yll-3L-vuj"/>
+                            <constraint firstItem="HQd-pF-3cE" firstAttribute="centerY" secondItem="szn-G7-5sK" secondAttribute="centerY" id="cG8-kL-pdu"/>
+                            <constraint firstItem="Al0-LA-Ndt" firstAttribute="centerY" secondItem="HQd-pF-3cE" secondAttribute="centerY" id="eOF-06-PmZ"/>
                             <constraint firstItem="5lM-dt-8fM" firstAttribute="top" secondItem="6tp-bh-Z9k" secondAttribute="bottom" constant="50" id="i5K-Jt-epF"/>
-                            <constraint firstItem="7q8-rl-x2M" firstAttribute="centerY" secondItem="jU7-Iw-XfU" secondAttribute="centerY" id="jhu-Tk-ifA"/>
-                            <constraint firstItem="8lf-3Y-f5R" firstAttribute="bottom" secondItem="owR-PS-F32" secondAttribute="bottom" id="kxd-eg-KfO"/>
-                            <constraint firstItem="szn-G7-5sK" firstAttribute="top" secondItem="BpI-xK-1SU" secondAttribute="bottom" id="lWz-Yy-NCO"/>
-                            <constraint firstItem="8lf-3Y-f5R" firstAttribute="trailing" secondItem="HQd-pF-3cE" secondAttribute="trailing" constant="50" id="mK0-hK-nIb"/>
+                            <constraint firstItem="szn-G7-5sK" firstAttribute="top" secondItem="BpI-xK-1SU" secondAttribute="bottom" constant="30" id="lWz-Yy-NCO"/>
                             <constraint firstItem="5lM-dt-8fM" firstAttribute="centerX" secondItem="8lf-3Y-f5R" secondAttribute="centerX" id="mKe-Nn-9dd"/>
-                            <constraint firstItem="fhk-o9-J0l" firstAttribute="centerY" secondItem="jU7-Iw-XfU" secondAttribute="centerY" id="mxp-Nw-IAQ"/>
-                            <constraint firstItem="HQd-pF-3cE" firstAttribute="leading" secondItem="8lf-3Y-f5R" secondAttribute="leading" constant="50" id="rwA-Qb-mto"/>
-                            <constraint firstItem="s9o-RX-XeS" firstAttribute="centerY" secondItem="szn-G7-5sK" secondAttribute="centerY" id="s6D-hp-8Fw"/>
-                            <constraint firstItem="8lf-3Y-f5R" firstAttribute="trailing" secondItem="fhk-o9-J0l" secondAttribute="trailing" constant="10" id="sSF-C0-MZp"/>
-                            <constraint firstItem="szn-G7-5sK" firstAttribute="leading" secondItem="s9o-RX-XeS" secondAttribute="trailing" constant="10" id="wG2-dF-inH"/>
-                            <constraint firstItem="1Gf-Bw-Nim" firstAttribute="top" secondItem="szn-G7-5sK" secondAttribute="bottom" id="wZI-EZ-zRI"/>
-                            <constraint firstItem="Mb1-fw-4Hf" firstAttribute="leading" secondItem="8lf-3Y-f5R" secondAttribute="leading" constant="50" id="xF9-aF-2dd"/>
-                            <constraint firstItem="8lf-3Y-f5R" firstAttribute="trailing" secondItem="1Gf-Bw-Nim" secondAttribute="trailing" constant="50" id="yHe-0f-GD6"/>
-                            <constraint firstItem="Kfq-Bg-a0E" firstAttribute="leading" secondItem="szn-G7-5sK" secondAttribute="trailing" constant="10" id="z3g-fw-GHs"/>
+                            <constraint firstItem="szn-G7-5sK" firstAttribute="leading" secondItem="8lf-3Y-f5R" secondAttribute="leading" constant="50" id="uQw-dy-Ga4"/>
+                            <constraint firstItem="8lf-3Y-f5R" firstAttribute="trailing" secondItem="PJH-5i-Tkf" secondAttribute="trailing" constant="60" id="zzV-UD-gRV"/>
                         </constraints>
                     </view>
                     <navigationItem key="navigationItem" id="6v9-Gy-jiv"/>
                     <connections>
-                        <outlet property="activity" destination="Kfq-Bg-a0E" id="SqA-zj-Vd6"/>
                         <outlet property="baseUrl" destination="szn-G7-5sK" id="rpO-mh-09O"/>
                         <outlet property="certificate" destination="5lM-dt-8fM" id="vw6-cH-njm"/>
-                        <outlet property="imageBaseUrl" destination="s9o-RX-XeS" id="Q81-S9-1P2"/>
                         <outlet property="imageBrand" destination="BpI-xK-1SU" id="0tB-69-RNs"/>
-                        <outlet property="imagePassword" destination="7q8-rl-x2M" id="Cr5-Te-Rkq"/>
-                        <outlet property="imageUser" destination="4OF-5u-Hd1" id="MJa-4H-w7m"/>
+                        <outlet property="imageBrandConstraintY" destination="Gkg-up-7eW" id="RKw-pM-dZr"/>
+                        <outlet property="loginAddressDetail" destination="PJH-5i-Tkf" id="wBQ-5P-HD4"/>
                         <outlet property="loginButton" destination="HQd-pF-3cE" id="XOc-dS-QZ8"/>
-                        <outlet property="loginModeButton" destination="owR-PS-F32" id="iXW-wC-T2H"/>
-                        <outlet property="password" destination="jU7-Iw-XfU" id="OWi-V0-Eij"/>
+                        <outlet property="loginImage" destination="Al0-LA-Ndt" id="dT5-vu-5eD"/>
                         <outlet property="qrCode" destination="6tp-bh-Z9k" id="Tw3-op-BgR"/>
-                        <outlet property="signupButton" destination="Mb1-fw-4Hf" id="EsI-uj-IKj"/>
-                        <outlet property="toggleVisiblePasswordButton" destination="fhk-o9-J0l" id="e0X-WA-5cz"/>
-                        <outlet property="user" destination="1Gf-Bw-Nim" id="BUW-sz-I3f"/>
                     </connections>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="dCU-1X-uQw" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -261,10 +172,6 @@
         </scene>
     </scenes>
     <resources>
-        <image name="loginPassword" width="25" height="25"/>
-        <image name="loginURL" width="25" height="25"/>
-        <image name="loginUser" width="25" height="25"/>
         <image name="logo" width="256" height="128"/>
-        <image name="visiblePassword" width="25" height="25"/>
     </resources>
 </document>

+ 43 - 143
iOSClient/Login/NCLogin.swift

@@ -27,35 +27,18 @@ import NCCommunication
 class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
     
     @IBOutlet weak var imageBrand: UIImageView!
-    
+    @IBOutlet weak var imageBrandConstraintY: NSLayoutConstraint!
     @IBOutlet weak var baseUrl: UITextField!
-    @IBOutlet weak var user: UITextField!
-    @IBOutlet weak var password: UITextField!
-
-    @IBOutlet weak var imageBaseUrl: UIImageView!
-    @IBOutlet weak var imageUser: UIImageView!
-    @IBOutlet weak var imagePassword: UIImageView!
-
-    @IBOutlet weak var activity: UIActivityIndicatorView!
-
+    @IBOutlet weak var loginAddressDetail: UILabel!
     @IBOutlet weak var loginButton: UIButton!
-    @IBOutlet weak var signupButton: UIButton!
-
-    @IBOutlet weak var toggleVisiblePasswordButton: UIButton!
-    @IBOutlet weak var loginModeButton: UIButton!
-    
+    @IBOutlet weak var loginImage: UIImageView!
     @IBOutlet weak var qrCode: UIButton!
     @IBOutlet weak var certificate: UIButton!
 
-    enum loginMode {
-        case traditional, webFlow
-    }
-    var currentLoginMode: loginMode = .webFlow
-    
-    let appDelegate = UIApplication.shared.delegate as! AppDelegate
-    var textColor: UIColor = .white
-    var textColorOpponent: UIColor = .black
-    
+    private let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    private var textColor: UIColor = .white
+    private var textColorOpponent: UIColor = .black
+
     // MARK: - View Life Cycle
 
     override func viewDidLoad() {
@@ -79,52 +62,29 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
         imageBrand.image = UIImage(named: "logo")
         
         // Url
-        imageBaseUrl.image = UIImage(named: "loginURL")?.image(color: textColor, size: 50)
         baseUrl.textColor = textColor
         baseUrl.tintColor = textColor
+        baseUrl.layer.cornerRadius = 10
+        baseUrl.layer.borderWidth = 1
+        baseUrl.layer.borderColor = textColor.cgColor
+        baseUrl.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: baseUrl.frame.height))
+        baseUrl.leftViewMode = .always
+        baseUrl.rightView = UIView(frame: CGRect(x: 0, y: 0, width: 35, height: baseUrl.frame.height))
+        baseUrl.rightViewMode = .always
         baseUrl.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("_login_url_", comment: ""), attributes: [NSAttributedString.Key.foregroundColor: textColor.withAlphaComponent(0.5)])
         baseUrl.delegate = self
         
-        // User
-        imageUser.image = UIImage(named: "loginUser")?.image(color: textColor, size: 50)
-        user.textColor = textColor
-        user.tintColor = textColor
-        user.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("_username_", comment: ""), attributes: [NSAttributedString.Key.foregroundColor: textColor.withAlphaComponent(0.5)])
-        user.delegate = self
-        
-        // password
-        imagePassword.image = UIImage(named: "loginPassword")?.image(color: textColor, size: 50)
-        password.textColor = textColor
-        password.tintColor = textColor
-        password.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("_password_", comment: ""), attributes: [NSAttributedString.Key.foregroundColor: textColor.withAlphaComponent(0.5)])
-        password.delegate = self
-        
-        // toggle visible password
-        toggleVisiblePasswordButton.setImage(UIImage(named: "visiblePassword")?.image(color: textColor, size: 50), for: .normal)
-        
-        // login
-        loginButton.setTitle(NSLocalizedString("_login_", comment: ""), for: .normal)
-        loginButton.backgroundColor = textColor
-        loginButton.tintColor = textColorOpponent
-        loginButton.layer.cornerRadius = 20
-        loginButton.clipsToBounds = true
-        
-        // signup
-        signupButton.layer.cornerRadius = 20
-        signupButton.setTitleColor(.white, for: .normal)
-        signupButton.backgroundColor = UIColor(red: 25.0 / 255.0, green: 89.0 / 255.0, blue: 141.0 / 255.0, alpha: 1)
-        signupButton.setTitle(NSLocalizedString("_sign_up_", comment: ""), for: .normal)
+        // Login button
+        loginAddressDetail.textColor = textColor
+        loginAddressDetail.text = String.localizedStringWithFormat(NSLocalizedString("_login_address_detail_", comment: ""), NCBrandOptions.shared.brand)
+                
+        // Login Image
+        loginImage.image = UIImage(named: "arrow.right")?.image(color: textColor, size: 100)
         
-        // type of login
-        loginModeButton.setTitle(NSLocalizedString("_traditional_login_", comment: ""), for: .normal)
-        loginModeButton.setTitleColor(textColor.withAlphaComponent(0.5), for: .normal)
-     
         // brand
         if NCBrandOptions.shared.disable_request_login_url {
             baseUrl.text = NCBrandOptions.shared.loginBaseUrl
-            imageBaseUrl.isHidden = true
             baseUrl.isHidden = true
-            signupButton.isHidden = true
         }
         
         // qrcode
@@ -137,18 +97,8 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
         
         if NCManageDatabase.shared.getAccounts()?.count ?? 0 == 0 {
             
-            imageUser.isHidden = true
-            user.isHidden = true
-            imagePassword.isHidden = true
-            password.isHidden = true
-            
         } else {
             
-            imageUser.isHidden = true
-            user.isHidden = true
-            imagePassword.isHidden = true
-            password.isHidden = true
-            
             // Cancel Button
             let navigationItemCancel = UIBarButtonItem.init(barButtonSystemItem: .stop, target: self, action: #selector(self.actionCancel))
             navigationItemCancel.tintColor = textColor
@@ -158,6 +108,9 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
         }
         
         self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
     }
     
     override func viewDidAppear(_ animated: Bool) {
@@ -183,24 +136,28 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
     
     func textFieldShouldReturn(_ textField: UITextField) -> Bool {
         textField.resignFirstResponder()
+        actionButtonLogin(self)
         return false
     }
     
+    // MARK: - Keyboard notification
+    
+    @objc internal func keyboardWillShow(_ notification : Notification?) {
+                
+        imageBrandConstraintY.constant = -(self.view.frame.height / 4)
+    }
+    
+    @objc func keyboardWillHide(_ notification: Notification) {
+        
+        imageBrandConstraintY.constant = 0
+    }
+    
     // MARK: - Action
 
     @objc func actionCancel() {
         dismiss(animated: true) { }
     }
 
-    @IBAction func actionButtonSignup(_ sender: Any) {
-
-        if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb {
-            
-            loginWeb.urlBase = NCBrandOptions.shared.linkloginPreferredProviders
-            self.navigationController?.pushViewController(loginWeb, animated: true)
-        }
-    }
-    
     @IBAction func actionButtonLogin(_ sender: Any) {
         
         guard var url = baseUrl.text?.trimmingCharacters(in: .whitespacesAndNewlines) else { return }
@@ -212,64 +169,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
             url = "https://" + url
         }
         self.baseUrl.text = url
-
-        if  currentLoginMode == .webFlow {
-            
-            isUrlValid(url: url)
-            
-        } else  {
-            
-            guard let username = user.text else { return }
-            guard let password = password.text else { return }
-            
-            if username.count == 0 { return }
-            if password.count == 0 { return }
-
-            loginButton.isEnabled = false
-            activity.startAnimating()
-            
-            NCCommunication.shared.getAppPassword(serverUrl: url, username:  username, password: password) { (token, errorCode, errorDescription) in
-                
-                self.loginButton.isEnabled = true
-                self.activity.stopAnimating()
-                
-                self.standardLogin(url: url, user: username, password: token ?? "", errorCode: errorCode, errorDescription: errorDescription)
-            }
-        }
-    }
-    
-    @IBAction func actionToggleVisiblePassword(_ sender: Any) {
-        
-        let currentPassword = self.password.text
-        
-        password.isSecureTextEntry = !password.isSecureTextEntry
-        password.text = currentPassword
-    }
-    
-    @IBAction func actionLoginModeButton(_ sender: Any) {
-                
-        if currentLoginMode == .webFlow {
-            
-            currentLoginMode = .traditional
-            imageUser.isHidden = false
-            user.isHidden = false
-            imagePassword.isHidden = false
-            password.isHidden = false
-            toggleVisiblePasswordButton.isHidden = false
-            
-            loginModeButton.setTitle(NSLocalizedString("_web_login_", comment: ""), for: .normal)
-            
-        } else {
-            
-            currentLoginMode = .webFlow
-            imageUser.isHidden = true
-            user.isHidden = true
-            imagePassword.isHidden = true
-            password.isHidden = true
-            toggleVisiblePasswordButton.isHidden = true
-            
-            loginModeButton.setTitle(NSLocalizedString("_traditional_login_", comment: ""), for: .normal)
-        }
+        isUrlValid(url: url)
     }
     
     @IBAction func actionQRCode(_ sender: Any) {
@@ -325,7 +225,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
     func isUrlValid(url: String) {
             
         loginButton.isEnabled = false
-        activity.startAnimating()
+        //activity.startAnimating()
         
         NCCommunication.shared.getServerStatus(serverUrl: url) { (serverProductName, serverVersion, versionMajor, versionMinor, versionMicro, extendedSupport, errorCode ,errorDescription) in
             
@@ -336,7 +236,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                 NCCommunication.shared.getLoginFlowV2(serverUrl: url) { (token, endpoint, login, errorCode, errorDescription) in
                     
                     self.loginButton.isEnabled = true
-                    self.activity.stopAnimating()
+                    //self.activity.stopAnimating()
                                         
                     // Login Flow V2
                     if errorCode == 0 && NCBrandOptions.shared.use_loginflowv2 && token != nil && endpoint != nil && login != nil {
@@ -353,7 +253,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                         }
                         
                     // Login Flow
-                    } else if self.currentLoginMode == .webFlow && versionMajor >= NCGlobal.shared.nextcloudVersion12 {
+                    } else if versionMajor >= NCGlobal.shared.nextcloudVersion12 {
                         
                         if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb {
                             
@@ -376,7 +276,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
             } else {
                
                 self.loginButton.isEnabled = true
-                self.activity.stopAnimating()
+                //self.activity.stopAnimating()
                 
                 if errorCode == NSURLErrorServerCertificateUntrusted {
                     
@@ -513,11 +413,11 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                 let serverUrl = urlBase + "/" + webDAV
                 
                 loginButton.isEnabled = false
-                activity.startAnimating()
+                //activity.startAnimating()
                 
                 NCCommunication.shared.checkServer(serverUrl: serverUrl) { (errorCode, errorDescription) in
                 
-                    self.activity.stopAnimating()
+                    //self.activity.stopAnimating()
                     self.loginButton.isEnabled = true
                     
                     self.standardLogin(url: urlBase, user: user, password: password, errorCode: errorCode, errorDescription: errorDescription)

+ 3 - 1
iOSClient/Login/NCLoginWeb.swift

@@ -106,11 +106,13 @@ class NCLoginWeb: UIViewController {
         
         let language = NSLocale.preferredLanguages[0] as String
         var request = URLRequest(url: url)
+        let deviceName = UIDevice.current.name
+        let userAgent = deviceName + " " + "(iOS Files)"
         
         request.addValue("true", forHTTPHeaderField: "OCS-APIRequest")
         request.addValue(language, forHTTPHeaderField: "Accept-Language")
-        webView.customUserAgent = CCUtility.getUserAgent()
         
+        webView.customUserAgent = userAgent
         webView.load(request)
     }
     

+ 6 - 5
iOSClient/Main/Account Request/NCAccountRequest.swift

@@ -235,13 +235,14 @@ extension NCAccountRequest: UITableViewDataSource {
         } else {
         
             let account = accounts[indexPath.row]
-
-            avatarImage?.image = NCUtility.shared.loadImage(named: "person.crop.circle")
-        
-            let fileNamePath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(account.user, urlBase: account.urlBase)) + "-" + account.user + ".png"
+            
+            let fileName = String(CCUtility.getUserUrlBase(account.user, urlBase: account.urlBase)) + "-" + account.user + ".png"
+            let fileNamePath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
             
             if let image = UIImage(contentsOfFile: fileNamePath) {
-                avatarImage?.image = NCUtility.shared.createAvatar(image: image, size: 40)
+                avatarImage?.image = image
+            } else {
+                avatarImage?.image = NCUtility.shared.loadImage(named: "person.crop.circle")
             }
                     
             if account.alias != "" {

+ 164 - 177
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift

@@ -361,21 +361,19 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     
     @objc func deleteFile(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-            if let ocId = userInfo["ocId"] as? String, let fileNameView = userInfo["fileNameView"] as? String, let onlyLocal = userInfo["onlyLocal"] as? Bool {
-                if onlyLocal {
-                    reloadDataSource()
-                } else if fileNameView.lowercased() == NCGlobal.shared.fileNameRichWorkspace.lowercased() {
-                    reloadDataSourceNetwork(forced: true)
-                } else {
-                    if let row = dataSource.deleteMetadata(ocId: ocId) {
-                        let indexPath = IndexPath(row: row, section: 0)
-                        collectionView?.performBatchUpdates({
-                            collectionView?.deleteItems(at: [indexPath])
-                        }, completion: { (_) in
-                            self.collectionView?.reloadData()
-                        })
-                    }
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let fileNameView = userInfo["fileNameView"] as? String, let onlyLocalCache = userInfo["onlyLocalCache"] as? Bool {
+            if onlyLocalCache {
+                reloadDataSource()
+            } else if fileNameView.lowercased() == NCGlobal.shared.fileNameRichWorkspace.lowercased() {
+                reloadDataSourceNetwork(forced: true)
+            } else {
+                if let row = dataSource.deleteMetadata(ocId: ocId) {
+                    let indexPath = IndexPath(row: row, section: 0)
+                    collectionView?.performBatchUpdates({
+                        collectionView?.deleteItems(at: [indexPath])
+                    }, completion: { (_) in
+                        self.collectionView?.reloadData()
+                    })
                 }
             }
         }
@@ -383,29 +381,26 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
    
     @objc func moveFile(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-            if let ocId = userInfo["ocId"] as? String, let serverUrlFrom = userInfo["serverUrlFrom"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                
-                // DEL
-                if serverUrlFrom == serverUrl && metadata.account == appDelegate.account {
-                    if let row = dataSource.deleteMetadata(ocId: ocId) {
-                        let indexPath = IndexPath(row: row, section: 0)
-                        collectionView?.performBatchUpdates({
-                            collectionView?.deleteItems(at: [indexPath])
-                        }, completion: { (_) in
-                            self.collectionView?.reloadData()
-                        })
-                    }
-                    // ADD
-                } else if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account {
-                    if let row = dataSource.addMetadata(metadata) {
-                        let indexPath = IndexPath(row: row, section: 0)
-                        collectionView?.performBatchUpdates({
-                            collectionView?.insertItems(at: [indexPath])
-                        }, completion: { (_) in
-                            self.collectionView?.reloadData()
-                        })
-                    }
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let serverUrlFrom = userInfo["serverUrlFrom"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
+            // DEL
+            if serverUrlFrom == serverUrl && metadata.account == appDelegate.account {
+                if let row = dataSource.deleteMetadata(ocId: ocId) {
+                    let indexPath = IndexPath(row: row, section: 0)
+                    collectionView?.performBatchUpdates({
+                        collectionView?.deleteItems(at: [indexPath])
+                    }, completion: { (_) in
+                        self.collectionView?.reloadData()
+                    })
+                }
+                // ADD
+            } else if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account {
+                if let row = dataSource.addMetadata(metadata) {
+                    let indexPath = IndexPath(row: row, section: 0)
+                    collectionView?.performBatchUpdates({
+                        collectionView?.insertItems(at: [indexPath])
+                    }, completion: { (_) in
+                        self.collectionView?.reloadData()
+                    })
                 }
             }
         }
@@ -413,12 +408,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     
     @objc func copyFile(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-            if let serverUrlTo = userInfo["serverUrlTo"] as? String {
-                
-                if serverUrlTo == self.serverUrl {
-                    reloadDataSource()
-                }
+        if let userInfo = notification.userInfo as NSDictionary?, let serverUrlTo = userInfo["serverUrlTo"] as? String {
+            if serverUrlTo == self.serverUrl {
+                reloadDataSource()
             }
         }
     }
@@ -430,22 +422,19 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     
     @objc func createFolder(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-            if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                
-                if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account {
-                    pushMetadata(metadata)
-                    /*
-                    if let row = dataSource.addMetadata(metadata) {
-                        let indexPath = IndexPath(row: row, section: 0)
-                        collectionView?.performBatchUpdates({
-                            collectionView?.insertItems(at: [indexPath])
-                        }, completion: { (_) in
-                            self.collectionView?.reloadData()
-                        })
-                    }
-                    */
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
+            if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account {
+                pushMetadata(metadata)
+                /*
+                if let row = dataSource.addMetadata(metadata) {
+                    let indexPath = IndexPath(row: row, section: 0)
+                    collectionView?.performBatchUpdates({
+                        collectionView?.insertItems(at: [indexPath])
+                    }, completion: { (_) in
+                        self.collectionView?.reloadData()
+                    })
                 }
+                */
             }
         } else {
             reloadDataSourceNetwork()
@@ -454,25 +443,20 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     
     @objc func favoriteFile(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-            if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                
-                if dataSource.getIndexMetadata(ocId: metadata.ocId) != nil {
-                    reloadDataSource()
-                }
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
+            if dataSource.getIndexMetadata(ocId: metadata.ocId) != nil {
+                reloadDataSource()
             }
         }
     }
     
     @objc func downloadStartFile(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-            if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                if let row = dataSource.reloadMetadata(ocId: metadata.ocId) {
-                    let indexPath = IndexPath(row: row, section: 0)
-                    if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) {
-                        collectionView?.reloadItems(at: [indexPath])
-                    }
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
+            if let row = dataSource.reloadMetadata(ocId: metadata.ocId) {
+                let indexPath = IndexPath(row: row, section: 0)
+                if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) {
+                    collectionView?.reloadItems(at: [indexPath])
                 }
             }
         }
@@ -480,13 +464,11 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     
     @objc func downloadedFile(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-            if let ocId = userInfo["ocId"] as? String, let _ = userInfo["errorCode"] as? Int, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                if let row = dataSource.reloadMetadata(ocId: metadata.ocId) {
-                    let indexPath = IndexPath(row: row, section: 0)
-                    if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) {
-                        collectionView?.reloadItems(at: [indexPath])
-                    }
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let _ = userInfo["errorCode"] as? Int, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
+            if let row = dataSource.reloadMetadata(ocId: metadata.ocId) {
+                let indexPath = IndexPath(row: row, section: 0)
+                if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) {
+                    collectionView?.reloadItems(at: [indexPath])
                 }
             }
         }
@@ -494,13 +476,11 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         
     @objc func downloadCancelFile(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-            if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                if let row = dataSource.reloadMetadata(ocId: metadata.ocId) {
-                    let indexPath = IndexPath(row: row, section: 0)
-                    if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) {
-                        collectionView?.reloadItems(at: [indexPath])
-                    }
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
+            if let row = dataSource.reloadMetadata(ocId: metadata.ocId) {
+                let indexPath = IndexPath(row: row, section: 0)
+                if indexPath.section < collectionView.numberOfSections && indexPath.row < collectionView.numberOfItems(inSection: indexPath.section) {
+                    collectionView?.reloadItems(at: [indexPath])
                 }
             }
         }
@@ -508,46 +488,40 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     
     @objc func uploadStartFile(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-            if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account {
-                    dataSource.addMetadata(metadata)
-                    self.collectionView?.reloadData()
-                }
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
+            if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account {
+                dataSource.addMetadata(metadata)
+                self.collectionView?.reloadData()
             }
         }
     }
         
     @objc func uploadedFile(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-        if let ocId = userInfo["ocId"] as? String, let ocIdTemp = userInfo["ocIdTemp"] as? String, let _ = userInfo["errorCode"] as? Int, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account {
-                    dataSource.reloadMetadata(ocId: metadata.ocId, ocIdTemp: ocIdTemp)
-                    collectionView?.reloadData()
-                }
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let ocIdTemp = userInfo["ocIdTemp"] as? String, let _ = userInfo["errorCode"] as? Int, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
+            if metadata.serverUrl == serverUrl && metadata.account == appDelegate.account {
+                dataSource.reloadMetadata(ocId: metadata.ocId, ocIdTemp: ocIdTemp)
+                collectionView?.reloadData()
             }
         }
     }
     
     @objc func uploadCancelFile(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary? {
-            if let ocId = userInfo["ocId"] as? String, let serverUrl = userInfo["serverUrl"] as? String, let account = userInfo["account"] as? String {
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String, let serverUrl = userInfo["serverUrl"] as? String, let account = userInfo["account"] as? String {
                 
-                if serverUrl == self.serverUrl && account == appDelegate.account {
-                    if let row = dataSource.deleteMetadata(ocId: ocId) {
-                        let indexPath = IndexPath(row: row, section: 0)
-                        collectionView?.performBatchUpdates({
-                            if indexPath.section < (collectionView?.numberOfSections ?? 0) && indexPath.row < (collectionView?.numberOfItems(inSection: indexPath.section) ?? 0) {
-                                collectionView?.deleteItems(at: [indexPath])
-                            }
-                        }, completion: { (_) in
-                            self.collectionView?.reloadData()
-                        })
-                    } else {
-                        self.reloadDataSource()
-                    }
+            if serverUrl == self.serverUrl && account == appDelegate.account {
+                if let row = dataSource.deleteMetadata(ocId: ocId) {
+                    let indexPath = IndexPath(row: row, section: 0)
+                    collectionView?.performBatchUpdates({
+                        if indexPath.section < (collectionView?.numberOfSections ?? 0) && indexPath.row < (collectionView?.numberOfItems(inSection: indexPath.section) ?? 0) {
+                            collectionView?.deleteItems(at: [indexPath])
+                        }
+                    }, completion: { (_) in
+                        self.collectionView?.reloadData()
+                    })
+                } else {
+                    self.reloadDataSource()
                 }
             }
         }
@@ -555,49 +529,43 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         
     @objc func triggerProgressTask(_ notification: NSNotification) {
         
-        if let userInfo = notification.userInfo as NSDictionary?, let progressNumber = userInfo["progress"] as? NSNumber, let totalBytes = userInfo["totalBytes"] as? Int64, let totalBytesExpected = userInfo["totalBytesExpected"] as? Int64 {
-            if let ocId = userInfo["ocId"] as? String {
+        if let userInfo = notification.userInfo as NSDictionary?, let progressNumber = userInfo["progress"] as? NSNumber, let totalBytes = userInfo["totalBytes"] as? Int64, let totalBytesExpected = userInfo["totalBytesExpected"] as? Int64, let ocId = userInfo["ocId"] as? String {
                 
-                let progress = progressNumber.floatValue
-                let status = userInfo["status"] as? Int ?? NCGlobal.shared.metadataStatusNormal
-                        
-                let progressType = NCGlobal.progressType(progress: progress, totalBytes: totalBytes, totalBytesExpected: totalBytesExpected)
-                appDelegate.listProgress[ocId] = progressType
-                                
-                if let index = dataSource.getIndexMetadata(ocId: ocId) {
-                    if let cell = collectionView?.cellForItem(at: IndexPath(row: index, section: 0)) {
-                        if cell is NCListCell {
-                            let cell = cell as! NCListCell
-                            if progress > 0 {
-                                cell.progressView?.isHidden = false
-                                cell.progressView?.progress = progress
-                                cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop)
-                                if status == NCGlobal.shared.metadataStatusInDownload {
-                                    cell.labelInfo.text = CCUtility.transformedSize(totalBytesExpected) + " - ↓ " + CCUtility.transformedSize(totalBytes)
-                                } else if status == NCGlobal.shared.metadataStatusInUpload {
-                                    cell.labelInfo.text = CCUtility.transformedSize(totalBytesExpected) + " - ↑ " + CCUtility.transformedSize(totalBytes)
-                                }
-                            }
-                        } else if cell is NCTransferCell {
-                            let cell = cell as! NCTransferCell
-                            if progress > 0 {
-                                cell.progressView?.isHidden = false
-                                cell.progressView?.progress = progress
-                                cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop)
-                                if status == NCGlobal.shared.metadataStatusInDownload {
-                                    cell.labelInfo.text = CCUtility.transformedSize(totalBytesExpected) + " - ↓ " + CCUtility.transformedSize(totalBytes)
-                                } else if status == NCGlobal.shared.metadataStatusInUpload {
-                                    cell.labelInfo.text = CCUtility.transformedSize(totalBytesExpected) + " - ↑ " + CCUtility.transformedSize(totalBytes)
-                                }
+            let status = userInfo["status"] as? Int ?? NCGlobal.shared.metadataStatusNormal
+    
+            if let index = dataSource.getIndexMetadata(ocId: ocId) {
+                if let cell = collectionView?.cellForItem(at: IndexPath(row: index, section: 0)) {
+                    if cell is NCListCell {
+                        let cell = cell as! NCListCell
+                        if progressNumber.floatValue > 0 {
+                            cell.progressView?.isHidden = false
+                            cell.progressView?.progress = progressNumber.floatValue
+                            cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop)
+                            if status == NCGlobal.shared.metadataStatusInDownload {
+                                cell.labelInfo.text = CCUtility.transformedSize(totalBytesExpected) + " - ↓ " + CCUtility.transformedSize(totalBytes)
+                            } else if status == NCGlobal.shared.metadataStatusInUpload {
+                                cell.labelInfo.text = CCUtility.transformedSize(totalBytesExpected) + " - ↑ " + CCUtility.transformedSize(totalBytes)
                             }
-                        } else if cell is NCGridCell {
-                            let cell = cell as! NCGridCell
-                            if progress > 0 {
-                                cell.progressView.isHidden = false
-                                cell.progressView.progress = progress
-                                cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop)
+                        }
+                    } else if cell is NCTransferCell {
+                        let cell = cell as! NCTransferCell
+                        if progressNumber.floatValue > 0 {
+                            cell.progressView?.isHidden = false
+                            cell.progressView?.progress = progressNumber.floatValue
+                            cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop)
+                            if status == NCGlobal.shared.metadataStatusInDownload {
+                                cell.labelInfo.text = CCUtility.transformedSize(totalBytesExpected) + " - ↓ " + CCUtility.transformedSize(totalBytes)
+                            } else if status == NCGlobal.shared.metadataStatusInUpload {
+                                cell.labelInfo.text = CCUtility.transformedSize(totalBytesExpected) + " - ↑ " + CCUtility.transformedSize(totalBytes)
                             }
                         }
+                    } else if cell is NCGridCell {
+                        let cell = cell as! NCGridCell
+                        if progressNumber.floatValue > 0 {
+                            cell.progressView.isHidden = false
+                            cell.progressView.progress = progressNumber.floatValue
+                            cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop)
+                        }
                     }
                 }
             }
@@ -624,13 +592,20 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
             
             if layoutKey == NCGlobal.shared.layoutViewFiles {
             
-                var image = NCUtility.shared.loadImage(named: "person.crop.circle")
-                let fileNamePath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + appDelegate.user + ".png"
-                if let userImage = UIImage(contentsOfFile: fileNamePath) {
-                    image = userImage
+                var image: UIImage?
+                
+                if #available(iOS 13.0, *) {
+                    let config = UIImage.SymbolConfiguration(pointSize: 30)
+                    image = NCUtility.shared.loadImage(named: "person.crop.circle", symbolConfiguration: config)
+                } else {
+                    image = NCUtility.shared.loadImage(named: "person.crop.circle", size: 30)
                 }
                 
-                image = NCUtility.shared.createAvatar(image: image, size: 30)
+                let fileName = String(CCUtility.getUserUrlBase(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + self.appDelegate.user + "-original.png"
+                let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+                if let imageUser = UIImage(contentsOfFile: fileNameLocalPath) {
+                    image = NCUtility.shared.createAvatar(image: imageUser, size: 30)
+                }
                 
                 let button = UIButton(type: .custom)
                 button.setImage(image, for: .normal)
@@ -1372,8 +1347,8 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
         
         // Avatar
         if metadata.ownerId.count > 0 && metadata.ownerId != appDelegate.userId && appDelegate.account == metadata.account {
-            let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(metadata.user, urlBase: metadata.urlBase)) + "-" + metadata.ownerId + ".png"
-            NCOperationQueue.shared.downloadAvatar(user: metadata.ownerId, fileNameLocalPath: fileNameLocalPath, placeholder: NCBrandColor.cacheImages.shared, cell: cell, view: collectionView)
+            let fileName = String(CCUtility.getUserUrlBase(metadata.user, urlBase: metadata.urlBase)) + "-" + metadata.ownerId + ".png"
+            NCOperationQueue.shared.downloadAvatar(user: metadata.ownerId, fileName: fileName, placeholder: NCBrandColor.cacheImages.shared, cell: cell, view: collectionView)
         }
     }
     
@@ -1446,7 +1421,20 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             cell.imageItem.image = nil
             cell.imageItem.backgroundColor = nil
             
-            cell.progressView.progress = 0.0
+            // Progress
+            var progress: Float = 0.0
+            var totalBytes: Int64 = 0
+            if let progressType = appDelegate.listProgress[metadata.ocId] {
+                progress = progressType.progress
+                totalBytes = progressType.totalBytes
+            }
+            if metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusUploading {
+                cell.progressView.isHidden = false
+                cell.progressView.progress = progress
+            } else {
+                cell.progressView.isHidden = true
+                cell.progressView.progress = 0.0
+            }
             
             if metadata.directory {
                 
@@ -1504,20 +1492,10 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             if appDelegate.account != metadata.account {
                 cell.imageShared.image = NCBrandColor.cacheImages.shared
             }
-                        
-            // Transfer
-            var progress: Float = 0.0
-            var totalBytes: Int64 = 0
-            if let progressType = appDelegate.listProgress[metadata.ocId] {
-                progress = progressType.progress
-                totalBytes = progressType.totalBytes
-            }
-            if metadata.status == NCGlobal.shared.metadataStatusInDownload || metadata.status == NCGlobal.shared.metadataStatusDownloading ||  metadata.status >= NCGlobal.shared.metadataStatusTypeUpload {
-                cell.progressView.isHidden = false
+            
+            if metadata.status == NCGlobal.shared.metadataStatusInDownload || metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusInUpload || metadata.status == NCGlobal.shared.metadataStatusUploading {
                 cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop)
             } else {
-                cell.progressView.isHidden = true
-                cell.progressView.progress = progress
                 cell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCBrandColor.cacheImages.buttonMore)
             }
             
@@ -1612,7 +1590,19 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             cell.imageItem.image = nil
             cell.imageItem.backgroundColor = nil
             
-            cell.progressView.progress = 0.0
+            // Progress
+            var progress: Float = 0.0
+            if let progressType = appDelegate.listProgress[metadata.ocId] {
+                progress = progressType.progress
+            }
+            
+            if metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusUploading {
+                cell.progressView.isHidden = false
+                cell.progressView.progress = progress
+            } else {
+                cell.progressView.isHidden = true
+                cell.progressView.progress = 0.0
+            }
 
             if metadata.directory {
                 
@@ -1658,12 +1648,9 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             }
             
             // Transfer
-            if metadata.status == NCGlobal.shared.metadataStatusInDownload || metadata.status == NCGlobal.shared.metadataStatusDownloading ||  metadata.status >= NCGlobal.shared.metadataStatusTypeUpload {
-                cell.progressView.isHidden = false
+            if metadata.status == NCGlobal.shared.metadataStatusInDownload || metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusInUpload || metadata.status == NCGlobal.shared.metadataStatusUploading {
                 cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop)
             } else {
-                cell.progressView.isHidden = true
-                cell.progressView.progress = 0.0
                 cell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCBrandColor.cacheImages.buttonMore)
             }
             

+ 2 - 2
iOSClient/Main/NCFunctionCenter.swift

@@ -733,7 +733,7 @@ import Queuer
         }
         
         let deleteConfirmFile = UIAction(title: titleDeleteConfirmFile, image: UIImage(systemName: "trash"), attributes: .destructive) { action in
-            NCNetworking.shared.deleteMetadata(metadata, onlyLocal: false) { (errorCode, errorDescription) in
+            NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false) { (errorCode, errorDescription) in
                 if errorCode != 0 {
                     NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode)
                 }
@@ -741,7 +741,7 @@ import Queuer
         }
         
         let deleteConfirmLocal = UIAction(title: NSLocalizedString("_remove_local_file_", comment: ""), image: UIImage(systemName: "trash"), attributes: .destructive) { action in
-            NCNetworking.shared.deleteMetadata(metadata, onlyLocal: true) { (errorCode, errorDescription) in
+            NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: true) { (errorCode, errorDescription) in
             }
         }
         

+ 5 - 9
iOSClient/Media/NCMedia.swift

@@ -216,7 +216,7 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
             if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
                 
                 if metadata.account == appDelegate.account {
-                    self.reloadDataSource()
+                    self.reloadDataSourceWithCompletion { (_) in }
                 }
             }
         }
@@ -227,7 +227,7 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
         if let userInfo = notification.userInfo as NSDictionary? {
             if let ocId = userInfo["ocId"] as? String, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId), let errorCode = userInfo["errorCode"] as? Int {
                 if errorCode == 0 && metadata.account == appDelegate.account {
-                    self.reloadDataSource()
+                    self.reloadDataSourceWithCompletion { (_) in }
                 }
             }
         }
@@ -458,10 +458,6 @@ extension NCMedia {
 
     // MARK: - Datasource
 
-    @objc func reloadDataSource() {
-        self.reloadDataSourceWithCompletion { (_) in }
-    }
-    
     @objc func reloadDataSourceWithCompletion(_ completion: @escaping (_ metadatas: [tableMetadata]) -> Void) {
         
         if appDelegate.account == "" { return }
@@ -564,7 +560,7 @@ extension NCMedia {
                         if metadatasChanged.metadatasUpdate.count == 0 {
                             self.researchOldMedia(value: value, limit: limit, withElseReloadDataSource: true)
                         } else {
-                            self.reloadDataSource()
+                            self.reloadDataSourceWithCompletion { (_) in }
                         }
                     }
                 } else {
@@ -588,7 +584,7 @@ extension NCMedia {
             searchOldMedia(value: -999, limit: 0)
         } else {
             if withElseReloadDataSource {
-                reloadDataSource()
+                self.reloadDataSourceWithCompletion { (_) in }
             }
         }
     }
@@ -639,7 +635,7 @@ extension NCMedia {
                         let metadatasResult = NCManageDatabase.shared.getMetadatas(predicate: predicateResult)
                         let updateMetadatas = NCManageDatabase.shared.updateMetadatas(metadatas, metadatasResult: metadatasResult, addCompareLivePhoto: false)
                         if updateMetadatas.metadatasUpdate.count > 0 || updateMetadatas.metadatasDelete.count > 0 {
-                            self.reloadDataSource()
+                            self.reloadDataSourceWithCompletion { (_) in }
                         }
                     }
                 } else if errorCode == 0 && files.count == 0 && self.metadatas.count == 0 {

+ 4 - 4
iOSClient/Menu/NCCollectionViewCommon+Menu.swift

@@ -385,10 +385,10 @@ extension NCCollectionViewCommon {
                 action: { menuAction in
                     let alertController = UIAlertController(title: "", message: metadata.fileNameView + "\n\n" + NSLocalizedString("_want_delete_", comment: ""), preferredStyle: .alert)
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (action:UIAlertAction) in
-                        NCOperationQueue.shared.delete(metadata: metadata, onlyLocal: false)
+                        NCOperationQueue.shared.delete(metadata: metadata, onlyLocalCache: false)
                     })
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_remove_local_file_", comment: ""), style: .default) { (action:UIAlertAction) in
-                        NCOperationQueue.shared.delete(metadata: metadata, onlyLocal: true)
+                        NCOperationQueue.shared.delete(metadata: metadata, onlyLocalCache: true)
                     })
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (action:UIAlertAction) in })
                     self.present(alertController, animated: true, completion:nil)
@@ -571,7 +571,7 @@ extension NCCollectionViewCommon {
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (action:UIAlertAction) in
                         for ocId in self.selectOcId {
                             if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                                NCOperationQueue.shared.delete(metadata: metadata, onlyLocal: false)
+                                NCOperationQueue.shared.delete(metadata: metadata, onlyLocalCache: false)
                             }
                         }
                         self.tapSelect(sender: self)
@@ -579,7 +579,7 @@ extension NCCollectionViewCommon {
                     alertController.addAction(UIAlertAction(title: NSLocalizedString("_remove_local_file_", comment: ""), style: .default) { (action:UIAlertAction) in
                         for ocId in self.selectOcId {
                             if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                                NCOperationQueue.shared.delete(metadata: metadata, onlyLocal: true)
+                                NCOperationQueue.shared.delete(metadata: metadata, onlyLocalCache: true)
                             }
                         }
                         self.tapSelect(sender: self)

+ 3 - 2
iOSClient/Menu/NCLoginWeb+Menu.swift

@@ -37,10 +37,11 @@ extension NCLoginWeb {
         for account in accounts {
             
             let title = account.user + " " + (URL(string: account.urlBase)?.host ?? "")
-            let fileNamePath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(account.user, urlBase: account.urlBase)) + "-" + account.user + ".png"
+            let fileName = String(CCUtility.getUserUrlBase(account.user, urlBase: account.urlBase)) + "-" + account.user + ".png"
+            let fileNamePath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
 
             if let image = UIImage(contentsOfFile: fileNamePath) {
-                avatar = NCUtility.shared.createAvatar(image: image, size: 50)
+                avatar = image
             }
             
             actions.append(

+ 6 - 6
iOSClient/Menu/NCMedia+Menu.swift

@@ -54,7 +54,7 @@ extension NCMedia {
                     action: { menuAction in
                         self.filterClassTypeImage = !self.filterClassTypeImage
                         self.filterClassTypeVideo = false
-                        self.reloadDataSource()
+                        self.reloadDataSourceWithCompletion { (_) in }
                     }
                 )
             )
@@ -68,7 +68,7 @@ extension NCMedia {
                     action: { menuAction in
                         self.filterClassTypeVideo = !self.filterClassTypeVideo
                         self.filterClassTypeImage = false
-                        self.reloadDataSource()
+                        self.reloadDataSourceWithCompletion { (_) in }
                     }
                 )
             )
@@ -98,7 +98,7 @@ extension NCMedia {
                     on: true,
                     action: { menuAction in
                         CCUtility.setMediaSortDate("date")
-                        self.reloadDataSource()
+                        self.reloadDataSourceWithCompletion { (_) in }
                     }
                 )
             )
@@ -111,7 +111,7 @@ extension NCMedia {
                     on: true,
                     action: { menuAction in
                         CCUtility.setMediaSortDate("creationDate")
-                        self.reloadDataSource()
+                        self.reloadDataSourceWithCompletion { (_) in }
                     }
                 )
             )
@@ -124,7 +124,7 @@ extension NCMedia {
                     on: true,
                     action: { menuAction in
                         CCUtility.setMediaSortDate("uploadDate")
-                        self.reloadDataSource()
+                        self.reloadDataSourceWithCompletion { (_) in }
                     }
                 )
             )
@@ -247,7 +247,7 @@ extension NCMedia {
                         self.isEditMode = false
                         for ocId in self.selectOcId {
                             if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
-                                NCNetworking.shared.deleteMetadata(metadata, onlyLocal: false) { (errorCode, errorDescription) in
+                                NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false) { (errorCode, errorDescription) in
                                     if errorCode != 0 {
                                         NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode)
                                     }

+ 1 - 1
iOSClient/Menu/NCViewer+Menu.swift

@@ -332,7 +332,7 @@ extension NCViewer {
                         
                         alertController.addAction(UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (action:UIAlertAction) in
                             
-                            NCNetworking.shared.deleteMetadata(metadata, onlyLocal: false) { (errorCode, errorDescription) in
+                            NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false) { (errorCode, errorDescription) in
                                 if errorCode != 0 {
                                     NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode)
                                 }

+ 6 - 6
iOSClient/More/NCMore.swift

@@ -21,9 +21,9 @@
 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 //
 
-
 import UIKit
 import NCCommunication
+import MarqueeLabel
 
 class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
 
@@ -323,9 +323,9 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
             cell.status.text = ""
             cell.displayName.text = ""
             
-            let fileNamePath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + appDelegate.user + ".png"
-            
-            if let image = UIImage.init(contentsOfFile: fileNamePath) {
+            let fileName = String(CCUtility.getUserUrlBase(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + self.appDelegate.user + "-original.png"
+            let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+            if let image = UIImage.init(contentsOfFile: fileNameLocalPath) {
                 cell.avatar?.image = NCUtility.shared.createAvatar(image: image, size: 50)
             } else {
                 cell.avatar?.image = UIImage.init(named: "avatar")?.imageColor(NCBrandColor.shared.gray)
@@ -349,6 +349,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
                     cell.icon.image = status.onlineStatus
                     cell.status.text = status.statusMessage
                     cell.status.textColor = NCBrandColor.shared.label
+                    cell.status.trailingBuffer = cell.status.frame.width
                 }
             }
             
@@ -470,6 +471,5 @@ class NCMoreUserCell: UITableViewCell {
     @IBOutlet weak var displayName: UILabel!
     @IBOutlet weak var avatar: UIImageView!
     @IBOutlet weak var icon: UIImageView!
-    @IBOutlet weak var status: UILabel!
-
+    @IBOutlet weak var status: MarqueeLabel!
 }

+ 6 - 3
iOSClient/More/NCMoreUserCell.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
@@ -21,10 +21,13 @@
                         <fontDescription key="fontDescription" type="system" pointSize="15"/>
                         <nil key="highlightedColor"/>
                     </label>
-                    <label opaque="NO" userInteractionEnabled="NO" tag="102" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="status" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p7I-KN-FVZ">
+                    <label opaque="NO" userInteractionEnabled="NO" tag="102" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="status" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p7I-KN-FVZ" customClass="MarqueeLabel" customModule="MarqueeLabel">
                         <rect key="frame" x="335" y="48" width="245" height="14.5"/>
                         <fontDescription key="fontDescription" type="system" pointSize="12"/>
                         <nil key="highlightedColor"/>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="boolean" keyPath="tapToScroll" value="YES"/>
+                        </userDefinedRuntimeAttributes>
                     </label>
                     <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="5">
                         <rect key="frame" x="275" y="10" width="50" height="50"/>

+ 16 - 16
iOSClient/NCGlobal.swift

@@ -79,7 +79,7 @@ class NCGlobal: NSObject {
     // Database Realm
     //
     let databaseDefault                             = "nextcloud.realm"
-    let databaseSchemaVersion: UInt64               = 196
+    let databaseSchemaVersion: UInt64               = 207
     
     // Intro selector
     //
@@ -92,7 +92,8 @@ class NCGlobal: NSObject {
     
     // Avatar & Preview size
     //
-    let avatarSize: Int                             = 512
+    let avatarSize: Int                             = 128 * Int(UIScreen.main.scale)
+    let avatarSizeRounded: Int                      = 128
     let sizePreview: Int                            = 1024
     let sizeIcon: Int                               = 512
     
@@ -180,6 +181,7 @@ class NCGlobal: NSObject {
     // Error
     //
     @objc let errorRequestExplicityCancelled: Int   = 15
+    @objc let errorNotModified: Int                 = 304
     @objc let errorBadRequest: Int                  = 400
     @objc let errorResourceNotFound: Int            = 404
     @objc let errordMethodNotSupported: Int         = 405
@@ -262,20 +264,15 @@ class NCGlobal: NSObject {
     //
     let metadataStatusNormal: Int                   = 0
 
-    let metadataStatustypeDownload: Int             = 1
+    let metadataStatusWaitDownload: Int             = -1
+    let metadataStatusInDownload: Int               = -2
+    let metadataStatusDownloading: Int              = -3
+    let metadataStatusDownloadError: Int            = -4
 
-    let metadataStatusWaitDownload: Int             = 2
-    let metadataStatusInDownload: Int               = 3
-    let metadataStatusDownloading: Int              = 4
-    let metadataStatusDownloadError: Int            = 5
-
-    let metadataStatusTypeUpload: Int               = 6
-
-    let metadataStatusWaitUpload: Int               = 7
-    let metadataStatusInUpload: Int                 = 8
-    let metadataStatusUploading: Int                = 9
-    let metadataStatusUploadError: Int              = 10
-    let metadataStatusUploadForcedStart: Int        = 11
+    let metadataStatusWaitUpload: Int               = 1
+    let metadataStatusInUpload: Int                 = 2
+    let metadataStatusUploading: Int                = 3
+    let metadataStatusUploadError: Int              = 4
     
     // Notification Center
     //
@@ -308,7 +305,7 @@ class NCGlobal: NSObject {
     let notificationCenterProgressTask                          = "progressTask"                    // userInfo: account, ocId, serverUrl, status, progress, totalBytes, totalBytesExpected
     
     let notificationCenterCreateFolder                          = "createFolder"                    // userInfo: ocId
-    let notificationCenterDeleteFile                            = "deleteFile"                      // userInfo: ocId, fileNameView, classFile, onlyLocal
+    let notificationCenterDeleteFile                            = "deleteFile"                      // userInfo: ocId, fileNameView, classFile, onlyLocalCache
     let notificationCenterRenameFile                            = "renameFile"                      // userInfo: ocId, errorCode, errorDescription
     let notificationCenterMoveFile                              = "moveFile"                        // userInfo: ocId, serverUrlTo
     let notificationCenterCopyFile                              = "copyFile"                        // userInfo: ocId, serverUrlFrom
@@ -346,3 +343,6 @@ class NCGlobal: NSObject {
 //    popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
 //    popoverController.permittedArrowDirections = []
 //}
+
+// @discardableResult
+

+ 72 - 14
iOSClient/Networking/NCNetworking.swift

@@ -100,6 +100,17 @@ import Queuer
         _ = sessionManagerBackground
         _ = sessionManagerBackgroundWWan
         #endif
+        
+        // Notification
+        NotificationCenter.default.addObserver(self, selector: #selector(downloadStartFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadStartFile), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(downloadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadedFile), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(downloadCancelFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDownloadCancelFile), object: nil)
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(uploadStartFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadStartFile), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(uploadedFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadedFile), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(uploadCancelFile(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUploadCancelFile), object: nil)
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object:nil)
     }
     
     //MARK: - Communication Delegate
@@ -154,6 +165,61 @@ import Queuer
         #endif
     }
     
+    // MARK: - NotificationCenter
+    
+    @objc func downloadStartFile(_ notification: NSNotification) {
+    }
+    
+    @objc func downloadedFile(_ notification: NSNotification) {
+        
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String {
+            #if !EXTENSION
+            (UIApplication.shared.delegate as! AppDelegate).listProgress[ocId] = nil
+            #endif
+        }
+    }
+    
+    @objc func downloadCancelFile(_ notification: NSNotification) {
+        
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String {
+            #if !EXTENSION
+            (UIApplication.shared.delegate as! AppDelegate).listProgress[ocId] = nil
+            #endif
+        }
+    }
+    
+    @objc func uploadStartFile(_ notification: NSNotification) {
+    }
+    
+    @objc func uploadedFile(_ notification: NSNotification) {
+        
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String {
+            #if !EXTENSION
+            (UIApplication.shared.delegate as! AppDelegate).listProgress[ocId] = nil
+            #endif
+        }
+    }
+    
+    @objc func uploadCancelFile(_ notification: NSNotification) {
+        
+        if let userInfo = notification.userInfo as NSDictionary?, let ocId = userInfo["ocId"] as? String {
+            #if !EXTENSION
+            (UIApplication.shared.delegate as! AppDelegate).listProgress[ocId] = nil
+            #endif
+        }
+    }
+    
+    @objc func triggerProgressTask(_ notification: NSNotification) {
+
+        if let userInfo = notification.userInfo as NSDictionary?, let progressNumber = userInfo["progress"] as? NSNumber, let totalBytes = userInfo["totalBytes"] as? Int64, let totalBytesExpected = userInfo["totalBytesExpected"] as? Int64, let ocId = userInfo["ocId"] as? String {
+             
+            #if !EXTENSION
+            let progressType = NCGlobal.progressType(progress: progressNumber.floatValue, totalBytes: totalBytes, totalBytesExpected: totalBytesExpected)
+            (UIApplication.shared.delegate as! AppDelegate).listProgress[ocId] = progressType
+            #endif
+        }
+    }
+    
     //MARK: - Pinning check
     
     func checkTrustedChallenge(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge) -> Bool {
@@ -585,16 +651,8 @@ import Queuer
                 
                 if errorCode == NSURLErrorCancelled || errorCode == NCGlobal.shared.errorRequestExplicityCancelled {
                 
-                    if metadata.status == NCGlobal.shared.metadataStatusUploadForcedStart {
-                        
-                        NCManageDatabase.shared.setMetadataSession(ocId: ocId!, session: sessionIdentifierBackground, sessionError: "", sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusInUpload)
-                        NCNetworking.shared.upload(metadata: metadata) { } completion: { (_, _) in }
-                                                
-                    } else {
-                        
-                        CCUtility.removeFile(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId))
-                        NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
-                    }
+                    CCUtility.removeFile(atPath: CCUtility.getDirectoryProviderStorageOcId(metadata.ocId))
+                    NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
                     
                     NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUploadCancelFile, userInfo: ["ocId":metadata.ocId, "serverUrl":metadata.serverUrl, "account":metadata.account])
                 
@@ -938,9 +996,9 @@ import Queuer
     
     //MARK: - WebDav Delete
 
-    @objc func deleteMetadata(_ metadata: tableMetadata, onlyLocal: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) {
+    @objc func deleteMetadata(_ metadata: tableMetadata, onlyLocalCache: Bool, completion: @escaping (_ errorCode: Int, _ errorDescription: String)->()) {
                 
-        if (onlyLocal) {
+        if (onlyLocalCache) {
             
             var metadatas = [metadata]
             
@@ -959,7 +1017,7 @@ import Queuer
                     NCUtilityFileSystem.shared.deleteFile(filePath: CCUtility.getDirectoryProviderStorageOcId(metadataLivePhoto.ocId))
                 }
             
-                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": metadata.ocId, "fileNameView": metadata.fileNameView, "classFile": metadata.classFile, "onlyLocal": true])
+                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": metadata.ocId, "fileNameView": metadata.fileNameView, "classFile": metadata.classFile, "onlyLocalCache": true])
             }
             return completion(0, "")
         }
@@ -1020,7 +1078,7 @@ import Queuer
                     NCManageDatabase.shared.deleteDirectoryAndSubDirectory(serverUrl: CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName), account: metadata.account)
                 }
                 
-                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": metadata.ocId, "fileNameView": metadata.fileNameView, "classFile": metadata.classFile, "onlyLocal": true])
+                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": metadata.ocId, "fileNameView": metadata.fileNameView, "classFile": metadata.classFile, "onlyLocalCache": true])
             }
             
             completion(errorCode, errorDescription)

+ 8 - 2
iOSClient/Networking/NCNetworkingCheckRemoteUser.swift

@@ -41,14 +41,20 @@ import NCCommunication
         }
         
         let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
-        guard let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) else { return }
+        guard let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) else {
+            self.checkRemoteUserInProgress = false
+            return
+        }
         
         if serverVersionMajor >= NCGlobal.shared.nextcloudVersion17 {
             
             if errorCode == 401 {
                 
                 let token = CCUtility.getPassword(account)!
-                if token == "" { return }
+                if token == "" {
+                    self.checkRemoteUserInProgress = false
+                    return
+                }
                 
                 NCCommunication.shared.getRemoteWipeStatus(serverUrl: tableAccount.urlBase, token: token) { (account, wipe, errorCode, errorDescriptiuon) in
                     

+ 58 - 38
iOSClient/Networking/NCOperationQueue.swift

@@ -77,13 +77,13 @@ import NCCommunication
     
     // Delete file
     
-    @objc func delete(metadata: tableMetadata, onlyLocal: Bool) {
+    @objc func delete(metadata: tableMetadata, onlyLocalCache: Bool) {
         for operation in deleteQueue.operations as! [NCOperationDelete]  {
             if operation.metadata.ocId == metadata.ocId {
                 return
             }
         }
-        deleteQueue.addOperation(NCOperationDelete.init(metadata: metadata, onlyLocal: onlyLocal))
+        deleteQueue.addOperation(NCOperationDelete.init(metadata: metadata, onlyLocalCache: onlyLocalCache))
     }
     @objc func deleteCancelAll() {
         deleteQueue.cancelAll()
@@ -161,23 +161,28 @@ import NCCommunication
     
     // Download Avatar
     
-    func downloadAvatar(user: String, fileNameLocalPath: String, placeholder: UIImage?, cell: UIView, view: UIView?) {
+    func downloadAvatar(user: String, fileName: String, placeholder: UIImage?, cell: UIView, view: UIView?) {
 
         let cell: NCCellProtocol = cell as! NCCellProtocol
-
-        #if !EXTENSION
-        if let image = (UIApplication.shared.delegate as! AppDelegate).avatars[user] {
+        let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+        
+        if let image = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) {
             cell.fileAvatarImageView?.image = image
             return
         }
-        #endif
-                
-        cell.fileAvatarImageView?.image = placeholder
+
         if let image = UIImage(contentsOfFile: fileNameLocalPath) {
-            cell.fileAvatarImageView?.image = NCUtility.shared.createAvatar(image: image, size: 30)
+            cell.fileAvatarImageView?.image = image
+        } else {
+            cell.fileAvatarImageView?.image = placeholder
         }
-    
-        downloadAvatarQueue.addOperation(NCOperationDownloadAvatar.init(user: user, fileNameLocalPath: fileNameLocalPath, cell: cell, view: view))
+        
+        for operation in downloadAvatarQueue.operations as! [NCOperationDownloadAvatar] {
+            if operation.fileName == fileName {
+                return
+            }
+        }
+        downloadAvatarQueue.addOperation(NCOperationDownloadAvatar.init(user: user, fileName: fileName, fileNameLocalPath: fileNameLocalPath, cell: cell, view: view))
     }
     
     func cancelDownloadAvatar(user: String) {
@@ -221,18 +226,18 @@ class NCOperationDownload: ConcurrentOperation {
 class NCOperationDelete: ConcurrentOperation {
    
     var metadata: tableMetadata
-    var onlyLocal: Bool
+    var onlyLocalCache: Bool
     
-    init(metadata: tableMetadata, onlyLocal: Bool) {
+    init(metadata: tableMetadata, onlyLocalCache: Bool) {
         self.metadata = tableMetadata.init(value: metadata)
-        self.onlyLocal = onlyLocal
+        self.onlyLocalCache = onlyLocalCache
     }
     
     override func start() {
         if isCancelled {
             self.finish()
         } else {
-            NCNetworking.shared.deleteMetadata(metadata, onlyLocal: onlyLocal) { (errorCode, errorDescription) in
+            NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: onlyLocalCache) { (errorCode, errorDescription) in
                 if errorCode != 0 {
                     NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode)
                 }
@@ -412,9 +417,14 @@ class NCOperationDownloadThumbnail: ConcurrentOperation {
         if isCancelled {
             self.finish()
         } else {
-            NCCommunication.shared.downloadPreview(fileNamePathOrFileId: fileNamePath, fileNamePreviewLocalPath: fileNamePreviewLocalPath , widthPreview: NCGlobal.shared.sizePreview, heightPreview: NCGlobal.shared.sizePreview, fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon) { (account, imagePreview, imageIcon,  errorCode, errorDescription) in
+            var etagResource: String?
+            if FileManager.default.fileExists(atPath: fileNameIconLocalPath) && FileManager.default.fileExists(atPath: fileNamePreviewLocalPath) {
+                etagResource = metadata.etagResource
+            }
+            NCCommunication.shared.downloadPreview(fileNamePathOrFileId: fileNamePath, fileNamePreviewLocalPath: fileNamePreviewLocalPath , widthPreview: NCGlobal.shared.sizePreview, heightPreview: NCGlobal.shared.sizePreview, fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, etag: etagResource) { (account, imagePreview, imageIcon, imageOriginal, etag, errorCode, errorDescription) in
                 
                 if errorCode == 0 && imageIcon != nil {
+                    NCManageDatabase.shared.setMetadataEtagResource(ocId: self.metadata.ocId, etagResource: etag)
                     if self.metadata.ocId == self.cell.fileObjectId {
                         if let filePreviewImageView = self.cell?.filePreviewImageView  {
                             UIView.transition(with: filePreviewImageView,
@@ -441,16 +451,21 @@ class NCOperationDownloadThumbnail: ConcurrentOperation {
 
 class NCOperationDownloadAvatar: ConcurrentOperation {
 
+    let appDelegate = UIApplication.shared.delegate as! AppDelegate
     var user: String
+    var fileName: String
+    var etag: String?
     var fileNameLocalPath: String
     var cell: NCCellProtocol!
     var view: UIView?
 
-    init(user: String, fileNameLocalPath: String, cell: NCCellProtocol, view: UIView?) {
+    init(user: String, fileName: String, fileNameLocalPath: String, cell: NCCellProtocol, view: UIView?) {
         self.user = user
+        self.fileName = fileName
         self.fileNameLocalPath = fileNameLocalPath
         self.cell = cell
         self.view = view
+        self.etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag
     }
     
     override func start() {
@@ -458,30 +473,35 @@ class NCOperationDownloadAvatar: ConcurrentOperation {
         if isCancelled {
             self.finish()
         } else {
-            NCCommunication.shared.downloadAvatar(user: user, fileNameLocalPath: fileNameLocalPath, size: NCGlobal.shared.avatarSize) { (account, data, errorCode, errorMessage) in
+            NCCommunication.shared.downloadAvatar(user: user, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: self.etag) { (account, imageAvatar, imageOriginal, etag, errorCode, errorMessage) in
                 
-                if errorCode == 0 && data != nil {
-                    if var image = UIImage.init(data: data!) {
-                        image = NCUtility.shared.createAvatar(image: image, size: 30)
-                        #if !EXTENSION
-                        (UIApplication.shared.delegate as! AppDelegate).avatars[self.user] = image
-                        #endif
-                        if self.user == self.cell.fileUser {
-                            if let avatarImageView = self.cell?.fileAvatarImageView  {
-                                UIView.transition(with: avatarImageView,
-                                                  duration: 0.75,
-                                                  options: .transitionCrossDissolve,
-                                                  animations: { avatarImageView.image = image },
-                                                  completion: nil)
-                            }
-                        } else {
-                            if self.view is UICollectionView {
-                                (self.view as? UICollectionView)?.reloadData()
-                            } else if self.view is UITableView{
-                                (self.view as? UITableView)?.reloadData()
+                if errorCode == 0, let imageAvatar = imageAvatar, let etag = etag {
+                    
+                    NCManageDatabase.shared.addAvatar(fileName: self.fileName, etag: etag)
+                    
+                    if self.user == self.cell.fileUser {
+                        if let avatarImageView = self.cell?.fileAvatarImageView  {
+                            UIView.transition(with: avatarImageView, duration: 0.75, options: .transitionCrossDissolve) {
+                                avatarImageView.image = imageAvatar
+                            } completion: { _ in
+                                if self.view is UICollectionView {
+                                    (self.view as? UICollectionView)?.reloadData()
+                                } else if self.view is UITableView{
+                                    (self.view as? UITableView)?.reloadData()
+                                }
                             }
                         }
+                    } else {
+                        if self.view is UICollectionView {
+                            (self.view as? UICollectionView)?.reloadData()
+                        } else if self.view is UITableView{
+                            (self.view as? UITableView)?.reloadData()
+                        }
                     }
+                    
+                } else if errorCode == NCGlobal.shared.errorNotModified {
+                    
+                    NCManageDatabase.shared.setAvatarLoaded(fileName: self.fileName)
                 }
                 
                 self.finish()

+ 22 - 13
iOSClient/Networking/NCService.swift

@@ -37,7 +37,8 @@ class NCService: NSObject {
     
     @objc public func startRequestServicesServer() {
    
-        appDelegate.avatars = [:]
+        NCManageDatabase.shared.clearAllAvatarLoaded()
+        
         if appDelegate.account == "" { return }
         
         self.addInternalTypeIdentifier()
@@ -96,7 +97,6 @@ class NCService: NSObject {
                 
                     let user = tableAccount.user
                     let url = tableAccount.urlBase
-                    let stringUser = CCUtility.getStringUser(user, urlBase: url)!
                     
                     self.appDelegate.settingAccount(tableAccount.account, urlBase: tableAccount.urlBase, user: tableAccount.user, userId: tableAccount.userId, password: CCUtility.getPassword(tableAccount.account))
                        
@@ -107,20 +107,29 @@ class NCService: NSObject {
                     self.synchronizeOffline(account: tableAccount.account)
                     
                     // Get Avatar
-                    let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + stringUser + "-" + self.appDelegate.user + ".png"
-                    let oldData = try? Data(contentsOf: URL(fileURLWithPath: fileNameLocalPath))
-                    NCCommunication.shared.downloadAvatar(user: user, fileNameLocalPath: fileNameLocalPath, size: NCGlobal.shared.avatarSize) { (account, data, errorCode, errorMessage) in
-                        if let data = data, let oldData = oldData {
+                    let fileName = String(CCUtility.getUserUrlBase(user, urlBase: url)) + "-" + self.appDelegate.user + ".png"
+                    let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+                    let etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag
+                    
+                    NCCommunication.shared.downloadAvatar(user: user, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag) { (account, image, imageOriginal, etag, errorCode, errorMessage) in
+                        
+                        if let etag = etag, errorCode == 0, let imageOriginal = imageOriginal {
+                            
                             do {
-                                let isEqual = try NCUtility.shared.compare(tolerance: 95, expected: data, observed: oldData)
-                                if !isEqual {
-                                    NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadAvatar, userInfo: nil)
+                                if let pngData = imageOriginal.pngData() {
+                                    let fileName = String(CCUtility.getUserUrlBase(user, urlBase: url)) + "-" + self.appDelegate.user + "-original.png"
+                                    let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+                                    let url = URL.init(fileURLWithPath: fileNameLocalPath)
+                                    try pngData.write(to: url)
                                 }
-                            } catch {
-                                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadAvatar, userInfo: nil)
-                            }
-                        } else {
+                            } catch {}
+                            
+                            NCManageDatabase.shared.addAvatar(fileName: fileName, etag: etag)
                             NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadAvatar, userInfo: nil)
+                            
+                        } else if errorCode == NCGlobal.shared.errorNotModified {
+                            
+                            NCManageDatabase.shared.setAvatarLoaded(fileName: fileName)
                         }
                     }
                     self.requestServerCapabilities()

+ 14 - 13
iOSClient/Notification/NCNotification.swift

@@ -133,22 +133,23 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
         cell.avatar.isHidden = true
         cell.avatarLeadingMargin.constant = 10
         if let subjectRichParameters = notification.subjectRichParameters {
-            if let parameter = JSON(subjectRichParameters).dictionary {
-                if let user = JSON(parameter).dictionary {
-                    if let userId = user["id"]?.string {
-                        let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + userId + ".png"
-                        if FileManager.default.fileExists(atPath: fileNameLocalPath) {
-                            if let image = UIImage(contentsOfFile: fileNameLocalPath) {
-                                cell.avatar.isHidden = false
-                                cell.avatarLeadingMargin.constant = 50
-                                cell.avatar.image = image
-                            }
-                        } else {
+            if let json = JSON(subjectRichParameters).dictionary {
+                if let user = json["user"]?["id"].stringValue {
+                    
+                    let fileName = String(CCUtility.getUserUrlBase(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + user + ".png"
+                    let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+                    
+                    if FileManager.default.fileExists(atPath: fileNameLocalPath) {
+                        if let image = UIImage(contentsOfFile: fileNameLocalPath) {
                             cell.avatar.isHidden = false
                             cell.avatarLeadingMargin.constant = 50
-                            cell.fileUser = userId
-                            NCOperationQueue.shared.downloadAvatar(user: userId, fileNameLocalPath: fileNameLocalPath, placeholder: UIImage(named: "avatar"), cell: cell, view: tableView)
+                            cell.avatar.image = image
                         }
+                    } else {
+                        cell.avatar.isHidden = false
+                        cell.avatarLeadingMargin.constant = 50
+                        cell.fileUser = user
+                        NCOperationQueue.shared.downloadAvatar(user: user, fileName: fileName, placeholder: UIImage(named: "avatar"), cell: cell, view: tableView)
                     }
                 }
             }

+ 2 - 2
iOSClient/Select/NCSelect.swift

@@ -416,8 +416,8 @@ extension NCSelect: UICollectionViewDataSource {
         
         // Avatar
         if metadata.ownerId.count > 0 && metadata.ownerId != activeAccount.userId && activeAccount.account == metadata.account {
-            let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(metadata.user, urlBase: metadata.urlBase)) + "-" + metadata.ownerId + ".png"
-            NCOperationQueue.shared.downloadAvatar(user: metadata.ownerId, fileNameLocalPath: fileNameLocalPath, placeholder: NCBrandColor.cacheImages.shared, cell: cell, view: collectionView)
+            let fileName = String(CCUtility.getUserUrlBase(metadata.user, urlBase: metadata.urlBase)) + "-" + metadata.ownerId + ".png"
+            NCOperationQueue.shared.downloadAvatar(user: metadata.ownerId, fileName: fileName, placeholder: NCBrandColor.cacheImages.shared, cell: cell, view: collectionView)
         }
     }
     

+ 1 - 1
iOSClient/Settings/CCAdvanced.m

@@ -431,7 +431,7 @@
     [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCGlobal.shared.notificationCenterInitialize object:nil userInfo:nil];
     
     // Clear Media
-    [appDelegate.activeMedia reloadDataSource];
+    [appDelegate.activeMedia reloadDataSourceWithCompletion:^(NSArray *metadatas) { }];
     
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
         [[NCUtility shared] stopActivityIndicator];

+ 2 - 2
iOSClient/Settings/CCManageAccount.m

@@ -56,10 +56,10 @@
         row = [XLFormRowDescriptor formRowDescriptorWithTag:account.account rowType:XLFormRowDescriptorTypeBooleanCheck title:title];
         
         // Avatar
-        NSString *fileNamePath = [NSString stringWithFormat:@"%@/%@-%@.png", [CCUtility getDirectoryUserData], [CCUtility getStringUser:account.user urlBase:account.urlBase], account.user];
+        NSString *fileNamePath = [NSString stringWithFormat:@"%@/%@-%@-original.png", [CCUtility getDirectoryUserData], [CCUtility getUserUrlBase:account.user urlBase:account.urlBase], account.user];
         UIImage *avatar = [UIImage imageWithContentsOfFile:fileNamePath];
         if (avatar) {
-            avatar = [[NCUtility shared] createAvatarWithImage:avatar size:40];
+            avatar = [NCUtility.shared createAvatarWithImage:avatar size:40];
         } else {
             avatar = [[UIImage imageNamed:@"avatar"] imageWithColor:NCBrandColor.shared.gray size:40];
         }

+ 61 - 29
iOSClient/Share/NCShare.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Ts3-RO-A9l">
-    <device id="retina6_1" orientation="portrait" appearance="light"/>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Ts3-RO-A9l">
+    <device id="retina5_5" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -13,9 +13,10 @@
             <objects>
                 <viewController id="UdT-J4-zvv" customClass="NCSharePaging" customModule="Nextcloud" customModuleProvider="target" sceneMemberID="viewController">
                     <view key="view" contentMode="scaleToFill" id="xka-e7-U7G">
-                        <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <viewLayoutGuide key="safeArea" id="EQO-kT-aOm"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                     </view>
                     <navigationItem key="navigationItem" id="3f0-GZ-Z6m"/>
                 </viewController>
@@ -29,7 +30,7 @@
                 <navigationController automaticallyAdjustsScrollViewInsets="NO" id="Ts3-RO-A9l" sceneMemberID="viewController">
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="RCF-gN-HcM">
-                        <rect key="frame" x="0.0" y="44" width="414" height="44"/>
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -46,11 +47,11 @@
             <objects>
                 <viewController storyboardIdentifier="comments" id="GMr-2Y-4vs" customClass="NCShareComments" customModule="Nextcloud" customModuleProvider="target" sceneMemberID="viewController">
                     <view key="view" contentMode="scaleToFill" id="5MM-pX-rNX">
-                        <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jzJ-Ra-l4b" userLabel="View container">
-                                <rect key="frame" x="0.0" y="0.0" width="409" height="862"/>
+                                <rect key="frame" x="0.0" y="0.0" width="409" height="736"/>
                                 <subviews>
                                     <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="j5C-gO-XF8">
                                         <rect key="frame" x="55" y="60" width="344" height="30"/>
@@ -64,7 +65,7 @@
                                         </connections>
                                     </textField>
                                     <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="DFs-4t-iWX">
-                                        <rect key="frame" x="5" y="100" width="404" height="752"/>
+                                        <rect key="frame" x="5" y="100" width="404" height="626"/>
                                         <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                         <color key="separatorColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                     </tableView>
@@ -76,7 +77,7 @@
                                         </constraints>
                                     </imageView>
                                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="user" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9sc-sV-YF1">
-                                        <rect key="frame" x="60" y="21.5" width="337" height="17"/>
+                                        <rect key="frame" x="60" y="21.666666666666668" width="337" height="17.000000000000004"/>
                                         <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                         <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                         <nil key="highlightedColor"/>
@@ -99,6 +100,7 @@
                             </view>
                         </subviews>
                         <viewLayoutGuide key="safeArea" id="j3W-IW-lzW"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                         <constraints>
                             <constraint firstItem="jzJ-Ra-l4b" firstAttribute="leading" secondItem="j3W-IW-lzW" secondAttribute="leading" id="B4V-GC-zYM"/>
                             <constraint firstItem="j3W-IW-lzW" firstAttribute="trailing" secondItem="jzJ-Ra-l4b" secondAttribute="trailing" constant="5" id="WPr-LS-NPk"/>
@@ -123,14 +125,14 @@
             <objects>
                 <viewController storyboardIdentifier="sharing" id="bgO-Rz-2M1" customClass="NCShare" customModule="Nextcloud" customModuleProvider="target" sceneMemberID="viewController">
                     <view key="view" contentMode="scaleToFill" id="aV2-U6-JTf">
-                        <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="X2m-IC-J1u" userLabel="View container">
-                                <rect key="frame" x="5" y="0.0" width="404" height="852"/>
+                                <rect key="frame" x="5" y="0.0" width="404" height="726"/>
                                 <subviews>
                                     <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="iSO-mc-0TB">
-                                        <rect key="frame" x="5" y="65" width="389" height="30"/>
+                                        <rect key="frame" x="5" y="95" width="389" height="30"/>
                                         <constraints>
                                             <constraint firstAttribute="height" constant="30" id="0aG-z9-fcy"/>
                                         </constraints>
@@ -141,37 +143,37 @@
                                         </connections>
                                     </textField>
                                     <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="c94-b9-Sim">
-                                        <rect key="frame" x="0.0" y="220" width="404" height="632"/>
+                                        <rect key="frame" x="0.0" y="250" width="404" height="476"/>
                                         <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                     </tableView>
                                     <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="8Cj-cK-AKZ">
-                                        <rect key="frame" x="5" y="109" width="40" height="40"/>
+                                        <rect key="frame" x="5" y="139" width="40" height="40"/>
                                         <constraints>
                                             <constraint firstAttribute="height" constant="40" id="CCv-Uu-Vel"/>
                                             <constraint firstAttribute="width" constant="40" id="egJ-xl-yj4"/>
                                         </constraints>
                                     </imageView>
                                     <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="HPl-mj-r5E">
-                                        <rect key="frame" x="5" y="169" width="40" height="40"/>
+                                        <rect key="frame" x="5" y="199" width="40" height="40"/>
                                         <constraints>
                                             <constraint firstAttribute="width" constant="40" id="6IE-lI-M6i"/>
                                             <constraint firstAttribute="height" constant="40" id="Odq-bX-Hoz"/>
                                         </constraints>
                                     </imageView>
                                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Share link" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SQW-aQ-ydN">
-                                        <rect key="frame" x="53" y="120" width="261" height="18"/>
+                                        <rect key="frame" x="53" y="150" width="261" height="18"/>
                                         <fontDescription key="fontDescription" type="system" pointSize="15"/>
                                         <nil key="textColor"/>
                                         <nil key="highlightedColor"/>
                                     </label>
                                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Share link" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YYp-o8-YJP">
-                                        <rect key="frame" x="53" y="165" width="317" height="18"/>
+                                        <rect key="frame" x="53" y="195" width="317" height="18"/>
                                         <fontDescription key="fontDescription" type="system" pointSize="15"/>
                                         <nil key="textColor"/>
                                         <nil key="highlightedColor"/>
                                     </label>
                                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pfo-D0-W7b">
-                                        <rect key="frame" x="53" y="186.5" width="317" height="35"/>
+                                        <rect key="frame" x="53" y="216.66666666666666" width="317" height="35"/>
                                         <constraints>
                                             <constraint firstAttribute="height" constant="35" id="f8b-mp-xLJ"/>
                                         </constraints>
@@ -180,7 +182,7 @@
                                         <nil key="highlightedColor"/>
                                     </label>
                                     <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Qek-aQ-NjE" userLabel="ButtonMenu">
-                                        <rect key="frame" x="374" y="119" width="20" height="20"/>
+                                        <rect key="frame" x="374" y="149" width="20" height="20"/>
                                         <constraints>
                                             <constraint firstAttribute="width" constant="20" id="BAT-jK-rUt"/>
                                             <constraint firstAttribute="height" constant="20" id="zc5-W6-SXG"/>
@@ -191,7 +193,7 @@
                                         </connections>
                                     </button>
                                     <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cLd-wD-cSC" userLabel="ButtonCopy">
-                                        <rect key="frame" x="324" y="119" width="20" height="20"/>
+                                        <rect key="frame" x="324" y="149" width="20" height="20"/>
                                         <constraints>
                                             <constraint firstAttribute="width" constant="20" id="Bzl-zW-yzd"/>
                                             <constraint firstAttribute="height" constant="20" id="RIV-EC-kwC"/>
@@ -202,33 +204,54 @@
                                         </connections>
                                     </button>
                                     <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oBQ-TP-qof" userLabel="View Shared with you by">
-                                        <rect key="frame" x="-5" y="10" width="409" height="45"/>
+                                        <rect key="frame" x="-5" y="10" width="409" height="90"/>
                                         <subviews>
                                             <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="fKv-xM-rVY">
-                                                <rect key="frame" x="10" y="2.5" width="40" height="40"/>
+                                                <rect key="frame" x="10" y="0.0" width="40" height="40"/>
                                                 <constraints>
                                                     <constraint firstAttribute="height" constant="40" id="DJa-7z-oGM"/>
                                                     <constraint firstAttribute="width" constant="40" id="PwX-iy-H0o"/>
                                                 </constraints>
                                             </imageView>
                                             <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Shared with you by" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ngi-GT-jvv">
-                                                <rect key="frame" x="58" y="13.5" width="341" height="18"/>
+                                                <rect key="frame" x="60" y="11" width="339" height="18"/>
                                                 <fontDescription key="fontDescription" type="system" pointSize="15"/>
                                                 <nil key="textColor"/>
                                                 <nil key="highlightedColor"/>
                                             </label>
+                                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="note.text" translatesAutoresizingMaskIntoConstraints="NO" id="fhO-Tk-u8Z">
+                                                <rect key="frame" x="60" y="45" width="25" height="25"/>
+                                                <constraints>
+                                                    <constraint firstAttribute="height" constant="25" id="81R-aq-eMi"/>
+                                                    <constraint firstAttribute="width" constant="25" id="mCr-49-nFF"/>
+                                                </constraints>
+                                            </imageView>
+                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KHG-xj-wfG" customClass="MarqueeLabel" customModule="MarqueeLabel">
+                                                <rect key="frame" x="95" y="48.666666666666664" width="294" height="17.999999999999993"/>
+                                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                <nil key="textColor"/>
+                                                <nil key="highlightedColor"/>
+                                                <userDefinedRuntimeAttributes>
+                                                    <userDefinedRuntimeAttribute type="boolean" keyPath="tapToScroll" value="YES"/>
+                                                </userDefinedRuntimeAttributes>
+                                            </label>
                                         </subviews>
                                         <constraints>
-                                            <constraint firstItem="ngi-GT-jvv" firstAttribute="centerY" secondItem="oBQ-TP-qof" secondAttribute="centerY" id="2Xz-A8-l0g"/>
+                                            <constraint firstItem="fhO-Tk-u8Z" firstAttribute="leading" secondItem="oBQ-TP-qof" secondAttribute="leading" constant="60" id="6Go-2t-dND"/>
+                                            <constraint firstItem="KHG-xj-wfG" firstAttribute="centerY" secondItem="fhO-Tk-u8Z" secondAttribute="centerY" id="DEz-SB-eWP"/>
+                                            <constraint firstItem="fKv-xM-rVY" firstAttribute="top" secondItem="oBQ-TP-qof" secondAttribute="top" id="Gap-v5-Pkh"/>
                                             <constraint firstAttribute="trailing" secondItem="ngi-GT-jvv" secondAttribute="trailing" constant="10" id="Gsg-bh-cgu"/>
-                                            <constraint firstItem="fKv-xM-rVY" firstAttribute="centerY" secondItem="oBQ-TP-qof" secondAttribute="centerY" id="M79-hE-qUg"/>
+                                            <constraint firstItem="ngi-GT-jvv" firstAttribute="centerY" secondItem="fKv-xM-rVY" secondAttribute="centerY" id="MIg-bS-4Te"/>
                                             <constraint firstItem="fKv-xM-rVY" firstAttribute="leading" secondItem="oBQ-TP-qof" secondAttribute="leading" constant="10" id="O2h-N9-cgt"/>
-                                            <constraint firstAttribute="height" constant="45" id="reh-5m-KFy"/>
-                                            <constraint firstItem="ngi-GT-jvv" firstAttribute="leading" secondItem="fKv-xM-rVY" secondAttribute="trailing" constant="8" id="taI-rs-B3r"/>
+                                            <constraint firstAttribute="trailing" secondItem="KHG-xj-wfG" secondAttribute="trailing" constant="20" id="kKc-BN-iLN"/>
+                                            <constraint firstAttribute="height" constant="90" id="reh-5m-KFy"/>
+                                            <constraint firstItem="ngi-GT-jvv" firstAttribute="leading" secondItem="fKv-xM-rVY" secondAttribute="trailing" constant="10" id="taI-rs-B3r"/>
+                                            <constraint firstItem="fhO-Tk-u8Z" firstAttribute="top" secondItem="fKv-xM-rVY" secondAttribute="bottom" constant="5" id="tpt-vT-Nto"/>
+                                            <constraint firstItem="KHG-xj-wfG" firstAttribute="leading" secondItem="fhO-Tk-u8Z" secondAttribute="trailing" constant="10" id="xk0-AH-pfR"/>
                                         </constraints>
                                     </view>
                                     <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FFi-7t-C8U" userLabel="ButtonCopy">
-                                        <rect key="frame" x="375" y="179" width="20" height="20"/>
+                                        <rect key="frame" x="375" y="209" width="20" height="20"/>
                                         <constraints>
                                             <constraint firstAttribute="height" constant="20" id="0KI-54-GMc"/>
                                             <constraint firstAttribute="width" constant="20" id="fcI-Wc-4GE"/>
@@ -259,7 +282,7 @@
                                     <constraint firstItem="iSO-mc-0TB" firstAttribute="leading" secondItem="X2m-IC-J1u" secondAttribute="leading" constant="5" id="d8E-WM-YfC"/>
                                     <constraint firstItem="FFi-7t-C8U" firstAttribute="centerY" secondItem="HPl-mj-r5E" secondAttribute="centerY" id="fkL-uP-Iob"/>
                                     <constraint firstItem="YYp-o8-YJP" firstAttribute="centerY" secondItem="HPl-mj-r5E" secondAttribute="centerY" constant="-15" id="iu4-c5-p5k"/>
-                                    <constraint firstItem="iSO-mc-0TB" firstAttribute="top" secondItem="X2m-IC-J1u" secondAttribute="top" constant="65" id="jPM-Uo-0lS"/>
+                                    <constraint firstItem="iSO-mc-0TB" firstAttribute="top" secondItem="X2m-IC-J1u" secondAttribute="top" constant="95" id="jPM-Uo-0lS"/>
                                     <constraint firstItem="pfo-D0-W7b" firstAttribute="leading" secondItem="HPl-mj-r5E" secondAttribute="trailing" constant="8" symbolic="YES" id="oKN-Ui-VIn"/>
                                     <constraint firstAttribute="trailing" secondItem="Qek-aQ-NjE" secondAttribute="trailing" constant="10" id="puY-4D-ARy"/>
                                     <constraint firstItem="c94-b9-Sim" firstAttribute="leading" secondItem="X2m-IC-J1u" secondAttribute="leading" id="rvD-u3-Dug"/>
@@ -271,6 +294,7 @@
                             </view>
                         </subviews>
                         <viewLayoutGuide key="safeArea" id="eAi-wv-a4Y"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                         <constraints>
                             <constraint firstItem="eAi-wv-a4Y" firstAttribute="bottom" secondItem="X2m-IC-J1u" secondAttribute="bottom" constant="10" id="Gvn-eF-b0b"/>
                             <constraint firstItem="X2m-IC-J1u" firstAttribute="leading" secondItem="eAi-wv-a4Y" secondAttribute="leading" constant="5" id="Ufw-7y-DMv"/>
@@ -293,6 +317,8 @@
                         <outlet property="shareLinkLabel" destination="SQW-aQ-ydN" id="nBK-WJ-oKy"/>
                         <outlet property="sharedWithYouByImage" destination="fKv-xM-rVY" id="EJ0-sV-By8"/>
                         <outlet property="sharedWithYouByLabel" destination="ngi-GT-jvv" id="Qay-IG-tZh"/>
+                        <outlet property="sharedWithYouByNote" destination="KHG-xj-wfG" id="4m5-u6-7RW"/>
+                        <outlet property="sharedWithYouByNoteImage" destination="fhO-Tk-u8Z" id="8Ly-gt-RXD"/>
                         <outlet property="sharedWithYouByView" destination="oBQ-TP-qof" id="nfN-yx-627"/>
                         <outlet property="tableView" destination="c94-b9-Sim" id="ZlE-Fh-kaR"/>
                         <outlet property="viewContainerConstraint" destination="aXO-v9-CBF" id="R19-WO-im5"/>
@@ -303,7 +329,13 @@
             <point key="canvasLocation" x="2689.8550724637685" y="-167.41071428571428"/>
         </scene>
     </scenes>
+    <designables>
+        <designable name="KHG-xj-wfG">
+            <size key="intrinsicContentSize" width="37.333333333333336" height="18"/>
+        </designable>
+    </designables>
     <resources>
+        <image name="note.text" width="24" height="24"/>
         <image name="shareCopy" width="329" height="329"/>
         <image name="shareMenu" width="329" height="329"/>
     </resources>

+ 67 - 17
iOSClient/Share/NCShare.swift

@@ -25,6 +25,7 @@ import UIKit
 import Parchment
 import DropDown
 import NCCommunication
+import MarqueeLabel
 
 class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareLinkCellDelegate, NCShareUserCellDelegate, NCShareNetworkingDelegate {
    
@@ -32,6 +33,8 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareLinkCellDel
     @IBOutlet weak var sharedWithYouByView: UIView!
     @IBOutlet weak var sharedWithYouByImage: UIImageView!
     @IBOutlet weak var sharedWithYouByLabel: UILabel!
+    @IBOutlet weak var sharedWithYouByNoteImage: UIImageView!
+    @IBOutlet weak var sharedWithYouByNote: MarqueeLabel!
     @IBOutlet weak var searchFieldTopConstraint: NSLayoutConstraint!
     @IBOutlet weak var searchField: UITextField!
     @IBOutlet weak var shareLinkImage: UIImageView!
@@ -95,19 +98,42 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareLinkCellDel
             sharedWithYouByView.isHidden = false
             sharedWithYouByLabel.text = NSLocalizedString("_shared_with_you_by_", comment: "") + " " + metadata!.ownerDisplayName
             sharedWithYouByImage.image = UIImage(named: "avatar")?.imageColor(NCBrandColor.shared.label)
-
-            let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + metadata!.ownerId + ".png"
-            if FileManager.default.fileExists(atPath: fileNameLocalPath) {
-                if let image = UIImage(contentsOfFile: fileNameLocalPath) {
-                    sharedWithYouByImage.image = NCUtility.shared.createAvatar(image: image, size: 40)
-                }
+            
+            if metadata?.note.count ?? 0 > 0 {
+                searchFieldTopConstraint.constant = 95
+                sharedWithYouByNoteImage.isHidden = false
+                sharedWithYouByNoteImage.image = NCUtility.shared.loadImage(named: "note.text", color: .gray)
+                sharedWithYouByNote.isHidden = false
+                sharedWithYouByNote.text = metadata?.note
+                sharedWithYouByNote.textColor = NCBrandColor.shared.label
+                sharedWithYouByNote.trailingBuffer = sharedWithYouByNote.frame.width
+            } else {
+                sharedWithYouByNoteImage.isHidden = true
+                sharedWithYouByNote.isHidden = true
+            }
+            
+            let fileName = String(CCUtility.getUserUrlBase(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + metadata!.ownerId + ".png"
+            
+            if let image = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) {
+                
+                sharedWithYouByImage.image = image
+                
             } else {
-                NCCommunication.shared.downloadAvatar(user: metadata!.ownerId, fileNameLocalPath: fileNameLocalPath, size: NCGlobal.shared.avatarSize) { (account, data, errorCode, errorMessage) in
-                    if errorCode == 0 && account == self.appDelegate.account && UIImage(data: data!) != nil {
-                        if let image = UIImage(contentsOfFile: fileNameLocalPath) {
-                            self.sharedWithYouByImage.image = NCUtility.shared.createAvatar(image: image, size: 40)
-                        }
-                    } 
+                
+                let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+                let etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag
+                
+                NCCommunication.shared.downloadAvatar(user: metadata!.ownerId, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag) { (account, imageAvatar, imageOriginal, etag, errorCode, errorMessage) in
+                    
+                    if errorCode == 0, let etag = etag, let imageAvatar = imageAvatar {
+                        
+                        NCManageDatabase.shared.addAvatar(fileName: fileName, etag: etag)
+                        self.sharedWithYouByImage.image = imageAvatar
+                        
+                    } else if errorCode == NCGlobal.shared.errorNotModified, let imageAvatar = NCManageDatabase.shared.setAvatarLoaded(fileName: fileName) {
+                        
+                        self.sharedWithYouByImage.image = imageAvatar
+                    }
                 }
             }
         } 
@@ -325,6 +351,7 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareLinkCellDel
             guard let cell = cell as? NCShareUserDropDownCell else { return }
             let sharee = sharees[index]
             cell.imageItem.image = NCShareCommon.shared.getImageShareType(shareType: sharee.shareType)
+            cell.imageShareeType.image = NCShareCommon.shared.getImageShareType(shareType: sharee.shareType)
             let status = NCUtility.shared.getUserStatus(userIcon: sharee.userIcon, userStatus: sharee.userStatus, userMessage: sharee.userMessage)
             cell.imageStatus.image = status.onlineStatus
             cell.status.text = status.statusMessage
@@ -333,9 +360,31 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareLinkCellDel
             } else {
                 cell.centerTitle.constant = 0
             }
-            let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(self.appDelegate.user, urlBase: self.appDelegate.urlBase)) + "-" + sharee.label + ".png"
-            NCOperationQueue.shared.downloadAvatar(user: sharee.shareWith, fileNameLocalPath: fileNameLocalPath, placeholder: UIImage(named: "avatar"), cell: cell, view: nil)
-            cell.imageShareeType.image = NCShareCommon.shared.getImageShareType(shareType: sharee.shareType)
+            
+            let fileName = String(CCUtility.getUserUrlBase(self.appDelegate.user, urlBase: self.appDelegate.urlBase)) + "-" + sharee.shareWith + ".png"
+            
+            if let image = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) {
+                
+                cell.imageItem.image = image
+                
+            } else {
+                
+                let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+                let etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag
+
+                NCCommunication.shared.downloadAvatar(user: sharee.shareWith, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag) { (account, imageAvatar, imageOriginal, etag, errorCode, errorMessage) in
+                    
+                    if errorCode == 0, let etag = etag, let imageAvatar = imageAvatar {
+                        
+                        NCManageDatabase.shared.addAvatar(fileName: fileName, etag: etag)
+                        cell.imageItem.image = imageAvatar
+                        
+                    } else if errorCode == NCGlobal.shared.errorNotModified, let imageAvatar = NCManageDatabase.shared.setAvatarLoaded(fileName: fileName) {
+                        
+                        cell.imageItem.image = imageAvatar
+                    }
+                }
+            }
         }
         
         dropDown.selectionAction = { [weak self] (index, item) in
@@ -411,8 +460,9 @@ extension NCShare: UITableViewDataSource {
                 cell.imageStatus.image = status.onlineStatus
                 cell.status.text = status.statusMessage
                 
-                let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + tableShare.shareWith + ".png"
-                NCOperationQueue.shared.downloadAvatar(user: tableShare.shareWith, fileNameLocalPath: fileNameLocalPath, placeholder: UIImage(named: "avatar"), cell: cell, view: tableView)
+                let fileName = String(CCUtility.getUserUrlBase(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + tableShare.shareWith + ".png"
+               
+                NCOperationQueue.shared.downloadAvatar(user: tableShare.shareWith, fileName: fileName, placeholder: UIImage(named: "avatar"), cell: cell, view: tableView)
                 
                 // If the initiator or the recipient is not the current user, show the list of sharees without any options to edit it.
                 if tableShare.uidOwner != self.appDelegate.userId && tableShare.uidFileOwner != self.appDelegate.userId {

+ 8 - 8
iOSClient/Share/NCShareComments.swift

@@ -71,12 +71,12 @@ class NCShareComments: UIViewController, NCShareCommentsCellDelegate {
         }
         labelUser.textColor = NCBrandColor.shared.label
         
-        imageItem.image = UIImage(named: "avatar")
-        let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + appDelegate.user + ".png"
-        if FileManager.default.fileExists(atPath: fileNameLocalPath) {
-            if let image = UIImage(contentsOfFile: fileNameLocalPath) {
-                imageItem.image = NCUtility.shared.createAvatar(image: image, size: 40)
-            }
+        let fileName = String(CCUtility.getUserUrlBase(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + appDelegate.user + ".png"
+        let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+        if let image = UIImage(contentsOfFile: fileNameLocalPath) {
+            imageItem.image = image
+        } else {
+            imageItem.image = UIImage(named: "avatar")
         }
         
         // Mark comment ad read
@@ -180,8 +180,8 @@ extension NCShareComments: UITableViewDataSource {
             cell.sizeToFit()
             
             // Image
-            let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + String(CCUtility.getStringUser(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + tableComments.actorId + ".png"
-            NCOperationQueue.shared.downloadAvatar(user: tableComments.actorId, fileNameLocalPath: fileNameLocalPath, placeholder: UIImage(named: "avatar"), cell: cell, view: tableView)
+            let fileName = String(CCUtility.getUserUrlBase(appDelegate.user, urlBase: appDelegate.urlBase)) + "-" + tableComments.actorId + ".png"
+            NCOperationQueue.shared.downloadAvatar(user: tableComments.actorId, fileName: fileName, placeholder: UIImage(named: "avatar"), cell: cell, view: tableView)
             // Username
             cell.labelUser.text = tableComments.actorDisplayName
             cell.labelUser.textColor = NCBrandColor.shared.label

+ 2 - 2
iOSClient/Share/NCShareCommentsCell.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>

+ 39 - 1
iOSClient/Share/NCShareLinkMenuView.swift

@@ -24,7 +24,7 @@ import UIKit
 import FSCalendar
 import NCCommunication
 
-class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, NCShareNetworkingDelegate, FSCalendarDelegate, FSCalendarDelegateAppearance {
+class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDelegate, NCShareNetworkingDelegate, FSCalendarDelegate, FSCalendarDelegateAppearance {
     
     @IBOutlet weak var fieldLabel: UITextField!
 
@@ -76,6 +76,8 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, NCShareNetworkin
     var viewWindow: UIView?
     var viewWindowCalendar: UIView?
     private var calendar: FSCalendar?
+    private var selfFrameOriginYDiff: CGFloat = 0
+    private var activeTextField = UITextField()
 
     override func awakeFromNib() {
         
@@ -126,9 +128,16 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, NCShareNetworkin
         
         fieldSetExpirationDate.inputView = UIView()
         
+        fieldLabel.delegate = self
+        fieldPasswordProtect.delegate = self
+        fieldNoteToRecipient.delegate = self
+        
         imageNoteToRecipient.image = UIImage.init(named: "file_txt")!.image(color: UIColor(red: 76/255, green: 76/255, blue: 76/255, alpha: 1), size: 50)
         imageDeleteShareLink.image = NCUtility.shared.loadImage(named: "trash", color: UIColor(red: 76/255, green: 76/255, blue: 76/255, alpha: 1), size: 50)
         imageAddAnotherLink.image =  NCUtility.shared.loadImage(named: "plus", color: UIColor(red: 76/255, green: 76/255, blue: 76/255, alpha: 1), size: 50)
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
     }
     
     override func willMove(toWindow newWindow: UIWindow?) {
@@ -223,7 +232,36 @@ class NCShareLinkMenuView: UIView, UIGestureRecognizerDelegate, NCShareNetworkin
         fieldNoteToRecipient.text = tableShare.note
     }
     
+    func textFieldDidBeginEditing(_ textField: UITextField) {
+   
+        self.activeTextField = textField
+    }
+    
+    // MARK: - Keyboard notification
+    
+    @objc internal func keyboardWillShow(_ notification : Notification?) {
+                
+        selfFrameOriginYDiff = 0
+        
+        if let info = notification?.userInfo, let centerObject = self.activeTextField.superview?.convert(self.activeTextField.center, to: nil) {
+
+            let frameEndUserInfoKey = UIResponder.keyboardFrameEndUserInfoKey
+            if let keyboardFrame = info[frameEndUserInfoKey] as? CGRect {
+                let diff = keyboardFrame.origin.y - centerObject.y - (self.activeTextField.frame.height / 2)
+                if diff < 0 {
+                    selfFrameOriginYDiff = diff
+                    self.frame.origin.y += selfFrameOriginYDiff
+                }
+            }
+        }
+    }
+    
+    @objc func keyboardWillHide(_ notification: Notification) {
+        self.frame.origin.y -= selfFrameOriginYDiff
+    }
+    
     // MARK: - Tap viewWindowCalendar
+    
     @objc func tapViewWindowCalendar(gesture: UITapGestureRecognizer) {
         calendar?.removeFromSuperview()
         viewWindowCalendar?.removeFromSuperview()

+ 21 - 4
iOSClient/Share/NCShareQuickStatusMenu.swift

@@ -21,14 +21,28 @@ class NCShareQuickStatusMenu: NSObject {
 //        "_share_allow_upload_"          = "Allow upload and editing";
 //        "_share_file_drop_"             = "File drop (upload only)";
         
+//        @objc let permissionReadShare: Int              = 1
+//        @objc let permissionUpdateShare: Int            = 2
+//        @objc let permissionCreateShare: Int            = 4
+//        @objc let permissionDeleteShare: Int            = 8
+//        @objc let permissionShareShare: Int             = 16
+        
+//        @objc let permissionMinFileShare: Int           = 1
+//        @objc let permissionMaxFileShare: Int           = 19
+//        @objc let permissionMinFolderShare: Int         = 1
+//        @objc let permissionMaxFolderShare: Int         = 31
+//        @objc let permissionDefaultFileRemoteShareNoSupportShareOption: Int     = 3
+//        @objc let permissionDefaultFolderRemoteShareNoSupportShareOption: Int   = 15
+        
         actions.append(
             NCMenuAction(
                 title: NSLocalizedString("_share_read_only_", comment: ""),
                 icon: UIImage(),
-                selected: tableShare.permissions == NCGlobal.shared.permissionReadShare + NCGlobal.shared.permissionShareShare,
+                selected: tableShare.permissions == (NCGlobal.shared.permissionReadShare + NCGlobal.shared.permissionShareShare) || tableShare.permissions == NCGlobal.shared.permissionReadShare,
                 on: false,
                 action: { menuAction in
-                    let permissions = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: false, andIsFolder: directory)
+                    let canShare = CCUtility.isPermission(toCanShare: tableShare.permissions)
+                    let permissions = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: canShare, andIsFolder: directory)
                     NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShareChangePermissions, userInfo: ["idShare": tableShare.idShare, "permissions": permissions, "hideDownload": tableShare.hideDownload])
                 }
             )
@@ -41,12 +55,14 @@ class NCShareQuickStatusMenu: NSObject {
                 selected: tableShare.permissions == NCGlobal.shared.permissionMaxFileShare || tableShare.permissions == NCGlobal.shared.permissionMaxFolderShare ||  tableShare.permissions == NCGlobal.shared.permissionDefaultFileRemoteShareNoSupportShareOption,
                 on: false,
                 action: { menuAction in
-                    let permissions = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: false, andIsFolder: directory)
+                    let canShare = CCUtility.isPermission(toCanShare: tableShare.permissions)
+                    let permissions = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: canShare, andIsFolder: directory)
                     NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterShareChangePermissions, userInfo: ["idShare": tableShare.idShare, "permissions": permissions, "hideDownload": tableShare.hideDownload])
                 }
             )
         )
         
+        /*
         if directory {
             actions.append(
                 NCMenuAction(
@@ -61,7 +77,8 @@ class NCShareQuickStatusMenu: NSObject {
                 )
             )
         }
-
+        */
+        
         menuViewController.actions = actions
 
         let menuPanelController = NCMenuPanelController()

+ 36 - 1
iOSClient/Share/NCShareUserMenuView.swift

@@ -24,7 +24,7 @@ import UIKit
 import FSCalendar
 import NCCommunication
 
-class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, NCShareNetworkingDelegate, FSCalendarDelegate, FSCalendarDelegateAppearance {
+class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, UITextFieldDelegate, NCShareNetworkingDelegate, FSCalendarDelegate, FSCalendarDelegateAppearance {
     
     @IBOutlet weak var switchCanReshare: UISwitch!
     @IBOutlet weak var labelCanReshare: UILabel!
@@ -63,6 +63,8 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, NCShareNetworkin
     var viewWindow: UIView?
     var viewWindowCalendar: UIView?
     private var calendar: FSCalendar?
+    private var selfFrameOriginYDiff: CGFloat = 0
+    private var activeTextField = UITextField()
 
     override func awakeFromNib() {
         
@@ -101,8 +103,13 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, NCShareNetworkin
         
         fieldSetExpirationDate.inputView = UIView()
         
+        fieldNoteToRecipient.delegate = self
+        
         imageNoteToRecipient.image = UIImage.init(named: "file_txt")!.image(color: UIColor(red: 76/255, green: 76/255, blue: 76/255, alpha: 1), size: 50)
         imageUnshare.image = NCUtility.shared.loadImage(named: "trash", color: UIColor(red: 76/255, green: 76/255, blue: 76/255, alpha: 1), size: 50)
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
     }
     
     override func willMove(toWindow newWindow: UIWindow?) {
@@ -168,6 +175,34 @@ class NCShareUserMenuView: UIView, UIGestureRecognizerDelegate, NCShareNetworkin
         fieldNoteToRecipient.text = tableShare.note
     }
     
+    func textFieldDidBeginEditing(_ textField: UITextField) {
+   
+        self.activeTextField = textField
+    }
+    
+    // MARK: - Keyboard notification
+    
+    @objc internal func keyboardWillShow(_ notification : Notification?) {
+                
+        selfFrameOriginYDiff = 0
+        
+        if let info = notification?.userInfo, let centerObject = self.activeTextField.superview?.convert(self.activeTextField.center, to: nil) {
+
+            let frameEndUserInfoKey = UIResponder.keyboardFrameEndUserInfoKey
+            if let keyboardFrame = info[frameEndUserInfoKey] as? CGRect {
+                let diff = keyboardFrame.origin.y - centerObject.y - (self.activeTextField.frame.height / 2)
+                if diff < 0 {
+                    selfFrameOriginYDiff = diff
+                    self.frame.origin.y += selfFrameOriginYDiff
+                }
+            }
+        }
+    }
+    
+    @objc func keyboardWillHide(_ notification: Notification) {
+        self.frame.origin.y -= selfFrameOriginYDiff
+    }
+    
     // MARK: - Tap viewWindowCalendar
     @objc func tapViewWindowCalendar(gesture: UITapGestureRecognizer) {
         calendar?.removeFromSuperview()

二进制
iOSClient/Supporting Files/af.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ar.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ast.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/az.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/br.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/bs.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ca.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/da.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/de.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/el.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/en-GB.lproj/Localizable.strings


+ 2 - 14
iOSClient/Supporting Files/en.lproj/Localizable.strings

@@ -724,6 +724,7 @@
 "_error_path_"                          = "Unable to open this file or folder. Please make sure it exists";
 "_file_upload_not_exitst_"              = "The file that you want to upload does not exist";
 "_forbidden_characters_from_server_"    = "The name contains at least one invalid character";
+"_error_not_modified_"                  = "Resource not modified";
 "_not_connected_internet_"              = "Server connection error";
 "_not_possible_connect_to_server_"      = "It is not possible to connect to the server at this time";
 "_not_possible_create_folder_"          = "Folder could not be created";
@@ -801,17 +802,4 @@
 "_used_space_"              = "Used space";
 "_open_in_onlyoffice_"      = "Open in ONLYOFFICE";
 "_open_in_collabora_"       = "Open with Collabora Online";
-
-// ----------------------------------------------------------------------------------------------------------------------------------
-// IM
-
-"_textnote_"                = "Text note";
-"_audionote_"               = "Audio note";
-"_removeaudionote_"         = "Do you want delete the audio note?";
-"_detailpicture_"           = "Detail picture";
-"_creation_archive_error_"  = "Error while creating archive";
-"_read_audio_error_"        = "Error while reading audio file";
-"_create_audio_error_"      = "Error while creating audio file";
-"_create_image_error_"      = "Error while creating image file";
-"_error_open_file_"         = "Error while opening a file";
-"_new_background_im_"       = "Select an image or take a picture and use it as background. You can also select nothing. Press \"Done\" to complete.";
+"_login_address_detail_"    = "The link to your %@ web interface when you open it in the browser.";

二进制
iOSClient/Supporting Files/eo.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-419.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-AR.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-CL.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-CO.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-CR.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-DO.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-EC.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-GT.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-HN.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-MX.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-NI.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-PA.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-PE.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-PR.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-PY.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-SV.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es-UY.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/es.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/et_EE.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/eu.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/fa.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/fr.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/gl.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/he.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/hr.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/hu.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/hy.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ia.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/id.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/is.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/it.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/km.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/ko.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/lb.lproj/Localizable.strings


二进制
iOSClient/Supporting Files/lo.lproj/Localizable.strings


部分文件因为文件数量过多而无法显示