瀏覽代碼

Merge pull request #2462 from nextcloud/develop

Version 4.8.3
Marino Faggiana 1 年之前
父節點
當前提交
3f21ccdd98
共有 100 個文件被更改,包括 1066 次插入1907 次删除
  1. 1 0
      .swiftlint.yml
  2. 24 29
      Brand/NCBrand.swift
  3. 9 0
      ExternalResources/NCApplicationHandle.swift
  4. 6 5
      File Provider Extension/FileProviderData.swift
  5. 1 1
      File Provider Extension/FileProviderExtension+Thumbnail.swift
  6. 72 54
      Nextcloud.xcodeproj/project.pbxproj
  7. 0 54
      NextcloudTests/NCGlobalTests.swift
  8. 0 85
      NextcloudTests/ParallelWorkerTest.swift
  9. 0 136
      NextcloudTests/SharePermissionTest.swift
  10. 0 64
      NextcloudTests/UserAgentTests.swift
  11. 17 15
      Notification Service Extension/NotificationService.swift
  12. 3 0
      Share/NCShareExtension+DataSource.swift
  13. 4 2
      Widget/Dashboard/DashboardData.swift
  14. 1 1
      Widget/Files/FilesWidgetView.swift
  15. 4 2
      Widget/Lockscreen/LockscreenData.swift
  16. 1 1
      Widget/Toolbar/ToolbarWidgetView.swift
  17. 3 54
      iOSClient/Activity/NCActivityTableViewCell.swift
  18. 19 11
      iOSClient/AppDelegate.swift
  19. 0 10
      iOSClient/Data/NCDatabase.swift
  20. 0 75
      iOSClient/Data/NCElementsJSON.swift
  21. 136 0
      iOSClient/Data/NCManageDatabase+Capabilities.swift
  22. 26 13
      iOSClient/Data/NCManageDatabase+Metadata.swift
  23. 0 113
      iOSClient/Data/NCManageDatabase.swift
  24. 66 122
      iOSClient/Diagnostics/NCCapabilitiesView.swift
  25. 15 0
      iOSClient/Extensions/Data+Extension.swift
  26. 15 0
      iOSClient/Extensions/Optional+Extensions.swift
  27. 34 0
      iOSClient/Extensions/PHAsset+Extension.swift
  28. 67 0
      iOSClient/Extensions/UILabel+Extension.swift
  29. 15 0
      iOSClient/Extensions/View+Extension.swift
  30. 0 6
      iOSClient/Files/NCFiles.swift
  31. 1 1
      iOSClient/Images.xcassets/collabora.imageset/Contents.json
  32. 二進制
      iOSClient/Images.xcassets/collabora.imageset/collabora.pdf
  33. 8 0
      iOSClient/Images.xcassets/collabora.imageset/collabora.svg
  34. 1 1
      iOSClient/Images.xcassets/onlyoffice.imageset/Contents.json
  35. 0 101
      iOSClient/Images.xcassets/onlyoffice.imageset/onlyoffice.pdf
  36. 3 0
      iOSClient/Images.xcassets/onlyoffice.imageset/onlyoffice.svg
  37. 6 5
      iOSClient/Login/NCLogin.swift
  38. 23 9
      iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
  39. 0 6
      iOSClient/Main/Collection Common/NCGridCell.swift
  40. 11 23
      iOSClient/Main/Collection Common/NCListCell.swift
  41. 86 45
      iOSClient/Main/Collection Common/NCListCell.xib
  42. 27 11
      iOSClient/Main/Collection Common/NCSelectableNavigationView.swift
  43. 0 457
      iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift
  44. 39 70
      iOSClient/Main/Create cloud/NCUploadAssets.swift
  45. 77 6
      iOSClient/Main/NCActionCenter.swift
  46. 0 6
      iOSClient/Main/NCCellProtocol.swift
  47. 3 12
      iOSClient/Main/NCPickerViewController.swift
  48. 2 1
      iOSClient/Media/NCMedia.swift
  49. 3 4
      iOSClient/Menu/AppDelegate+Menu.swift
  50. 1 2
      iOSClient/Menu/NCCollectionViewCommon+Menu.swift
  51. 4 2
      iOSClient/Menu/NCContextMenu.swift
  52. 13 2
      iOSClient/Menu/NCMenuAction.swift
  53. 1 2
      iOSClient/Menu/UIViewController+Menu.swift
  54. 13 26
      iOSClient/More/NCMore.swift
  55. 41 4
      iOSClient/NCGlobal.swift
  56. 1 2
      iOSClient/Networking/E2EE/NCEndToEndMetadata.swift
  57. 1 3
      iOSClient/Networking/E2EE/NCNetworkingE2EE.swift
  58. 1 1
      iOSClient/Networking/NCAutoUpload.swift
  59. 2 4
      iOSClient/Networking/NCNetworkingCheckRemoteUser.swift
  60. 73 86
      iOSClient/Networking/NCService.swift
  61. 1 0
      iOSClient/Nextcloud-Bridging-Header.h
  62. 5 5
      iOSClient/Notification/NCNotification.storyboard
  63. 33 27
      iOSClient/Notification/NCNotification.swift
  64. 2 6
      iOSClient/Scan document/NCUploadScanDocument.swift
  65. 1 85
      iOSClient/Settings/CCManageAccount.m
  66. 8 10
      iOSClient/Settings/NCManageE2EE.swift
  67. 10 8
      iOSClient/Settings/NCSettings.m
  68. 6 6
      iOSClient/Share/Advanced/NCShareCells.swift
  69. 1 1
      iOSClient/Share/NCShare+Helper.swift
  70. 7 7
      iOSClient/Share/NCShare.storyboard
  71. 1 2
      iOSClient/Share/NCShare.swift
  72. 6 1
      iOSClient/Share/NCSharePaging.swift
  73. 2 2
      iOSClient/Shares/NCShares.swift
  74. 二進制
      iOSClient/Supporting Files/af.lproj/Localizable.strings
  75. 二進制
      iOSClient/Supporting Files/an.lproj/Localizable.strings
  76. 二進制
      iOSClient/Supporting Files/ar.lproj/Localizable.strings
  77. 二進制
      iOSClient/Supporting Files/ast.lproj/Localizable.strings
  78. 二進制
      iOSClient/Supporting Files/az.lproj/Localizable.strings
  79. 二進制
      iOSClient/Supporting Files/be.lproj/Localizable.strings
  80. 二進制
      iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings
  81. 二進制
      iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings
  82. 二進制
      iOSClient/Supporting Files/br.lproj/Localizable.strings
  83. 二進制
      iOSClient/Supporting Files/bs.lproj/Localizable.strings
  84. 二進制
      iOSClient/Supporting Files/ca.lproj/Localizable.strings
  85. 二進制
      iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings
  86. 二進制
      iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings
  87. 二進制
      iOSClient/Supporting Files/da.lproj/Localizable.strings
  88. 二進制
      iOSClient/Supporting Files/de.lproj/Localizable.strings
  89. 二進制
      iOSClient/Supporting Files/el.lproj/Localizable.strings
  90. 二進制
      iOSClient/Supporting Files/en-GB.lproj/Localizable.strings
  91. 3 2
      iOSClient/Supporting Files/en.lproj/Localizable.strings
  92. 二進制
      iOSClient/Supporting Files/eo.lproj/Localizable.strings
  93. 二進制
      iOSClient/Supporting Files/es-419.lproj/Localizable.strings
  94. 二進制
      iOSClient/Supporting Files/es-AR.lproj/Localizable.strings
  95. 二進制
      iOSClient/Supporting Files/es-CL.lproj/Localizable.strings
  96. 二進制
      iOSClient/Supporting Files/es-CO.lproj/Localizable.strings
  97. 二進制
      iOSClient/Supporting Files/es-CR.lproj/Localizable.strings
  98. 二進制
      iOSClient/Supporting Files/es-DO.lproj/Localizable.strings
  99. 二進制
      iOSClient/Supporting Files/es-EC.lproj/Localizable.strings
  100. 二進制
      iOSClient/Supporting Files/es-GT.lproj/Localizable.strings

+ 1 - 0
.swiftlint.yml

@@ -72,6 +72,7 @@ excluded:
   - iOSClient/Data/NCDataSource.swift
   - iOSClient/Data/NCDatabase.swift
   - iOSClient/Data/NCElementsJSON.swift
+  - iOSClient/Data/NCManageDatabase+Capabilities.swift
   - iOSClient/Data/NCManageDatabase+Account.swift
   - iOSClient/Data/NCManageDatabase+Activity.swift
   - iOSClient/Data/NCManageDatabase+Avatar.swift

+ 24 - 29
Brand/NCBrand.swift

@@ -251,46 +251,41 @@ class NCBrandColor: NSObject {
 
         if NCBrandOptions.shared.use_themingColor {
 
-            if let themingColor = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesThemingColor),
-               let themingColorElement = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesThemingColorElement),
-               let themingColorText = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesThemingColorText) {
-
-                self.themingColor = themingColor
-                self.themingColorElement = themingColorElement
-                self.themingColorText = themingColorText
-                
-                // COLOR
-                if themingColor.first == "#" {
-                    if let color = UIColor(hex: themingColor) {
-                        brand = color
-                    } else {
-                        brand = customer
-                    }
+            self.themingColor = NCGlobal.shared.capabilityThemingColor
+            self.themingColorElement = NCGlobal.shared.capabilityThemingColorElement
+            self.themingColorText = NCGlobal.shared.capabilityThemingColorText
+
+            // COLOR
+            if themingColor.first == "#" {
+                if let color = UIColor(hex: themingColor) {
+                    brand = color
                 } else {
                     brand = customer
                 }
+            } else {
+                brand = customer
+            }
 
-                // COLOR TEXT
-                if themingColorText.first == "#" {
-                    if let color = UIColor(hex: themingColorText) {
-                        brandText = color
-                    } else {
-                        brandText = customerText
-                    }
+            // COLOR TEXT
+            if themingColorText.first == "#" {
+                if let color = UIColor(hex: themingColorText) {
+                    brandText = color
                 } else {
                     brandText = customerText
                 }
+            } else {
+                brandText = customerText
+            }
 
-                // COLOR ELEMENT
-                if themingColorElement.first == "#" {
-                    if let color = UIColor(hex: themingColorElement) {
-                        brandElement = color
-                    } else {
-                        brandElement = brand
-                    }
+            // COLOR ELEMENT
+            if themingColorElement.first == "#" {
+                if let color = UIColor(hex: themingColorElement) {
+                    brandElement = color
                 } else {
                     brandElement = brand
                 }
+            } else {
+                brandElement = brand
             }
 
             if brandElement.isTooLight() {

+ 9 - 0
ExternalResources/NCApplicationHandle.swift

@@ -30,6 +30,11 @@ class NCApplicationHandle: NSObject {
 
     let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
 
+    // class: AppDelegate
+    // func nextcloudPushNotificationAction(data: [String: AnyObject])
+    func nextcloudPushNotificationAction(data: [String: AnyObject]) {
+    }
+
     // class: AppDelegate
     // func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void)
     func applicationOpenUserActivity(_ userActivity: NSUserActivity) -> Bool {
@@ -78,4 +83,8 @@ class NCApplicationHandle: NSObject {
     func filterPages(pages: [NCBrandOptions.NCInfoPagingTab], page: NCBrandOptions.NCInfoPagingTab, metadata: tableMetadata) -> ([NCBrandOptions.NCInfoPagingTab], NCBrandOptions.NCInfoPagingTab) {
         return (pages, page)
     }
+
+    // class: NCNotification
+    func didSelectNotification(_ notification: NKNotifications, viewController: UIViewController) {
+    }
 }

+ 6 - 5
File Provider Extension/FileProviderData.swift

@@ -84,7 +84,6 @@ class fileProviderData: NSObject {
         if domain == nil {
 
             guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return nil }
-            let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: activeAccount.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
 
             account = activeAccount.account
             user = activeAccount.user
@@ -92,7 +91,9 @@ class fileProviderData: NSObject {
             accountUrlBase = activeAccount.urlBase
             homeServerUrl = NCUtilityFileSystem.shared.getHomeServer(urlBase: activeAccount.urlBase, userId: activeAccount.userId)
 
-            NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), nextcloudVersion: serverVersionMajor, delegate: NCNetworking.shared)
+            NCManageDatabase.shared.setCapabilities(account: account)
+
+            NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor, delegate: NCNetworking.shared)
             NCNetworking.shared.delegate = providerExtension as? NCNetworkingDelegate
 
             return tableAccount.init(value: activeAccount)
@@ -108,15 +109,15 @@ class fileProviderData: NSObject {
             let accountDomain = activeAccount.userId + " (" + host + ")"
             if accountDomain == domain!.identifier.rawValue {
 
-                let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: activeAccount.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
-
                 account = activeAccount.account
                 user = activeAccount.user
                 userId = activeAccount.userId
                 accountUrlBase = activeAccount.urlBase
                 homeServerUrl = NCUtilityFileSystem.shared.getHomeServer(urlBase: activeAccount.urlBase, userId: activeAccount.userId)
 
-                NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), nextcloudVersion: serverVersionMajor, delegate: NCNetworking.shared)
+                NCManageDatabase.shared.setCapabilities(account: account)
+
+                NextcloudKit.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor, delegate: NCNetworking.shared)
                 NCNetworking.shared.delegate = providerExtension as? NCNetworkingDelegate
 
                 return tableAccount.init(value: activeAccount)

+ 1 - 1
File Provider Extension/FileProviderExtension+Thumbnail.swift

@@ -47,7 +47,7 @@ extension FileProviderExtension {
 
                 if let urlBase = metadata.urlBase.urlEncoded,
                    let fileNamePath = fileNamePath.urlEncoded,
-                   let url = URL(string: "\(urlBase)/index.php/core/preview.png?file=\(fileNamePath)&x=\(size)&y=\(size)&a=1&mode=cover") {
+                   let url = URL(string: "\(urlBase)/index.php/core/preview.png?file=\(fileNamePath)&x=\(size.width)&y=\(size.height)&a=1&mode=cover") {
 
                     NextcloudKit.shared.getPreview(url: url) { _, data, error in
                         if error == .success && data != nil {

+ 72 - 54
Nextcloud.xcodeproj/project.pbxproj

@@ -29,8 +29,6 @@
 		AF2D7C7C2742556F00ADF566 /* NCShareLinkCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2D7C7B2742556F00ADF566 /* NCShareLinkCell.swift */; };
 		AF2D7C7E2742559100ADF566 /* NCShareUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */; };
 		AF36077127BFA4E8001A243D /* ParallelWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF36077027BFA4E8001A243D /* ParallelWorker.swift */; };
-		AF36077627BFB019001A243D /* ParallelWorkerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF36077527BFB019001A243D /* ParallelWorkerTest.swift */; };
-		AF3F909A28213BEA0048A93E /* UserAgentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF3F909928213BEA0048A93E /* UserAgentTests.swift */; };
 		AF3FDCC22796ECC300710F60 /* NCTrash+CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF3FDCC12796ECC300710F60 /* NCTrash+CollectionView.swift */; };
 		AF3FDCC32796F3FB00710F60 /* NCTrashListCell+NCTrashCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78ACD4821903F850088454D /* NCTrashListCell+NCTrashCellProtocol.swift */; };
 		AF4BF614275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; };
@@ -47,7 +45,6 @@
 		AF4BF62127562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */; };
 		AF56C1DC2784856200D8BAE2 /* NCActivityCommentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AF56C1DB2784856200D8BAE2 /* NCActivityCommentView.xib */; };
 		AF68326A27BE65A90010BF0B /* NCMenuAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF68326927BE65A90010BF0B /* NCMenuAction.swift */; };
-		AF70C14D27F3484D00E13DF2 /* SharePermissionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF70C14C27F3484D00E13DF2 /* SharePermissionTest.swift */; };
 		AF730AF827834B1400B7520E /* NCShare+NCCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF730AF727834B1400B7520E /* NCShare+NCCellDelegate.swift */; };
 		AF730AFA27843E4C00B7520E /* NCShareExtension+NCDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF730AF927843E4C00B7520E /* NCShareExtension+NCDelegate.swift */; };
 		AF7E504E27A2D8FF00B5E4AF /* UIBarButton+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF7E504D27A2D8FF00B5E4AF /* UIBarButton+Extension.swift */; };
@@ -57,7 +54,6 @@
 		AF817EF3274BC781009ED85B /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; };
 		AF817EF4274BC781009ED85B /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; };
 		AF8ED1FC2757821000B8DBC4 /* NextcloudTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */; };
-		AF8ED2032757822700B8DBC4 /* NCGlobalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */; };
 		AF93471227E2341B002537EE /* NCShare+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93471127E2341B002537EE /* NCShare+Menu.swift */; };
 		AF93471927E2361E002537EE /* NCShareAdvancePermissionFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = AF93471427E2361E002537EE /* NCShareAdvancePermissionFooter.xib */; };
 		AF93471A27E2361E002537EE /* NCShareAdvancePermissionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93471527E2361E002537EE /* NCShareAdvancePermissionHeader.swift */; };
@@ -75,6 +71,20 @@
 		AFD33240276A02C100F5AE02 /* UIApplication+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD3323F276A02C000F5AE02 /* UIApplication+Extension.swift */; };
 		D575039F27146F93008DC9DC /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; };
 		D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; };
+		F343A4B32A1E01FF00DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
+		F343A4B42A1E084100DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
+		F343A4B52A1E084200DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
+		F343A4B62A1E084200DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
+		F343A4B72A1E084300DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
+		F343A4B82A1E084300DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
+		F343A4B92A1E084400DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
+		F343A4BB2A1E734600DDA874 /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extensions.swift */; };
+		F343A4BC2A1E734600DDA874 /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extensions.swift */; };
+		F343A4BD2A1E734600DDA874 /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extensions.swift */; };
+		F343A4BE2A1E734600DDA874 /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extensions.swift */; };
+		F343A4BF2A1E734600DDA874 /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extensions.swift */; };
+		F343A4C02A1E734600DDA874 /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extensions.swift */; };
+		F343A4C12A1E734600DDA874 /* Optional+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extensions.swift */; };
 		F700222C1EC479840080073F /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; };
 		F700222D1EC479840080073F /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; };
 		F700510122DF63AC003A3356 /* NCShare.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F700510022DF63AC003A3356 /* NCShare.storyboard */; };
@@ -199,11 +209,8 @@
 		F73B422C2476764F00A30FD3 /* NCNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73B422A2476764F00A30FD3 /* NCNotification.swift */; };
 		F73CB3B222E072A000AD728E /* NCShareHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F73CB3B122E072A000AD728E /* NCShareHeaderView.xib */; };
 		F73D11FA253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F73D11F9253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard */; };
-		F73D5E47246DE09200DF6467 /* NCElementsJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */; };
-		F73D5E48246DE09200DF6467 /* NCElementsJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */; };
-		F73D5E49246DE09200DF6467 /* NCElementsJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */; };
-		F73D5E4A246DE09200DF6467 /* NCElementsJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */; };
 		F73F537F1E929C8500F8678D /* NCMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73F537E1E929C8500F8678D /* NCMore.swift */; };
+		F740BEF02A35C2AD00E9B6D5 /* UILabel+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7EE66AC2A20B226009AE765 /* UILabel+Extension.swift */; };
 		F7434B3420E23FD700417916 /* NCDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB41ED5A87C00B7EAD4 /* NCDatabase.swift */; };
 		F7434B3620E23FE000417916 /* NCManageDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */; };
 		F7434B3820E2400600417916 /* NCBrand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */; };
@@ -224,7 +231,6 @@
 		F7490E7629882BF3009DCE94 /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; };
 		F7490E7729882C10009DCE94 /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */; };
 		F7490E7829882C28009DCE94 /* NCUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70BFC7320E0FA7C00C67599 /* NCUtility.swift */; };
-		F7490E7929882C2F009DCE94 /* NCElementsJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */; };
 		F7490E7E29882C6E009DCE94 /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; };
 		F7490E7F29882C73009DCE94 /* NCManageDatabase+Activity.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */; };
 		F7490E8029882C76009DCE94 /* NCManageDatabase+Avatar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F749B650297B0F2400087535 /* NCManageDatabase+Avatar.swift */; };
@@ -240,7 +246,6 @@
 		F7490E8C29882D02009DCE94 /* CCUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = F7053E3D1C639DF500741EA5 /* CCUtility.m */; };
 		F7490E8D29882F5B009DCE94 /* Custom.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F700222B1EC479840080073F /* Custom.xcassets */; };
 		F7490E8E2988334A009DCE94 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F7E70DE91A24DE4100E1B66A /* Localizable.strings */; };
-		F7490E902988F0C2009DCE94 /* NCCreateFormUploadAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7490E8F2988F0C2009DCE94 /* NCCreateFormUploadAssets.swift */; };
 		F749B64A297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = F749B649297B0CBB00087535 /* NCManageDatabase+Share.swift */; };
 		F749B64B297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = F749B649297B0CBB00087535 /* NCManageDatabase+Share.swift */; };
 		F749B64C297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = F749B649297B0CBB00087535 /* NCManageDatabase+Share.swift */; };
@@ -299,6 +304,13 @@
 		F761856B29E98543006EB3B0 /* NCIntroViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761856729E98543006EB3B0 /* NCIntroViewController.swift */; };
 		F761856C29E98543006EB3B0 /* NCIntroCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761856829E98543006EB3B0 /* NCIntroCollectionViewCell.swift */; };
 		F761856D29E98543006EB3B0 /* NCIntroCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F761856929E98543006EB3B0 /* NCIntroCollectionViewCell.xib */; };
+		F763D29D2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */; };
+		F763D29E2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */; };
+		F763D29F2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */; };
+		F763D2A02A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */; };
+		F763D2A12A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */; };
+		F763D2A22A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */; };
+		F763D2A32A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */; };
 		F7651A8A23A2A3F2001403D2 /* NCCreateFormUploadDocuments.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7651A8823A2A3F2001403D2 /* NCCreateFormUploadDocuments.storyboard */; };
 		F7651A8B23A2A3F2001403D2 /* NCCreateFormUploadDocuments.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7651A8923A2A3F2001403D2 /* NCCreateFormUploadDocuments.swift */; };
 		F765608F23BF813600765969 /* NCContentPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F765608E23BF813500765969 /* NCContentPresenter.swift */; };
@@ -395,7 +407,6 @@
 		F78302F928B4C3E600B84583 /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; };
 		F78302FA28B4C3EA00B84583 /* NCManageDatabase+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */; };
 		F78302FB28B4C3EE00B84583 /* NCManageDatabase+Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E98C1527E0D0FC001F9F19 /* NCManageDatabase+Video.swift */; };
-		F78302FC28B4C3F300B84583 /* NCElementsJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */; };
 		F78302FD28B4C42B00B84583 /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; };
 		F78302FE28B4C44700B84583 /* NCBrand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */; };
 		F78302FF28B4C45000B84583 /* NCUtilityFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */; };
@@ -488,7 +499,6 @@
 		F7A8D73828F17E21008BBE1C /* NCManageDatabase+DashboardWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D68FCB28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift */; };
 		F7A8D73928F17E25008BBE1C /* NCManageDatabase+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */; };
 		F7A8D73A28F17E28008BBE1C /* NCManageDatabase+Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E98C1527E0D0FC001F9F19 /* NCManageDatabase+Video.swift */; };
-		F7A8D73B28F17E2C008BBE1C /* NCElementsJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */; };
 		F7A8D73C28F181BC008BBE1C /* NCBrand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */; };
 		F7A8D73D28F181D3008BBE1C /* NCUtilityFileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */; };
 		F7A8D73E28F181E2008BBE1C /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; };
@@ -578,6 +588,7 @@
 		F7EDE509262DA9D600414FE6 /* NCSelectCommandViewSelect.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7EDE508262DA9D600414FE6 /* NCSelectCommandViewSelect.xib */; };
 		F7EDE514262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7EDE513262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib */; };
 		F7EDE51B262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7EDE51A262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib */; };
+		F7EE66AD2A20B226009AE765 /* UILabel+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7EE66AC2A20B226009AE765 /* UILabel+Extension.swift */; };
 		F7EFA47825ADBA500083159A /* NCViewerProviderContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7EFA47725ADBA500083159A /* NCViewerProviderContextMenu.swift */; };
 		F7EFC0C6256BC77700461AAD /* NCMoreUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7EFC0C5256BC77700461AAD /* NCMoreUserCell.xib */; };
 		F7EFC0CD256BF8DD00461AAD /* NCUserStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7EFC0CC256BF8DD00461AAD /* NCUserStatus.swift */; };
@@ -705,15 +716,12 @@
 		AF2D7C7B2742556F00ADF566 /* NCShareLinkCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareLinkCell.swift; sourceTree = "<group>"; };
 		AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareUserCell.swift; sourceTree = "<group>"; };
 		AF36077027BFA4E8001A243D /* ParallelWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallelWorker.swift; sourceTree = "<group>"; };
-		AF36077527BFB019001A243D /* ParallelWorkerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallelWorkerTest.swift; sourceTree = "<group>"; };
-		AF3F909928213BEA0048A93E /* UserAgentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentTests.swift; sourceTree = "<group>"; };
 		AF3FDCC12796ECC300710F60 /* NCTrash+CollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCTrash+CollectionView.swift"; sourceTree = "<group>"; };
 		AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Account.swift"; sourceTree = "<group>"; };
 		AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Metadata.swift"; sourceTree = "<group>"; };
 		AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Activity.swift"; sourceTree = "<group>"; };
 		AF56C1DB2784856200D8BAE2 /* NCActivityCommentView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCActivityCommentView.xib; sourceTree = "<group>"; };
 		AF68326927BE65A90010BF0B /* NCMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMenuAction.swift; sourceTree = "<group>"; };
-		AF70C14C27F3484D00E13DF2 /* SharePermissionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharePermissionTest.swift; sourceTree = "<group>"; };
 		AF730AF727834B1400B7520E /* NCShare+NCCellDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+NCCellDelegate.swift"; sourceTree = "<group>"; };
 		AF730AF927843E4C00B7520E /* NCShareExtension+NCDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShareExtension+NCDelegate.swift"; sourceTree = "<group>"; };
 		AF7E504D27A2D8FF00B5E4AF /* UIBarButton+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIBarButton+Extension.swift"; sourceTree = "<group>"; };
@@ -721,7 +729,6 @@
 		AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCUserBaseUrl.swift; sourceTree = "<group>"; };
 		AF8ED1F92757821000B8DBC4 /* NextcloudTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudTests.swift; sourceTree = "<group>"; };
-		AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCGlobalTests.swift; sourceTree = "<group>"; };
 		AF93471127E2341B002537EE /* NCShare+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Menu.swift"; sourceTree = "<group>"; };
 		AF93471427E2361E002537EE /* NCShareAdvancePermissionFooter.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareAdvancePermissionFooter.xib; sourceTree = "<group>"; };
 		AF93471527E2361E002537EE /* NCShareAdvancePermissionHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShareAdvancePermissionHeader.swift; sourceTree = "<group>"; };
@@ -738,6 +745,8 @@
 		AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = "<group>"; };
 		AFD3323F276A02C000F5AE02 /* UIApplication+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Extension.swift"; sourceTree = "<group>"; };
 		D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = "<group>"; };
+		F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PHAsset+Extension.swift"; sourceTree = "<group>"; };
+		F343A4BA2A1E734600DDA874 /* Optional+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extensions.swift"; sourceTree = "<group>"; };
 		F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = "<group>"; };
 		F700510022DF63AC003A3356 /* NCShare.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShare.storyboard; sourceTree = "<group>"; };
 		F700510222DF6897003A3356 /* Parchment.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Parchment.framework; path = Carthage/Build/iOS/Parchment.framework; sourceTree = "<group>"; };
@@ -886,14 +895,12 @@
 		F73CB3B122E072A000AD728E /* NCShareHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCShareHeaderView.xib; sourceTree = "<group>"; };
 		F73CB5771ED46807005F2A5A /* NCBridgeSwift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NCBridgeSwift.h; sourceTree = "<group>"; };
 		F73D11F9253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCViewerNextcloudText.storyboard; sourceTree = "<group>"; };
-		F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCElementsJSON.swift; sourceTree = "<group>"; };
 		F73F537E1E929C8500F8678D /* NCMore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCMore.swift; sourceTree = "<group>"; };
 		F7421EAE2294044B00C4B7C1 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
 		F7434B5F20E2440600417916 /* FileProviderExtension-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FileProviderExtension-Bridging-Header.h"; sourceTree = "<group>"; };
 		F745B250222D871800346520 /* QRCodeReader.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QRCodeReader.framework; path = Carthage/Build/iOS/QRCodeReader.framework; sourceTree = "<group>"; };
 		F745B252222D88AE00346520 /* NCLoginQRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCLoginQRCode.swift; sourceTree = "<group>"; };
 		F747BA1E22354D2000971601 /* NCCreateFormUploadVoiceNote.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCCreateFormUploadVoiceNote.storyboard; sourceTree = "<group>"; };
-		F7490E8F2988F0C2009DCE94 /* NCCreateFormUploadAssets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCCreateFormUploadAssets.swift; sourceTree = "<group>"; };
 		F749B649297B0CBB00087535 /* NCManageDatabase+Share.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Share.swift"; sourceTree = "<group>"; };
 		F749B650297B0F2400087535 /* NCManageDatabase+Avatar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Avatar.swift"; sourceTree = "<group>"; };
 		F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCUtilityFileSystem.swift; sourceTree = "<group>"; };
@@ -936,6 +943,7 @@
 		F761856729E98543006EB3B0 /* NCIntroViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCIntroViewController.swift; sourceTree = "<group>"; };
 		F761856829E98543006EB3B0 /* NCIntroCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCIntroCollectionViewCell.swift; sourceTree = "<group>"; };
 		F761856929E98543006EB3B0 /* NCIntroCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCIntroCollectionViewCell.xib; sourceTree = "<group>"; };
+		F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Capabilities.swift"; sourceTree = "<group>"; };
 		F7651A8823A2A3F2001403D2 /* NCCreateFormUploadDocuments.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCCreateFormUploadDocuments.storyboard; sourceTree = "<group>"; };
 		F7651A8923A2A3F2001403D2 /* NCCreateFormUploadDocuments.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCCreateFormUploadDocuments.swift; sourceTree = "<group>"; };
 		F765608623BF806C00765969 /* QuickLayout.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLayout.framework; path = Carthage/Build/iOS/QuickLayout.framework; sourceTree = "<group>"; };
@@ -1222,6 +1230,7 @@
 		F7EDE508262DA9D600414FE6 /* NCSelectCommandViewSelect.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCSelectCommandViewSelect.xib; sourceTree = "<group>"; };
 		F7EDE513262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "NCSelectCommandViewSelect+CreateFolder.xib"; sourceTree = "<group>"; };
 		F7EDE51A262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCSelectCommandViewCopyMove.xib; sourceTree = "<group>"; };
+		F7EE66AC2A20B226009AE765 /* UILabel+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Extension.swift"; sourceTree = "<group>"; };
 		F7EFA47725ADBA500083159A /* NCViewerProviderContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCViewerProviderContextMenu.swift; sourceTree = "<group>"; };
 		F7EFC0C5256BC77700461AAD /* NCMoreUserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCMoreUserCell.xib; sourceTree = "<group>"; };
 		F7EFC0CC256BF8DD00461AAD /* NCUserStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCUserStatus.swift; sourceTree = "<group>"; };
@@ -1394,10 +1403,6 @@
 		AF8ED1FA2757821000B8DBC4 /* NextcloudTests */ = {
 			isa = PBXGroup;
 			children = (
-				AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */,
-				AF36077527BFB019001A243D /* ParallelWorkerTest.swift */,
-				AF70C14C27F3484D00E13DF2 /* SharePermissionTest.swift */,
-				AF3F909928213BEA0048A93E /* UserAgentTests.swift */,
 				AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */,
 			);
 			path = NextcloudTests;
@@ -1729,9 +1734,9 @@
 			isa = PBXGroup;
 			children = (
 				F76D3CF42428D0C0005DFA87 /* NCViewerPDF.storyboard */,
-				F76D3CF22428B94E005DFA87 /* NCViewerPDFSearchCell.xib */,
 				F710D1F42405770F00A6033D /* NCViewerPDF.swift */,
 				F76D3CF02428B40E005DFA87 /* NCViewerPDFSearch.swift */,
+				F76D3CF22428B94E005DFA87 /* NCViewerPDFSearchCell.xib */,
 			);
 			path = NCViewerPDF;
 			sourceTree = "<group>";
@@ -1871,30 +1876,33 @@
 		F7A0D14E259229FA008F8A13 /* Extensions */ = {
 			isa = PBXGroup;
 			children = (
+				F7AC1CAF28AB94490032D99F /* Array+Extension.swift */,
+				F7817CF729801A3500FFBC65 /* Data+Extension.swift */,
+				AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */,
 				F70460512499061800BB98A7 /* NotificationCenter+MainThread.swift */,
 				F79B869A265E19D40085C0E0 /* NSMutableAttributedString+Extension.swift */,
 				F78071071EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.h */,
 				F78071081EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.m */,
+				F343A4BA2A1E734600DDA874 /* Optional+Extensions.swift */,
+				F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */,
 				F7A0D1342591FBC5008F8A13 /* String+Extension.swift */,
-				F7817CF729801A3500FFBC65 /* Data+Extension.swift */,
-				AFD3323F276A02C000F5AE02 /* UIApplication+Extension.swift */,
-				AFCE353227E4ED1900FEA6C2 /* UIToolbar+Extension.swift */,
 				AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */,
-				AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */,
+				AFD3323F276A02C000F5AE02 /* UIApplication+Extension.swift */,
 				AF7E504D27A2D8FF00B5E4AF /* UIBarButton+Extension.swift */,
 				F70CEF5523E9C7E50007035B /* UIColor+Extension.swift */,
 				F79B645F26CA661600838ACA /* UIControl+Extension.swift */,
-				F7AC1CAF28AB94490032D99F /* Array+Extension.swift */,
 				F7F4F10F27ECDC4A008676F9 /* UIDevice+Extension.swift */,
-				F77BB747289985270090FC19 /* UITabBarController+Extension.swift */,
-				F77BB745289984CA0090FC19 /* UIViewController+Extension.swift */,
-				F77BB7492899857B0090FC19 /* UINavigationController+Extension.swift */,
 				F7F4F11127ECDC52008676F9 /* UIFont+Extension.swift */,
-				F7E41315294A19B300839300 /* UIView+Extension.swift */,
-				F7E8A390295DC5E0006CB2D0 /* View+Extension.swift */,
 				F713FEFE2472764000214AF6 /* UIImage+animatedGIF.h */,
 				F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */,
 				F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */,
+				F77BB7492899857B0090FC19 /* UINavigationController+Extension.swift */,
+				F77BB747289985270090FC19 /* UITabBarController+Extension.swift */,
+				AFCE353227E4ED1900FEA6C2 /* UIToolbar+Extension.swift */,
+				F7E41315294A19B300839300 /* UIView+Extension.swift */,
+				F77BB745289984CA0090FC19 /* UIViewController+Extension.swift */,
+				F7E8A390295DC5E0006CB2D0 /* View+Extension.swift */,
+				F7EE66AC2A20B226009AE765 /* UILabel+Extension.swift */,
 			);
 			path = Extensions;
 			sourceTree = "<group>";
@@ -1958,11 +1966,11 @@
 			children = (
 				F7BAADB41ED5A87C00B7EAD4 /* NCDatabase.swift */,
 				F7C1EEA425053A9C00866ACC /* NCDataSource.swift */,
-				F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */,
 				F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */,
 				AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */,
 				AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */,
 				F749B650297B0F2400087535 /* NCManageDatabase+Avatar.swift */,
+				F763D29C2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift */,
 				F7D68FCB28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift */,
 				F78A10BE29322E8A008499B8 /* NCManageDatabase+Directory.swift */,
 				F72FD3B4297ED49A00075D28 /* NCManageDatabase+E2EE.swift */,
@@ -2107,7 +2115,6 @@
 			isa = PBXGroup;
 			children = (
 				F769CA162965AB7C00039397 /* NCUploadAssets.swift */,
-				F7490E8F2988F0C2009DCE94 /* NCCreateFormUploadAssets.swift */,
 				F704B5E22430AA6F00632F5F /* NCCreateFormUploadConflict.storyboard */,
 				F704B5E42430AA8000632F5F /* NCCreateFormUploadConflict.swift */,
 				F704B5E82430C0B800632F5F /* NCCreateFormUploadConflictCell.swift */,
@@ -2935,6 +2942,7 @@
 				F7E98C1927E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				2C1D5D7623E2DE3300334ABB /* NCManageDatabase.swift in Sources */,
 				F7D68FD028CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
+				F343A4C12A1E734600DDA874 /* Optional+Extensions.swift in Sources */,
 				F7245927289BB59300474787 /* ThreadSafeDictionary.swift in Sources */,
 				2C33C48223E2C475005F963B /* NotificationService.swift in Sources */,
 				AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */,
@@ -2943,7 +2951,6 @@
 				D575039F27146F93008DC9DC /* String+Extension.swift in Sources */,
 				F769CA1A2966EA3C00039397 /* ComponentView.swift in Sources */,
 				F757CC8829E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
-				F73D5E4A246DE09200DF6467 /* NCElementsJSON.swift in Sources */,
 				F79B646326CA661600838ACA /* UIControl+Extension.swift in Sources */,
 				F78A10C429322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */,
 				F75CA1482962F13700B01130 /* HUDView.swift in Sources */,
@@ -2952,6 +2959,8 @@
 				F78E2D6B29AF02DB0024D4F3 /* Database.swift in Sources */,
 				F7817CFF29802D1A00FFBC65 /* NCPushNotificationEncryption.m in Sources */,
 				F798F0EC2588060A000DAFFD /* UIColor+Extension.swift in Sources */,
+				F343A4B92A1E084400DDA874 /* PHAsset+Extension.swift in Sources */,
+				F763D2A32A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F749B656297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
 				F782FDC424E6933900666099 /* NCUtility.swift in Sources */,
 			);
@@ -2961,11 +2970,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				AF70C14D27F3484D00E13DF2 /* SharePermissionTest.swift in Sources */,
-				AF3F909A28213BEA0048A93E /* UserAgentTests.swift in Sources */,
-				AF36077627BFB019001A243D /* ParallelWorkerTest.swift in Sources */,
 				AF8ED1FC2757821000B8DBC4 /* NextcloudTests.swift in Sources */,
-				AF8ED2032757822700B8DBC4 /* NCGlobalTests.swift in Sources */,
 				F78E2D6C29AF02DB0024D4F3 /* Database.swift in Sources */,
 				F7817CFE29801A3500FFBC65 /* Data+Extension.swift in Sources */,
 			);
@@ -2978,11 +2983,14 @@
 				F7490E8329882C84009DCE94 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F7490E7629882BF3009DCE94 /* NCUserBaseUrl.swift in Sources */,
 				F7490E8029882C76009DCE94 /* NCManageDatabase+Avatar.swift in Sources */,
+				F343A4B82A1E084300DDA874 /* PHAsset+Extension.swift in Sources */,
 				F78E2D6A29AF02DB0024D4F3 /* Database.swift in Sources */,
 				F7490E7429882BCC009DCE94 /* NCManageDatabase.swift in Sources */,
 				F7490E6E29882B56009DCE94 /* NCBrand.swift in Sources */,
 				F7490E8129882C79009DCE94 /* NCManageDatabase+DashboardWidget.swift in Sources */,
 				F7490E8629882C99009DCE94 /* NCUtilityFileSystem.swift in Sources */,
+				F763D2A22A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
+				F343A4C02A1E734600DDA874 /* Optional+Extensions.swift in Sources */,
 				F7490E8529882C8C009DCE94 /* NCManageDatabase+Video.swift in Sources */,
 				F7490E8C29882D02009DCE94 /* CCUtility.m in Sources */,
 				F7490E7729882C10009DCE94 /* UIColor+Extension.swift in Sources */,
@@ -2995,7 +3003,6 @@
 				F7490E6C29882AEA009DCE94 /* String+Extension.swift in Sources */,
 				F7490E6B29882A92009DCE94 /* NCGlobal.swift in Sources */,
 				F7490E7529882BE2009DCE94 /* NCManageDatabase+Directory.swift in Sources */,
-				F7490E7929882C2F009DCE94 /* NCElementsJSON.swift in Sources */,
 				F7490E8729882CA8009DCE94 /* ThreadSafeDictionary.swift in Sources */,
 				F757CC8729E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F7490E8229882C80009DCE94 /* NCManageDatabase+E2EE.swift in Sources */,
@@ -3009,7 +3016,6 @@
 			buildActionMask = 2147483647;
 			files = (
 				F7245925289BB59100474787 /* ThreadSafeDictionary.swift in Sources */,
-				F73D5E48246DE09200DF6467 /* NCElementsJSON.swift in Sources */,
 				F7EDE4E5262D7BBE00414FE6 /* NCSectionHeaderFooter.swift in Sources */,
 				F7BF9D852934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F79EC78926316AC4004E59D6 /* NCPopupViewController.swift in Sources */,
@@ -3019,12 +3025,14 @@
 				F7A0D1362591FBC5008F8A13 /* String+Extension.swift in Sources */,
 				F7EDE4D6262D7B9600414FE6 /* NCListCell.swift in Sources */,
 				F7707687263A853700A1BA94 /* NCContentPresenter.swift in Sources */,
+				F343A4B62A1E084200DDA874 /* PHAsset+Extension.swift in Sources */,
 				F70460532499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F70BFC7520E0FA7D00C67599 /* NCUtility.swift in Sources */,
 				AF22B20C277C6F4D00DAB0CC /* NCShareCell.swift in Sources */,
 				F7E98C1727E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				F79B646126CA661600838ACA /* UIControl+Extension.swift in Sources */,
 				F77C973A2953143A00FDDD09 /* NCCameraRoll.swift in Sources */,
+				F740BEF02A35C2AD00E9B6D5 /* UILabel+Extension.swift in Sources */,
 				F7EDE4CC262D7B6F00414FE6 /* NCEmptyDataSet.swift in Sources */,
 				F7C30E01291BD2610017149B /* NCNetworkingE2EERename.swift in Sources */,
 				AF4BF61A27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
@@ -3042,6 +3050,7 @@
 				F7F878AF1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */,
 				AF22B218277D196700DAB0CC /* NCShareExtension+Files.swift in Sources */,
 				F702F2D025EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
+				F343A4BE2A1E734600DDA874 /* Optional+Extensions.swift in Sources */,
 				F7EDE4DB262D7BA200414FE6 /* NCCellProtocol.swift in Sources */,
 				F7EDE4D1262D7B8400414FE6 /* NCDataSource.swift in Sources */,
 				F71459D21D12E3B700CAFEEC /* CCUtility.m in Sources */,
@@ -3052,6 +3061,7 @@
 				F7EDE4E0262D7BAF00414FE6 /* NCGridCell.swift in Sources */,
 				F7A76DC8256A71CD00119AB3 /* UIImage+Extension.swift in Sources */,
 				F7B8CD96261AF401007C1359 /* NCNetworkingChunkedUpload.swift in Sources */,
+				F763D2A02A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F757CC8529E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F7BAADC91ED5A87C00B7EAD4 /* NCDatabase.swift in Sources */,
 				F7817D0129802D5F00FFBC65 /* NCViewCertificateDetails.swift in Sources */,
@@ -3093,6 +3103,7 @@
 				F78302FE28B4C44700B84583 /* NCBrand.swift in Sources */,
 				F749B64B297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				F7817CF929801A3500FFBC65 /* Data+Extension.swift in Sources */,
+				F343A4B42A1E084100DDA874 /* PHAsset+Extension.swift in Sources */,
 				F793E59F28B764F6005E4B02 /* NCContentPresenter.swift in Sources */,
 				F76DEE9828F808AF0041B1C9 /* LockscreenWidgetProvider.swift in Sources */,
 				F78A10C029322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */,
@@ -3101,16 +3112,17 @@
 				F783030728B4C52800B84583 /* UIColor+Extension.swift in Sources */,
 				F783030028B4C45800B84583 /* NCGlobal.swift in Sources */,
 				F793E59D28B761E7005E4B02 /* NCNetworking.swift in Sources */,
-				F78302FC28B4C3F300B84583 /* NCElementsJSON.swift in Sources */,
 				F7BF9D832934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F757CC8329E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F749B652297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
 				F783030628B4C51E00B84583 /* String+Extension.swift in Sources */,
+				F763D29E2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F77ED59328C9CEA000E24ED0 /* ToolbarWidgetProvider.swift in Sources */,
 				F72A17D828B221E300F3F159 /* DashboardWidgetView.swift in Sources */,
 				F77ED59528C9CEA400E24ED0 /* ToolbarWidgetView.swift in Sources */,
 				F78302FB28B4C3EE00B84583 /* NCManageDatabase+Video.swift in Sources */,
 				F72EA95228B7BA2A00C88F0C /* DashboardWidgetProvider.swift in Sources */,
+				F343A4BC2A1E734600DDA874 /* Optional+Extensions.swift in Sources */,
 				F793E5A228B76580005E4B02 /* NCNetworkingChunkedUpload.swift in Sources */,
 				F783031228B4C8EC00B84583 /* CCUtility.m in Sources */,
 				F72EA95828B7BC4F00C88F0C /* FilesData.swift in Sources */,
@@ -3132,6 +3144,7 @@
 				F771E3F720E239B500AFB62D /* FileProviderExtension+Actions.swift in Sources */,
 				F7245926289BB59300474787 /* ThreadSafeDictionary.swift in Sources */,
 				F76673F022C90434007ED366 /* FileProviderUtility.swift in Sources */,
+				F763D2A12A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F7434B3420E23FD700417916 /* NCDatabase.swift in Sources */,
 				F757CC8629E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */,
 				F702F2D125EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
@@ -3141,9 +3154,9 @@
 				F785EE9E2461A09900B3F945 /* NCNetworking.swift in Sources */,
 				F749B655297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
 				F771E3D320E2392D00AFB62D /* FileProviderExtension.swift in Sources */,
-				F73D5E49246DE09200DF6467 /* NCElementsJSON.swift in Sources */,
 				F771E3D520E2392D00AFB62D /* FileProviderItem.swift in Sources */,
 				AF4BF616275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */,
+				F343A4B72A1E084300DDA874 /* PHAsset+Extension.swift in Sources */,
 				F7434B3620E23FE000417916 /* NCManageDatabase.swift in Sources */,
 				F798F0E725880609000DAFFD /* UIColor+Extension.swift in Sources */,
 				F7D68FCF28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
@@ -3165,6 +3178,7 @@
 				F7817CFC29801A3500FFBC65 /* Data+Extension.swift in Sources */,
 				F7A76DCD256A71CE00119AB3 /* UIImage+Extension.swift in Sources */,
 				F771E3F820E239B500AFB62D /* FileProviderExtension+Thumbnail.swift in Sources */,
+				F343A4BF2A1E734600DDA874 /* Optional+Extensions.swift in Sources */,
 				AF4BF62027562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */,
 				F785EEA62461A4FB00B3F945 /* CCUtility.m in Sources */,
 				F73ADD2226554FD10069EA0D /* NCContentPresenter.swift in Sources */,
@@ -3193,6 +3207,7 @@
 				AF935067276B84E700BD078F /* NCMenu+FloatingPanel.swift in Sources */,
 				F702F2CD25EE5B4F008F8E80 /* AppDelegate.swift in Sources */,
 				F769454022E9F077000A798A /* NCSharePaging.swift in Sources */,
+				F7EE66AD2A20B226009AE765 /* UILabel+Extension.swift in Sources */,
 				F78ACD4221903CE00088454D /* NCListCell.swift in Sources */,
 				F76D3CF12428B40E005DFA87 /* NCViewerPDFSearch.swift in Sources */,
 				F7245924289BB50C00474787 /* ThreadSafeDictionary.swift in Sources */,
@@ -3221,7 +3236,6 @@
 				F75A9EE623796C6F0044CFCE /* NCNetworking.swift in Sources */,
 				F758B460212C56A400515F55 /* NCScan.swift in Sources */,
 				F78ACD52219046DC0088454D /* NCSectionHeaderFooter.swift in Sources */,
-				F7490E902988F0C2009DCE94 /* NCCreateFormUploadAssets.swift in Sources */,
 				F710D2022405826100A6033D /* NCViewer+Menu.swift in Sources */,
 				F765E9CD295C585800A09ED8 /* NCUploadScanDocument.swift in Sources */,
 				F77A697D250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift in Sources */,
@@ -3269,7 +3283,6 @@
 				AF93471A27E2361E002537EE /* NCShareAdvancePermissionHeader.swift in Sources */,
 				F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */,
 				3781B9B023DB2B7E006B4B1D /* AppDelegate+Menu.swift in Sources */,
-				F73D5E47246DE09200DF6467 /* NCElementsJSON.swift in Sources */,
 				F710D1F52405770F00A6033D /* NCViewerPDF.swift in Sources */,
 				F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */,
 				F7C30DF6291BC0CA0017149B /* NCNetworkingE2EEUpload.swift in Sources */,
@@ -3327,6 +3340,7 @@
 				F707C26521A2DC5200F6181E /* NCStoreReview.swift in Sources */,
 				F7BAADCB1ED5A87C00B7EAD4 /* NCManageDatabase.swift in Sources */,
 				F77C97392953131000FDDD09 /* NCCameraRoll.swift in Sources */,
+				F343A4B32A1E01FF00DDA874 /* PHAsset+Extension.swift in Sources */,
 				F70968A424212C4E00ED60E5 /* NCLivePhoto.swift in Sources */,
 				F7C30DFA291BCF790017149B /* NCNetworkingE2EECreateFolder.swift in Sources */,
 				F7BC288026663F85004D46C5 /* NCViewCertificateDetails.swift in Sources */,
@@ -3340,12 +3354,14 @@
 				F7725A60251F33BB00D125E0 /* NCFiles.swift in Sources */,
 				F704B5E52430AA8000632F5F /* NCCreateFormUploadConflict.swift in Sources */,
 				F765608F23BF813600765969 /* NCContentPresenter.swift in Sources */,
+				F343A4BB2A1E734600DDA874 /* Optional+Extensions.swift in Sources */,
 				F7D68FCC28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
 				F78E2D6529AF02DB0024D4F3 /* Database.swift in Sources */,
 				F70CEF5623E9C7E50007035B /* UIColor+Extension.swift in Sources */,
 				F75CA1472962F13700B01130 /* HUDView.swift in Sources */,
 				F7A48413297022E000BD1B49 /* ViewerQuickLook.swift in Sources */,
 				F77BB748289985270090FC19 /* UITabBarController+Extension.swift in Sources */,
+				F763D29D2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F75AC2431F1F62450073EC19 /* NCManageAutoUploadFileName.swift in Sources */,
 				F7A7FA6329265CF4000603EF /* NCManageE2EE.swift in Sources */,
 				F7C7B489245EBA4100D93E60 /* NCViewerQuickLook.swift in Sources */,
@@ -3370,6 +3386,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				F78A10C129322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */,
+				F343A4BD2A1E734600DDA874 /* Optional+Extensions.swift in Sources */,
 				F7A8D73528F17E16008BBE1C /* NCManageDatabase.swift in Sources */,
 				F7A8D74428F1827B008BBE1C /* ThreadSafeDictionary.swift in Sources */,
 				F7C9739528F17131002C43E2 /* IntentHandler.swift in Sources */,
@@ -3379,9 +3396,9 @@
 				F749B64C297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */,
 				F7A8D73F28F181EF008BBE1C /* NCGlobal.swift in Sources */,
 				F749B653297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */,
+				F763D29F2A249C4500A3C901 /* NCManageDatabase+Capabilities.swift in Sources */,
 				F7A8D74328F1826F008BBE1C /* String+Extension.swift in Sources */,
 				F7A8D73728F17E1E008BBE1C /* NCManageDatabase+Account.swift in Sources */,
-				F7A8D73B28F17E2C008BBE1C /* NCElementsJSON.swift in Sources */,
 				F7817CFA29801A3500FFBC65 /* Data+Extension.swift in Sources */,
 				F7BF9D842934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				F7A8D73C28F181BC008BBE1C /* NCBrand.swift in Sources */,
@@ -3389,6 +3406,7 @@
 				F7A8D73A28F17E28008BBE1C /* NCManageDatabase+Video.swift in Sources */,
 				F7A8D73828F17E21008BBE1C /* NCManageDatabase+DashboardWidget.swift in Sources */,
 				F7A8D73928F17E25008BBE1C /* NCManageDatabase+Metadata.swift in Sources */,
+				F343A4B52A1E084200DDA874 /* PHAsset+Extension.swift in Sources */,
 				F72FD3B7297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */,
 				F7A8D74128F18254008BBE1C /* UIColor+Extension.swift in Sources */,
 				F7A8D73428F17E12008BBE1C /* NCDatabase.swift in Sources */,
@@ -3954,7 +3972,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 23;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -3972,13 +3990,13 @@
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nextcloud. All rights reserved.";
-				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 15.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 4.8.1;
+				MARKETING_VERSION = 4.8.3;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				SDKROOT = iphoneos;
@@ -4017,7 +4035,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 23;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -4033,13 +4051,13 @@
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Nextcloud. All rights reserved.";
-				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 15.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 4.8.1;
+				MARKETING_VERSION = 4.8.3;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				SDKROOT = iphoneos;
@@ -4272,7 +4290,7 @@
 			repositoryURL = "https://github.com/nextcloud/NextcloudKit";
 			requirement = {
 				kind = exactVersion;
-				version = 2.4.0;
+				version = 2.6.0;
 			};
 		};
 		F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = {

+ 0 - 54
NextcloudTests/NCGlobalTests.swift

@@ -1,54 +0,0 @@
-//
-//  NCGlobalTests.swift
-//  Nextcloud
-//
-//  Created by Henrik Storch on 01.12.21.
-//  Copyright © 2021 Henrik Storch. All rights reserved.
-//
-//  Author Henrik Storch <henrik.storch@nextcloud.com>
-//
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, either version 3 of the License, or
-//  (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-//
-
-@testable import Nextcloud
-import XCTest
-
-class NCGlobalTests: XCTestCase {
-
-    func testSharedInatance() throws {
-        XCTAssertNotNil(NCGlobal.shared, "Shared instance should be initialized")
-    }
-
-    func testHashToInt() {
-        let emptyHash10 = NCGlobal.hashToInt(hash: "", maximum: 10)
-        let emptyHash2 = NCGlobal.hashToInt(hash: "", maximum: 2)
-        XCTAssertEqual(emptyHash10, 0, "Empty hash should be zero")
-        XCTAssertEqual(emptyHash10, emptyHash2, "Empty hashes should be the same")
-        let emptyHashA = NCGlobal.hashToInt(hash: "a", maximum: 10)
-        XCTAssertEqual(emptyHashA, 0, "Hash of 'a' mod 10 should be zero")
-        let emptyHash22 = NCGlobal.hashToInt(hash: "1ab", maximum: 100)
-        XCTAssertEqual(emptyHash22, 22, "Hash of '1ab' mod 100 should be 22")
-        let nonHexHash = NCGlobal.hashToInt(hash: "1qw&(*}", maximum: 10)
-        XCTAssertEqual(nonHexHash, 1, "Non hex characters should be ignored")
-    }
-
-    func testUsernameToColor() {
-        let color = NCGlobal.shared.usernameToColor("00000000")
-        let userColor = NCBrandColor.shared.userColors[0]
-        XCTAssertEqual(color, userColor, "Zero usercolor doesn't match")
-        let emptyColor = NCGlobal.shared.usernameToColor("")
-        let emptyUserColor = NCBrandColor.shared.userColors[12]
-        XCTAssertEqual(emptyColor, emptyUserColor, "Empty usercolor doesn't match")
-    }
-}

+ 0 - 85
NextcloudTests/ParallelWorkerTest.swift

@@ -1,85 +0,0 @@
-//
-//  ParallelWorkerTest.swift
-//  Nextcloud
-//
-//  Created by Henrik Storch on 18.02.22.
-//  Copyright © 2021 Henrik Storch. All rights reserved.
-//
-//  Author Henrik Storch <henrik.storch@nextcloud.com>
-//
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, either version 3 of the License, or
-//  (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-//
-
-@testable import Nextcloud
-import XCTest
-
-class ParallelWorkerTest: XCTestCase {
-
-    func testWorkerComplete() throws {
-        let expectation = XCTestExpectation(description: "Worker executes all tasks")
-        let taskCount = 20
-        var tasksComplete = 0
-        let worker = ParallelWorker(n: 5, titleKey: nil, totalTasks: nil, hudView: nil)
-        for _ in 0..<taskCount {
-            worker.execute { completion in
-                tasksComplete += 1
-                completion()
-            }
-        }
-        worker.completeWork {
-            XCTAssertEqual(tasksComplete, taskCount)
-            if tasksComplete == taskCount {
-                expectation.fulfill()
-            }
-        }
-
-        let result = XCTWaiter.wait(for: [expectation], timeout: 5)
-        XCTAssertEqual(result, .completed)
-    }
-
-    func testWorkerOrder() throws {
-        let expectation = XCTestExpectation(description: "Worker executes work in sequence for n = 1")
-        let sortedArray = Array(0..<20)
-        var array: [Int] = []
-        let worker = ParallelWorker(n: 1, titleKey: nil, totalTasks: nil, hudView: nil)
-        for i in sortedArray {
-            worker.execute { completion in
-                DispatchQueue.main.asyncAfter(deadline: .now() + Double.random(in: 0...0.2)) {
-                    array.append(i)
-                    completion()
-                }
-            }
-        }
-        worker.completeWork {
-            XCTAssertEqual(sortedArray, array)
-            if sortedArray == array {
-                expectation.fulfill()
-            }
-        }
-        let result = XCTWaiter.wait(for: [expectation], timeout: 5)
-        XCTAssertEqual(result, .completed)
-    }
-
-    func testWorkerFailsWithoutCompletion() throws {
-        let expectation = XCTestExpectation(description: "Worker fails if completion isn't called")
-        expectation.isInverted = true
-        let worker = ParallelWorker(n: 5, titleKey: nil, totalTasks: nil, hudView: nil)
-        for _ in 0..<20 {
-            worker.execute { _ in }
-        }
-        worker.completeWork { expectation.fulfill() }
-        let result = XCTWaiter.wait(for: [expectation], timeout: 5)
-        XCTAssertEqual(result, .completed)
-    }
-}

+ 0 - 136
NextcloudTests/SharePermissionTest.swift

@@ -1,136 +0,0 @@
-//
-//  SharePermissionTest.swift
-//  Nextcloud
-//
-//  Created by Henrik Storch on 29.03.22.
-//  Copyright © 2021 Henrik Storch. All rights reserved.
-//
-//  Author Henrik Storch <henrik.storch@nextcloud.com>
-//
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, either version 3 of the License, or
-//  (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-//
-
-@testable import Nextcloud
-import XCTest
-import NextcloudKit
-
-class SharePermissionTest: XCTestCase {
-    override func setUp() {
-        let json =
-        """
-        {"ocs":{"data":{"capabilities":{"files_sharing":{"default_permissions":31}}}}}
-        """.data(using: .utf8)!
-        NCManageDatabase.shared.addCapabilitiesJSon(json, account: "")
-    }
-
-    func testShareCellPermissionCell() throws {
-        let share = NCTableShareOptions(sharee: NKSharee(), metadata: tableMetadata(), password: nil)
-        let shareConfig = NCShareConfig(parentMetadata: tableMetadata(), share: share)
-
-        for row in 0..<shareConfig.permissions.count {
-            guard let cell = shareConfig.config(for: IndexPath(row: row, section: 0)) as? NCToggleCellConfig else {
-                XCTFail("Invalid share permission cell")
-                continue
-            }
-            XCTAssertFalse(cell.isOn(for: share))
-        }
-
-        let meta = tableMetadata()
-        meta.sharePermissionsCollaborationServices = 31
-        let fullShare = NCTableShareOptions(sharee: NKSharee(), metadata: meta, password: nil)
-        let shareFullConfig = NCShareConfig(parentMetadata: meta, share: fullShare)
-
-        for row in 0..<shareFullConfig.permissions.count {
-            guard let cell = shareConfig.config(for: IndexPath(row: row, section: 0)) as? NCToggleCellConfig else {
-                XCTFail("Invalid share permission cell")
-                continue
-            }
-            XCTAssertTrue(cell.isOn(for: fullShare))
-        }
-    }
-
-    func testSharePermission() throws {
-        XCTAssertTrue(NCLinkPermission.allowEdit.hasResharePermission(for: 15))
-        XCTAssertTrue(NCLinkPermission.allowEdit.hasResharePermission(for: 11))
-        XCTAssertTrue(NCLinkPermission.allowEdit.hasResharePermission(for: 7))
-        XCTAssertFalse(NCLinkPermission.allowEdit.hasResharePermission(for: 13))
-        XCTAssertFalse(NCLinkPermission.allowEdit.hasResharePermission(for: 1))
-
-        XCTAssertTrue(NCLinkPermission.viewOnly.hasResharePermission(for: 25))
-        XCTAssertTrue(NCLinkPermission.viewOnly.hasResharePermission(for: 17))
-        XCTAssertFalse(NCLinkPermission.viewOnly.hasResharePermission(for: 12))
-        XCTAssertFalse(NCLinkPermission.viewOnly.hasResharePermission(for: 2))
-
-        XCTAssertTrue(NCLinkPermission.fileDrop.hasResharePermission(for: 4))
-        XCTAssertFalse(NCLinkPermission.fileDrop.hasResharePermission(for: 27))
-
-        XCTAssertTrue(NCUserPermission.create.hasResharePermission(for: 4))
-        XCTAssertFalse(NCUserPermission.create.hasResharePermission(for: 27))
-
-        XCTAssertTrue(NCUserPermission.edit.hasResharePermission(for: 2))
-        XCTAssertFalse(NCUserPermission.edit.hasResharePermission(for: 29))
-
-        XCTAssertTrue(NCUserPermission.reshare.hasResharePermission(for: 16))
-        XCTAssertFalse(NCUserPermission.reshare.hasResharePermission(for: 15))
-    }
-
-    func testFileShare() throws {
-        let meta = tableMetadata()
-        meta.directory = false
-        let share = NCTableShareOptions.shareLink(metadata: meta, password: nil)
-        let fileConfig = NCShareConfig(parentMetadata: meta, share: share)
-        XCTAssertEqual(fileConfig.advanced, NCShareDetails.forLink)
-        XCTAssertEqual(fileConfig.permissions as? [NCLinkPermission], NCLinkPermission.forFile)
-
-        meta.directory = true
-        let folderConfig = NCShareConfig(parentMetadata: meta, share: share)
-        XCTAssertEqual(folderConfig.advanced, NCShareDetails.forLink)
-        XCTAssertEqual(folderConfig.permissions as? [NCLinkPermission], NCLinkPermission.forDirectory)
-    }
-
-    func testUserShare() throws {
-        let meta = tableMetadata()
-        meta.directory = false
-        let sharee = NKSharee()
-        let share = NCTableShareOptions(sharee: sharee, metadata: meta, password: nil)
-        let fileConfig = NCShareConfig(parentMetadata: meta, share: share)
-        XCTAssertEqual(fileConfig.advanced, NCShareDetails.forUser)
-        XCTAssertEqual(fileConfig.permissions as? [NCUserPermission], NCUserPermission.forFile)
-
-        meta.directory = true
-        let folderConfig = NCShareConfig(parentMetadata: meta, share: share)
-        XCTAssertEqual(folderConfig.advanced, NCShareDetails.forUser)
-        XCTAssertEqual(folderConfig.permissions as? [NCUserPermission], NCUserPermission.forDirectory)
-    }
-
-    func testResharePermission() throws {
-        let meta = tableMetadata()
-        let permissionReadShare = NCGlobal.shared.permissionShareShare + NCGlobal.shared.permissionReadShare
-        meta.sharePermissionsCollaborationServices = permissionReadShare
-        meta.directory = false
-        let share = NCTableShareOptions.shareLink(metadata: meta, password: nil)
-        let fileConfig = NCShareConfig(parentMetadata: meta, share: share)
-        XCTAssertEqual(fileConfig.resharePermission, meta.sharePermissionsCollaborationServices)
-        XCTAssertEqual(fileConfig.advanced, NCShareDetails.forLink)
-        XCTAssertEqual(fileConfig.permissions as? [NCLinkPermission], NCLinkPermission.forFile)
-
-        meta.directory = true
-        let sharee = NKSharee()
-        let folderShare = NCTableShareOptions(sharee: sharee, metadata: meta, password: nil)
-        let folderConfig = NCShareConfig(parentMetadata: meta, share: folderShare)
-        XCTAssertEqual(folderConfig.resharePermission, meta.sharePermissionsCollaborationServices)
-        XCTAssertEqual(folderConfig.advanced, NCShareDetails.forUser)
-        XCTAssertEqual(folderConfig.permissions as? [NCUserPermission], NCUserPermission.forDirectory)
-    }
-}

+ 0 - 64
NextcloudTests/UserAgentTests.swift

@@ -1,64 +0,0 @@
-//
-//  UserAgentTests.swift
-//  Nextcloud
-//
-//  Created by Henrik Storch on 03.05.22.
-//  Copyright © 2022 Henrik Storch. All rights reserved.
-//
-//  Author Henrik Storch <henrik.storch@nextcloud.com>
-//
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, either version 3 of the License, or
-//  (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-//
-
-@testable import Nextcloud
-import XCTest
-
-class UserAgentTests: XCTestCase {
-    // https://github.com/nextcloud/server/blob/fc826e98115b510313ddacbf6fef4ce8d041e373/lib/public/IRequest.php#L83
-    let ncServerUARegex = "^Mozilla\\/5\\.0 \\(iOS\\) (ownCloud|Nextcloud)\\-iOS.*$"
-
-    // https://github.com/ProseMirror/prosemirror-view/blob/427d278aaaacde422ed1f2b8c84bb53337162775/src/browser.js#L18-L22
-    let proseMirrorWebKitUARegex = "\\bAppleWebKit\\/(\\d+)"
-    let proseMirroriOSUARegex = "Mobile\\/\\w+"
-
-    func testDefaultUserAgent() throws {
-        let userAgent: String = CCUtility.getUserAgent()
-        let match = try matches(for: ncServerUARegex, in: userAgent).first
-        XCTAssertNotNil(match)
-    }
-
-    func testTextUserAgent() throws {
-        let userAgent: String = NCUtility.shared.getCustomUserAgentNCText()
-        let match = try matches(for: ncServerUARegex, in: userAgent).first
-        XCTAssertNotNil(match)
-
-        let iOSMatch = try matches(for: proseMirroriOSUARegex, in: userAgent).first
-        XCTAssertNotNil(iOSMatch)
-
-        // https://github.com/ProseMirror/prosemirror-view/blob/8f246f320801f8e3cac92c97f71ac91e3e327f2f/src/input.js#L521-L522
-        let webKitMatch = try matches(for: proseMirrorWebKitUARegex, in: userAgent).first
-        XCTAssertNotNil(webKitMatch)
-        XCTAssertEqual(webKitMatch!.numberOfRanges, 2)
-        let versionRange = webKitMatch!.range(at: 1)
-        let versionString = userAgent[Range(versionRange, in: userAgent)!]
-        let webkitVersion = Int(versionString) ?? 0
-        XCTAssertGreaterThanOrEqual(webkitVersion, 604)
-    }
-
-    func matches(for regex: String, in text: String) throws -> [NSTextCheckingResult] {
-        let range = NSRange(location: 0, length: text.utf16.count)
-        let regex = try NSRegularExpression(pattern: regex)
-        return regex.matches(in: text, range: range)
-    }
-}

+ 17 - 15
Notification Service Extension/NotificationService.swift

@@ -35,21 +35,23 @@ class NotificationService: UNNotificationServiceExtension {
             bestAttemptContent.title = ""
             bestAttemptContent.body = "Nextcloud notification"
             do {
-                let message = bestAttemptContent.userInfo["subject"] as! String
-                let tableAccounts = NCManageDatabase.shared.getAllAccount()
-                for tableAccount in tableAccounts {
-                    guard let privateKey = CCUtility.getPushNotificationPrivateKey(tableAccount.account) else {
-                        continue
-                    }
-                    guard let decryptedMessage = NCPushNotificationEncryption.shared().decryptPushNotification(message, withDevicePrivateKey: privateKey) else {
-                        continue
-                    }
-                    guard let data = decryptedMessage.data(using: .utf8) else {
-                        continue
-                    }
-                    let json = try JSONSerialization.jsonObject(with: data) as! [String: AnyObject]
-                    if let subject = json["subject"] as? String {
-                        bestAttemptContent.body = subject
+                if let message = bestAttemptContent.userInfo["subject"] as? String {
+                    let tableAccounts = NCManageDatabase.shared.getAllAccount()
+                    for tableAccount in tableAccounts {
+                        guard let privateKey = CCUtility.getPushNotificationPrivateKey(tableAccount.account),
+                              let decryptedMessage = NCPushNotificationEncryption.shared().decryptPushNotification(message, withDevicePrivateKey: privateKey),
+                              let data = decryptedMessage.data(using: .utf8) else {
+                            continue
+                        }
+                        if var json = try JSONSerialization.jsonObject(with: data) as? [String: AnyObject],
+                           let subject = json["subject"] as? String {
+                            bestAttemptContent.body = subject
+                            if let pref = UserDefaults.init(suiteName: NCBrandOptions.shared.capabilitiesGroups) {
+                                json["account"] = tableAccount.account as AnyObject
+                                pref.set(json, forKey: "NOTIFICATION_DATA")
+                                pref.synchronize()
+                            }
+                        }
                     }
                 }
             } catch let error as NSError {

+ 3 - 0
Share/NCShareExtension+DataSource.swift

@@ -100,6 +100,9 @@ extension NCShareExtension: UICollectionViewDataSource {
             cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto
         }
 
+        // Add TAGS
+        cell.setTags(tags: Array(metadata.tags))
+
         // Remove last separator
         cell.separator.isHidden = collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1
 

+ 4 - 2
Widget/Dashboard/DashboardData.swift

@@ -128,8 +128,10 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis
     let result = NCManageDatabase.shared.getDashboardWidgetApplications(account: account.account).first
     let id: String = configuration?.applications?.identifier ?? (result?.id ?? "recommendations")
 
-    let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
-    guard serverVersionMajor >= NCGlobal.shared.nextcloudVersion25 else {
+    // Capabilities
+    NCManageDatabase.shared.setCapabilities(account: account.account)
+
+    guard NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion25 else {
         return completion(DashboardDataEntry(date: Date(), datas: datasPlaceholder, dashboard: nil, buttons: nil, isPlaceholder: true, isEmpty: false, titleImage: UIImage(named: "widget")!, title: "Dashboard", footerImage: "xmark.icloud", footerText: NSLocalizedString("_widget_available_nc25_", comment: "")))
     }
         

+ 1 - 1
Widget/Files/FilesWidgetView.swift

@@ -127,7 +127,7 @@ struct FilesWidgetView: View {
                     })
 
                     Link(destination: entry.isPlaceholder ? linkNoAction : linkActionScanDocument, label: {
-                        Image("scan")
+                        Image(systemName: "doc.text.viewfinder")
                             .resizable()
                             .renderingMode(.template)
                             .foregroundColor(entry.isPlaceholder ? Color(.systemGray4) : Color(NCBrandColor.shared.brandText))

+ 4 - 2
Widget/Lockscreen/LockscreenData.swift

@@ -55,8 +55,10 @@ func getLockscreenDataEntry(configuration: AccountIntent?, isPreview: Bool, fami
         return completion(LockscreenData(date: Date(), isPlaceholder: true, activity: "", link: URL(string: "https://")!, quotaRelative: 0, quotaUsed: "", quotaTotal: "", error: false))
     }
 
-    let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
-    if serverVersionMajor < NCGlobal.shared.nextcloudVersion25 {
+    // Capabilities
+    NCManageDatabase.shared.setCapabilities(account: account.account)
+
+    if NCGlobal.shared.capabilityServerVersionMajor < NCGlobal.shared.nextcloudVersion25 {
         completion(LockscreenData(date: Date(), isPlaceholder: false, activity: NSLocalizedString("_widget_available_nc25_", comment: ""), link: URL(string: "https://")!, quotaRelative: 0, quotaUsed: "", quotaTotal: "", error: true))
     }
 

+ 1 - 1
Widget/Toolbar/ToolbarWidgetView.swift

@@ -61,7 +61,7 @@ struct ToolbarWidgetView: View {
                     })
 
                     Link(destination: entry.isPlaceholder ? linkNoAction : linkActionScanDocument, label: {
-                        Image("scan")
+                        Image(systemName: "doc.text.viewfinder")
                             .resizable()
                             .renderingMode(.template)
                             .foregroundColor(entry.isPlaceholder ? Color(.systemGray4) : Color(NCBrandColor.shared.brandText))

+ 3 - 54
iOSClient/Activity/NCActivityTableViewCell.swift

@@ -53,7 +53,7 @@ class NCActivityTableViewCell: UITableViewCell, NCCellProtocol {
     var idActivity: Int = 0
     var activityPreviews: [tableActivityPreview] = []
     var didSelectItemEnable: Bool = true
-    var viewController: UIViewController?
+    var viewController = UIViewController()
 
     var fileAvatarImageView: UIImageView? {
         get { return avatar }
@@ -74,7 +74,7 @@ class NCActivityTableViewCell: UITableViewCell, NCCellProtocol {
 
     @objc func tapAvatarImage() {
         guard let fileUser = fileUser else { return }
-        viewController?.showProfileMenu(userId: fileUser)
+        viewController.showProfileMenu(userId: fileUser)
     }
 }
 
@@ -124,58 +124,7 @@ extension NCActivityTableViewCell: UICollectionViewDelegate {
                 return
             }
 
-            if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "fileId == %@", activitySubjectRich.id)) {
-                if let filePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView) {
-                    do {
-                        let attr = try FileManager.default.attributesOfItem(atPath: filePath)
-                        let fileSize = attr[FileAttributeKey.size] as! UInt64
-                        if fileSize > 0 {
-                            if let viewController = self.viewController {
-                                NCViewer.shared.view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: cell?.imageView.image)
-                            }
-                            return
-                        }
-                    } catch {
-                        print("Error: \(error)")
-                    }
-                }
-            }
-
-            let hud = JGProgressHUD()
-            hud.indicatorView = JGProgressHUDRingIndicatorView()
-            if let indicatorView = hud.indicatorView as? JGProgressHUDRingIndicatorView {
-                indicatorView.ringWidth = 1.5
-            }
-            guard let view = appDelegate.window?.rootViewController?.view else { return }
-            hud.show(in: view)
-
-            NextcloudKit.shared.getFileFromFileId(fileId: String(activityPreview.fileId)) { account, file, data, error in
-                if let file = file {
-                    let isDirectoryE2EE = NCUtility.shared.isDirectoryE2EE(file: file)
-                    let metadata = NCManageDatabase.shared.convertFileToMetadata(file, isDirectoryE2EE: isDirectoryE2EE)
-                    NCManageDatabase.shared.addMetadata(metadata)
-
-                    let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
-                    let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
-
-                    NextcloudKit.shared.download(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, requestHandler: { _ in
-                    }, taskHandler: { _ in
-                    }, progressHandler: { progress in
-                        hud.progress = Float(progress.fractionCompleted)
-                    }) { account, _, _, _, _, _, error in
-                        hud.dismiss()
-                        if account == self.appDelegate.account && error == .success {
-                            NCManageDatabase.shared.addLocalFile(metadata: metadata)
-                            if let viewController = self.viewController {
-                                NCViewer.shared.view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: cell?.imageView.image)
-                            }
-                        }
-                    }
-                } else {
-                    hud.dismiss()
-                    NCContentPresenter.shared.showError(error: error)
-                }
-            }
+            NCActionCenter.shared.viewerFile(account: appDelegate.account, fileId: activitySubjectRich.id, viewController: viewController)
         }
     }
 }

+ 19 - 11
iOSClient/AppDelegate.swift

@@ -41,7 +41,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     @objc var userId: String = ""
     @objc var password: String = ""
 
-    var deletePasswordSession: Bool = false
     var activeLogin: NCLogin?
     var activeLoginWeb: NCLoginWeb?
     var activeServerUrl: String = ""
@@ -113,8 +112,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         // Activate user account
         if let activeAccount = NCManageDatabase.shared.getActiveAccount() {
 
-            settingAccount(activeAccount.account, urlBase: activeAccount.urlBase, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account))
+            settingAccount(activeAccount.account, urlBase: activeAccount.urlBase, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), initialize: false)
             NCBrandColor.shared.settingThemingColor(account: activeAccount.account)
+            initialize()
 
         } else {
 
@@ -186,8 +186,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         NCNetworkingProcessUpload.shared.observeTableMetadata()
         NCNetworkingProcessUpload.shared.startTimer()
 
-        self.deletePasswordSession = false
-
         if !NCAskAuthorization.shared.isRequesting {
             hidePrivacyProtectionWindow()
         }
@@ -408,6 +406,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     }
 
     func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
+
+        if let pref = UserDefaults.init(suiteName: NCBrandOptions.shared.capabilitiesGroups),
+           let data = pref.object(forKey: "NOTIFICATION_DATA") as? [String: AnyObject] {
+            nextcloudPushNotificationAction(data: data)
+            pref.set(nil, forKey: "NOTIFICATION_DATA")
+        }
+
         completionHandler()
     }
 
@@ -425,6 +430,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         }
     }
 
+    func nextcloudPushNotificationAction(data: [String: AnyObject]) {
+        NCApplicationHandle().nextcloudPushNotificationAction(data: data)
+    }
+
     // MARK: - Login & checkErrorNetworking
 
     @objc func openLogin(viewController: UIViewController?, selector: Int, openLoginWeb: Bool) {
@@ -514,8 +523,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     }
 
     @objc private func checkErrorNetworking() {
-        
-        // check unauthorized server (401/403)
         if account != "" && CCUtility.getPassword(account)!.count == 0 {
             openLogin(viewController: window?.rootViewController, selector: NCGlobal.shared.introLogin, openLoginWeb: true)
         }
@@ -562,7 +569,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
     // MARK: - Account
 
-    @objc func settingAccount(_ account: String, urlBase: String, user: String, userId: String, password: String) {
+    @objc func settingAccount(_ account: String, urlBase: String, user: String, userId: String, password: String, initialize: Bool = true) {
 
         let accountTestBackup = self.account + "/" + self.userId
         let accountTest = account +  "/" + userId
@@ -576,13 +583,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         _ = NCActionCenter.shared
 
         NextcloudKit.shared.setup(account: account, user: user, userId: userId, password: password, urlBase: urlBase)
-        let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
-        if serverVersionMajor > 0 {
-            NextcloudKit.shared.setup(nextcloudVersion: serverVersionMajor)
+        NCManageDatabase.shared.setCapabilities(account: account)
+
+        if NCGlobal.shared.capabilityServerVersionMajor > 0 {
+            NextcloudKit.shared.setup(nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor)
         }
 
         DispatchQueue.main.async {
-            if UIApplication.shared.applicationState != .background && accountTestBackup != accountTest {
+            if initialize, UIApplication.shared.applicationState != .background && accountTestBackup != accountTest {
                 NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterInitialize, second: 0.2)
             }
         }

+ 0 - 10
iOSClient/Data/NCDatabase.swift

@@ -30,16 +30,6 @@ protocol DateCompareable {
     var dateKey: Date { get }
 }
 
-class tableCapabilities: Object {
-
-    @objc dynamic var account = ""
-    @objc dynamic var jsondata: Data?
-
-    override static func primaryKey() -> String {
-        return "account"
-    }
-}
-
 class tableChunk: Object {
 
     @objc dynamic var account = ""

+ 0 - 75
iOSClient/Data/NCElementsJSON.swift

@@ -1,75 +0,0 @@
-//
-//  NCElementsJSON.swift
-//  Nextcloud
-//
-//  Created by Marino Faggiana on 14/05/2020.
-//  Copyright © 2020 Marino Faggiana. All rights reserved.
-//
-//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
-//
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, either version 3 of the License, or
-//  (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-//
-
-import UIKit
-
-@objc class NCElementsJSON: NSObject {
-    @objc static let shared: NCElementsJSON = {
-        let instance = NCElementsJSON()
-        return instance
-    }()
-
-    @objc public let capabilitiesVersionString: Array = ["ocs", "data", "version", "string"]
-    @objc public let capabilitiesVersionMajor: Array = ["ocs", "data", "version", "major"]
-
-    @objc public let capabilitiesFileSharingApiEnabled: Array = ["ocs", "data", "capabilities", "files_sharing", "api_enabled"]
-    @objc public let capabilitiesFileSharingPubPasswdEnforced: Array = ["ocs", "data", "capabilities", "files_sharing", "public", "password", "enforced"]
-    @objc public let capabilitiesFileSharingPubExpireDateEnforced: Array = ["ocs", "data", "capabilities", "files_sharing", "public", "expire_date", "enforced"]
-    @objc public let capabilitiesFileSharingPubExpireDateDays: Array = ["ocs", "data", "capabilities", "files_sharing", "public", "expire_date", "days"]
-    @objc public let capabilitiesFileSharingInternalExpireDateEnforced: Array = ["ocs", "data", "capabilities", "files_sharing", "public", "expire_date_internal", "enforced"]
-    @objc public let capabilitiesFileSharingInternalExpireDateDays: Array = ["ocs", "data", "capabilities", "files_sharing", "public", "expire_date_internal", "days"]
-    @objc public let capabilitiesFileSharingRemoteExpireDateEnforced: Array = ["ocs", "data", "capabilities", "files_sharing", "public", "expire_date_remote", "enforced"]
-    @objc public let capabilitiesFileSharingRemoteExpireDateDays: Array = ["ocs", "data", "capabilities", "files_sharing", "public", "expire_date_remote", "days"]
-    @objc public let capabilitiesFileSharingDefaultPermissions: Array = ["ocs", "data", "capabilities", "files_sharing", "default_permissions"]
-    @objc public let capabilitiesFileSharingSendPasswordMail: Array = ["ocs", "data", "capabilities", "files_sharing", "sharebymail", "send_password_by_mail"]
-
-    @objc public let capabilitiesThemingColor: Array = ["ocs", "data", "capabilities", "theming", "color"]
-    @objc public let capabilitiesThemingColorElement: Array = ["ocs", "data", "capabilities", "theming", "color-element"]
-    @objc public let capabilitiesThemingColorText: Array = ["ocs", "data", "capabilities", "theming", "color-text"]
-    @objc public let capabilitiesThemingName: Array = ["ocs", "data", "capabilities", "theming", "name"]
-    @objc public let capabilitiesThemingSlogan: Array = ["ocs", "data", "capabilities", "theming", "slogan"]
-
-    @objc public let capabilitiesWebDavRoot: Array = ["ocs", "data", "capabilities", "core", "webdav-root"]
-
-    @objc public let capabilitiesE2EEEnabled: Array = ["ocs", "data", "capabilities", "end-to-end-encryption", "enabled"]
-    @objc public let capabilitiesE2EEApiVersion: Array = ["ocs", "data", "capabilities", "end-to-end-encryption", "api-version"]
-
-    @objc public let capabilitiesExternalSites: Array = ["ocs", "data", "capabilities", "external"]
-
-    @objc public let capabilitiesRichdocumentsMimetypes: Array = ["ocs", "data", "capabilities", "richdocuments", "mimetypes"]
-
-    @objc public let capabilitiesActivity: Array = ["ocs", "data", "capabilities", "activity", "apiv2"]
-
-    @objc public let capabilitiesNotification: Array = ["ocs", "data", "capabilities", "notifications", "ocs-endpoints"]
-
-    @objc public let capabilitiesFilesUndelete: Array = ["ocs", "data", "capabilities", "files", "undelete"]
-    @objc public let capabilitiesFilesLockVersion: Array = ["ocs", "data", "capabilities", "files", "locking"] // NC 24
-    @objc public let capabilitiesFilesComments: Array = ["ocs", "data", "capabilities", "files", "comments"] // NC 20
-
-    @objc public let capabilitiesHWCEnabled: Array = ["ocs", "data", "capabilities", "handwerkcloud", "enabled"]
-
-    @objc public let capabilitiesUserStatusEnabled: Array = ["ocs", "data", "capabilities", "user_status", "enabled"]
-    @objc public let capabilitiesUserStatusSupportsEmoji: Array = ["ocs", "data", "capabilities", "user_status", "supports_emoji"]
-
-    @objc public let capabilitiesGroupfoldersEnabled: Array = ["ocs", "data", "capabilities", "groupfolders", "hasGroupFolders"]
-}

+ 136 - 0
iOSClient/Data/NCManageDatabase+Capabilities.swift

@@ -0,0 +1,136 @@
+//
+//  NCManageDatabase+Capabilities.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 29/05/23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import Foundation
+import RealmSwift
+import NextcloudKit
+import SwiftyJSON
+
+class tableCapabilities: Object {
+
+    @objc dynamic var account = ""
+    @objc dynamic var jsondata: Data?
+
+    override static func primaryKey() -> String {
+        return "account"
+    }
+}
+
+extension NCManageDatabase {
+
+    func addCapabilitiesJSon(_ data: Data, account: String) {
+
+        let realm = try! Realm()
+
+        do {
+            try realm.write {
+                let addObject = tableCapabilities()
+
+                addObject.account = account
+                addObject.jsondata = data
+
+                realm.add(addObject, update: .all)
+            }
+        } catch let error {
+            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func getCapabilities(account: String) -> Data? {
+
+        let realm = try! Realm()
+
+        guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else {
+            return nil
+        }
+
+        return result.jsondata
+    }
+
+    func setCapabilities(account: String, data: Data? = nil) {
+
+        let realm = try! Realm()
+        let json: JSON?
+
+        if let data = data {
+            json = JSON(data)
+        } else {
+            guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first,
+                  let data = result.jsondata else {
+                return
+            }
+            json = JSON(data)
+        }
+
+        guard let json = json else { return }
+
+        NCGlobal.shared.capabilityServerVersion = json["ocs", "data", "version", "string"].stringValue
+        NCGlobal.shared.capabilityServerVersionMajor = json["ocs", "data", "version", "major"].intValue
+
+        NCGlobal.shared.capabilityFileSharingApiEnabled = json["ocs", "data", "capabilities", "files_sharing", "api_enabled"].boolValue
+        NCGlobal.shared.capabilityFileSharingPubPasswdEnforced = json["ocs", "data", "capabilities", "files_sharing", "public", "password", "enforced"].boolValue
+        NCGlobal.shared.capabilityFileSharingPubExpireDateEnforced = json["ocs", "data", "capabilities", "files_sharing", "public", "expire_date", "enforced"].boolValue
+        NCGlobal.shared.capabilityFileSharingPubExpireDateDays = json["ocs", "data", "capabilities", "files_sharing", "public", "expire_date", "days"].intValue
+        NCGlobal.shared.capabilityFileSharingInternalExpireDateEnforced = json["ocs", "data", "capabilities", "files_sharing", "public", "expire_date_internal", "enforced"].boolValue
+        NCGlobal.shared.capabilityFileSharingInternalExpireDateDays = json["ocs", "data", "capabilities", "files_sharing", "public", "expire_date_internal", "days"].intValue
+        NCGlobal.shared.capabilityFileSharingRemoteExpireDateEnforced = json["ocs", "data", "capabilities", "files_sharing", "public", "expire_date_remote", "enforced"].boolValue
+        NCGlobal.shared.capabilityFileSharingRemoteExpireDateDays = json["ocs", "data", "capabilities", "files_sharing", "public", "expire_date_remote", "days"].intValue
+        NCGlobal.shared.capabilityFileSharingDefaultPermission = json["ocs", "data", "capabilities", "files_sharing", "default_permissions"].intValue
+
+        NCGlobal.shared.capabilityThemingColor = json["ocs", "data", "capabilities", "theming", "color"].stringValue
+        NCGlobal.shared.capabilityThemingColorElement = json["ocs", "data", "capabilities", "theming", "color-element"].stringValue
+        NCGlobal.shared.capabilityThemingColorText = json["ocs", "data", "capabilities", "theming", "color-text"].stringValue
+        NCGlobal.shared.capabilityThemingName = json["ocs", "data", "capabilities", "theming", "name"].stringValue
+        NCGlobal.shared.capabilityThemingSlogan = json["ocs", "data", "capabilities", "theming", "slogan"].stringValue
+
+        NCGlobal.shared.capabilityE2EEEnabled = json["ocs", "data", "capabilities", "end-to-end-encryption", "enabled"].boolValue
+        NCGlobal.shared.capabilityE2EEApiVersion = json["ocs", "data", "capabilities", "end-to-end-encryption", "api-version"].stringValue
+
+
+        NCGlobal.shared.capabilityRichdocumentsMimetypes.removeAll()
+        let mimetypes = json["ocs", "data", "capabilities", "richdocuments", "mimetypes"].arrayValue
+        for mimetype in mimetypes {
+            NCGlobal.shared.capabilityRichdocumentsMimetypes.append(mimetype.stringValue)
+        }
+
+        NCGlobal.shared.capabilityActivity.removeAll()
+        let activities = json["ocs", "data", "capabilities", "activity", "apiv2"].arrayValue
+        for activity in activities {
+            NCGlobal.shared.capabilityActivity.append(activity.stringValue)
+        }
+
+        NCGlobal.shared.capabilityNotification.removeAll()
+        let notifications = json["ocs", "data", "capabilities", "notifications", "ocs-endpoints"].arrayValue
+        for notify in notifications {
+            NCGlobal.shared.capabilityNotification.append(notify.stringValue)
+        }
+
+        NCGlobal.shared.capabilityFilesUndelete = json["ocs", "data", "capabilities", "files", "undelete"].boolValue
+        NCGlobal.shared.capabilityFilesLockVersion = json["ocs", "data", "capabilities", "files", "locking"].stringValue
+        NCGlobal.shared.capabilityFilesComments = json["ocs", "data", "capabilities", "files", "comments"].boolValue
+
+        NCGlobal.shared.capabilityUserStatusEnabled = json["ocs", "data", "capabilities", "user_status", "enabled"].boolValue
+        NCGlobal.shared.capabilityExternalSites = json["ocs", "data", "capabilities", "external"].exists()
+        NCGlobal.shared.capabilityGroupfoldersEnabled = json["ocs", "data", "capabilities", "groupfolders", "hasGroupFolders"].boolValue
+    }
+}

+ 26 - 13
iOSClient/Data/NCManageDatabase+Metadata.swift

@@ -198,19 +198,6 @@ extension tableMetadata {
         return directory && size == 0 && !e2eEncrypted && CCUtility.isEnd(toEndEnabled: account)
     }
 
-    var isSharable: Bool {
-        let sharing = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingApiEnabled, exists: false)
-        if !sharing { return false }
-        if !e2eEncrypted && !isDirectoryE2EE { return true }
-        let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
-        if serverVersionMajor >= NCGlobal.shared.nextcloudVersion26 && directory {
-            // E2EE DIRECTORY SECURE FILE DROP (SHARE AVAILABLE)
-            return true
-        } else {
-            return false
-        }
-    }
-
     var isDirectoryUnsettableE2EE: Bool {
         return !isDirectoryE2EE && directory && size == 0 && e2eEncrypted && CCUtility.isEnd(toEndEnabled: account)
     }
@@ -246,6 +233,21 @@ extension tableMetadata {
     func canUnlock(as user: String) -> Bool {
         return !lock || (lockOwner == user && lockOwnerType == 0)
     }
+
+    /// Return if is sharable (temp)
+    // TODO: modifify for E2EE 2.0
+    func isSharable() -> Bool {
+        guard NCGlobal.shared.capabilityFileSharingApiEnabled else { return false }
+
+        if !e2eEncrypted && !isDirectoryE2EE {
+            return true
+        } else if NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion26 && directory {
+            // E2EE DIRECTORY SECURE FILE DROP (SHARE AVAILABLE)
+            return true
+        } else {
+            return false
+        }
+    }
 }
 
 extension NCManageDatabase {
@@ -875,6 +877,17 @@ extension NCManageDatabase {
         return tableMetadata.init(value: result)
     }
 
+    func getMetadataFromFileId(_ fileId: String?) -> tableMetadata? {
+
+        let realm = try! Realm()
+        realm.refresh()
+
+        guard let fileId = fileId else { return nil }
+        guard let result = realm.objects(tableMetadata.self).filter("fileId == %@", fileId).first else { return nil }
+
+        return tableMetadata.init(value: result)
+    }
+
     func getMetadataFolder(account: String, urlBase: String, userId: String, serverUrl: String) -> tableMetadata? {
 
         let realm = try! Realm()

+ 0 - 113
iOSClient/Data/NCManageDatabase.swift

@@ -25,7 +25,6 @@
 import UIKit
 import RealmSwift
 import NextcloudKit
-import SwiftyJSON
 import CoreMedia
 import Photos
 
@@ -252,118 +251,6 @@ class NCManageDatabase: NSObject {
         return object.isInvalidated
     }
 
-    // MARK: -
-    // MARK: Table Avatar
-
-    
-    // MARK: -
-    // MARK: Table Capabilities
-
-    func addCapabilitiesJSon(_ data: Data, account: String) {
-
-        let realm = try! Realm()
-
-        do {
-            try realm.write {
-                let addObject = tableCapabilities()
-
-                addObject.account = account
-                addObject.jsondata = data
-
-                realm.add(addObject, update: .all)
-            }
-        } catch let error {
-            NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
-        }
-    }
-
-    func getCapabilities(account: String) -> String? {
-
-        let realm = try! Realm()
-
-        guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else {
-            return nil
-        }
-        guard let jsondata = result.jsondata else {
-            return nil
-        }
-
-        let json = JSON(jsondata)
-
-        return json.rawString()?.replacingOccurrences(of: "\\/", with: "/")
-    }
-
-    @objc func getCapabilitiesServerString(account: String, elements: [String]) -> String? {
-
-        let realm = try! Realm()
-
-        guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else {
-            return nil
-        }
-        guard let jsondata = result.jsondata else {
-            return nil
-        }
-
-        let json = JSON(jsondata)
-        return json[elements].string
-    }
-
-    func getCapabilitiesServerInt(account: String, elements: [String]) -> Int {
-
-        let realm = try! Realm()
-
-        guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first,
-              let jsondata = result.jsondata else {
-            return 0
-        }
-
-        let json = JSON(jsondata)
-        return json[elements].intValue
-    }
-
-    @objc func getCapabilitiesServerBool(account: String, elements: [String], exists: Bool) -> Bool {
-
-        let realm = try! Realm()
-
-        guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else {
-            return false
-        }
-        guard let jsondata = result.jsondata else {
-            return false
-        }
-
-        let json = JSON(jsondata)
-        if exists {
-            return json[elements].exists()
-        } else {
-            return json[elements].boolValue
-        }
-    }
-
-    func getCapabilitiesServerArray(account: String, elements: [String]) -> [String]? {
-
-        let realm = try! Realm()
-        var resultArray: [String] = []
-
-        guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else {
-            return nil
-        }
-        guard let jsondata = result.jsondata else {
-            return nil
-        }
-
-        let json = JSON(jsondata)
-
-        if let results = json[elements].array {
-            for result in results {
-                resultArray.append(result.string ?? "")
-            }
-            return resultArray
-        }
-
-        return nil
-    }
-
     // MARK: -
     // MARK: Table Chunk
 

+ 66 - 122
iOSClient/Diagnostics/NCCapabilitiesView.swift

@@ -27,136 +27,77 @@ class NCCapabilitiesViewOO: ObservableObject {
         let id = UUID()
         let text: String
         let image: UIImage
+        let resize: Bool
         let available: Bool
     }
 
     @Published var capabililies: [Capability] = []
-    @Published var json = "Lorem ipsum dolor sit amet.\nEa voluptas aperiam aut inventore saepe in tenetur modi.\nCum sint tempore sed maiores quos aut quaerat deleniti.\nQui beatae quia qui repellat sunt in Quis libero aut quidem porro non explicabo tenetur et natus doloribus non voluptatum consequatur.\n"
     @Published var homeServer = ""
 
     init() {
 
         if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
-            capabililies = [Capability(text: "File sharing", image: UIImage(named: "share")!.resizeImage(size: CGSize(width: 25, height: 25))!, available: true),
-                            Capability(text: "Externa site", image: UIImage(systemName: "network")!, available: false)
+            capabililies = [Capability(text: "Collabora", image: UIImage(named: "collabora")!, resize: true, available: true),
+                            Capability(text: "XXX site", image: UIImage(systemName: "lock.shield")!, resize: false, available: false)
             ]
             homeServer = "https://cloud.nextcloud.com/remote.php.dav/files/marino/"
         } else {
             guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return }
-            homeServer = NCUtilityFileSystem.shared.getHomeServer(urlBase: activeAccount.urlBase, userId: activeAccount.userId) + "/"
-            getCapabilities(account: activeAccount.account)
-        }
-    }
+            var textEditor = false
+            var onlyofficeEditors = false
 
-    func getCapabilities(account: String) {
-
-        NextcloudKit.shared.getCapabilities { account, data, error in
-            if error == .success, let data = data {
-                NCManageDatabase.shared.addCapabilitiesJSon(data, account: account)
-                let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
-                if serverVersionMajor >= NCGlobal.shared.nextcloudVersion18 {
-                    NextcloudKit.shared.NCTextObtainEditorDetails { account, editors, creators, _, error in
-                        if error == .success {
-                            NCManageDatabase.shared.addDirectEditing(account: account, editors: editors, creators: creators)
-                            self.updateCapabilities(account: account)
-                        }
-                    }
-                } else {
-                    self.updateCapabilities(account: account)
-                }
-            } else {
-                self.updateCapabilities(account: account)
+            if let image = UIImage(named: "share") {
+                capabililies.append(Capability(text: "File sharing", image: image, resize: true, available: NCGlobal.shared.capabilityFileSharingApiEnabled))
+            }
+            if let image = UIImage(systemName: "network") {
+                capabililies.append(Capability(text: "External site", image: image, resize: false, available: NCGlobal.shared.capabilityExternalSites))
+            }
+            if let image = UIImage(systemName: "lock") {
+                capabililies.append(Capability(text: "End-to-End Encryption", image: image, resize: false, available: NCGlobal.shared.capabilityE2EEEnabled))
+            }
+            if let image = UIImage(systemName: "bolt") {
+                capabililies.append(Capability(text: "Activity", image: image, resize: false, available: !NCGlobal.shared.capabilityActivity.isEmpty))
+            }
+            if let image = UIImage(systemName: "bell") {
+                capabililies.append(Capability(text: "Notification", image: image, resize: false, available: !NCGlobal.shared.capabilityNotification.isEmpty))
+            }
+            if let image = UIImage(systemName: "trash") {
+                capabililies.append(Capability(text: "Deleted files", image: image, resize: false, available: NCGlobal.shared.capabilityFilesUndelete))
             }
-        }
-
-        updateCapabilities(account: account)
-    }
-
-    func updateCapabilities(account: String) {
-
-        var available: Bool = false
-
-        capabililies.removeAll()
-        json = ""
-
-        // FILE SHARING
-        available = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingApiEnabled, exists: false)
-        capabililies.append(Capability(text: "File sharing", image: UIImage(named: "share")!.resizeImage(size: CGSize(width: 25, height: 25))!, available: available))
-
-        // EXTERNAL SITE
-        available = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesExternalSites, exists: true)
-        capabililies.append(Capability(text: "External site", image: UIImage(systemName: "network")!, available: available))
-
-        // E2EE
-        available = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesE2EEEnabled, exists: false)
-        capabililies.append(Capability(text: "End-to-End Encryption", image: UIImage(systemName: "lock")!, available: available))
-
-        // ACTIVITY
-        if NCManageDatabase.shared.getCapabilitiesServerArray(account: account, elements: NCElementsJSON.shared.capabilitiesActivity) == nil {
-            available = false
-        } else {
-            available = true
-        }
-        capabililies.append(Capability(text: "Activity", image: UIImage(systemName: "bolt")!, available: available))
 
-        // NOTIFICATION
-        if NCManageDatabase.shared.getCapabilitiesServerArray(account: account, elements: NCElementsJSON.shared.capabilitiesNotification) == nil {
-            available = false
-        } else {
-            available = true
-        }
-        capabililies.append(Capability(text: "Notification", image: UIImage(systemName: "bell")!, available: available))
-
-        // DELETE FILES
-        available = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFilesUndelete, exists: false)
-        capabililies.append(Capability(text: "Deleted files", image: UIImage(systemName: "trash")!, available: available))
-
-        // TEXT - ONLYOFFICE
-        var textEditor = false
-        var onlyofficeEditors = false
-        if let editors = NCManageDatabase.shared.getDirectEditingEditors(account: account) {
-            for editor in editors {
-                if editor.editor == NCGlobal.shared.editorText {
-                    textEditor = true
-                } else if editor.editor == NCGlobal.shared.editorOnlyoffice {
-                    onlyofficeEditors = true
+            if let editors = NCManageDatabase.shared.getDirectEditingEditors(account: activeAccount.account) {
+                for editor in editors {
+                    if editor.editor == NCGlobal.shared.editorText {
+                        textEditor = true
+                    } else if editor.editor == NCGlobal.shared.editorOnlyoffice {
+                        onlyofficeEditors = true
+                    }
                 }
             }
-        }
-        capabililies.append(Capability(text: "Text", image: UIImage(named: "text")!.resizeImage(size: CGSize(width: 25, height: 25))!, available: textEditor))
-        capabililies.append(Capability(text: "ONLYOFFICE", image: UIImage(named: "onlyoffice")!.resizeImage(size: CGSize(width: 25, height: 25))!, available: onlyofficeEditors))
-
-        // COLLABORA
-        if NCManageDatabase.shared.getCapabilitiesServerArray(account: account, elements: NCElementsJSON.shared.capabilitiesRichdocumentsMimetypes) == nil {
-            available = false
-        } else {
-            available = true
-        }
-        capabililies.append(Capability(text: "Collabora", image: UIImage(named: "collabora")!.resizeImage(size: CGSize(width: 25, height: 25))!, available: available))
 
-        // USER STATUS
-        available = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesUserStatusEnabled, exists: false)
-        capabililies.append(Capability(text: "User Status", image: UIImage(systemName: "moon")!, available: available))
-
-        // COMMENTS
-        available = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFilesComments, exists: false)
-        capabililies.append(Capability(text: "Comments", image: UIImage(systemName: "ellipsis.bubble")!, available: available))
-
-        // LOCK FILE
-        let hasLockCapability = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesFilesLockVersion) >= 1
-        if hasLockCapability {
-            available = false
-        } else {
-            available = true
-        }
-        capabililies.append(Capability(text: "Lock file", image: UIImage(systemName: "lock")!, available: available))
-
-        // GROUP FOLDERS
-        available = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesGroupfoldersEnabled, exists: false)
-        capabililies.append(Capability(text: "Group folders", image: UIImage(systemName: "person.2")!, available: available))
+            if let image = UIImage(systemName: "doc.text") {
+                capabililies.append(Capability(text: "Text", image: image, resize: false, available: textEditor))
+            }
+            if let image = UIImage(named: "onlyoffice") {
+                capabililies.append(Capability(text: "ONLYOFFICE", image: image, resize: true, available: onlyofficeEditors))
+            }
+            if let image = UIImage(named: "collabora") {
+                capabililies.append(Capability(text: "Collabora", image: image, resize: true, available: !NCGlobal.shared.capabilityRichdocumentsMimetypes.isEmpty))
+            }
+            if let image = UIImage(systemName: "moon") {
+                capabililies.append(Capability(text: "User Status", image: image, resize: false, available: NCGlobal.shared.capabilityUserStatusEnabled))
+            }
+            if let image = UIImage(systemName: "ellipsis.bubble") {
+                capabililies.append(Capability(text: "Comments", image: image, resize: false, available: NCGlobal.shared.capabilityFilesComments))
+            }
+            if let image = UIImage(systemName: "lock") {
+                capabililies.append(Capability(text: "Lock file", image: image, resize: false, available: !NCGlobal.shared.capabilityFilesLockVersion.isEmpty))
+            }
+            if let image = UIImage(systemName: "person.2") {
+                capabililies.append(Capability(text: "Group folders", image: image, resize: false, available: NCGlobal.shared.capabilityGroupfoldersEnabled))
+            }
 
-        if let json = NCManageDatabase.shared.getCapabilities(account: account) {
-            self.json = json
+            homeServer = NCUtilityFileSystem.shared.getHomeServer(urlBase: activeAccount.urlBase, userId: activeAccount.userId) + "/"
         }
     }
 }
@@ -175,19 +116,13 @@ struct NCCapabilitiesView: View {
                 Section {
                     ForEach(capabilitiesViewOO.capabililies, id: \.id) { capability in
                         HStack {
-                            CapabilityName(text: capability.text, image: Image(uiImage: capability.image))
+                            CapabilityName(text: capability.text, image: Image(uiImage: capability.image), resize: capability.resize)
                             CapabilityStatus(available: capability.available)
                         }
                     }
                 }
                 Section {
-                    CapabilityName(text: capabilitiesViewOO.homeServer, image: Image(uiImage: UIImage(systemName: "house")!))
-                }
-                Section {
-                    ScrollView(.horizontal) {
-                        Text(capabilitiesViewOO.json)
-                            .font(.system(size: 12))
-                    }
+                    CapabilityName(text: capabilitiesViewOO.homeServer, image: Image(systemName: "house"), resize: false)
                 }
             }
         }
@@ -198,16 +133,25 @@ struct NCCapabilitiesView: View {
 
         @State var text: String = ""
         @State var image: Image
+        @State var resize: Bool
 
         var body: some View {
             Label {
                 Text(text)
                     .font(.system(size: 15))
-                    .foregroundColor(Color(UIColor.systemGray))
             } icon: {
-                image
-                    .renderingMode(.template)
-                    .foregroundColor(Color(UIColor.systemGray))
+                if resize {
+                    image
+                        .renderingMode(.template)
+                        .resizable()
+                        .scaledToFill()
+                        .frame(width: 23.0, height: 23.0)
+                        .foregroundColor(.primary)
+                } else {
+                    image
+                        .renderingMode(.template)
+                        .foregroundColor(.primary)
+                }
             }
             .frame(maxWidth: .infinity, alignment: .leading)
         }

+ 15 - 0
iOSClient/Extensions/Data+Extension.swift

@@ -38,4 +38,19 @@ extension Data {
             print("Error: \(error.localizedDescription)")
         }
     }
+
+    func jsonToString() -> String {
+        do {
+            let json = try JSONSerialization.jsonObject(with: self, options: [])
+            let data = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
+            guard let jsonString = String(data: data, encoding: .utf8) else {
+                print("Inavlid data")
+                return ""
+            }
+            return jsonString
+        } catch {
+            print("Error: \(error.localizedDescription)")
+        }
+        return ""
+    }
 }

+ 15 - 0
iOSClient/Extensions/Optional+Extensions.swift

@@ -0,0 +1,15 @@
+//
+//  Optional+Extensions.swift
+//  Nextcloud
+//
+//  Created by Milen on 24.05.23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+
+extension Optional where Wrapped: Collection {
+    var isEmptyOrNil: Bool {
+        return self?.isEmpty ?? true
+    }
+}

+ 34 - 0
iOSClient/Extensions/PHAsset+Extension.swift

@@ -0,0 +1,34 @@
+//
+//  PHAsset+Extension.swift
+//  Nextcloud
+//
+//  Created by Milen on 24.05.23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+import UIKit
+
+extension PHAsset {
+    var originalFilename: NSString {
+        if let resource = PHAssetResource.assetResources(for: self).first {
+            return resource.originalFilename as NSString
+        } else {
+            return self.value(forKey: "filename") as? NSString
+            ?? ("IMG_" + CCUtility.getIncrementalNumber() + getExtension()) as NSString 
+        }
+    }
+
+    private func getExtension() -> String {
+        switch mediaType {
+        case .video:
+            return ".mp4"
+        case .image:
+            return ".jpg"
+        case .audio:
+            return ".mp3"
+        default:
+            return ".unknownType"
+        }
+    }
+}

+ 67 - 0
iOSClient/Extensions/UILabel+Extension.swift

@@ -0,0 +1,67 @@
+//
+//  UILabel+Extension.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 26/05/23.
+//  Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import UIKit
+
+//
+// https://stackoverflow.com/questions/67317975/how-can-i-make-a-padded-uilabel-with-rounded-border-in-ios
+//
+@IBDesignable class PaddedAndBorderedLabel: UILabel {
+
+    @IBInspectable var topInset: CGFloat = 5.0
+    @IBInspectable var bottomInset: CGFloat = 5.0
+    @IBInspectable var leftInset: CGFloat = 7.0
+    @IBInspectable var rightInset: CGFloat = 7.0
+    @IBInspectable var borderColor: UIColor = UIColor.black
+    @IBInspectable var borderWidth: CGFloat = 1
+    @IBInspectable var cornerRadius: CGFloat = 5
+
+    override func drawText(in rect: CGRect) {
+        let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
+        super.drawText(in: rect.inset(by: insets))
+    }
+
+    override var intrinsicContentSize: CGSize {
+        let size = super.intrinsicContentSize
+        return CGSize(width: size.width + leftInset + rightInset,
+              height: size.height + topInset + bottomInset)
+    }
+
+    override func textRect(forBounds bounds: CGRect,
+                           limitedToNumberOfLines n: Int) -> CGRect {
+        let b = bounds
+        let UIEI = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
+        let tr = b.inset(by: UIEI)
+        let ctr = super.textRect(forBounds: tr, limitedToNumberOfLines: 0)
+        // that line of code MUST be LAST in this function, NOT first
+        return ctr
+    }
+
+    override func draw(_ rect: CGRect) {
+        layer.borderColor = borderColor.cgColor
+        layer.borderWidth = borderWidth
+        layer.cornerRadius = cornerRadius
+        layer.masksToBounds = true
+        super.draw(rect)
+    }
+}

+ 15 - 0
iOSClient/Extensions/View+Extension.swift

@@ -5,6 +5,21 @@
 //  Created by Marino Faggiana on 29/12/22.
 //  Copyright © 2022 Marino Faggiana. All rights reserved.
 //
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
 
 import SwiftUI
 

+ 0 - 6
iOSClient/Files/NCFiles.swift

@@ -74,12 +74,6 @@ class NCFiles: NCCollectionViewCommon {
         }
         super.initialize()
 
-        /*
-        if let userInfo = notification.userInfo as NSDictionary?, userInfo["atStart"] as? Int == 1 {
-            return
-        }
-        */
-
         reloadDataSource(forced: false)
         reloadDataSourceNetwork()
     }

+ 1 - 1
iOSClient/Images.xcassets/collabora.imageset/Contents.json

@@ -1,7 +1,7 @@
 {
   "images" : [
     {
-      "filename" : "collabora.pdf",
+      "filename" : "collabora.svg",
       "idiom" : "universal"
     }
   ],

二進制
iOSClient/Images.xcassets/collabora.imageset/collabora.pdf


+ 8 - 0
iOSClient/Images.xcassets/collabora.imageset/collabora.svg

@@ -0,0 +1,8 @@
+<svg width="32" height="32" version="1.0" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
+ <style id="stylish-12" class="stylish" type="text/css">.lo-menu &gt; li &gt; a:hover, .lo-menu &gt; li &gt; a:focus, .lo-menu &gt; li &gt; a:active, .lo-menu &gt; li &gt; a.highlighted {
+    background-color: #f5f4f9;
+    border-bottom-color: var(--color-primary-element);
+    color: var(--color-primary-element);
+}</style>
+ <path style="color:#000000;block-progression:tb;text-transform:none;text-indent:0" fill="#000" d="m14.357 1-7.0001 7.002 0.00549 0.00732 8.1738 7.7014 0.37537 0.35339-0.37537 0.35522-8.0804 7.6154 6.9617 6.9653 14.967-14.967zm-7.3572 8.2452v13.585l7.2363-6.7657z"/>
+</svg>

+ 1 - 1
iOSClient/Images.xcassets/onlyoffice.imageset/Contents.json

@@ -1,7 +1,7 @@
 {
   "images" : [
     {
-      "filename" : "onlyoffice.pdf",
+      "filename" : "onlyoffice.svg",
       "idiom" : "universal"
     }
   ],

+ 0 - 101
iOSClient/Images.xcassets/onlyoffice.imageset/onlyoffice.pdf

@@ -1,101 +0,0 @@
-%PDF-1.4
-%Óëéá
-1 0 obj
-<</Creator (Mozilla/5.0 \(Macintosh; Intel Mac OS X 10_15_5\) AppleWebKit/537.36 \(KHTML, like Gecko\) BoxySVG/3.41.0 Chrome/83.0.4103.122 Electron/9.1.0 Safari/537.36)
-/Producer (Skia/PDF m83)
-/CreationDate (D:20200729103828+00'00')
-/ModDate (D:20200729103828+00'00')>>
-endobj
-3 0 obj
-<</ca 1
-/BM /Normal>>
-endobj
-4 0 obj
-<</ca .4196
-/BM /Normal>>
-endobj
-5 0 obj
-<</Type /XObject
-/Subtype /Form
-/Resources <</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
-/ExtGState <</G3 3 0 R>>>>
-/BBox [0 0 1771 610]
-/Group <</Type /Group
-/S /Transparency
-/I true>>
-/Filter /FlateDecode
-/Length 170>> stream
-xœmP9Â0ìõ
-} B‡í8/ æ
ž
-R0ü+&‰
-äfµ^¯V~CÎdV³-ÈýÄná‚m…ËÕðñ1ªì¥hLºxá
-‚šH�|Á4 sF5šI¥exˆã4pƒ>÷ç­|º…‘qˆdoæR¨lšÉ™æð|×@Ë;éËìÚ#Pg5dõæØ&胷T¿°#br®A/‰ê†J$ÿ}kƒ'Üá_"ÚP
-endstream
-endobj
-6 0 obj
-<</ca .7176
-/BM /Normal>>
-endobj
-7 0 obj
-<</Type /XObject
-/Subtype /Form
-/Resources <</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
-/ExtGState <</G3 3 0 R>>>>
-/BBox [0 0 1771 665]
-/Group <</Type /Group
-/S /Transparency
-/I true>>
-/Filter /FlateDecode
-/Length 174>> stream
-xœU�KÂ0†÷œ‚$‘žÀµgÈŒºhŽ÷Ÿ‘<ª)Yý_xüð†”HÕ’®üÍjÉ9bÙárS|~€•,ÔÅ9ÓŠ,$�‡T‰®52Î4Qj4"W†(àÈB6j6àxtõ<nØ�¯Ôðµé!­'�LùÜD™|Nœ‰�Œâôs8ÁÜgÙŠ½Ö[]€­oÂ(rXp{n§­g~�ºÅ\קkxÁîðyH6
-endstream
-endobj
-8 0 obj
-<</Filter /FlateDecode
-/Length 225>> stream
-xœmQAn!¼û>GŠƒ1ö^©çœ’ûªMI«¤ÿ—j »°RX	Í3¶aÉËT:ûö4Ðà•œÑŒóPÎ9%GYDôü‚ÓÌÁµFÙ™],©ÃgÀËΊ¿pÜxbÍ›%-UÉ*m¤-«)Ê®,�¬+¼[ƒ‰beo`ªØ©Éü’1“,E0­UæMuJ‰•c5ÚÂ~BŽk§QM”ÚöäâH‹˜‡67^¼}�®õ‰{º_Άì�ôÕ*—!ãJúÊÕ7êÛWœá
-ßö/Žð?¾jT
-endstream
-endobj
-2 0 obj
-<</Type /Page
-/Resources <</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
-/ExtGState <</G3 3 0 R
-/G4 4 0 R
-/G6 6 0 R>>
-/XObject <</X5 5 0 R
-/X7 7 0 R>>>>
-/MediaBox [0 0 425.03998 425.03998]
-/Contents 8 0 R
-/StructParents 0
-/Parent 9 0 R>>
-endobj
-9 0 obj
-<</Type /Pages
-/Count 1
-/Kids [2 0 R]>>
-endobj
-10 0 obj
-<</Type /Catalog
-/Pages 9 0 R>>
-endobj
-xref
-0 11
-0000000000 65535 f 
-0000000015 00000 n 
-0000001571 00000 n 
-0000000301 00000 n 
-0000000338 00000 n 
-0000000379 00000 n 
-0000000805 00000 n 
-0000000846 00000 n 
-0000001276 00000 n 
-0000001824 00000 n 
-0000001879 00000 n 
-trailer
-<</Size 11
-/Root 10 0 R
-/Info 1 0 R>>
-startxref
-1927
-%%EOF

+ 3 - 0
iOSClient/Images.xcassets/onlyoffice.imageset/onlyoffice.svg

@@ -0,0 +1,3 @@
+<?xml version="1.0" standalone="no"?>
+        <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
+        "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">  <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>ONLYOFFICE</title><path d="M10.501 11.724.631 7.16c-.841-.399-.841-1.014 0-1.376l9.87-4.563c.841-.399 2.194-.399 2.998 0l9.87 4.563c.841.398.841 1.014 0 1.376l-9.87 4.563c-.841.362-2.194.362-2.998 0zm0 5.468-9.87-4.563c-.841-.399-.841-1.014 0-1.376l3.363-1.558 6.507 3.006c.841.398 2.194.398 2.998 0l6.507-3.006 3.363 1.558c.841.398.841 1.014 0 1.376l-9.87 4.563c-.841.398-2.194.398-2.998 0zm0 0.0001-9.87-4.563c-.841-.399-.841-1.014 0-1.376l3.363-1.558 6.507 3.006c.841.398 2.194.398 2.998 0l6.507-3.006 3.363 1.558c.841.398.841 1.014 0 1.376l-9.87 4.563c-.841.398-2.194.398-2.998 0zm0 5.613-9.87-4.563c-.841-.398-.841-1.014 0-1.376l3.436-1.593 6.398 2.97c.84.398 2.193.398 2.997 0l6.398-2.97 3.436 1.593c.841.399.841 1.014 0 1.376l-9.87 4.563c-.768.362-2.12.362-2.925 0z"/></svg>  

+ 6 - 5
iOSClient/Login/NCLogin.swift

@@ -260,9 +260,10 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
 
         loginButton.isEnabled = false
 
-        NextcloudKit.shared.getServerStatus(serverUrl: url) { _, _, versionMajor, _, _, _, _, error in
+        NextcloudKit.shared.getServerStatus(serverUrl: url) { serverInfoResult in
 
-            if error == .success {
+            switch serverInfoResult {
+            case .success(let serverInfo):
 
                 if let host = URL(string: url)?.host {
                     NCNetworking.shared.writeCertificate(host: host)
@@ -288,7 +289,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                         }
 
                     // Login Flow
-                    } else if versionMajor >= NCGlobal.shared.nextcloudVersion12 {
+                    } else if serverInfo.versionMajor >= NCGlobal.shared.nextcloudVersion12 {
 
                         if let loginWeb = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLoginWeb") as? NCLoginWeb {
 
@@ -299,7 +300,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                         }
 
                     // NO Login flow available
-                    } else if versionMajor < NCGlobal.shared.nextcloudVersion12 {
+                    } else if serverInfo.versionMajor < NCGlobal.shared.nextcloudVersion12 {
 
                         let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_webflow_not_available_", comment: ""), preferredStyle: .alert)
 
@@ -309,7 +310,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate {
                     }
                 }
 
-            } else {
+            case .failure(let error):
 
                 self.loginButton.isEnabled = true
 

+ 23 - 9
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift

@@ -70,6 +70,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     // DECLARE
     internal var layoutKey = ""
     internal var titleCurrentFolder = ""
+    internal var titlePreviusFolder: String?
     internal var enableSearchBar: Bool = false
     internal var headerMenuButtonsCommand: Bool = true
     internal var headerMenuButtonsView: Bool = true
@@ -123,7 +124,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter")
 
         // Refresh Control
-        collectionView.addSubview(refreshControl)
+        collectionView.refreshControl = refreshControl
         refreshControl.action(for: .valueChanged) { _ in
             self.dataSource.clearDirectory()
             self.reloadDataSourceNetwork(forced: true)
@@ -353,10 +354,11 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     @objc func deleteFile(_ notification: NSNotification) {
 
         guard let userInfo = notification.userInfo as NSDictionary?,
+              let account = userInfo["account"] as? String,
               let error = userInfo["error"] as? NKError
         else { return }
 
-        if error == .success {
+        if error == .success, account == appDelegate.account {
             reloadDataSource()
         }
     }
@@ -609,14 +611,16 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     // MARK: - Layout
 
     @objc func setNavigationItem() {
-        self.setNavigationHeader()
 
-        guard !isEditMode, layoutKey == NCGlobal.shared.layoutViewFiles else { return }
+        self.setNavigationRightItems()
+        navigationItem.title = titleCurrentFolder
+
+        guard layoutKey == NCGlobal.shared.layoutViewFiles else { return }
         
         // PROFILE BUTTON
         
         let activeAccount = NCManageDatabase.shared.getActiveAccount()
-        
+
         let image = NCUtility.shared.loadUserImage(
             for: appDelegate.user,
                displayName: activeAccount?.displayName,
@@ -670,6 +674,11 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         }
         navigationItem.setLeftBarButton(UIBarButtonItem(customView: button), animated: true)
         navigationItem.leftItemsSupplementBackButton = true
+        if titlePreviusFolder == nil {
+            navigationController?.navigationBar.topItem?.title = getNavigationTitle()
+        } else {
+            navigationController?.navigationBar.topItem?.title = titlePreviusFolder
+        }
     }
 
     func getNavigationTitle() -> String {
@@ -980,8 +989,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         self.refreshControl.beginRefreshing()
         self.collectionView.reloadData()
 
-        let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
-        if serverVersionMajor >= NCGlobal.shared.nextcloudVersion20 {
+        if NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion20 {
             NCNetworking.shared.unifiedSearchFiles(userBaseUrl: appDelegate, literal: literalSearch) { account, searchProviders in
                 self.providers = searchProviders
                 self.searchResults = []
@@ -1116,6 +1124,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
                     viewController.isRoot = false
                     viewController.serverUrl = serverUrlPush
+                    viewController.titlePreviusFolder = navigationItem.title
                     viewController.titleCurrentFolder = metadata.fileNameView
 
                     appDelegate.listFilesVC[serverUrlPush] = viewController
@@ -1139,6 +1148,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
                 if let viewController: NCFavorite = UIStoryboard(name: "NCFavorite", bundle: nil).instantiateInitialViewController() as? NCFavorite {
 
                     viewController.serverUrl = serverUrlPush
+                    viewController.titlePreviusFolder = navigationItem.title
                     viewController.titleCurrentFolder = metadata.fileNameView
 
                     appDelegate.listFavoriteVC[serverUrlPush] = viewController
@@ -1162,6 +1172,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
                 if let viewController: NCOffline = UIStoryboard(name: "NCOffline", bundle: nil).instantiateInitialViewController() as? NCOffline {
 
                     viewController.serverUrl = serverUrlPush
+                    viewController.titlePreviusFolder = navigationItem.title
                     viewController.titleCurrentFolder = metadata.fileNameView
 
                     appDelegate.listOfflineVC[serverUrlPush] = viewController
@@ -1186,6 +1197,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
                     viewController.isRoot = false
                     viewController.serverUrl = serverUrlPush
+                    viewController.titlePreviusFolder = navigationItem.title
                     viewController.titleCurrentFolder = metadata.fileNameView
 
                     appDelegate.listFilesVC[serverUrlPush] = viewController
@@ -1210,6 +1222,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
                     viewController.isRoot = false
                     viewController.serverUrl = serverUrlPush
+                    viewController.titlePreviusFolder = navigationItem.title
                     viewController.titleCurrentFolder = metadata.fileNameView
 
                     appDelegate.listFilesVC[serverUrlPush] = viewController
@@ -1233,6 +1246,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
                 if let viewController: NCGroupfolders = UIStoryboard(name: "NCGroupfolders", bundle: nil).instantiateInitialViewController() as? NCGroupfolders {
 
                     viewController.serverUrl = serverUrlPush
+                    viewController.titlePreviusFolder = navigationItem.title
                     viewController.titleCurrentFolder = metadata.fileNameView
 
                     appDelegate.listGroupfoldersVC[serverUrlPush] = viewController
@@ -1272,7 +1286,6 @@ extension NCCollectionViewCommon: UICollectionViewDelegate {
                 selectOcId.append(metadata.ocId)
             }
             collectionView.reloadItems(at: [indexPath])
-            self.navigationItem.title = NSLocalizedString("_selected_", comment: "") + " : \(selectOcId.count)" + " / \(metadataSourceForAllSections.count)"
             return
         }
 
@@ -1657,7 +1670,8 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
 
         // ** IMPORT MUST BE AT THE END **
         //
-        if !metadata.isSharable {
+
+        if !metadata.isSharable() {
             cell.hideButtonShare(true)
         }
         

+ 0 - 6
iOSClient/Main/Collection Common/NCGridCell.swift

@@ -22,7 +22,6 @@
 //
 
 import UIKit
-import TagListView
 
 class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProtocol, NCTrashCellProtocol {
 
@@ -36,7 +35,6 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     @IBOutlet weak var buttonMore: UIButton!
     @IBOutlet weak var imageVisualEffect: UIVisualEffectView!
     @IBOutlet weak var progressView: UIProgressView!
-    var tagListView: TagListView?
 
     internal var objectId = ""
     private var user = ""
@@ -84,10 +82,6 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
         get { return imageFavorite }
         set { imageFavorite = newValue }
     }
-    var cellTagListView: TagListView? {
-        get { return nil}
-        set { tagListView = nil }
-    }
 
     override func awakeFromNib() {
         super.awakeFromNib()

+ 11 - 23
iOSClient/Main/Collection Common/NCListCell.swift

@@ -22,7 +22,6 @@
 //
 
 import UIKit
-import TagListView
 
 class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProtocol {
 
@@ -39,14 +38,14 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     @IBOutlet weak var buttonMore: UIButton!
     @IBOutlet weak var progressView: UIProgressView!
     @IBOutlet weak var separator: UIView!
+    @IBOutlet weak var tag0: UILabel!
+    @IBOutlet weak var tag1: UILabel!
 
     @IBOutlet weak var imageItemLeftConstraint: NSLayoutConstraint!
     @IBOutlet weak var separatorHeightConstraint: NSLayoutConstraint!
     @IBOutlet weak var titleTrailingConstraint: NSLayoutConstraint!
     @IBOutlet weak var infoTrailingConstraint: NSLayoutConstraint!
 
-    @IBOutlet weak var tagListView: TagListView!
-
     private var objectId = ""
     private var user = ""
 
@@ -108,11 +107,7 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
         get { return separator }
         set { separator = newValue }
     }
-    var cellTagListView: TagListView? {
-        get { return tagListView}
-        set { tagListView = newValue }
-    }
- 
+
     override func awakeFromNib() {
         super.awakeFromNib()
 
@@ -284,26 +279,19 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     }
 
     func setTags(tags: [String]) {
-        tagListView.removeAllTags()
         if tags.isEmpty {
-            tagListView.isHidden = true
+            tag0.isHidden = true
+            tag1.isHidden = true
             labelInfo.isHidden = false
         } else {
-            tagListView.isHidden = false
+            tag0.isHidden = false
+            tag1.isHidden = true
             labelInfo.isHidden = true
             if let tag = tags.first {
-                tagListView.addTag(tag)
-                if UIDevice.current.userInterfaceIdiom == .pad {
-                    if tags.count >= 2 {
-                        tagListView.addTag(tags[1])
-                    }
-                    if tags.count > 2 {
-                        tagListView.addTag("+\(tags.count-2)")
-                    }
-                } else {
-                    if tags.count > 1 {
-                        tagListView.addTag("+\(tags.count-1)")
-                    }
+                tag0.text = tag
+                if tags.count > 1 {
+                    tag1.isHidden = false
+                    tag1.text = "+\(tags.count-1)"
                 }
             }
         }

+ 86 - 45
iOSClient/Main/Collection Common/NCListCell.xib

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
-    <device id="retina4_7" orientation="landscape" appearance="light"/>
+    <device id="retina6_0" orientation="landscape" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
@@ -19,78 +19,54 @@
                 <autoresizingMask key="autoresizingMask"/>
                 <subviews>
                     <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="w2m-Vw-hpd" userLabel="ImageItem">
-                        <rect key="frame" x="10" y="54" width="40" height="40"/>
+                        <rect key="frame" x="57" y="43.666666666666664" width="40" height="39.999999999999993"/>
                         <constraints>
                             <constraint firstAttribute="height" constant="40" id="Dpd-Xj-z4U"/>
                             <constraint firstAttribute="width" constant="40" id="v0e-MW-EeE"/>
                         </constraints>
                     </imageView>
                     <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="7Q9-Tv-9yo" userLabel="imageStatus">
-                        <rect key="frame" x="5" y="84" width="15" height="15"/>
+                        <rect key="frame" x="52" y="73.666666666666671" width="15" height="15"/>
                         <constraints>
                             <constraint firstAttribute="width" constant="15" id="f8p-9B-Rgw"/>
                             <constraint firstAttribute="height" constant="15" id="ndy-wW-xdL"/>
                         </constraints>
                     </imageView>
                     <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="C4K-Nv-phA" userLabel="imageFavorite">
-                        <rect key="frame" x="40" y="49" width="15" height="15"/>
+                        <rect key="frame" x="87" y="38.666666666666664" width="15" height="15"/>
                         <constraints>
                             <constraint firstAttribute="width" constant="15" id="hXC-b9-Q2V"/>
                             <constraint firstAttribute="height" constant="15" id="mPH-zc-eH5"/>
                         </constraints>
                     </imageView>
                     <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="AyA-hP-r6w" userLabel="imageSelect">
-                        <rect key="frame" x="10" y="61.5" width="25" height="25"/>
+                        <rect key="frame" x="57" y="51" width="25" height="25"/>
                         <constraints>
                             <constraint firstAttribute="width" constant="25" id="bIF-gu-6Jj"/>
                             <constraint firstAttribute="height" constant="25" id="nJa-oj-gcQ"/>
                         </constraints>
                     </imageView>
                     <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="H4E-G2-C1H" userLabel="imageLocal">
-                        <rect key="frame" x="40" y="84" width="15" height="15"/>
+                        <rect key="frame" x="87" y="73.666666666666671" width="15" height="15"/>
                         <constraints>
                             <constraint firstAttribute="width" constant="15" id="BEs-Rd-5Ov"/>
                             <constraint firstAttribute="height" constant="15" id="N8h-3R-JpE"/>
                         </constraints>
                     </imageView>
                     <label opaque="NO" userInteractionEnabled="NO" tag="101" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UtT-L6-mgW" userLabel="labelTitle">
-                        <rect key="frame" x="60" y="13" width="519" height="18"/>
+                        <rect key="frame" x="107" y="13" width="425" height="18"/>
                         <fontDescription key="fontDescription" type="system" pointSize="15"/>
                         <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                         <nil key="highlightedColor"/>
                     </label>
                     <label opaque="NO" userInteractionEnabled="NO" tag="102" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AXX-71-9Q6" userLabel="labelInfo">
-                        <rect key="frame" x="60" y="120" width="519" height="15"/>
+                        <rect key="frame" x="107" y="120" width="425" height="15"/>
                         <fontDescription key="fontDescription" type="system" pointSize="12"/>
                         <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
                         <nil key="highlightedColor"/>
                     </label>
-                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="z1r-ZA-ft8" customClass="TagListView" customModule="TagListView">
-                        <rect key="frame" x="60" y="124" width="519" height="15"/>
-                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
-                        <constraints>
-                            <constraint firstAttribute="height" constant="15" id="9NQ-gM-wQ6"/>
-                        </constraints>
-                        <userDefinedRuntimeAttributes>
-                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                <real key="value" value="8"/>
-                            </userDefinedRuntimeAttribute>
-                            <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
-                                <real key="value" value="1"/>
-                            </userDefinedRuntimeAttribute>
-                            <userDefinedRuntimeAttribute type="color" keyPath="textColor">
-                                <color key="value" systemColor="systemGrayColor"/>
-                            </userDefinedRuntimeAttribute>
-                            <userDefinedRuntimeAttribute type="color" keyPath="tagBackgroundColor">
-                                <color key="value" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                            </userDefinedRuntimeAttribute>
-                            <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
-                                <color key="value" systemColor="systemGray5Color"/>
-                            </userDefinedRuntimeAttribute>
-                        </userDefinedRuntimeAttributes>
-                    </view>
                     <button opaque="NO" alpha="0.29999999999999999" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="o4u-0K-Qpt" userLabel="buttonShare">
-                        <rect key="frame" x="584" y="45" width="40" height="58"/>
+                        <rect key="frame" x="537" y="34.666666666666664" width="40" height="57.999999999999993"/>
                         <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                         <constraints>
                             <constraint firstAttribute="height" constant="58" id="WOg-y5-5UA"/>
@@ -101,14 +77,14 @@
                         </connections>
                     </button>
                     <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="jc6-Vg-TaS" userLabel="imageShared">
-                        <rect key="frame" x="589" y="59" width="30" height="30"/>
+                        <rect key="frame" x="542" y="48.666666666666664" width="30" height="29.999999999999993"/>
                         <constraints>
                             <constraint firstAttribute="height" constant="30" id="Cvy-nZ-zyD"/>
                             <constraint firstAttribute="width" constant="30" id="jfe-Fg-vA8"/>
                         </constraints>
                     </imageView>
                     <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yhy-xd-w5C" userLabel="buttonMore">
-                        <rect key="frame" x="629" y="44" width="40" height="60"/>
+                        <rect key="frame" x="582" y="33.666666666666664" width="40" height="59.999999999999993"/>
                         <constraints>
                             <constraint firstAttribute="width" constant="40" id="ZgH-mI-l2k"/>
                             <constraint firstAttribute="height" constant="60" id="woC-64-Tyc"/>
@@ -118,29 +94,87 @@
                         </connections>
                     </button>
                     <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="dgL-g5-Nkc" userLabel="imageMore">
-                        <rect key="frame" x="636.5" y="61.5" width="25" height="25"/>
+                        <rect key="frame" x="589.66666666666663" y="51" width="25" height="25"/>
                         <constraints>
                             <constraint firstAttribute="width" constant="25" id="05P-NL-pd8"/>
                             <constraint firstAttribute="height" constant="25" id="Jet-eo-x1M"/>
                         </constraints>
                     </imageView>
                     <progressView hidden="YES" opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="m2p-oJ-j15">
-                        <rect key="frame" x="60" y="137" width="519" height="4"/>
+                        <rect key="frame" x="107" y="116" width="425" height="4"/>
                     </progressView>
                     <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Egg-cb-EhZ" userLabel="separator">
-                        <rect key="frame" x="50" y="147" width="619" height="1"/>
+                        <rect key="frame" x="97" y="126" width="525" height="1"/>
                         <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                         <color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                         <constraints>
                             <constraint firstAttribute="height" constant="1" id="G5S-67-boG"/>
                         </constraints>
                     </view>
+                    <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="tag0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qnc-hI-Z9r" customClass="PaddedAndBorderedLabel" customModule="Nextcloud" customModuleProvider="target">
+                        <rect key="frame" x="107" y="103.66666666666667" width="26" height="14.333333333333329"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                        <color key="textColor" systemColor="systemGrayColor"/>
+                        <nil key="highlightedColor"/>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="bottomInset">
+                                <real key="value" value="1"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="leftInset">
+                                <real key="value" value="5"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="rightInset">
+                                <real key="value" value="5"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                <color key="value" systemColor="systemGray5Color"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                <real key="value" value="1"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="8"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="topInset">
+                                <real key="value" value="1"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </label>
+                    <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="tag1" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jUe-8q-VJd" customClass="PaddedAndBorderedLabel" customModule="Nextcloud" customModuleProvider="target">
+                        <rect key="frame" x="138" y="103.66666666666667" width="24" height="14.333333333333329"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                        <color key="textColor" systemColor="systemGrayColor"/>
+                        <nil key="highlightedColor"/>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="number" keyPath="bottomInset">
+                                <real key="value" value="1"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="leftInset">
+                                <real key="value" value="5"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="rightInset">
+                                <real key="value" value="5"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                <color key="value" systemColor="systemGray5Color"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                <real key="value" value="1"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                <real key="value" value="8"/>
+                            </userDefinedRuntimeAttribute>
+                            <userDefinedRuntimeAttribute type="number" keyPath="topInset">
+                                <real key="value" value="1"/>
+                            </userDefinedRuntimeAttribute>
+                        </userDefinedRuntimeAttributes>
+                    </label>
                 </subviews>
             </view>
             <viewLayoutGuide key="safeArea" id="Gu8-oz-zWa"/>
             <constraints>
+                <constraint firstItem="jUe-8q-VJd" firstAttribute="centerY" secondItem="qnc-hI-Z9r" secondAttribute="centerY" id="2Z4-Yh-1lR"/>
                 <constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="m2p-oJ-j15" secondAttribute="trailing" constant="90" id="2zI-li-v77"/>
-                <constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="z1r-ZA-ft8" secondAttribute="trailing" constant="90" id="467-SN-bxI"/>
                 <constraint firstItem="H4E-G2-C1H" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="-10" id="6fN-Jc-WID"/>
                 <constraint firstItem="Gu8-oz-zWa" firstAttribute="bottom" secondItem="Egg-cb-EhZ" secondAttribute="bottom" id="81D-sw-EaX"/>
                 <constraint firstItem="AXX-71-9Q6" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="10" id="Bxx-kv-KT3"/>
@@ -149,19 +183,21 @@
                 <constraint firstItem="Egg-cb-EhZ" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" id="JCm-UU-Pxu"/>
                 <constraint firstItem="dgL-g5-Nkc" firstAttribute="centerY" secondItem="yhy-xd-w5C" secondAttribute="centerY" id="OMy-Cu-HAx"/>
                 <constraint firstItem="UtT-L6-mgW" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="10" id="PQ8-0b-fLa"/>
-                <constraint firstItem="z1r-ZA-ft8" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="10" id="RJQ-ha-NSq"/>
                 <constraint firstItem="AyA-hP-r6w" firstAttribute="leading" secondItem="Gu8-oz-zWa" secondAttribute="leading" constant="10" id="RYl-cO-cCN"/>
                 <constraint firstItem="Gu8-oz-zWa" firstAttribute="bottom" secondItem="m2p-oJ-j15" secondAttribute="bottom" constant="7" id="SYv-gc-ahx"/>
                 <constraint firstItem="C4K-Nv-phA" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="-10" id="Sof-wy-toF"/>
                 <constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="UtT-L6-mgW" secondAttribute="trailing" constant="90" id="Tq4-bB-YMV"/>
                 <constraint firstItem="H4E-G2-C1H" firstAttribute="top" secondItem="w2m-Vw-hpd" secondAttribute="bottom" constant="-10" id="UWI-r9-vcA"/>
                 <constraint firstItem="dgL-g5-Nkc" firstAttribute="centerX" secondItem="yhy-xd-w5C" secondAttribute="centerX" id="VSJ-7R-Srk"/>
+                <constraint firstItem="Gu8-oz-zWa" firstAttribute="bottom" secondItem="qnc-hI-Z9r" secondAttribute="bottom" constant="9" id="XTs-Qg-kiX"/>
                 <constraint firstItem="7Q9-Tv-9yo" firstAttribute="top" secondItem="w2m-Vw-hpd" secondAttribute="bottom" constant="-10" id="XbB-4a-WpA"/>
                 <constraint firstItem="yhy-xd-w5C" firstAttribute="centerY" secondItem="Gu8-oz-zWa" secondAttribute="centerY" id="ZO7-Ny-L3I"/>
                 <constraint firstItem="m2p-oJ-j15" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="10" id="Zyr-qM-9qP"/>
                 <constraint firstAttribute="bottom" secondItem="AXX-71-9Q6" secondAttribute="bottom" constant="13" id="d06-sn-I3Y"/>
                 <constraint firstItem="jc6-Vg-TaS" firstAttribute="centerX" secondItem="o4u-0K-Qpt" secondAttribute="centerX" id="fAq-0d-u57"/>
+                <constraint firstItem="jUe-8q-VJd" firstAttribute="leading" secondItem="qnc-hI-Z9r" secondAttribute="trailing" constant="5" id="jMG-V1-hgF"/>
                 <constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="Egg-cb-EhZ" secondAttribute="trailing" id="k8f-bU-D6I"/>
+                <constraint firstItem="qnc-hI-Z9r" firstAttribute="leading" secondItem="w2m-Vw-hpd" secondAttribute="trailing" constant="10" id="l6K-6H-QIr"/>
                 <constraint firstItem="w2m-Vw-hpd" firstAttribute="leading" secondItem="Gu8-oz-zWa" secondAttribute="leading" constant="10" id="mBb-ff-7HD"/>
                 <constraint firstItem="w2m-Vw-hpd" firstAttribute="leading" secondItem="7Q9-Tv-9yo" secondAttribute="trailing" constant="-10" id="mon-aq-gcP"/>
                 <constraint firstItem="UtT-L6-mgW" firstAttribute="top" secondItem="Gu8-oz-zWa" secondAttribute="top" constant="13" id="nrY-2F-QZ2"/>
@@ -170,7 +206,6 @@
                 <constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="yhy-xd-w5C" secondAttribute="trailing" id="s2S-RP-cw5"/>
                 <constraint firstItem="AyA-hP-r6w" firstAttribute="centerY" secondItem="Gu8-oz-zWa" secondAttribute="centerY" id="sJp-0x-bdC"/>
                 <constraint firstItem="Gu8-oz-zWa" firstAttribute="trailing" secondItem="o4u-0K-Qpt" secondAttribute="trailing" constant="45" id="tOD-Sd-Uhy"/>
-                <constraint firstAttribute="bottom" secondItem="z1r-ZA-ft8" secondAttribute="bottom" constant="9" id="wfc-n7-tCT"/>
                 <constraint firstItem="jc6-Vg-TaS" firstAttribute="centerY" secondItem="o4u-0K-Qpt" secondAttribute="centerY" id="xnq-6u-TXH"/>
             </constraints>
             <size key="customSize" width="719" height="146"/>
@@ -191,16 +226,22 @@
                 <outlet property="progressView" destination="m2p-oJ-j15" id="yFv-KS-nEy"/>
                 <outlet property="separator" destination="Egg-cb-EhZ" id="uhq-Nc-z8K"/>
                 <outlet property="separatorHeightConstraint" destination="G5S-67-boG" id="B6g-qe-MTb"/>
-                <outlet property="tagListView" destination="z1r-ZA-ft8" id="3mW-9T-7Bm"/>
+                <outlet property="tag0" destination="qnc-hI-Z9r" id="6jJ-lV-0ck"/>
+                <outlet property="tag1" destination="jUe-8q-VJd" id="Wcm-rS-rEd"/>
                 <outlet property="titleTrailingConstraint" destination="Tq4-bB-YMV" id="v4n-j5-ZWT"/>
             </connections>
             <point key="canvasLocation" x="128.18590704647679" y="198.40000000000001"/>
         </collectionViewCell>
     </objects>
+    <designables>
+        <designable name="jUe-8q-VJd">
+            <size key="intrinsicContentSize" width="24" height="14.333333333333334"/>
+        </designable>
+        <designable name="qnc-hI-Z9r">
+            <size key="intrinsicContentSize" width="26" height="14.333333333333334"/>
+        </designable>
+    </designables>
     <resources>
-        <systemColor name="systemBackgroundColor">
-            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-        </systemColor>
         <systemColor name="systemGray5Color">
             <color red="0.89803921568627454" green="0.89803921568627454" blue="0.91764705882352937" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>

+ 27 - 11
iOSClient/Main/Collection Common/NCSelectableNavigationView.swift

@@ -42,7 +42,8 @@ protocol NCSelectableNavigationView: AnyObject {
     var selectOcId: [String] { get set }
     var titleCurrentFolder: String { get }
     var navigationItem: UINavigationItem { get }
-
+    var navigationController: UINavigationController? { get }
+    var layoutKey: String { get }
     var selectActions: [NCMenuAction] { get }
 
     func reloadDataSource(forced: Bool)
@@ -55,18 +56,21 @@ protocol NCSelectableNavigationView: AnyObject {
 extension NCSelectableNavigationView {
 
     func setNavigationItem() {
-        setNavigationHeader()
+        setNavigationRightItems()
     }
 
-    func setNavigationHeader() {
+    func setNavigationRightItems() {
         if isEditMode {
-            navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "navigationMore"), style: .plain, action: tapSelectMenu)
-            navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: .plain, action: tapSelect)
-            navigationItem.title = NSLocalizedString("_selected_", comment: "") + " : \(selectOcId.count)" + " / \(selectableDataSource.count)"
+            let more = UIBarButtonItem(image: UIImage(systemName: "ellipsis"), style: .plain, action: tapSelectMenu)
+            navigationItem.rightBarButtonItems = [more]
         } else {
-            navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_select_", comment: ""), style: UIBarButtonItem.Style.plain, action: tapSelect)
-            navigationItem.leftBarButtonItem = nil
-            navigationItem.title = titleCurrentFolder
+            let select = UIBarButtonItem(title: NSLocalizedString("_select_", comment: ""), style: UIBarButtonItem.Style.plain, action: tapSelect)
+            let notification = UIBarButtonItem(image: UIImage(systemName: "bell"), style: .plain, action: tapNotification)
+            if layoutKey == NCGlobal.shared.layoutViewFiles {
+                navigationItem.rightBarButtonItems = [select, notification]
+            } else {
+                navigationItem.rightBarButtonItems = [select]
+            }
         }
     }
 
@@ -79,9 +83,14 @@ extension NCSelectableNavigationView {
 
     func collectionViewSelectAll() {
         selectOcId = selectableDataSource.compactMap({ $0.primaryKeyValue })
-        navigationItem.title = NSLocalizedString("_selected_", comment: "") + " : \(selectOcId.count)" + " / \(selectableDataSource.count)"
         collectionView.reloadData()
     }
+
+    func tapNotification() {
+        if let viewController = UIStoryboard(name: "NCNotification", bundle: nil).instantiateInitialViewController() as? NCNotification {
+            navigationController?.pushViewController(viewController, animated: true)
+        }
+    }
 }
 
 extension NCSelectableNavigationView where Self: UIViewController {
@@ -91,11 +100,18 @@ extension NCSelectableNavigationView where Self: UIViewController {
 
     var selectActions: [NCMenuAction] {
         var actions = [NCMenuAction]()
+
+        actions.append(.cancelAction {
+            self.tapSelect()
+        })
         if selectOcId.count != selectableDataSource.count {
             actions.append(.selectAllAction(action: collectionViewSelectAll))
         }
 
         guard !selectOcId.isEmpty else { return actions }
+
+        actions.append(.seperator(order: 0))
+
         var selectedMetadatas: [tableMetadata] = []
         var selectedMediaMetadatas: [tableMetadata] = []
         var isAnyOffline = false
@@ -128,7 +144,7 @@ extension NCSelectableNavigationView where Self: UIViewController {
 
         actions.append(.openInAction(selectedMetadatas: selectedMetadatas, viewController: self, completion: tapSelect))
 
-        if !isAnyFolder, canUnlock, NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesFilesLockVersion) >= 1 {
+        if !isAnyFolder, canUnlock, !NCGlobal.shared.capabilityFilesLockVersion.isEmpty {
             actions.append(.lockUnlockFiles(shouldLock: !isAnyLocked, metadatas: selectedMetadatas, completion: tapSelect))
         }
 

+ 0 - 457
iOSClient/Main/Create cloud/NCCreateFormUploadAssets.swift

@@ -1,457 +0,0 @@
-//
-//  NCCreateFormUploadAssets.swift
-//  Nextcloud
-//
-//  Created by Marino Faggiana on 14/11/2018.
-//  Copyright © 2018 Marino Faggiana. All rights reserved.
-//
-//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
-//
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, either version 3 of the License, or
-//  (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-//
-
-import UIKit
-import Queuer
-import NextcloudKit
-import XLForm
-import Photos
-
-class NCCreateFormUploadAssets: XLFormViewController, NCSelectDelegate {
-
-    var serverUrl: String = ""
-    var titleServerUrl: String?
-    var assets: [PHAsset] = []
-    var cryptated: Bool = false
-    var session: String = ""
-    let requestOptions = PHImageRequestOptions()
-    var imagePreview: UIImage?
-    let targetSizeImagePreview = CGSize(width: 100, height: 100)
-    let appDelegate = UIApplication.shared.delegate as! AppDelegate
-
-    var cellBackgoundColor = UIColor.secondarySystemGroupedBackground
-
-    // MARK: - View Life Cycle
-
-    convenience init(serverUrl: String, assets: [PHAsset], cryptated: Bool, session: String) {
-
-        self.init()
-
-        if serverUrl == NCUtilityFileSystem.shared.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) {
-            titleServerUrl = "/"
-        } else {
-            if let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, serverUrl)) {
-                if let metadata = NCManageDatabase.shared.getMetadataFromOcId(tableDirectory.ocId) {
-                    titleServerUrl = metadata.fileNameView
-                } else { titleServerUrl = (serverUrl as NSString).lastPathComponent }
-            } else { titleServerUrl = (serverUrl as NSString).lastPathComponent }
-        }
-
-        self.serverUrl = serverUrl
-        self.assets = assets
-        self.cryptated = cryptated
-        self.session = session
-
-        requestOptions.resizeMode = PHImageRequestOptionsResizeMode.exact
-        requestOptions.deliveryMode = PHImageRequestOptionsDeliveryMode.highQualityFormat
-        requestOptions.isSynchronous = true
-    }
-
-    override func viewDidLoad() {
-
-        super.viewDidLoad()
-
-        self.title = NSLocalizedString("_upload_photos_videos_", comment: "")
-
-        view.backgroundColor = .systemGroupedBackground
-        tableView.backgroundColor = .systemGroupedBackground
-        cellBackgoundColor = .secondarySystemGroupedBackground
-
-        self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(cancel))
-        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_save_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(save))
-
-        self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
-
-        if assets.count == 1 && assets[0].mediaType == PHAssetMediaType.image {
-            PHImageManager.default().requestImage(for: assets[0], targetSize: targetSizeImagePreview, contentMode: PHImageContentMode.aspectFill, options: requestOptions, resultHandler: { image, _ in
-                self.imagePreview = image
-            })
-        }
-
-        initializeForm()
-        reloadForm()
-    }
-
-    // MARK: XLForm
-
-    func initializeForm() {
-
-        let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor
-        form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow
-
-        var section: XLFormSectionDescriptor
-        var row: XLFormRowDescriptor
-
-        // Section: Destination Folder
-
-        section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_path_", comment: ""))
-        form.addFormSection(section)
-
-        row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: XLFormRowDescriptorTypeButton, title: self.titleServerUrl)
-        row.action.formSelector = #selector(changeDestinationFolder(_:))
-        row.cellConfig["backgroundColor"] = cellBackgoundColor
-
-        row.cellConfig["imageView.image"] = UIImage(named: "folder")!.image(color: NCBrandColor.shared.brandElement, size: 25)
-        row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.right.rawValue
-        row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0)
-        row.cellConfig["textLabel.textColor"] = UIColor.label
-
-        section.addFormRow(row)
-
-        // User folder Autoupload
-        row = XLFormRowDescriptor(tag: "useFolderAutoUpload", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_use_folder_auto_upload_", comment: ""))
-        row.value = 0
-        row.cellConfig["backgroundColor"] = cellBackgoundColor
-
-        row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0)
-        row.cellConfig["textLabel.textColor"] = UIColor.label
-
-        section.addFormRow(row)
-
-        // Use Sub folder
-        row = XLFormRowDescriptor(tag: "useSubFolder", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_autoupload_create_subfolder_", comment: ""))
-        let activeAccount = NCManageDatabase.shared.getActiveAccount()
-        if activeAccount?.autoUploadCreateSubfolder == true {
-            row.value = 1
-        } else {
-            row.value = 0
-        }
-        row.hidden = "$\("useFolderAutoUpload") == 0"
-
-        row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0)
-        row.cellConfig["textLabel.textColor"] = UIColor.label
-
-        section.addFormRow(row)
-
-        // Section Mode filename
-
-        section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_mode_filename_", comment: ""))
-        form.addFormSection(section)
-
-        // Maintain the original fileName
-
-        row = XLFormRowDescriptor(tag: "maintainOriginalFileName", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_maintain_original_filename_", comment: ""))
-        row.value = CCUtility.getOriginalFileName(NCGlobal.shared.keyFileNameOriginal)
-        row.cellConfig["backgroundColor"] = cellBackgoundColor
-
-        row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0)
-        row.cellConfig["textLabel.textColor"] = UIColor.label
-
-        section.addFormRow(row)
-
-        // Add File Name Type
-
-        row = XLFormRowDescriptor(tag: "addFileNameType", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: NSLocalizedString("_add_filenametype_", comment: ""))
-        row.value = CCUtility.getFileNameType(NCGlobal.shared.keyFileNameType)
-        row.hidden = "$\("maintainOriginalFileName") == 1"
-        row.cellConfig["backgroundColor"] = cellBackgoundColor
-
-        row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0)
-        row.cellConfig["textLabel.textColor"] = UIColor.label
-
-        section.addFormRow(row)
-
-        // Section: Rename File Name
-
-        section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_filename_", comment: ""))
-        form.addFormSection(section)
-
-        row = XLFormRowDescriptor(tag: "maskFileName", rowType: XLFormRowDescriptorTypeText, title: (NSLocalizedString("_filename_", comment: "")))
-        let fileNameMask: String = CCUtility.getFileNameMask(NCGlobal.shared.keyFileNameMask)
-        if fileNameMask.count > 0 {
-            row.value = fileNameMask
-        }
-        row.hidden = "$\("maintainOriginalFileName") == 1"
-        row.cellConfig["backgroundColor"] = cellBackgoundColor
-
-        row.cellConfig["textLabel.font"] = UIFont.systemFont(ofSize: 15.0)
-        row.cellConfig["textLabel.textColor"] = UIColor.label
-
-        row.cellConfig["textField.textAlignment"] = NSTextAlignment.right.rawValue
-        row.cellConfig["textField.font"] = UIFont.systemFont(ofSize: 15.0)
-        row.cellConfig["textField.textColor"] = UIColor.label
-
-        section.addFormRow(row)
-
-        // Section: Preview File Name
-
-        row = XLFormRowDescriptor(tag: "previewFileName", rowType: XLFormRowDescriptorTypeTextView, title: "")
-        row.height = 180
-        row.disabled = true
-        row.cellConfig["backgroundColor"] = cellBackgoundColor
-
-        row.cellConfig["textView.backgroundColor"] = cellBackgoundColor
-        row.cellConfig["textView.font"] = UIFont.systemFont(ofSize: 14.0)
-        row.cellConfig["textView.textColor"] = UIColor.label
-
-        section.addFormRow(row)
-
-        self.form = form
-    }
-
-    override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) {
-
-        super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue)
-
-        if formRow.tag == "useFolderAutoUpload" {
-
-            if (formRow.value! as AnyObject).boolValue  == true {
-
-                let buttonDestinationFolder: XLFormRowDescriptor  = self.form.formRow(withTag: "ButtonDestinationFolder")!
-                buttonDestinationFolder.hidden = true
-
-            } else {
-
-                let buttonDestinationFolder: XLFormRowDescriptor  = self.form.formRow(withTag: "ButtonDestinationFolder")!
-                buttonDestinationFolder.hidden = false
-            }
-        } else if formRow.tag == "useSubFolder" {
-
-            if (formRow.value! as AnyObject).boolValue  == true {
-
-            } else {
-
-            }
-        } else if formRow.tag == "maintainOriginalFileName" {
-            CCUtility.setOriginalFileName((formRow.value! as AnyObject).boolValue, key: NCGlobal.shared.keyFileNameOriginal)
-            self.reloadForm()
-        } else if formRow.tag == "addFileNameType" {
-            CCUtility.setFileNameType((formRow.value! as AnyObject).boolValue, key: NCGlobal.shared.keyFileNameType)
-            self.reloadForm()
-        } else if formRow.tag == "maskFileName" {
-
-            let fileName = formRow.value as? String
-
-            self.form.delegate = nil
-
-            if let fileName = fileName {
-                formRow.value = CCUtility.removeForbiddenCharactersServer(fileName)
-            }
-
-            self.form.delegate = self
-
-            let previewFileName: XLFormRowDescriptor  = self.form.formRow(withTag: "previewFileName")!
-            previewFileName.value = self.previewFileName(valueRename: formRow.value as? String)
-
-            // reload cell
-            if fileName != nil {
-
-                if newValue as! String != formRow.value as! String {
-
-                    self.reloadFormRow(formRow)
-
-                    let error = NKError(errorCode: NCGlobal.shared.errorCharactersForbidden, errorDescription: "_forbidden_characters_")
-                    NCContentPresenter.shared.showInfo(error: error)
-                }
-            }
-
-            self.reloadFormRow(previewFileName)
-        }
-    }
-
-    func reloadForm() {
-
-        self.form.delegate = nil
-
-        let buttonDestinationFolder: XLFormRowDescriptor  = self.form.formRow(withTag: "ButtonDestinationFolder")!
-        buttonDestinationFolder.title = self.titleServerUrl
-
-        let maskFileName: XLFormRowDescriptor = self.form.formRow(withTag: "maskFileName")!
-        let previewFileName: XLFormRowDescriptor  = self.form.formRow(withTag: "previewFileName")!
-        previewFileName.value = self.previewFileName(valueRename: maskFileName.value as? String)
-
-        self.tableView.reloadData()
-        self.form.delegate = self
-    }
-
-    // MARK: - Action
-
-    func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) {
-
-        if serverUrl != nil {
-
-            self.serverUrl = serverUrl!
-
-            if serverUrl == NCUtilityFileSystem.shared.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) {
-                self.titleServerUrl = "/"
-            } else {
-                if let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, self.serverUrl)) {
-                    if let metadata = NCManageDatabase.shared.getMetadataFromOcId(tableDirectory.ocId) {
-                        titleServerUrl = metadata.fileNameView
-                    } else { titleServerUrl = (self.serverUrl as NSString).lastPathComponent }
-                } else { titleServerUrl = (self.serverUrl as NSString).lastPathComponent }
-            }
-
-            // Update
-            let row: XLFormRowDescriptor  = self.form.formRow(withTag: "ButtonDestinationFolder")!
-            row.title = self.titleServerUrl
-            self.updateFormRow(row)
-        }
-    }
-
-    @objc func save() {
-
-        DispatchQueue.global().async {
-
-            let useFolderPhotoRow: XLFormRowDescriptor  = self.form.formRow(withTag: "useFolderAutoUpload")!
-            let useSubFolderRow: XLFormRowDescriptor  = self.form.formRow(withTag: "useSubFolder")!
-            var useSubFolder: Bool = false
-            var metadatasNOConflict: [tableMetadata] = []
-            var metadatasUploadInConflict: [tableMetadata] = []
-            let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, account: self.appDelegate.account)
-
-            if (useFolderPhotoRow.value! as AnyObject).boolValue == true {
-                self.serverUrl = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, account: self.appDelegate.account)
-                useSubFolder = (useSubFolderRow.value! as AnyObject).boolValue
-            }
-
-            if autoUploadPath == self.serverUrl {
-                if !NCNetworking.shared.createFolder(assets: self.assets, selector: NCGlobal.shared.selectorUploadFile, useSubFolder: useSubFolder, account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, withPush: false) {
-                    
-                    let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_error_createsubfolders_upload_")
-                    NCContentPresenter.shared.showError(error: error)
-                    return
-                }
-            }
-
-            for asset in self.assets {
-
-                var serverUrl = self.serverUrl
-                var livePhoto: Bool = false
-                let creationDate = asset.creationDate ?? Date()
-                let fileName = CCUtility.createFileName(asset.value(forKey: "filename") as? String, fileDate: creationDate, fileType: asset.mediaType, keyFileName: NCGlobal.shared.keyFileNameMask, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: false)!
-
-                if asset.mediaSubtypes.contains(.photoLive) && CCUtility.getLivePhoto() {
-                    livePhoto = true
-                }
-
-                if useSubFolder {
-                    let dateFormatter = DateFormatter()
-                    dateFormatter.dateFormat = "yyyy"
-                    let yearString = dateFormatter.string(from: creationDate)
-                    dateFormatter.dateFormat = "MM"
-                    let monthString = dateFormatter.string(from: creationDate)
-                    serverUrl = autoUploadPath + "/" + yearString + "/" + monthString
-                }
-
-                // Check if is in upload
-                let isRecordInSessions = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@ AND session != ''", self.appDelegate.account, serverUrl, fileName), sorted: "fileName", ascending: false)
-                if isRecordInSessions.count > 0 { continue }
-
-                let metadataForUpload = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: serverUrl, urlBase: self.appDelegate.urlBase, url: "", contentType: "", isLivePhoto: livePhoto)
-
-                metadataForUpload.assetLocalIdentifier = asset.localIdentifier
-                metadataForUpload.session = self.session
-                metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile
-                metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload
-
-                if let result = NCManageDatabase.shared.getMetadataConflict(account: self.appDelegate.account, serverUrl: serverUrl, fileNameView: fileName) {
-                    metadataForUpload.fileName = result.fileName
-                    metadatasUploadInConflict.append(metadataForUpload)
-                } else {
-                    metadatasNOConflict.append(metadataForUpload)
-                }
-            }
-
-            // Verify if file(s) exists
-            if metadatasUploadInConflict.count > 0 {
-
-                DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
-                    if let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict {
-
-                        conflict.serverUrl = self.serverUrl
-                        conflict.metadatasNOConflict = metadatasNOConflict
-                        conflict.metadatasUploadInConflict = metadatasUploadInConflict
-                        conflict.delegate = self.appDelegate
-
-                        self.appDelegate.window?.rootViewController?.present(conflict, animated: true, completion: nil)
-                    }
-                }
-
-            } else {
-                NCNetworkingProcessUpload.shared.createProcessUploads(metadatas: metadatasNOConflict, completion: { _ in })
-            }
-
-            DispatchQueue.main.async {self.dismiss(animated: true, completion: nil)  }
-        }
-    }
-
-    @objc func cancel() {
-
-        self.dismiss(animated: true, completion: nil)
-    }
-
-    // MARK: - Utility
-
-    func previewFileName(valueRename: String?) -> String {
-
-        var returnString: String = ""
-        let asset = assets[0]
-        let creationDate = asset.creationDate ?? Date()
-
-        if CCUtility.getOriginalFileName(NCGlobal.shared.keyFileNameOriginal) {
-
-            return (NSLocalizedString("_filename_", comment: "") + ": " + (asset.value(forKey: "filename") as! String))
-
-        } else if let valueRename = valueRename {
-
-            let valueRenameTrimming = valueRename.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
-
-            if valueRenameTrimming.count > 0 {
-
-                self.form.delegate = nil
-                CCUtility.setFileNameMask(valueRename, key: NCGlobal.shared.keyFileNameMask)
-                self.form.delegate = self
-
-                returnString = CCUtility.createFileName(asset.value(forKey: "filename") as! String?, fileDate: creationDate, fileType: asset.mediaType, keyFileName: NCGlobal.shared.keyFileNameMask, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: false)
-
-            } else {
-
-                CCUtility.setFileNameMask("", key: NCGlobal.shared.keyFileNameMask)
-                returnString = CCUtility.createFileName(asset.value(forKey: "filename") as! String?, fileDate: creationDate, fileType: asset.mediaType, keyFileName: nil, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: false)
-            }
-
-        } else {
-
-            CCUtility.setFileNameMask("", key: NCGlobal.shared.keyFileNameMask)
-            returnString = CCUtility.createFileName(asset.value(forKey: "filename") as! String?, fileDate: creationDate, fileType: asset.mediaType, keyFileName: nil, keyFileNameType: NCGlobal.shared.keyFileNameType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal, forcedNewFileName: false)
-        }
-
-        return String(format: NSLocalizedString("_preview_filename_", comment: ""), "MM, MMM, DD, YY, YYYY, HH, hh, mm, ss, ampm") + ":" + "\n\n" + returnString
-    }
-
-    @objc func changeDestinationFolder(_ sender: XLFormRowDescriptor) {
-
-        self.deselectFormRow(sender)
-
-        let storyboard = UIStoryboard(name: "NCSelect", bundle: nil)
-        let navigationController = storyboard.instantiateInitialViewController() as! UINavigationController
-        let viewController = navigationController.topViewController as! NCSelect
-
-        viewController.delegate = self
-        viewController.typeOfCommandView = .selectCreateFolder
-        viewController.includeDirectoryE2EEncryption = true
-
-        self.present(navigationController, animated: true, completion: nil)
-    }
-}

+ 39 - 70
iOSClient/Main/Create cloud/NCUploadAssets.swift

@@ -28,7 +28,6 @@ import Mantis
 import Photos
 import QuickLook
 
-@available(iOS 15, *)
 class NCHostingUploadAssetsView: NSObject {
 
     func makeShipDetailsUI(assets: [TLPHAsset], serverUrl: String, userBaseUrl: NCUserBaseUrl) -> UIViewController {
@@ -146,7 +145,6 @@ class NCUploadAssets: NSObject, ObservableObject, NCCreateFormUploadConflictDele
 
 // MARK: - View
 
-@available(iOS 15, *)
 struct UploadAssetsView: View {
 
     @State private var fileName: String = CCUtility.getFileNameMask(NCGlobal.shared.keyFileNameMask)
@@ -173,19 +171,7 @@ struct UploadAssetsView: View {
         uploadAssets.loadImages()
     }
 
-    func getOriginalFilename() -> String {
-
-        CCUtility.setOriginalFileName(isMaintainOriginalFilename, key: NCGlobal.shared.keyFileNameOriginal)
-
-        if let asset = uploadAssets.assets.first?.phAsset, let name = (asset.value(forKey: "filename") as? String) {
-            return (name as NSString).deletingPathExtension
-        } else {
-            return ""
-        }
-    }
-
     func getTextServerUrl(_ serverUrl: String) -> String {
-
         if let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", uploadAssets.userBaseUrl.account, serverUrl)), let metadata = NCManageDatabase.shared.getMetadataFromOcId(directory.ocId) {
             return (metadata.fileNameView)
         } else {
@@ -193,7 +179,7 @@ struct UploadAssetsView: View {
         }
     }
 
-    func setFileNameMask(fileName: String?) -> String {
+    private func setFileNameMaskForPreview(fileName: String?) -> String {
 
         guard let asset = uploadAssets.assets.first?.phAsset else { return "" }
         var preview: String = ""
@@ -201,49 +187,24 @@ struct UploadAssetsView: View {
 
         CCUtility.setOriginalFileName(isMaintainOriginalFilename, key: NCGlobal.shared.keyFileNameOriginal)
         CCUtility.setFileNameType(isAddFilenametype, key: NCGlobal.shared.keyFileNameType)
+        CCUtility.setFileNameMask(fileName, key: NCGlobal.shared.keyFileNameMask)
 
-        if let fileName = fileName {
-
-            let fileName = fileName.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
-
-            if !fileName.isEmpty {
-
-                CCUtility.setFileNameMask(fileName, key: NCGlobal.shared.keyFileNameMask)
-                preview = CCUtility.createFileName(asset.value(forKey: "filename") as? String,
-                                                   fileDate: creationDate, fileType: asset.mediaType,
-                                                   keyFileName: NCGlobal.shared.keyFileNameMask,
-                                                   keyFileNameType: NCGlobal.shared.keyFileNameType,
-                                                   keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal,
-                                                   forcedNewFileName: false)
-
-            } else {
-
-                CCUtility.setFileNameMask("", key: NCGlobal.shared.keyFileNameMask)
-                preview = CCUtility.createFileName(asset.value(forKey: "filename") as? String,
-                                                   fileDate: creationDate,
-                                                   fileType: asset.mediaType,
-                                                   keyFileName: nil,
-                                                   keyFileNameType: NCGlobal.shared.keyFileNameType,
-                                                   keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal,
-                                                   forcedNewFileName: false)
-            }
+        preview = CCUtility.createFileName(
+            getOriginalFilenameForPreview() as String,
+            fileDate: creationDate,
+            fileType: asset.mediaType,
+            keyFileName: fileName.isEmptyOrNil ? nil : NCGlobal.shared.keyFileNameMask,
+            keyFileNameType: NCGlobal.shared.keyFileNameType,
+            keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal,
+            forcedNewFileName: false
+        )
 
-        } else {
+        let trimmedPreview = preview.trimmingCharacters(in: .whitespacesAndNewlines)
 
-            CCUtility.setFileNameMask("", key: NCGlobal.shared.keyFileNameMask)
-            preview = CCUtility.createFileName(asset.value(forKey: "filename") as? String,
-                                               fileDate: creationDate,
-                                               fileType: asset.mediaType,
-                                               keyFileName: nil,
-                                               keyFileNameType: NCGlobal.shared.keyFileNameType,
-                                               keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal,
-                                               forcedNewFileName: false)
-        }
-
-        return String(format: NSLocalizedString("_preview_filename_", comment: ""), "MM, MMM, DD, YY, YYYY, HH, hh, mm, ss, ampm") + ":" + "\n\n" + (preview as NSString).deletingPathExtension
+        return String(format: NSLocalizedString("_preview_filename_", comment: ""), "MM, MMM, DD, YY, YYYY, HH, hh, mm, ss, ampm") + ":" + "\n\n" + (trimmedPreview as NSString).deletingPathExtension
     }
 
-    func save(completion: @escaping (_ metadatasNOConflict: [tableMetadata], _ metadatasUploadInConflict: [tableMetadata]) -> Void) {
+    private func save(completion: @escaping (_ metadatasNOConflict: [tableMetadata], _ metadatasUploadInConflict: [tableMetadata]) -> Void) {
 
         var metadatasNOConflict: [tableMetadata] = []
         var metadatasUploadInConflict: [tableMetadata] = []
@@ -252,21 +213,21 @@ struct UploadAssetsView: View {
         let autoUploadSubfolderGranularity = NCManageDatabase.shared.getAccountAutoUploadSubfolderGranularity()
 
         for tlAsset in uploadAssets.assets {
-            guard let asset = tlAsset.phAsset,
-                  let previewStore = uploadAssets.previewStore.first(where: { $0.id == asset.localIdentifier }),
-                  let assetFileName = asset.value(forKey: "filename") as? NSString else { continue }
+            guard let asset = tlAsset.phAsset, let previewStore = uploadAssets.previewStore.first(where: { $0.id == asset.localIdentifier }) else { continue }
 
+            let assetFileName = asset.originalFilename
             var livePhoto: Bool = false
             let creationDate = asset.creationDate ?? Date()
             let ext = assetFileName.pathExtension.lowercased()
-            let fileName = previewStore.fileName.isEmpty ?
-            CCUtility.createFileName(assetFileName as String,
-                                                    fileDate: creationDate,
-                                                    fileType: asset.mediaType,
-                                                    keyFileName: NCGlobal.shared.keyFileNameMask,
-                                                    keyFileNameType: NCGlobal.shared.keyFileNameType,
-                                                    keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal,
-                                                    forcedNewFileName: false)!
+
+            let fileName = previewStore.fileName.isEmpty
+            ? CCUtility.createFileName(assetFileName as String,
+                                       fileDate: creationDate,
+                                       fileType: asset.mediaType,
+                                       keyFileName: NCGlobal.shared.keyFileNameMask,
+                                       keyFileNameType: NCGlobal.shared.keyFileNameType,
+                                       keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginal,
+                                       forcedNewFileName: false)!
             : (previewStore.fileName + "." + ext)
 
             if previewStore.assetType == .livePhoto && CCUtility.getLivePhoto() && previewStore.data == nil {
@@ -331,7 +292,7 @@ struct UploadAssetsView: View {
         completion(metadatasNOConflict, metadatasUploadInConflict)
     }
 
-    func presentedQuickLook(index: Int) {
+    private func presentedQuickLook(index: Int) {
 
         var image: UIImage?
 
@@ -353,8 +314,7 @@ struct UploadAssetsView: View {
         }
     }
 
-    func deleteAsset(index: Int) {
-
+    private func deleteAsset(index: Int) {
         uploadAssets.assets.remove(at: index)
         uploadAssets.previewStore.remove(at: index)
         if uploadAssets.previewStore.isEmpty {
@@ -362,6 +322,16 @@ struct UploadAssetsView: View {
         }
     }
 
+    private func getOriginalFilenameForPreview() -> NSString {
+        CCUtility.setOriginalFileName(isMaintainOriginalFilename, key: NCGlobal.shared.keyFileNameOriginal)
+
+        if let asset = uploadAssets.assets.first?.phAsset {
+            return asset.originalFilename
+        } else {
+            return ""
+        }
+    }
+
     var body: some View {
 
         NavigationView {
@@ -496,7 +466,7 @@ struct UploadAssetsView: View {
                         HStack {
                             Text(NSLocalizedString("_filename_", comment: ""))
                             if isMaintainOriginalFilename {
-                                Text(getOriginalFilename())
+                                Text(getOriginalFilenameForPreview().deletingPathExtension)
                                     .font(.system(size: 15))
                                     .frame(maxWidth: .infinity, alignment: .trailing)
                                     .foregroundColor(Color.gray)
@@ -508,7 +478,7 @@ struct UploadAssetsView: View {
                             }
                         }
                         if !isMaintainOriginalFilename {
-                            Text(setFileNameMask(fileName: fileName))
+                            Text(setFileNameMaskForPreview(fileName: fileName))
                                 .font(.system(size: 11))
                                 .foregroundColor(Color.gray)
                         }
@@ -608,7 +578,6 @@ struct UploadAssetsView: View {
 
 // MARK: - Preview
 
-@available(iOS 15, *)
 struct UploadAssetsView_Previews: PreviewProvider {
     static var previews: some View {
         if let appDelegate = UIApplication.shared.delegate as? AppDelegate {

+ 77 - 6
iOSClient/Main/NCActionCenter.swift

@@ -27,6 +27,7 @@ import Queuer
 import JGProgressHUD
 import SVGKit
 import Photos
+import Alamofire
 
 class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelectDelegate {
     public static let shared: NCActionCenter = {
@@ -170,6 +171,76 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
         }
     }
 
+    func viewerFile(account: String, fileId: String, viewController: UIViewController) {
+
+        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, let hudView = appDelegate.window?.rootViewController?.view else { return }
+        var downloadRequest: DownloadRequest?
+
+        if let metadata = NCManageDatabase.shared.getMetadataFromFileId(fileId) {
+            if let filePath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView) {
+                do {
+                    let attr = try FileManager.default.attributesOfItem(atPath: filePath)
+                    let fileSize = attr[FileAttributeKey.size] as? UInt64 ?? 0
+                    if fileSize > 0 {
+                        NCViewer.shared.view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: nil)
+                        return
+                    }
+                } catch {
+                    print("Error: \(error)")
+                }
+            }
+        }
+
+        let hud = JGProgressHUD()
+        hud.indicatorView = JGProgressHUDRingIndicatorView()
+        if let indicatorView = hud.indicatorView as? JGProgressHUDRingIndicatorView {
+            indicatorView.ringWidth = 1.5
+        }
+        hud.tapOnHUDViewBlock = { _ in
+            if let request = downloadRequest {
+                request.cancel()
+            }
+        }
+        hud.show(in: hudView)
+
+        NextcloudKit.shared.getFileFromFileId(fileId: fileId) { account, file, _, error in
+
+            hud.dismiss()
+            if error != .success {
+                NCContentPresenter.shared.showError(error: error)
+            } else if let file = file {
+
+                let isDirectoryE2EE = NCUtility.shared.isDirectoryE2EE(file: file)
+                let metadata = NCManageDatabase.shared.convertFileToMetadata(file, isDirectoryE2EE: isDirectoryE2EE)
+                NCManageDatabase.shared.addMetadata(metadata)
+
+                let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
+                let fileNameLocalPath = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)!
+
+                if metadata.isMovie {
+                    NCViewer.shared.view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: nil)
+                } else {
+                    hud.show(in: hudView)
+                    NextcloudKit.shared.download(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, requestHandler: { request in
+                        downloadRequest = request
+                    }, taskHandler: { _ in
+                    }, progressHandler: { progress in
+                        hud.progress = Float(progress.fractionCompleted)
+                    }) { accountDownload, _, _, _, _, _, error in
+                        hud.dismiss()
+                        if account == accountDownload && error == .success {
+                            NCManageDatabase.shared.addLocalFile(metadata: metadata)
+                            NCViewer.shared.view(viewController: viewController, metadata: metadata, metadatas: [metadata], imageIcon: nil)
+                        }
+                    }
+                }
+            } else {
+                let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_file_not_found_")
+                NCContentPresenter.shared.showError(error: error)
+            }
+        }
+    }
+
     // MARK: - Upload
 
     @objc func uploadedFile(_ notification: NSNotification) {
@@ -204,20 +275,23 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
 
                 let shareNavigationController = UIStoryboard(name: "NCShare", bundle: nil).instantiateInitialViewController() as? UINavigationController
                 let shareViewController = shareNavigationController?.topViewController as? NCSharePaging
-                let activity = NCManageDatabase.shared.getCapabilitiesServerArray(account: metadata.account, elements: NCElementsJSON.shared.capabilitiesActivity)
 
                 for value in NCBrandOptions.NCInfoPagingTab.allCases {
                     pages.append(value)
                 }
 
-                if activity == nil, let idx = pages.firstIndex(of: .activity) {
+                if NCGlobal.shared.capabilityActivity.isEmpty, let idx = pages.firstIndex(of: .activity) {
                     pages.remove(at: idx)
                 }
-                if !metadata.isSharable, let idx = pages.firstIndex(of: .sharing) {
+                if !metadata.isSharable(), let idx = pages.firstIndex(of: .sharing) {
                     pages.remove(at: idx)
                 }
+
                 (pages, page) = NCApplicationHandle().filterPages(pages: pages, page: page, metadata: metadata)
 
+                shareViewController?.pages = pages
+                shareViewController?.metadata = metadata
+
                 if pages.contains(page) {
                     shareViewController?.page = page
                 } else if let page = pages.first {
@@ -226,9 +300,6 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
                     return
                 }
 
-                shareViewController?.pages = pages
-                shareViewController?.metadata = metadata
-
                 shareNavigationController?.modalPresentationStyle = .formSheet
                 if let shareNavigationController = shareNavigationController {
                     viewController.present(shareNavigationController, animated: true, completion: nil)

+ 0 - 6
iOSClient/Main/NCCellProtocol.swift

@@ -22,7 +22,6 @@
 //
 
 import UIKit
-import TagListView
 
 protocol NCCellProtocol {
 
@@ -40,7 +39,6 @@ protocol NCCellProtocol {
     var fileSharedImage: UIImageView? { get set }
     var fileMoreImage: UIImageView? { get set }
     var cellSeparatorView: UIView? { get set }
-    var cellTagListView: TagListView? { get set }
 
     func titleInfoTrailingDefault()
     func titleInfoTrailingFull()
@@ -107,10 +105,6 @@ extension NCCellProtocol {
         get { return nil }
         set {}
     }
-    var cellTagListView: TagListView? {
-        get { return nil }
-        set {}
-    }
 
     func titleInfoTrailingDefault() {}
     func titleInfoTrailingFull() {}

+ 3 - 12
iOSClient/Main/NCPickerViewController.swift

@@ -46,18 +46,9 @@ class NCPhotosPickerViewController: NSObject {
 
         self.openPhotosPickerViewController { assets in
             if !assets.isEmpty {
-                if #available(iOS 15, *) {
-                    let vc = NCHostingUploadAssetsView().makeShipDetailsUI(assets: assets, serverUrl: self.appDelegate.activeServerUrl, userBaseUrl: self.appDelegate)
-                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
-                        viewController.present(vc, animated: true, completion: nil)
-                    }
-                } else {
-                    let assets = assets.compactMap { $0.phAsset }
-                    let vc = NCCreateFormUploadAssets(serverUrl: self.appDelegate.activeServerUrl, assets: assets, cryptated: false, session: NCNetworking.shared.sessionIdentifierBackground)
-                    let navigationController = UINavigationController(rootViewController: vc)
-                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
-                        viewController.present(navigationController, animated: true, completion: nil)
-                    }
+                let vc = NCHostingUploadAssetsView().makeShipDetailsUI(assets: assets, serverUrl: self.appDelegate.activeServerUrl, userBaseUrl: self.appDelegate)
+                DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
+                    viewController.present(vc, animated: true, completion: nil)
                 }
             }
         }

+ 2 - 1
iOSClient/Media/NCMedia.swift

@@ -170,11 +170,12 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate, NCSelectDelegate {
     @objc func deleteFile(_ notification: NSNotification) {
 
         guard let userInfo = notification.userInfo as NSDictionary?,
+              let account = userInfo["account"] as? String,
               let ocIds = userInfo["ocId"] as? [String],
               let error = userInfo["error"] as? NKError
         else { return }
 
-        if error == .success {
+        if error == .success, account == appDelegate.account {
             var items: [IndexPath] = []
             var index: Int = 0
             for metadata in metadatas {

+ 3 - 4
iOSClient/Menu/AppDelegate+Menu.swift

@@ -37,7 +37,6 @@ extension AppDelegate {
         let directEditingCreators = NCManageDatabase.shared.getDirectEditingCreators(account: appDelegate.account)
         let isDirectoryE2EE = NCUtility.shared.isDirectoryE2EE(serverUrl: appDelegate.activeServerUrl, userBase: appDelegate)
         let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, appDelegate.activeServerUrl))
-        let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
         let serverUrlHome = NCUtilityFileSystem.shared.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId)
 
 
@@ -148,7 +147,7 @@ extension AppDelegate {
             actions.append(.seperator(order: 0))
         }
 
-        if serverVersionMajor >= NCGlobal.shared.nextcloudVersion18 && directory?.richWorkspace == nil && !isDirectoryE2EE && NextcloudKit.shared.isNetworkReachable() {
+        if NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion18 && directory?.richWorkspace == nil && !isDirectoryE2EE && NextcloudKit.shared.isNetworkReachable() {
             actions.append(
                 NCMenuAction(
                     title: NSLocalizedString("_add_folder_info_", comment: ""), icon: UIImage(named: "addFolderInfo")!.image(color: UIColor.systemGray, size: 50), action: { _ in
@@ -234,8 +233,8 @@ extension AppDelegate {
             )
         }
 
-        if let richdocumentsMimetypes = NCManageDatabase.shared.getCapabilitiesServerArray(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesRichdocumentsMimetypes) {
-            if richdocumentsMimetypes.count > 0 &&  NextcloudKit.shared.isNetworkReachable() && !isDirectoryE2EE {
+        if !NCGlobal.shared.capabilityRichdocumentsMimetypes.isEmpty {
+            if NextcloudKit.shared.isNetworkReachable() && !isDirectoryE2EE {
                 actions.append(
                     NCMenuAction(
                         title: NSLocalizedString("_create_new_document_", comment: ""), icon: UIImage(named: "create_file_document")!, action: { _ in

+ 1 - 2
iOSClient/Menu/NCCollectionViewCommon+Menu.swift

@@ -140,8 +140,7 @@ extension NCCollectionViewCommon {
         //
         // LOCK / UNLOCK
         //
-        let hasLockCapability = NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesFilesLockVersion) >= 1
-        if !metadata.directory, metadata.canUnlock(as: appDelegate.userId), hasLockCapability {
+        if !metadata.directory, metadata.canUnlock(as: appDelegate.userId), !NCGlobal.shared.capabilityFilesLockVersion.isEmpty {
             actions.append(NCMenuAction.lockUnlockFiles(shouldLock: !metadata.lock, metadatas: [metadata], order: 30))
         }
 

+ 4 - 2
iOSClient/Menu/NCContextMenu.swift

@@ -160,13 +160,14 @@ class NCContextMenu: NSObject {
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_delete_file_", comment: ""), style: .destructive) { _ in
                 Task {
                     var ocId: [String] = []
+                    let account: String = metadata.account
                     let error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false)
                     if error == .success {
                         ocId.append(metadata.ocId)
                     } else {
                         NCContentPresenter.shared.showError(error: error)
                     }
-                    NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "error": error])
+                    NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["account": account, "ocId": ocId, "error": error])
                 }
             })
             alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { _ in })
@@ -177,13 +178,14 @@ class NCContextMenu: NSObject {
                                           image: UIImage(systemName: "trash"), attributes: .destructive) { _ in
             Task {
                 var ocId: [String] = []
+                let account: String = metadata.account
                 let error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: true)
                 if error == .success {
                     ocId.append(metadata.ocId)
                 } else {
                     NCContentPresenter.shared.showError(error: error)
                 }
-                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "error": error])
+                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["account": account, "ocId": ocId, "error": error])
             }
         }
 

+ 13 - 2
iOSClient/Menu/NCMenuAction.swift

@@ -82,6 +82,15 @@ extension NCMenuAction {
         )
     }
 
+    /// Cancel
+    static func cancelAction(action: @escaping () -> Void) -> NCMenuAction {
+        NCMenuAction(
+            title: NSLocalizedString("_cancel_", comment: ""),
+            icon: NCUtility.shared.loadImage(named: "xmark"),
+            action: { _ in action() }
+        )
+    }
+
     /// Copy files to pasteboard
     static func copyAction(selectOcId: [String], hudView: UIView, order: Int = 0, completion: (() -> Void)? = nil) -> NCMenuAction {
         NCMenuAction(
@@ -139,6 +148,7 @@ extension NCMenuAction {
                         Task {
                             var error = NKError()
                             var ocId: [String] = []
+                            let account = selectedMetadatas.first?.account ?? ""
                             for metadata in selectedMetadatas where error == .success {
                                 error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: false)
                                 if error == .success {
@@ -148,7 +158,7 @@ extension NCMenuAction {
                             if error != .success {
                                 NCContentPresenter.shared.showError(error: error)
                             }
-                            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "error": error])
+                            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["account": account, "ocId": ocId, "error": error])
                         }
                         completion?()
                     })
@@ -160,6 +170,7 @@ extension NCMenuAction {
                         Task {
                             var error = NKError()
                             var ocId: [String] = []
+                            let account = selectedMetadatas.first?.account ?? ""
                             for metadata in selectedMetadatas where error == .success {
                                 error = await NCNetworking.shared.deleteMetadata(metadata, onlyLocalCache: true)
                                 if error == .success {
@@ -169,7 +180,7 @@ extension NCMenuAction {
                             if error != .success {
                                 NCContentPresenter.shared.showError(error: error)
                             }
-                            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["ocId": ocId, "error": error])
+                            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDeleteFile, userInfo: ["account": account, "ocId": ocId, "error": error])
                         }
                         completion?()
                     })

+ 1 - 2
iOSClient/Menu/UIViewController+Menu.swift

@@ -62,8 +62,7 @@ extension UIViewController {
     func showProfileMenu(userId: String) {
 
         guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
-        let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
-        guard serverVersionMajor >= NCGlobal.shared.nextcloudVersion23 else { return }
+        guard NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion23 else { return }
 
         NextcloudKit.shared.getHovercard(for: userId) { account, card, _, _ in
             guard let card = card, account == appDelegate.account else { return }

+ 13 - 26
iOSClient/More/NCMore.swift

@@ -88,7 +88,6 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
 
         var item = NKExternalSite()
         var quota: String = ""
-        let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
 
         // Clear
         functionMenu.removeAll()
@@ -114,14 +113,6 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
         item.order = 20
         functionMenu.append(item)
 
-        // ITEM : Notification
-        item = NKExternalSite()
-        item.name = "_notifications_"
-        item.icon = "bell"
-        item.url = "segueNotification"
-        item.order = 30
-        functionMenu.append(item)
-
         // ITEM : Activity
         item = NKExternalSite()
         item.name = "_activity_"
@@ -131,8 +122,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
         functionMenu.append(item)
 
         // ITEM : Shares
-        let isFilesSharingEnabled = NCManageDatabase.shared.getCapabilitiesServerBool(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesFileSharingApiEnabled, exists: false)
-        if isFilesSharingEnabled {
+        if NCGlobal.shared.capabilityFileSharingApiEnabled {
             item = NKExternalSite()
             item.name = "_list_shares_"
             item.icon = "share"
@@ -150,8 +140,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
         functionMenu.append(item)
 
         // ITEM : Groupfolders
-        let hasAccessibleGroupFolders = NCManageDatabase.shared.getCapabilitiesServerBool(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesGroupfoldersEnabled, exists: false)
-        if hasAccessibleGroupFolders {
+        if NCGlobal.shared.capabilityGroupfoldersEnabled {
             item = NKExternalSite()
             item.name = "_group_folders_"
             item.icon = "person.2"
@@ -168,7 +157,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
         functionMenu.append(item)
 
         // ITEM : Trash
-        if serverVersionMajor >= NCGlobal.shared.nextcloudVersion15 {
+        if NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion15 {
             item = NKExternalSite()
             item.name = "_trash_view_"
             item.icon = "trash"
@@ -358,18 +347,16 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource {
             cell.backgroundColor = .secondarySystemGroupedBackground
             cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator
 
-            if NCManageDatabase.shared.getCapabilitiesServerBool(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesUserStatusEnabled, exists: false) {
-                if let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", appDelegate.account)) {
-                    let status = NCUtility.shared.getUserStatus(userIcon: account.userStatusIcon, userStatus: account.userStatusStatus, userMessage: account.userStatusMessage)
-                    cell.icon.image = status.onlineStatus
-                    cell.status.text = status.statusMessage
-                    cell.status.textColor = .label
-                    cell.status.trailingBuffer = cell.status.frame.width
-                    if cell.status.labelShouldScroll() {
-                        cell.status.tapToScroll = true
-                    } else {
-                        cell.status.tapToScroll = false
-                    }
+            if NCGlobal.shared.capabilityUserStatusEnabled, let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", appDelegate.account)) {
+                let status = NCUtility.shared.getUserStatus(userIcon: account.userStatusIcon, userStatus: account.userStatusStatus, userMessage: account.userStatusMessage)
+                cell.icon.image = status.onlineStatus
+                cell.status.text = status.statusMessage
+                cell.status.textColor = .label
+                cell.status.trailingBuffer = cell.status.frame.width
+                if cell.status.labelShouldScroll() {
+                    cell.status.tapToScroll = true
+                } else {
+                    cell.status.tapToScroll = false
                 }
             }
             

+ 41 - 4
iOSClient/NCGlobal.swift

@@ -22,6 +22,7 @@
 //
 
 import UIKit
+import SwiftyJSON
 
 class NCGlobal: NSObject {
     @objc static let shared: NCGlobal = {
@@ -207,13 +208,13 @@ class NCGlobal: NSObject {
     @objc let errorRequestExplicityCancelled: Int   = 15
     @objc let errorNotModified: Int                 = 304
     @objc let errorBadRequest: Int                  = 400
-    @objc let errorUnauthorized: Int                = 401
+    @objc let errorUnauthorized401: Int             = 401
     @objc let errorForbidden: Int                   = 403
     @objc let errorResourceNotFound: Int            = 404
     @objc let errordMethodNotSupported: Int         = 405
     @objc let errorConflict: Int                    = 409
     @objc let errorPreconditionFailed: Int          = 412
-    @objc let errorNCUnauthorized: Int              = 997
+    @objc let errorUnauthorized997: Int             = 997
     @objc let errorConnectionLost: Int              = -1005
     @objc let errorNetworkNotAvailable: Int         = -1009
     @objc let errorBadServerResponse: Int           = -1011
@@ -318,7 +319,7 @@ class NCGlobal: NSObject {
     let notificationCenterApplicationDidBecomeActive            = "applicationDidBecomeActive"
     let notificationCenterApplicationWillResignActive           = "applicationWillResignActive"
 
-    @objc let notificationCenterInitialize                      = "initialize"                      // userInfo?: atStart
+    @objc let notificationCenterInitialize                      = "initialize"
     @objc let notificationCenterChangeTheming                   = "changeTheming"
     let notificationCenterRichdocumentGrabFocus                 = "richdocumentGrabFocus"
     let notificationCenterReloadDataNCShare                     = "reloadDataNCShare"
@@ -343,7 +344,7 @@ class NCGlobal: NSObject {
     let notificationCenterProgressTask                          = "progressTask"                    // userInfo: account, ocId, serverUrl, status, progress, totalBytes, totalBytesExpected
 
     let notificationCenterCreateFolder                          = "createFolder"                    // userInfo: ocId, serverUrl, account, e2ee, withPush
-    let notificationCenterDeleteFile                            = "deleteFile"                      // userInfo: ocIds, error
+    let notificationCenterDeleteFile                            = "deleteFile"                      // userInfo: account, ocIds, error
     let notificationCenterRenameFile                            = "renameFile"                      // userInfo: ocId, account
     let notificationCenterMoveFile                              = "moveFile"                        // userInfo: ocId, account, serverUrlFrom
     let notificationCenterCopyFile                              = "copyFile"                        // userInfo: ocId, serverUrlTo
@@ -404,4 +405,40 @@ class NCGlobal: NSObject {
     let configuration_disable_manage_account                    = "disable_manage_account"
     let configuration_disable_more_external_site                = "disable_more_external_site"
     let configuration_disable_openin_file                       = "disable_openin_file"
+
+    // CAPABILITIES
+    //
+    var capabilityServerVersionMajor: Int                       = 0
+    @objc var capabilityServerVersion: String                   = ""
+    
+    var capabilityFileSharingApiEnabled: Bool                   = false
+    var capabilityFileSharingPubPasswdEnforced: Bool            = false
+    var capabilityFileSharingPubExpireDateEnforced: Bool        = false
+    var capabilityFileSharingPubExpireDateDays: Int             = 0
+    var capabilityFileSharingInternalExpireDateEnforced: Bool   = false
+    var capabilityFileSharingInternalExpireDateDays: Int        = 0
+    var capabilityFileSharingRemoteExpireDateEnforced: Bool     = false
+    var capabilityFileSharingRemoteExpireDateDays: Int          = 0
+    var capabilityFileSharingDefaultPermission: Int             = 0
+
+    var capabilityThemingColor: String                          = ""
+    var capabilityThemingColorElement: String                   = ""
+    var capabilityThemingColorText: String                      = ""
+    @objc var capabilityThemingName: String                     = ""
+    @objc var capabilityThemingSlogan: String                   = ""
+
+    @objc var capabilityE2EEEnabled: Bool                       = false
+    @objc var capabilityE2EEApiVersion: String                  = ""
+
+    var capabilityRichdocumentsMimetypes: [String]              = []
+    var capabilityActivity: [String]                            = []
+    var capabilityNotification: [String]                        = []
+
+    var capabilityFilesUndelete: Bool                           = false
+    var capabilityFilesLockVersion: String                      = ""    // NC 24
+    var capabilityFilesComments: Bool                           = false // NC 20
+
+    @objc var capabilityUserStatusEnabled: Bool                 = false
+    var capabilityExternalSites: Bool                           = false
+    var capabilityGroupfoldersEnabled: Bool                     = false // NC27
 }

+ 1 - 2
iOSClient/Networking/E2EE/NCEndToEndMetadata.swift

@@ -202,7 +202,6 @@ class NCEndToEndMetadata: NSObject {
             return (0, "", NKError(errorCode: NCGlobal.shared.errorE2EE, errorDescription: "Error decoding JSON"))
         }
 
-        let versionE2EE = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesE2EEApiVersion) ?? ""
         data.printJson()
 
         let decoder = JSONDecoder()
@@ -212,7 +211,7 @@ class NCEndToEndMetadata: NSObject {
         } else if (try? decoder.decode(E2eeV12.self, from: data)) != nil {
             return decoderMetadataV12(json, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId, ownerId: ownerId)
         } else {
-            return (0, "", NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "Server E2EE version " + versionE2EE + ", not compatible"))
+            return (0, "", NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "Server E2EE version " + NCGlobal.shared.capabilityE2EEApiVersion + ", not compatible"))
         }
     }
 

+ 1 - 3
iOSClient/Networking/E2EE/NCNetworkingE2EE.swift

@@ -33,9 +33,7 @@ class NCNetworkingE2EE: NSObject {
 
     func isE2EEVersionWriteable(account: String) -> NKError? {
 
-        let versionE2EE = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesE2EEApiVersion) ?? ""
-
-        if NCGlobal.shared.e2eeReadVersions.last == versionE2EE {
+        if NCGlobal.shared.e2eeReadVersions.last == NCGlobal.shared.capabilityE2EEApiVersion {
             return nil
         }
         

+ 1 - 1
iOSClient/Networking/NCAutoUpload.swift

@@ -118,7 +118,7 @@ class NCAutoUpload: NSObject {
                 let day = dateFormatter.string(from: assetDate)
                 let assetMediaType = asset.mediaType
                 var serverUrl: String = ""
-                let fileName = CCUtility.createFileName(asset.value(forKey: "filename") as? String, fileDate: assetDate, fileType: assetMediaType, keyFileName: NCGlobal.shared.keyFileNameAutoUploadMask, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false)!
+                let fileName = CCUtility.createFileName(asset.originalFilename as String, fileDate: assetDate, fileType: assetMediaType, keyFileName: NCGlobal.shared.keyFileNameAutoUploadMask, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false)!
 
                 if asset.mediaSubtypes.contains(.photoLive) && CCUtility.getLivePhoto() {
                     livePhoto = true

+ 2 - 4
iOSClient/Networking/NCNetworkingCheckRemoteUser.swift

@@ -27,7 +27,6 @@ class NCNetworkingCheckRemoteUser {
 
     func checkRemoteUser(account: String, error: NKError) {
 
-        let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
         guard let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) else {
             return
         }
@@ -40,7 +39,7 @@ class NCNetworkingCheckRemoteUser {
 
         // -----------------------
 
-        if serverVersionMajor >= NCGlobal.shared.nextcloudVersion17 {
+        if NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion17 {
 
             let token = CCUtility.getPassword(account)!
             if token.isEmpty {
@@ -59,13 +58,12 @@ class NCNetworkingCheckRemoteUser {
 
                 } else {
 
-                    if UIApplication.shared.applicationState == .active && NextcloudKit.shared.isNetworkReachable() && !CCUtility.getPassword(account).isEmpty && !appDelegate.deletePasswordSession {
+                    if UIApplication.shared.applicationState == .active && NextcloudKit.shared.isNetworkReachable() && !CCUtility.getPassword(account).isEmpty {
                         let description = String.localizedStringWithFormat(NSLocalizedString("_error_check_remote_user_", comment: ""), tableAccount.user, tableAccount.urlBase)
                         let error = NKError(errorCode: error.errorCode, errorDescription: description)
                         NCContentPresenter.shared.showError(error: error, priority: .max)
                         CCUtility.setPassword(account, password: nil)
                         NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Password removed.")
-                        appDelegate.deletePasswordSession = true
                     }
                 }
             }

+ 73 - 86
iOSClient/Networking/NCService.swift

@@ -41,9 +41,17 @@ class NCService: NSObject {
         NCManageDatabase.shared.clearAllAvatarLoaded()
         guard !appDelegate.account.isEmpty else { return }
 
-        addInternalTypeIdentifier()
-        requestServerStatus()
-        requestUserProfile()        
+        Task {
+            addInternalTypeIdentifier()
+            let result = await requestServerStatus()
+            if result.serverStatus, let tableAccount = result.tableAccount {
+                synchronize(tableAccount: tableAccount)
+                getAvatar(tableAccount: tableAccount)
+                requestServerCapabilities()
+                requestDashboardWidget()
+                NCNetworkingE2EE.shared.unlockAll(account: tableAccount.account)
+            }
+        }
     }
 
     // MARK: -
@@ -81,91 +89,78 @@ class NCService: NSObject {
 
     // MARK: -
 
-    private func requestServerStatus() {
+    private func requestServerStatus() async -> (serverStatus: Bool, tableAccount: tableAccount?) {
 
         let options = NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
 
-        NextcloudKit.shared.getServerStatus(serverUrl: appDelegate.urlBase, options: options) { serverProductName, _, versionMajor, _, _, extendedSupport, data, error in
-            guard error == .success, extendedSupport == false else {
-                return
-            }
-
-            if serverProductName == "owncloud" {
+        switch await NextcloudKit.shared.getServerStatus(serverUrl: appDelegate.urlBase, options: options) {
+        case .success(let serverInfo):
+            if serverInfo.maintenance {
+                let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_maintenance_mode_")
+                NCContentPresenter.shared.showWarning(error: error, priority: .max)
+                return (false, nil)
+            } else if serverInfo.productName.lowercased().contains("owncloud") {
                 let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_warning_owncloud_")
                 NCContentPresenter.shared.showWarning(error: error, priority: .max)
-            } else if versionMajor <=  NCGlobal.shared.nextcloud_unsupported_version {
+                return (false, nil)
+            } else if serverInfo.versionMajor <=  NCGlobal.shared.nextcloud_unsupported_version {
                 let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_warning_unsupported_")
                 NCContentPresenter.shared.showWarning(error: error, priority: .max)
             }
+        case .failure(_):
+            return(false, nil)
         }
-    }
-
-    // MARK: -
-
-    private func requestUserProfile() {
-        guard !appDelegate.account.isEmpty else { return }
-
-        let options = NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
 
-        NextcloudKit.shared.getUserProfile(options: options) { account, userProfile, data, error in
-            guard error == .success, let userProfile = userProfile else {
-                
-                // Ops the server has Unauthorized
-                NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] The server has response with Unauthorized \(error.errorCode)")
-
-                DispatchQueue.main.async {
-                    if  (UIApplication.shared.applicationState == .active) &&
-                        (NCNetworking.shared.networkReachability != NKCommon.TypeReachability.notReachable) &&
-                        (error.errorCode == NCGlobal.shared.errorNCUnauthorized || error.errorCode == NCGlobal.shared.errorUnauthorized || error.errorCode == NCGlobal.shared.errorForbidden) {
-                        
-                        NCBrandColor.shared.settingThemingColor(account: account)
-                        NCNetworkingCheckRemoteUser().checkRemoteUser(account: account, error: error)
-                    }
-                }
-                return
-            }
-
-            // Update User (+ userProfile.id) & active account & account network
-            guard let tableAccount = NCManageDatabase.shared.setAccountUserProfile(account: account, userProfile: userProfile) else {
-                let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "Internal error : account not found on DB")
+        let resultUserProfile = await NextcloudKit.shared.getUserProfile(options: options)
+        if resultUserProfile.error == .success, let userProfile = resultUserProfile.userProfile {
+            guard let tableAccount = NCManageDatabase.shared.setAccountUserProfile(account: resultUserProfile.account, userProfile: userProfile) else {
+                let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "Internal error: account not found on DB")
                 NCContentPresenter.shared.showError(error: error, priority: .max)
-                return
+                return (false, nil)
+            }
+            await self.appDelegate.settingAccount(tableAccount.account, urlBase: tableAccount.urlBase, user: tableAccount.user, userId: tableAccount.userId, password: CCUtility.getPassword(tableAccount.account))
+            return (true, tableAccount)
+        } else if resultUserProfile.error.errorCode == NCGlobal.shared.errorUnauthorized401 ||
+                    resultUserProfile.error.errorCode == NCGlobal.shared.errorUnauthorized997 {
+            // Ops the server has Unauthorized
+            DispatchQueue.main.async {
+                if UIApplication.shared.applicationState == .active && NCNetworking.shared.networkReachability != NKCommon.TypeReachability.notReachable {
+                    NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] The server has response with Unauthorized go checkRemoteUser \(resultUserProfile.error.errorCode)")
+                    NCNetworkingCheckRemoteUser().checkRemoteUser(account: resultUserProfile.account, error: resultUserProfile.error)
+                }
             }
+            return (false, nil)
+        } else {
+            NCContentPresenter.shared.showError(error: resultUserProfile.error, priority: .max)
+            return (false, nil)
+        }
+    }
 
-            self.appDelegate.settingAccount(tableAccount.account, urlBase: tableAccount.urlBase, user: tableAccount.user, userId: tableAccount.userId, password: CCUtility.getPassword(tableAccount.account))
+    func synchronize(tableAccount: tableAccount) {
 
-            // Synchronize favorite
-            NCNetworking.shared.listingFavoritescompletion(selector: NCGlobal.shared.selectorReadFile) { _, _, _ in }
+        NCNetworking.shared.listingFavoritescompletion(selector: NCGlobal.shared.selectorReadFile) { _, _, _ in }
+        self.synchronizeOffline(account: tableAccount.account)
+    }
 
-            // Synchronize Offline
-            self.synchronizeOffline(account: tableAccount.account)
+    func getAvatar(tableAccount: tableAccount) {
 
-            // Get Avatar
-            let fileName = tableAccount.userBaseUrl + "-" + self.appDelegate.user + ".png"
-            let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
-            let etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag
-            let options = NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
+        let fileName = tableAccount.userBaseUrl + "-" + self.appDelegate.user + ".png"
+        let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+        let etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag
+        let options = NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
 
-            NextcloudKit.shared.downloadAvatar(user: tableAccount.userId, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag, options: options) { _, _, _, etag, error in
-                guard let etag = etag, error == .success else {
-                    if error.errorCode == NCGlobal.shared.errorNotModified {
-                        NCManageDatabase.shared.setAvatarLoaded(fileName: fileName)
-                    }
-                    return
+        NextcloudKit.shared.downloadAvatar(user: tableAccount.userId, fileNameLocalPath: fileNameLocalPath, sizeImage: NCGlobal.shared.avatarSize, avatarSizeRounded: NCGlobal.shared.avatarSizeRounded, etag: etag, options: options) { _, _, _, etag, error in
+            guard let etag = etag, error == .success else {
+                if error.errorCode == NCGlobal.shared.errorNotModified {
+                    NCManageDatabase.shared.setAvatarLoaded(fileName: fileName)
                 }
-                NCManageDatabase.shared.addAvatar(fileName: fileName, etag: etag)
-                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadAvatar, userInfo: nil)
+                return
             }
-
-            self.requestServerCapabilities()
-            self.requestDashboardWidget()
-            // Unlock E2EE
-            NCNetworkingE2EE.shared.unlockAll(account: account)
+            NCManageDatabase.shared.addAvatar(fileName: fileName, etag: etag)
+            NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadAvatar, userInfo: nil)
         }
     }
 
-    // MARK: -
-
     private func requestServerCapabilities() {
         guard !appDelegate.account.isEmpty else { return }
 
@@ -177,34 +172,30 @@ class NCService: NSObject {
                 return
             }
 
+            data.printJson()
+            
             NCManageDatabase.shared.addCapabilitiesJSon(data, account: account)
-            let serverVersionMajor = NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesVersionMajor)
+            NCManageDatabase.shared.setCapabilities(account: account, data: data)
 
             // Setup communication
-            if serverVersionMajor > 0 {
-                NextcloudKit.shared.setup(nextcloudVersion: serverVersionMajor)
+            if NCGlobal.shared.capabilityServerVersionMajor > 0 {
+                NextcloudKit.shared.setup(nextcloudVersion: NCGlobal.shared.capabilityServerVersionMajor)
             }
 
             // Theming
-            let themingColorNew = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesThemingColor)
-            let themingColorElementNew = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesThemingColorElement)
-            let themingColorTextNew = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesThemingColorText)
-            if themingColorNew != NCBrandColor.shared.themingColor || themingColorElementNew != NCBrandColor.shared.themingColorElement || themingColorTextNew != NCBrandColor.shared.themingColorText {
+            if NCGlobal.shared.capabilityThemingColor != NCBrandColor.shared.themingColor || NCGlobal.shared.capabilityThemingColorElement != NCBrandColor.shared.themingColorElement || NCGlobal.shared.capabilityThemingColorText != NCBrandColor.shared.themingColorText {
                 NCBrandColor.shared.settingThemingColor(account: account)
             }
 
             // Sharing & Comments
-            let isFilesSharingEnabled = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingApiEnabled, exists: false)
-            let comments = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFilesComments, exists: false)
-            let activity = NCManageDatabase.shared.getCapabilitiesServerArray(account: account, elements: NCElementsJSON.shared.capabilitiesActivity)
-            if !isFilesSharingEnabled && !comments && activity == nil {
+            if !NCGlobal.shared.capabilityFileSharingApiEnabled && !NCGlobal.shared.capabilityFilesComments && NCGlobal.shared.capabilityActivity.isEmpty {
                 self.appDelegate.disableSharesView = true
             } else {
                 self.appDelegate.disableSharesView = false
             }
 
             // Text direct editor detail
-            if serverVersionMajor >= NCGlobal.shared.nextcloudVersion18 {
+            if NCGlobal.shared.capabilityServerVersionMajor >= NCGlobal.shared.nextcloudVersion18 {
                 let options = NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
                 NextcloudKit.shared.NCTextObtainEditorDetails(options: options) { account, editors, creators, data, error in
                     if error == .success && account == self.appDelegate.account {
@@ -214,8 +205,7 @@ class NCService: NSObject {
             }
 
             // External file Server
-            let isExternalSitesServerEnabled = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesExternalSites, exists: true)
-            if isExternalSitesServerEnabled {
+            if NCGlobal.shared.capabilityExternalSites {
                 NextcloudKit.shared.getExternalSite(options: options) { account, externalSites, data, error in
                     if error == .success && account == self.appDelegate.account {
                         NCManageDatabase.shared.deleteExternalSites(account: account)
@@ -229,8 +219,7 @@ class NCService: NSObject {
             }
 
             // User Status
-            let userStatus = NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesUserStatusEnabled, exists: false)
-            if userStatus {
+            if NCGlobal.shared.capabilityUserStatusEnabled {
                 NextcloudKit.shared.getUserStatus(options: options) { account, clearAt, icon, message, messageId, messageIsPredefined, status, statusIsUserDefined, userId, data, error in
                     if error == .success && account == self.appDelegate.account && userId == self.appDelegate.userId {
                         NCManageDatabase.shared.setAccountUserStatus(userStatusClearAt: clearAt, userStatusIcon: icon, userStatusMessage: message, userStatusMessageId: messageId, userStatusMessageIsPredefined: messageIsPredefined, userStatusStatus: status, userStatusStatusIsUserDefined: statusIsUserDefined, account: account)
@@ -239,10 +228,8 @@ class NCService: NSObject {
             }
 
             // Added UTI for Collabora
-            if let richdocumentsMimetypes = NCManageDatabase.shared.getCapabilitiesServerArray(account: account, elements: NCElementsJSON.shared.capabilitiesRichdocumentsMimetypes) {
-                for mimeType in richdocumentsMimetypes {
-                    NextcloudKit.shared.nkCommonInstance.addInternalTypeIdentifier(typeIdentifier: mimeType, classFile: NKCommon.TypeClassFile.document.rawValue, editor: NCGlobal.shared.editorCollabora, iconName: NKCommon.TypeIconFile.document.rawValue, name: "document")
-                }
+            for mimeType in NCGlobal.shared.capabilityRichdocumentsMimetypes {
+                NextcloudKit.shared.nkCommonInstance.addInternalTypeIdentifier(typeIdentifier: mimeType, classFile: NKCommon.TypeClassFile.document.rawValue, editor: NCGlobal.shared.editorCollabora, iconName: NKCommon.TypeIconFile.document.rawValue, name: "document")
             }
 
             // Added UTI for ONLYOFFICE & Text

+ 1 - 0
iOSClient/Nextcloud-Bridging-Header.h

@@ -8,3 +8,4 @@
 #import "UIImage+animatedGIF.h"
 #import "CCUtility.h"
 #import "NCPushNotification.h"
+#import "NCPushNotificationEncryption.h"

+ 5 - 5
iOSClient/Notification/NCNotification.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="c26-Us-IIn">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="c26-Us-IIn">
     <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <scenes>
@@ -17,7 +17,7 @@
                         <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" rowHeight="187" id="R1c-h5-BOp" customClass="NCNotificationCell" customModule="Nextcloud" customModuleProvider="target">
-                                <rect key="frame" x="0.0" y="44.5" width="375" height="187"/>
+                                <rect key="frame" x="0.0" y="50" width="375" height="187"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="R1c-h5-BOp" id="9Bv-1W-yVV">
                                     <rect key="frame" x="0.0" y="0.0" width="375" height="187"/>
@@ -64,7 +64,7 @@
                                                 <constraint firstAttribute="height" constant="20" id="IIr-Ys-RMx"/>
                                                 <constraint firstAttribute="width" constant="20" id="YaB-cW-gAT"/>
                                             </constraints>
-                                            <state key="normal" image="exit"/>
+                                            <state key="normal" image="xmark" catalog="system"/>
                                             <connections>
                                                 <action selector="touchUpInsideRemove:" destination="R1c-h5-BOp" eventType="touchUpInside" id="Wlp-VM-Vf2"/>
                                             </connections>
@@ -166,6 +166,6 @@
         </scene>
     </scenes>
     <resources>
-        <image name="exit" width="300" height="300"/>
+        <image name="xmark" catalog="system" width="128" height="113"/>
     </resources>
 </document>

+ 33 - 27
iOSClient/Notification/NCNotification.swift

@@ -25,12 +25,15 @@
 import UIKit
 import NextcloudKit
 import SwiftyJSON
+import JGProgressHUD
 
 class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmptyDataSetDelegate {
 
     let appDelegate = UIApplication.shared.delegate as! AppDelegate
     var notifications: [NKNotifications] = []
     var emptyDataSet: NCEmptyDataSet?
+    var isReloadDataSourceNetworkInProgress: Bool = false
+
 
     // MARK: - View Life Cycle
 
@@ -43,7 +46,6 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
         tableView.tableFooterView = UIView()
         tableView.rowHeight = UITableView.automaticDimension
         tableView.estimatedRowHeight = 50.0
-        tableView.allowsSelection = false
         tableView.backgroundColor = .systemBackground
 
         // Empty
@@ -55,14 +57,10 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
         super.viewWillAppear(animated)
 
         appDelegate.activeViewController = self
-        
+
         navigationController?.setFileAppreance()
 
         NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil)
-    }
-
-    override func viewDidAppear(_ animated: Bool) {
-        super.viewDidAppear(animated)
 
         getNetwokingNotification()
     }
@@ -87,26 +85,40 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
 
     func emptyDataSetView(_ view: NCEmptyView) {
 
-        view.emptyImage.image = NCUtility.shared.loadImage(named: "bell", color: .gray, size: UIScreen.main.bounds.width)
-        view.emptyTitle.text = NSLocalizedString("_no_notification_", comment: "")
-        view.emptyDescription.text = ""
+        if isReloadDataSourceNetworkInProgress {
+            view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
+            view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
+            view.emptyDescription.text = ""
+        } else {
+            view.emptyImage.image = NCUtility.shared.loadImage(named: "bell", color: .gray, size: UIScreen.main.bounds.width)
+            view.emptyTitle.text = NSLocalizedString("_no_notification_", comment: "")
+            view.emptyDescription.text = ""
+        }
     }
 
     // MARK: - Table
 
-    @objc func reloadDatasource() {
-        self.tableView.reloadData()
-    }
-
     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
         emptyDataSet?.numberOfItemsInSection(notifications.count, section: section)
         return notifications.count
     }
 
+    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+
+        let notification = notifications[indexPath.row]
+
+        if notification.app == "files_sharing" {
+            NCActionCenter.shared.viewerFile(account: appDelegate.account, fileId: notification.objectId, viewController: self)
+        } else {
+            NCApplicationHandle().didSelectNotification(notification, viewController: self)
+        }
+    }
+
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 
         let cell = self.tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! NCNotificationCell
         cell.delegate = self
+        cell.selectionStyle = .none
 
         let notification = notifications[indexPath.row]
         let urlIcon = URL(string: notification.icon)
@@ -178,7 +190,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
         cell.secondary.layer.borderWidth = 1
         cell.secondary.layer.borderColor = UIColor.systemGray.cgColor
         cell.secondary.layer.backgroundColor = UIColor.secondarySystemBackground.cgColor
-        cell.secondary.setTitleColor(.black, for: .normal)
+        cell.secondary.setTitleColor(.gray, for: .normal)
 
         // Action
         if let actions = notification.actions,
@@ -231,14 +243,11 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
 
         NextcloudKit.shared.setNotification(serverUrl: nil, idNotification: notification.idNotification , method: "DELETE") { (account, error) in
             if error == .success && account == self.appDelegate.account {
-
                 if let index = self.notifications
                     .firstIndex(where: { $0.idNotification == notification.idNotification })  {
                     self.notifications.remove(at: index)
                 }
-
-                self.reloadDatasource()
-
+                self.tableView.reloadData()
             } else if error != .success {
                 NCContentPresenter.shared.showError(error: error)
             } else {
@@ -265,14 +274,11 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
             }
 
             NextcloudKit.shared.setNotification(serverUrl: serverUrl, idNotification: 0, method: method) { (account, error) in
-
                 if error == .success && account == self.appDelegate.account {
                     if let index = self.notifications.firstIndex(where: { $0.idNotification == notification.idNotification }) {
                         self.notifications.remove(at: index)
                     }
-
-                    self.reloadDatasource()
-
+                    self.tableView.reloadData()
                 } else if error != .success {
                     NCContentPresenter.shared.showError(error: error)
                 } else {
@@ -290,21 +296,21 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
 
     func getNetwokingNotification() {
 
-        NextcloudKit.shared.getNotifications { account, notifications, data, error in
+        isReloadDataSourceNetworkInProgress = true
+        self.tableView.reloadData()
 
+        NextcloudKit.shared.getNotifications { account, notifications, data, error in
             if error == .success && account == self.appDelegate.account {
-
                 self.notifications.removeAll()
                 let sortedListOfNotifications = (notifications! as NSArray).sortedArray(using: [NSSortDescriptor(key: "date", ascending: false)])
-
                 for notification in sortedListOfNotifications {
                     if let icon = (notification as! NKNotifications).icon {
                         NCUtility.shared.convertSVGtoPNGWriteToUserData(svgUrlString: icon, fileName: nil, width: 25, rewrite: false, account: self.appDelegate.account, completion: { _, _ in })
                     }
                     self.notifications.append(notification as! NKNotifications)
                 }
-
-                self.reloadDatasource()
+                self.isReloadDataSourceNetworkInProgress = false
+                self.tableView.reloadData()
             }
         }
     }

+ 2 - 6
iOSClient/Scan document/NCUploadScanDocument.swift

@@ -452,9 +452,7 @@ struct UploadScanDocumentView: View {
                         }
                     }
                     .complexModifier { view in
-                        if #available(iOS 15, *) {
-                            view.listRowSeparator(.hidden)
-                        }
+                        view.listRowSeparator(.hidden)
                     }
 
                     VStack(spacing: 20) {
@@ -499,9 +497,7 @@ struct UploadScanDocumentView: View {
                             .frame(maxWidth: .infinity, minHeight: geo.size.height / 2)
                     }
                     .complexModifier { view in
-                        if #available(iOS 15, *) {
-                            view.listRowSeparator(.hidden)
-                        }
+                        view.listRowSeparator(.hidden)
                     }
                 }
                 HUDView(showHUD: $uploadScanDocument.showHUD, textLabel: NSLocalizedString("_wait_", comment: ""), image: "doc.badge.arrow.up")

+ 1 - 85
iOSClient/Settings/CCManageAccount.m

@@ -103,7 +103,7 @@
         
         // Set user status
         
-        BOOL userStatus = [[NCManageDatabase shared] getCapabilitiesServerBoolWithAccount:activeAccount.account elements:NCElementsJSON.shared.capabilitiesUserStatusEnabled exists:false];
+        BOOL userStatus = [[NCGlobal shared] capabilityUserStatusEnabled];
         if (userStatus) {
             row = [XLFormRowDescriptor formRowDescriptorWithTag:@"setUserStatus" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_set_user_status_", nil)];
             row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor;
@@ -257,90 +257,6 @@
         [section addFormRow:row];
     }
     
-    // Section : THIRT PART -------------------------------------------
-    BOOL isHandwerkcloudEnabled = [[NCManageDatabase shared] getCapabilitiesServerBoolWithAccount:activeAccount.account elements:NCElementsJSON.shared.capabilitiesHWCEnabled exists:false];
-    if (isHandwerkcloudEnabled) {
-
-        section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_user_job_", nil)];
-        [form addFormSection:section];
-        
-        // Business Type
-        row = [XLFormRowDescriptor formRowDescriptorWithTag:@"userbusinesstype" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_businesstype_", nil)];
-        row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor;
-        [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"];
-        [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"];
-        [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"];
-        [row.cellConfig setObject:[[UIImage imageNamed:@"businesstype"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"];
-        row.value = activeAccount.businessType;
-        [section addFormRow:row];
-        
-        // Business Size
-        row = [XLFormRowDescriptor formRowDescriptorWithTag:@"userbusinesssize" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_businesssize_", nil)];
-        row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor;
-        [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"];
-        [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"];
-        [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"];
-        [row.cellConfig setObject:[[UIImage imageNamed:@"users"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"];
-        row.value = activeAccount.businessSize;
-        [section addFormRow:row];
-        
-        // Role
-        row = [XLFormRowDescriptor formRowDescriptorWithTag:@"userrole" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_role_", nil)];
-        row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor;
-        [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"];
-        [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"];
-        [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"];
-        [row.cellConfig setObject:[[UIImage imageNamed:@"role"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"];
-        if ([activeAccount.role isEqualToString:@"owner"]) row.value = NSLocalizedString(@"_user_owner_", nil);
-        else if ([activeAccount.role isEqualToString:@"employee"]) row.value = NSLocalizedString(@"_user_employee_", nil);
-        else if ([activeAccount.role isEqualToString:@"contractor"]) row.value = NSLocalizedString(@"_user_contractor_", nil);
-        else row.value = @"";
-        [section addFormRow:row];
-        
-        // Company
-        row = [XLFormRowDescriptor formRowDescriptorWithTag:@"usercompany" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_company_", nil)];
-        row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor;
-        [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"];
-        [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"];
-        [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"];
-        [row.cellConfig setObject:[[UIImage imageNamed:@"company"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"];
-        row.value = activeAccount.organisation;
-        [section addFormRow:row];
-    
-        if (activeAccount.hcIsTrial) {
-        
-            section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_trial_", nil)];
-            [form addFormSection:section];
-            
-            row = [XLFormRowDescriptor formRowDescriptorWithTag:@"trial" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_trial_expired_day_", nil)];
-            row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor;
-            [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"];
-            [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"];
-            [row.cellConfig setObject:[UIColor redColor] forKey:@"textLabel.textColor"];
-            [row.cellConfig setObject:[UIColor redColor] forKey:@"detailTextLabel.textColor"];
-            [row.cellConfig setObject:[[UIImage imageNamed:@"timer"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"];
-            NSInteger numberOfDays = activeAccount.hcTrialRemainingSec / (24*3600);
-            row.value = [@(numberOfDays) stringValue];
-            [section addFormRow:row];
-        }
-    
-        section = [XLFormSectionDescriptor formSection];
-        [form addFormSection:section];
-        
-        // Edit profile
-        row = [XLFormRowDescriptor formRowDescriptorWithTag:@"editUserProfile" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_user_editprofile_", nil)];
-        row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor;
-        [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"];
-        [row.cellConfig setObject:[[UIImage imageNamed:@"editUserProfile"] imageWithColor:UIColor.systemGrayColor size:25] forKey:@"imageView.image"];
-        [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"];
-        [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"];
-#if defined(HC)
-        row.action.viewControllerClass = [HCEditProfile class];
-#endif
-        if (accounts.count == 0) row.disabled = @YES;
-        [section addFormRow:row];
-    }
-    
     self.tableView.showsVerticalScrollIndicator = NO;
     self.form = form;
     

+ 8 - 10
iOSClient/Settings/NCManageE2EE.swift

@@ -164,15 +164,13 @@ struct NCViewE2EE: View {
 
     var body: some View {
 
-        let versionE2EE = NCManageDatabase.shared.getCapabilitiesServerString(account: account, elements: NCElementsJSON.shared.capabilitiesE2EEApiVersion) ?? ""
-
         VStack {
 
             if manageE2EE.isEndToEndEnabled {
 
                 List {
 
-                    Section(header: Text(""), footer: Text(manageE2EE.statusOfService + "\n\n" + "End-to-End Encryption " + versionE2EE)) {
+                    Section(header: Text(""), footer: Text(manageE2EE.statusOfService + "\n\n" + "End-to-End Encryption " + NCGlobal.shared.capabilityE2EEApiVersion)) {
                         Label {
                             Text(NSLocalizedString("_e2e_settings_activated_", comment: ""))
                         } icon: {
@@ -196,10 +194,10 @@ struct NCViewE2EE: View {
                     }
                     .contentShape(Rectangle())
                     .onTapGesture {
-                        if CCUtility.getPasscode().isEmpty {
-                            NCContentPresenter.shared.showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_"))
-                        } else {
+                        if let passcode = CCUtility.getPasscode(), !passcode.isEmpty {
                             manageE2EE.requestPasscodeType("readPassphrase")
+                        } else {
+                            NCContentPresenter.shared.showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_"))
                         }
                     }
 
@@ -216,10 +214,10 @@ struct NCViewE2EE: View {
                     }
                     .contentShape(Rectangle())
                     .onTapGesture {
-                        if CCUtility.getPasscode().isEmpty {
-                            NCContentPresenter.shared.showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_"))
-                        } else {
+                        if let passcode = CCUtility.getPasscode(), !passcode.isEmpty {
                             manageE2EE.requestPasscodeType("removeLocallyEncryption")
+                        } else {
+                            NCContentPresenter.shared.showInfo(error: NKError(errorCode: 0, errorDescription: "_e2e_settings_lock_not_active_"))
                         }
                     }
 
@@ -232,7 +230,7 @@ struct NCViewE2EE: View {
 
                 List {
 
-                    Section(header: Text(""), footer:Text(manageE2EE.statusOfService + "\n\n" + "End-to-End Encryption " + versionE2EE)) {
+                    Section(header: Text(""), footer:Text(manageE2EE.statusOfService + "\n\n" + "End-to-End Encryption " + NCGlobal.shared.capabilityE2EEApiVersion)) {
                         HStack {
                             Label {
                                 Text(NSLocalizedString("_e2e_settings_start_", comment: ""))

+ 10 - 8
iOSClient/Settings/NCSettings.m

@@ -38,6 +38,10 @@
     AppDelegate *appDelegate;
     TOPasscodeViewController *passcodeViewController;
     TOPasscodeSettingsViewController *passcodeSettingsViewController;
+
+    NSString *versionServer;
+    NSString *themingName;
+    NSString *themingSlogan;
 }
 @end
 
@@ -117,8 +121,8 @@
 
     // Section : E2EEncryption --------------------------------------------------------------
 
-    BOOL isE2EEEnabled = [[NCManageDatabase shared] getCapabilitiesServerBoolWithAccount:appDelegate.account elements:NCElementsJSON.shared.capabilitiesE2EEEnabled exists:false];
-    NSString *versionE2EE = [[NCManageDatabase shared] getCapabilitiesServerStringWithAccount:appDelegate.account elements:NCElementsJSON.shared.capabilitiesE2EEApiVersion];
+    BOOL isE2EEEnabled = [[NCGlobal shared] capabilityE2EEEnabled];
+    NSString *versionE2EE = [[NCGlobal shared] capabilityE2EEApiVersion];
 
     if (isE2EEEnabled == YES && [NCGlobal.shared.e2eeReadVersions containsObject:versionE2EE]) {
 
@@ -220,6 +224,10 @@
     [super viewWillAppear:animated];
     
     appDelegate.activeViewController = self;
+
+    versionServer = [[NCGlobal shared] capabilityServerVersion];
+    themingName = [[NCGlobal shared] capabilityThemingName];
+    themingSlogan = [[NCGlobal shared] capabilityThemingSlogan];
 }
 
 #pragma mark - NotificationCenter
@@ -454,15 +462,9 @@
     } else if (section == 2 && !NCBrandOptions.shared.disable_mobileconfig) {
         sectionName = NSLocalizedString(@"_calendar_contacts_footer_", nil);
     } else if (section == numSections) {
-        NSString *versionServer = [[NCManageDatabase shared] getCapabilitiesServerStringWithAccount:appDelegate.account elements:NCElementsJSON.shared.capabilitiesVersionString];
-        NSString *themingName = [[NCManageDatabase shared] getCapabilitiesServerStringWithAccount:appDelegate.account elements:NCElementsJSON.shared.capabilitiesThemingName];
-        NSString *themingSlogan = [[NCManageDatabase shared] getCapabilitiesServerStringWithAccount:appDelegate.account elements:NCElementsJSON.shared.capabilitiesThemingSlogan];
-
         NSString *versionNextcloud = [NSString stringWithFormat:[NCBrandOptions shared].textCopyrightNextcloudServer, versionServer];
         NSString *versionNextcloudiOS = [NSString stringWithFormat:[NCBrandOptions shared].textCopyrightNextcloudiOS, [[NCUtility shared] getVersionAppWithBuild:true]];
-
         NSString *nameSlogan = [NSString stringWithFormat:@"%@ - %@", themingName, themingSlogan];
-
         sectionName = [NSString stringWithFormat:@"\n%@\n\n%@\n%@", versionNextcloudiOS, versionNextcloud, nameSlogan];
     }
     return sectionName;

+ 6 - 6
iOSClient/Share/Advanced/NCShareCells.swift

@@ -322,15 +322,15 @@ class NCShareDateCell: UITableViewCell {
         case NCShareCommon.shared.SHARE_TYPE_LINK,
             NCShareCommon.shared.SHARE_TYPE_EMAIL,
             NCShareCommon.shared.SHARE_TYPE_GUEST:
-            return NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingPubExpireDateEnforced, exists: false)
+            return NCGlobal.shared.capabilityFileSharingPubExpireDateEnforced
         case NCShareCommon.shared.SHARE_TYPE_USER,
             NCShareCommon.shared.SHARE_TYPE_GROUP,
             NCShareCommon.shared.SHARE_TYPE_CIRCLE,
             NCShareCommon.shared.SHARE_TYPE_ROOM:
-            return NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingInternalExpireDateEnforced, exists: false)
+            return NCGlobal.shared.capabilityFileSharingInternalExpireDateEnforced
         case NCShareCommon.shared.SHARE_TYPE_REMOTE,
             NCShareCommon.shared.SHARE_TYPE_REMOTE_GROUP:
-            return NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingRemoteExpireDateEnforced, exists: false)
+            return NCGlobal.shared.capabilityFileSharingRemoteExpireDateEnforced
         default:
             return false
         }
@@ -341,15 +341,15 @@ class NCShareDateCell: UITableViewCell {
         case NCShareCommon.shared.SHARE_TYPE_LINK,
             NCShareCommon.shared.SHARE_TYPE_EMAIL,
             NCShareCommon.shared.SHARE_TYPE_GUEST:
-            return NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingPubExpireDateDays)
+            return NCGlobal.shared.capabilityFileSharingPubExpireDateDays
         case NCShareCommon.shared.SHARE_TYPE_USER,
             NCShareCommon.shared.SHARE_TYPE_GROUP,
             NCShareCommon.shared.SHARE_TYPE_CIRCLE,
             NCShareCommon.shared.SHARE_TYPE_ROOM:
-            return NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingInternalExpireDateDays)
+            return NCGlobal.shared.capabilityFileSharingInternalExpireDateDays
         case NCShareCommon.shared.SHARE_TYPE_REMOTE,
             NCShareCommon.shared.SHARE_TYPE_REMOTE_GROUP:
-            return NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingRemoteExpireDateDays)
+            return NCGlobal.shared.capabilityFileSharingRemoteExpireDateDays
         default:
             return 0
         }

+ 1 - 1
iOSClient/Share/NCShare+Helper.swift

@@ -79,7 +79,7 @@ class NCTableShareOptions: NCTableShareable {
         if metadata.e2eEncrypted {
             self.permissions = NCGlobal.shared.permissionCreateShare
         } else {
-            self.permissions = NCManageDatabase.shared.getCapabilitiesServerInt(account: metadata.account, elements: ["ocs", "data", "capabilities", "files_sharing", "default_permissions"]) & metadata.sharePermissionsCollaborationServices
+            self.permissions = NCGlobal.shared.capabilityFileSharingDefaultPermission & metadata.sharePermissionsCollaborationServices
         }
         self.shareType = shareType
         if let password = password {

+ 7 - 7
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="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Ts3-RO-A9l">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" 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="20020"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -31,7 +31,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="0.0" width="414" height="44"/>
+                        <rect key="frame" x="0.0" y="20" width="414" height="44"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -111,7 +111,7 @@
                                             <constraint firstAttribute="height" constant="30" id="0aG-z9-fcy"/>
                                         </constraints>
                                         <fontDescription key="fontDescription" type="system" pointSize="15"/>
-                                        <textInputTraits key="textInputTraits"/>
+                                        <textInputTraits key="textInputTraits" returnKeyType="search"/>
                                         <connections>
                                             <action selector="searchFieldDidEndOnExitWithTextField:" destination="bgO-Rz-2M1" eventType="editingDidEndOnExit" id="xH6-YR-5W9"/>
                                         </connections>
@@ -165,7 +165,7 @@
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="UNN-v3-g1S">
-                                <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                                <rect key="frame" x="0.0" y="20" width="414" height="716"/>
                                 <subviews>
                                     <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="rZ9-oE-c21">
                                         <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
@@ -262,7 +262,7 @@
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" id="0qP-1F-pHW">
-                                <rect key="frame" x="0.0" y="44.666666030883789" width="414" height="43.666667938232422"/>
+                                <rect key="frame" x="0.0" y="50" width="414" height="43.666667938232422"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="0qP-1F-pHW" id="z1u-eI-gTZ">
                                     <rect key="frame" x="0.0" y="0.0" width="414" height="43.666667938232422"/>
@@ -289,7 +289,7 @@
     <resources>
         <image name="note.text" width="24" height="24"/>
         <systemColor name="labelColor">
-            <color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         <systemColor name="secondarySystemBackgroundColor">
             <color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>

+ 1 - 2
iOSClient/Share/NCShare.swift

@@ -195,8 +195,7 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
     }
 
     func checkEnforcedPassword(shareType: Int, completion: @escaping (String?) -> Void) {
-        guard let metadata = self.metadata,
-              NCManageDatabase.shared.getCapabilitiesServerBool(account: metadata.account, elements: NCElementsJSON.shared.capabilitiesFileSharingPubPasswdEnforced, exists: false),
+        guard NCGlobal.shared.capabilityFileSharingPubPasswdEnforced,
               shareType == NCShareCommon.shared.SHARE_TYPE_LINK || shareType == NCShareCommon.shared.SHARE_TYPE_EMAIL
         else { return completion(nil) }
 

+ 6 - 1
iOSClient/Share/NCSharePaging.swift

@@ -89,8 +89,13 @@ class NCSharePaging: UIViewController {
 
         pagingViewController.dataSource = self
         pagingViewController.delegate = self
-        pagingViewController.select(index: page.rawValue < pages.count ? page.rawValue : max(pages.count - 1, 0))
 
+        if page.rawValue < pages.count {
+            pagingViewController.select(index: page.rawValue)
+        } else {
+            pagingViewController.select(index: 0)
+        }
+       
         (pagingViewController.view as? NCSharePagingView)?.setupConstraints()
         pagingViewController.reloadMenu()
     }

+ 2 - 2
iOSClient/Shares/NCShares.swift

@@ -85,11 +85,11 @@ class NCShares: NCCollectionViewCommon {
     override func reloadDataSourceNetwork(forced: Bool = false) {
         super.reloadDataSourceNetwork(forced: forced)
 
+        if UIApplication.shared.applicationState != .active { return }
+
         isReloadDataSourceNetworkInProgress = true
         collectionView?.reloadData()
 
-        NextcloudKit.shared.nkCommonInstance.writeLog("[TEST] READSHARES")
-
         NextcloudKit.shared.readShares(parameters: NKShareParameter()) { account, shares, data, error in
 
             self.refreshControl.endRefreshing()

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


二進制
iOSClient/Supporting Files/an.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/be.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


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

@@ -627,8 +627,8 @@
 "_enforce_password_protection_" = "Enforce password protection";
 "_password_obligatory_"         = "Enforce password protection enabled, password obligatory";
 "_shared_with_you_by_"          = "Shared with you by";
-"_shareLinksearch_placeholder_" = "Type a name and press Enter";
-"_shareLinksearch_mail_placeholder_" = "Type a name or an email and press Enter";
+"_shareLinksearch_placeholder_" = "Type a name and press Search";
+"_shareLinksearch_mail_placeholder_" = "Type a name or an email and press Search";
 "_new_comment_"                 = "New comment …";
 "_edit_comment_"                = "Edit comment";
 "_delete_comment_"              = "Delete comment";
@@ -966,6 +966,7 @@
 "_user_"                    = "User";
 "_add_subtitle_"            = "Add an external subtitle";
 "_add_audio_"               = "Add an external audio";
+"_maintenance_mode_"        = "Server is currently in maintenance mode";
 
 // Tip
 "_tip_pdf_thumbnails_"      = "Swipe left from the right edge of the screen to show the thumbnails.";

二進制
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


Some files were not shown because too many files changed in this diff