Browse Source

Merge pull request #2254 from nextcloud/develop

Version 4.5.5
Marino Faggiana 2 years ago
parent
commit
7f4252fd77
100 changed files with 282 additions and 217 deletions
  1. 5 5
      Nextcloud.xcodeproj/project.pbxproj
  2. 2 2
      Widget/Dashboard/DashboardData.swift
  3. 1 1
      Widget/Dashboard/DashboardWidgetView.swift
  4. 2 2
      Widget/Files/FilesData.swift
  5. 1 1
      Widget/Lockscreen/LockscreenData.swift
  6. 8 3
      Widget/Lockscreen/LockscreenWidgetView.swift
  7. 10 10
      iOSClient/AppDelegate.swift
  8. 6 4
      iOSClient/BrowserWeb/NCBrowserWeb.swift
  9. 6 1
      iOSClient/Data/NCElementsJSON.swift
  10. 0 4
      iOSClient/Data/NCManageDatabase+Account.swift
  11. 0 16
      iOSClient/Data/NCManageDatabase+Metadata.swift
  12. 0 8
      iOSClient/Data/NCManageDatabase.swift
  13. 2 2
      iOSClient/Files/NCFiles.swift
  14. 6 4
      iOSClient/Login/NCLoginWeb.swift
  15. 35 27
      iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
  16. 28 17
      iOSClient/Main/NCFunctionCenter.swift
  17. 39 40
      iOSClient/Networking/NCNetworking.swift
  18. 73 52
      iOSClient/Networking/NCNetworkingProcessUpload.swift
  19. 0 1
      iOSClient/Networking/NCService.swift
  20. 6 4
      iOSClient/RichWorkspace/NCViewerRichWorkspaceWebView.swift
  21. 0 4
      iOSClient/Select/NCSelect.swift
  22. 1 0
      iOSClient/Share/Advanced/NCShareAdvancePermission.swift
  23. 50 4
      iOSClient/Share/Advanced/NCShareCells.swift
  24. 0 3
      iOSClient/Share/NCShareNetworking.swift
  25. 0 1
      iOSClient/Shares/NCShares.swift
  26. BIN
      iOSClient/Supporting Files/af.lproj/Localizable.strings
  27. BIN
      iOSClient/Supporting Files/an.lproj/Localizable.strings
  28. BIN
      iOSClient/Supporting Files/ar.lproj/Localizable.strings
  29. BIN
      iOSClient/Supporting Files/ast.lproj/Localizable.strings
  30. BIN
      iOSClient/Supporting Files/az.lproj/Localizable.strings
  31. BIN
      iOSClient/Supporting Files/be.lproj/Localizable.strings
  32. BIN
      iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings
  33. BIN
      iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings
  34. BIN
      iOSClient/Supporting Files/br.lproj/Localizable.strings
  35. BIN
      iOSClient/Supporting Files/bs.lproj/Localizable.strings
  36. BIN
      iOSClient/Supporting Files/ca.lproj/Localizable.strings
  37. BIN
      iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings
  38. BIN
      iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings
  39. BIN
      iOSClient/Supporting Files/da.lproj/Localizable.strings
  40. BIN
      iOSClient/Supporting Files/de.lproj/Localizable.strings
  41. BIN
      iOSClient/Supporting Files/el.lproj/Localizable.strings
  42. BIN
      iOSClient/Supporting Files/en-GB.lproj/Localizable.strings
  43. 1 1
      iOSClient/Supporting Files/en.lproj/Localizable.strings
  44. BIN
      iOSClient/Supporting Files/eo.lproj/Localizable.strings
  45. BIN
      iOSClient/Supporting Files/es-419.lproj/Localizable.strings
  46. BIN
      iOSClient/Supporting Files/es-AR.lproj/Localizable.strings
  47. BIN
      iOSClient/Supporting Files/es-CL.lproj/Localizable.strings
  48. BIN
      iOSClient/Supporting Files/es-CO.lproj/Localizable.strings
  49. BIN
      iOSClient/Supporting Files/es-CR.lproj/Localizable.strings
  50. BIN
      iOSClient/Supporting Files/es-DO.lproj/Localizable.strings
  51. BIN
      iOSClient/Supporting Files/es-EC.lproj/Localizable.strings
  52. BIN
      iOSClient/Supporting Files/es-GT.lproj/Localizable.strings
  53. BIN
      iOSClient/Supporting Files/es-HN.lproj/Localizable.strings
  54. BIN
      iOSClient/Supporting Files/es-MX.lproj/Localizable.strings
  55. BIN
      iOSClient/Supporting Files/es-NI.lproj/Localizable.strings
  56. BIN
      iOSClient/Supporting Files/es-PA.lproj/Localizable.strings
  57. BIN
      iOSClient/Supporting Files/es-PE.lproj/Localizable.strings
  58. BIN
      iOSClient/Supporting Files/es-PR.lproj/Localizable.strings
  59. BIN
      iOSClient/Supporting Files/es-PY.lproj/Localizable.strings
  60. BIN
      iOSClient/Supporting Files/es-SV.lproj/Localizable.strings
  61. BIN
      iOSClient/Supporting Files/es-UY.lproj/Localizable.strings
  62. BIN
      iOSClient/Supporting Files/es.lproj/Localizable.strings
  63. BIN
      iOSClient/Supporting Files/et_EE.lproj/Localizable.strings
  64. BIN
      iOSClient/Supporting Files/eu.lproj/Localizable.strings
  65. BIN
      iOSClient/Supporting Files/fa.lproj/Localizable.strings
  66. BIN
      iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings
  67. BIN
      iOSClient/Supporting Files/fo.lproj/Localizable.strings
  68. BIN
      iOSClient/Supporting Files/fr.lproj/Localizable.strings
  69. BIN
      iOSClient/Supporting Files/gd.lproj/Localizable.strings
  70. BIN
      iOSClient/Supporting Files/gl.lproj/Localizable.strings
  71. BIN
      iOSClient/Supporting Files/he.lproj/Localizable.strings
  72. BIN
      iOSClient/Supporting Files/hi_IN.lproj/Localizable.strings
  73. BIN
      iOSClient/Supporting Files/hr.lproj/Localizable.strings
  74. BIN
      iOSClient/Supporting Files/hsb.lproj/Localizable.strings
  75. BIN
      iOSClient/Supporting Files/hu.lproj/Localizable.strings
  76. BIN
      iOSClient/Supporting Files/hy.lproj/Localizable.strings
  77. BIN
      iOSClient/Supporting Files/ia.lproj/Localizable.strings
  78. BIN
      iOSClient/Supporting Files/id.lproj/Localizable.strings
  79. BIN
      iOSClient/Supporting Files/ig.lproj/Localizable.strings
  80. BIN
      iOSClient/Supporting Files/is.lproj/Localizable.strings
  81. BIN
      iOSClient/Supporting Files/it.lproj/Localizable.strings
  82. BIN
      iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings
  83. BIN
      iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings
  84. BIN
      iOSClient/Supporting Files/ka.lproj/Localizable.strings
  85. BIN
      iOSClient/Supporting Files/kab.lproj/Localizable.strings
  86. BIN
      iOSClient/Supporting Files/km.lproj/Localizable.strings
  87. BIN
      iOSClient/Supporting Files/kn.lproj/Localizable.strings
  88. BIN
      iOSClient/Supporting Files/ko.lproj/Localizable.strings
  89. BIN
      iOSClient/Supporting Files/la.lproj/Localizable.strings
  90. BIN
      iOSClient/Supporting Files/lb.lproj/Localizable.strings
  91. BIN
      iOSClient/Supporting Files/lo.lproj/Localizable.strings
  92. BIN
      iOSClient/Supporting Files/lt_LT.lproj/Localizable.strings
  93. BIN
      iOSClient/Supporting Files/lv.lproj/Localizable.strings
  94. BIN
      iOSClient/Supporting Files/mk.lproj/Localizable.strings
  95. BIN
      iOSClient/Supporting Files/mn.lproj/Localizable.strings
  96. BIN
      iOSClient/Supporting Files/mr.lproj/Localizable.strings
  97. BIN
      iOSClient/Supporting Files/ms_MY.lproj/Localizable.strings
  98. BIN
      iOSClient/Supporting Files/my.lproj/Localizable.strings
  99. BIN
      iOSClient/Supporting Files/nb-NO.lproj/Localizable.strings
  100. BIN
      iOSClient/Supporting Files/ne.lproj/Localizable.strings

+ 5 - 5
Nextcloud.xcodeproj/project.pbxproj

@@ -3619,7 +3619,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 9;
+				CURRENT_PROJECT_VERSION = 2;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -3643,7 +3643,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 4.5.4;
+				MARKETING_VERSION = 4.5.5;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				SDKROOT = iphoneos;
@@ -3682,7 +3682,7 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 9;
+				CURRENT_PROJECT_VERSION = 2;
 				DEVELOPMENT_TEAM = NKUJUXUJ3B;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -3704,7 +3704,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 4.5.4;
+				MARKETING_VERSION = 4.5.5;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				SDKROOT = iphoneos;
@@ -3912,7 +3912,7 @@
 			repositoryURL = "https://github.com/nextcloud/NextcloudKit";
 			requirement = {
 				kind = exactVersion;
-				version = 1.2.0;
+				version = 1.3.0;
 			};
 		};
 		F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = {

+ 2 - 2
Widget/Dashboard/DashboardData.swift

@@ -140,7 +140,6 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis
     
     let (tableDashboard, tableButton) = NCManageDatabase.shared.getDashboardWidget(account: account.account, id: id)
     let existsButton = (tableButton?.isEmpty ?? true) ? false : true
-    let options = NKRequestOptions(timeout: 15, queue: NKCommon.shared.backgroundQueue)
     let title = tableDashboard?.title ?? id
 
     var imagetmp = UIImage(named: "widget")!
@@ -151,7 +150,8 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis
         }
     }
     let titleImage = imagetmp
-        
+
+    let options = NKRequestOptions(timeout: 90, queue: NKCommon.shared.backgroundQueue)
     NextcloudKit.shared.getDashboardWidgetsApplication(id, options: options) { _, results, data, error in
 
         Task {

+ 1 - 1
Widget/Dashboard/DashboardWidgetView.swift

@@ -168,7 +168,7 @@ struct DashboardWidgetView: View {
                                     .background(brandColor)
                                     .foregroundColor(brandTextColor)
                                     .border(brandColor, width: 1)
-                                    .cornerRadius(16)
+                                    .cornerRadius(.infinity)
                             })
                         }
                     }

+ 2 - 2
Widget/Files/FilesData.swift

@@ -197,7 +197,7 @@ func getFilesDataEntry(configuration: AccountIntent?, isPreview: Bool, displaySi
         NKCommon.shared.writeLog("[INFO] Start \(NCBrandOptions.shared.brand) widget session with level \(levelLog) " + versionNextcloudiOS)
     }
     
-    let options = NKRequestOptions(timeout: 15)
+    let options = NKRequestOptions(timeout: 90, queue: NKCommon.shared.backgroundQueue)
     NextcloudKit.shared.searchBodyRequest(serverUrl: account.urlBase, requestBody: requestBody, showHiddenFiles: CCUtility.getShowHiddenFiles(), options: options) { _, files, data, error in
         Task {
             var datas: [FilesData] = []
@@ -230,7 +230,7 @@ func getFilesDataEntry(configuration: AccountIntent?, isPreview: Bool, displaySi
                     let fileNamePathOrFileId = CCUtility.returnFileNamePath(fromFileName: file.fileName, serverUrl: file.serverUrl, urlBase: file.urlBase, userId: file.userId, account: account.account)!
                     let fileNamePreviewLocalPath = CCUtility.getDirectoryProviderStoragePreviewOcId(file.ocId, etag: file.etag)!
                     let fileNameIconLocalPath = CCUtility.getDirectoryProviderStorageIconOcId(file.ocId, etag: file.etag)!
-                    let (_, _, imageIcon, _, _, _) = await NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePathOrFileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, widthPreview: NCGlobal.shared.sizePreview, heightPreview: NCGlobal.shared.sizePreview, fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon)
+                    let (_, _, imageIcon, _, _, _) = await NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePathOrFileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, widthPreview: NCGlobal.shared.sizePreview, heightPreview: NCGlobal.shared.sizePreview, fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, options: options)
                     if let image = imageIcon {
                         imageRecent = image
                     }

+ 1 - 1
Widget/Lockscreen/LockscreenData.swift

@@ -39,7 +39,6 @@ func getLockscreenDataEntry(configuration: AccountIntent?, isPreview: Bool, fami
 
     var account: tableAccount?
     var quotaRelative: Float = 0
-    let options = NKRequestOptions(timeout: 15, queue: NKCommon.shared.backgroundQueue)
 
     if isPreview {
         return completion(LockscreenData(date: Date(), isPlaceholder: true, activity: "", link: URL(string: "https://")!, quotaRelative: 0, quotaUsed: "", quotaTotal: "", error: false))
@@ -73,6 +72,7 @@ func getLockscreenDataEntry(configuration: AccountIntent?, isPreview: Bool, fami
         nextcloudVersion: 0,
         delegate: NCNetworking.shared)
 
+    let options = NKRequestOptions(timeout: 90, queue: NKCommon.shared.backgroundQueue)
     if #available(iOSApplicationExtension 16.0, *) {
         if family == .accessoryCircular {
             NextcloudKit.shared.getUserProfile(options: options) { _, userProfile, _, error in

+ 8 - 3
Widget/Lockscreen/LockscreenWidgetView.swift

@@ -46,8 +46,13 @@ struct LockscreenWidgetView: View {
             } else {
                 Gauge(
                     value: entry.quotaRelative,
-                    label: { Text("  " + entry.quotaTotal + "  ") },
-                    currentValueLabel: { Text(entry.quotaUsed) }
+                    label: {
+                        Text(" " + entry.quotaTotal + " ")
+                            .font(.system(size: 8.0))
+                    },
+                    currentValueLabel: {
+                        Text(entry.quotaUsed)
+                    }
                 )
                 .gaugeStyle(.accessoryCircular)
                 .redacted(reason: entry.isPlaceholder ? .placeholder : [])
@@ -88,7 +93,7 @@ struct LockscreenWidgetView: View {
 @available(iOSApplicationExtension 16.0, *)
 struct LockscreenWidgetView_Previews: PreviewProvider {
     static var previews: some View {
-        let entry = LockscreenData(date: Date(), isPlaceholder: false, activity: "Alba Mayoral changed Marketing / Regional Marketing / Agenda Meetings / Q4 2022 / OCTOBER / 13.11 Afrah Kahlid.md", link: URL(string: "https://")!, quotaRelative: 0.5, quotaUsed: "22 GB", quotaTotal: "50 GB", error: true)
+        let entry = LockscreenData(date: Date(), isPlaceholder: false, activity: "Alba Mayoral changed Marketing / Regional Marketing / Agenda Meetings / Q4 2022 / OCTOBER / 13.11 Afrah Kahlid.md", link: URL(string: "https://")!, quotaRelative: 0.5, quotaUsed: "999 GB", quotaTotal: "999 GB", error: false)
         LockscreenWidgetView(entry: entry).previewContext(WidgetPreviewContext(family: .accessoryRectangular)).previewDisplayName("Rectangular")
         LockscreenWidgetView(entry: entry).previewContext(WidgetPreviewContext(family: .accessoryCircular)).previewDisplayName("Circular")
     }

+ 10 - 10
iOSClient/AppDelegate.swift

@@ -48,7 +48,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     @objc var activeViewController: UIViewController?
     var mainTabBar: NCMainTabBar?
     var activeMetadata: tableMetadata?
-    var isSearchingMode: Bool = false
 
     let listFilesVC = ThreadSafeDictionary<String,NCFiles>()
     let listFavoriteVC = ThreadSafeDictionary<String,NCFavorite>()
@@ -56,7 +55,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
     var disableSharesView: Bool = false
     var documentPickerViewController: NCDocumentPickerViewController?
-    var shares: [tableShare] = []
     var timerErrorNetworking: Timer?
 
     private var privacyProtectionWindow: UIWindow?
@@ -190,6 +188,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
         NKCommon.shared.writeLog("[INFO] Application did become active")
 
+        // START OBSERVE/TIMER UPLOAD PROCESS
+        NCNetworkingProcessUpload.shared.observeTableMetadata()
+        NCNetworkingProcessUpload.shared.startTimer()
+
         self.deletePasswordSession = false
 
         if !NCAskAuthorization.shared.isRequesting {
@@ -207,9 +209,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
             NKCommon.shared.writeLog("[INFO] Initialize Auto upload with \(items) uploads")
         }
 
-        // START UPLOAD PROCESS
-        NCNetworkingProcessUpload.shared.startTimer()
-
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationDidBecomeActive)
     }
 
@@ -244,14 +243,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
         NKCommon.shared.writeLog("[INFO] Application will resign active")
 
+        // STOP OBSERVE/TIMER UPLOAD PROCESS
+        NCNetworkingProcessUpload.shared.invalidateObserveTableMetadata()
+        NCNetworkingProcessUpload.shared.stopTimer()
+
         if CCUtility.getPrivacyScreenEnabled() {
             // Privacy
             showPrivacyProtectionWindow()
         }
 
-        // STOP UPLOAD PROCESS
-        NCNetworkingProcessUpload.shared.stopTimer()
-
         // Reload Widget
         WidgetCenter.shared.reloadAllTimelines()
 
@@ -372,7 +372,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
         NCAutoUpload.shared.initAutoUpload(viewController: nil) { items in
             NKCommon.shared.writeLog("[INFO] Refresh task auto upload with \(items) uploads")
-            NCNetworkingProcessUpload.shared.process { items in
+            NCNetworkingProcessUpload.shared.start { items in
                 NKCommon.shared.writeLog("[INFO] Refresh task upload process with \(items) uploads")
                 task.setTaskCompleted(success: true)
             }
@@ -865,7 +865,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
         else if scheme == "nextcloud" && action == "open-file" {
 
-            if !isSearchingMode, let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) {
+            if let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) {
 
                 let queryItems = urlComponents.queryItems
                 guard let userScheme = CCUtility.value(forKey: "user", fromQueryItems: queryItems) else { return false }

+ 6 - 4
iOSClient/BrowserWeb/NCBrowserWeb.swift

@@ -110,10 +110,12 @@ class NCBrowserWeb: UIViewController {
 extension NCBrowserWeb: WKNavigationDelegate {
 
     public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
-        if let serverTrust = challenge.protectionSpace.serverTrust {
-            completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
-        } else {
-            completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil)
+        DispatchQueue.global().async {
+            if let serverTrust = challenge.protectionSpace.serverTrust {
+                completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
+            } else {
+                completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil)
+            }
         }
     }
 

+ 6 - 1
iOSClient/Data/NCElementsJSON.swift

@@ -34,8 +34,13 @@ import UIKit
 
     @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"]
-    // NC >= 23
     @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"]

+ 0 - 4
iOSClient/Data/NCManageDatabase+Account.swift

@@ -27,10 +27,6 @@ import NextcloudKit
 
 extension NCManageDatabase {
 
-    @objc func copyObject(account: tableAccount) -> tableAccount {
-        return tableAccount.init(value: account)
-    }
-
     @objc func addAccount(_ account: String, urlBase: String, user: String, password: String) {
 
         let realm = try! Realm()

+ 0 - 16
iOSClient/Data/NCManageDatabase+Metadata.swift

@@ -285,22 +285,6 @@ extension NCManageDatabase {
         }
     }
 
-    @objc func addMetadataServerUrl(ocId: String, serverUrl: String) {
-
-        let realm = try! Realm()
-
-        do {
-            try realm.write {
-                let results = realm.objects(tableMetadata.self).filter("ocId == %@", ocId)
-                for result in results {
-                    result.serverUrl = serverUrl
-                }
-            }
-        } catch let error {
-            NKCommon.shared.writeLog("Could not write to database: \(error)")
-        }
-    }
-
     @objc func renameMetadata(fileNameTo: String, ocId: String) {
 
         let realm = try! Realm()

+ 0 - 8
iOSClient/Data/NCManageDatabase.swift

@@ -641,10 +641,6 @@ class NCManageDatabase: NSObject {
     // MARK: -
     // MARK: Table Directory
 
-    @objc func copyObject(directory: tableDirectory) -> tableDirectory {
-        return tableDirectory.init(value: directory)
-    }
-
     @objc func addDirectory(encrypted: Bool, favorite: Bool, ocId: String, fileId: String, etag: String? = nil, permissions: String? = nil, serverUrl: String, account: String) {
 
         let realm = try! Realm()
@@ -1078,10 +1074,6 @@ class NCManageDatabase: NSObject {
     // MARK: -
     // MARK: Table LocalFile
 
-    @objc func copyObject(localFile: tableLocalFile) -> tableLocalFile {
-        return tableLocalFile.init(value: localFile)
-    }
-
     func addLocalFile(metadata: tableMetadata) {
 
         let realm = try! Realm()

+ 2 - 2
iOSClient/Files/NCFiles.swift

@@ -94,7 +94,7 @@ class NCFiles: NCCollectionViewCommon {
 
         DispatchQueue.main.async { self.refreshControl.endRefreshing() }
         DispatchQueue.global().async {
-            guard !self.appDelegate.isSearchingMode, !self.appDelegate.account.isEmpty, !self.appDelegate.urlBase.isEmpty, !self.serverUrl.isEmpty else { return }
+            guard !self.isSearchingMode, !self.appDelegate.account.isEmpty, !self.appDelegate.urlBase.isEmpty, !self.serverUrl.isEmpty else { return }
 
             let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", self.appDelegate.account, self.serverUrl))
             if self.metadataFolder == nil {
@@ -136,7 +136,7 @@ class NCFiles: NCCollectionViewCommon {
 
     override func reloadDataSourceNetwork(forced: Bool = false) {
         super.reloadDataSourceNetwork(forced: forced)
-        guard !appDelegate.isSearchingMode else {
+        guard !isSearchingMode else {
             networkSearch()
             return
         }

+ 6 - 4
iOSClient/Login/NCLoginWeb.swift

@@ -259,10 +259,12 @@ extension NCLoginWeb: WKNavigationDelegate {
     }
 
     func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
-        if let serverTrust = challenge.protectionSpace.serverTrust {
-            completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
-        } else {
-            completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil)
+        DispatchQueue.global().async {
+            if let serverTrust = challenge.protectionSpace.serverTrust {
+                completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
+            } else {
+                completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil)
+            }
         }
     }
 

+ 35 - 27
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift

@@ -44,6 +44,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     internal var dataSource = NCDataSource()
     internal var richWorkspaceText: String?
     internal var headerMenu: NCSectionHeaderMenu?
+    internal var isSearchingMode: Bool = false
 
     internal var layoutForView: NCGlobal.layoutForViewType?
     internal var selectableDataSource: [RealmSwiftObject] { dataSource.getMetadataSourceForAllSections() }
@@ -88,6 +89,16 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
         self.navigationController?.presentationController?.delegate = self
 
+        // CollectionView & layout
+        listLayout = NCListLayout()
+        gridLayout = NCGridLayout()
+        layoutForView = NCUtility.shared.getLayoutForView(key: layoutKey, serverUrl: serverUrl)
+        gridLayout.itemForLine = CGFloat(layoutForView?.itemForLine ?? 3)
+        if layoutForView?.layout == NCGlobal.shared.layoutList {
+            collectionView?.collectionViewLayout = listLayout
+        } else {
+            collectionView?.collectionViewLayout = gridLayout
+        }
         collectionView.alwaysBounceVertical = true
 
         // Color
@@ -118,9 +129,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         // Footer
         collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter")
 
-        listLayout = NCListLayout()
-        gridLayout = NCGridLayout()
-
         // Refresh Control
         collectionView.addSubview(refreshControl)
         refreshControl.action(for: .valueChanged) { _ in
@@ -209,7 +217,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         setNavigationItem()
 
         reloadDataSource(forced: false)
-        if !appDelegate.isSearchingMode {
+        if !isSearchingMode {
             reloadDataSourceNetwork()
         }
 
@@ -284,9 +292,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         guard !appDelegate.account.isEmpty else { return }
 
         // Search
-        if searchController?.isActive ?? false || appDelegate.isSearchingMode {
+        if searchController?.isActive ?? false || isSearchingMode {
             searchController?.isActive = false
-            appDelegate.isSearchingMode = false
+            isSearchingMode = false
         }
 
         // Select
@@ -336,7 +344,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
     @objc func reloadDataSourceNetworkForced(_ notification: NSNotification) {
 
-        if !appDelegate.isSearchingMode {
+        if !isSearchingMode {
             reloadDataSourceNetwork(forced: true)
         }
     }
@@ -419,7 +427,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
     @objc func renameFile(_ notification: NSNotification) {
 
-        if appDelegate.isSearchingMode {
+        if isSearchingMode {
             reloadDataSourceNetwork()
         } else {
             reloadDataSource()
@@ -538,7 +546,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
               account == appDelegate.account
         else { return }
 
-        guard !appDelegate.isSearchingMode, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
+        guard !isSearchingMode, let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
         dataSource.addMetadata(metadata)
         self.collectionView?.reloadData()
     }
@@ -734,7 +742,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     func emptyDataSetView(_ view: NCEmptyView) {
 
         self.emptyDataSet?.setOffset(getHeaderHeight())
-        if appDelegate.isSearchingMode {
+        if isSearchingMode {
             view.emptyImage.image = UIImage(named: "search")?.image(color: .gray, size: UIScreen.main.bounds.width)
             if isReloadDataSourceNetworkInProgress {
                 view.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "")
@@ -767,7 +775,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
     func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
 
-        appDelegate.isSearchingMode = true
+        isSearchingMode = true
         self.providers?.removeAll()
         self.dataSource.clearDataSource()
         self.collectionView.reloadData()
@@ -778,7 +786,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
     func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
 
-        if appDelegate.isSearchingMode && self.literalSearch?.count ?? 0 >= 2 {
+        if isSearchingMode && self.literalSearch?.count ?? 0 >= 2 {
             reloadDataSourceNetwork()
         }
     }
@@ -788,7 +796,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         DispatchQueue.global().async {
             NCNetworking.shared.cancelUnifiedSearchFiles()
 
-            self.appDelegate.isSearchingMode = false
+            self.isSearchingMode = false
             self.literalSearch = ""
             self.providers?.removeAll()
             self.dataSource.clearDataSource()
@@ -838,7 +846,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
             headerMenu?.buttonSwitch.accessibilityLabel = NSLocalizedString("_list_view_", comment: "")
             layoutForView?.layout = NCGlobal.shared.layoutGrid
             NCUtility.shared.setLayoutForView(key: layoutKey, serverUrl: serverUrl, layout: layoutForView?.layout)
-            if appDelegate.isSearchingMode {
+            if isSearchingMode {
                 self.groupByField = "name"
             } else {
                 self.groupByField = "classFile"
@@ -1009,7 +1017,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         layoutForView = NCUtility.shared.getLayoutForView(key: layoutKey, serverUrl: serverUrl)
 
         // set GroupField for Grid
-        if !appDelegate.isSearchingMode && layoutForView?.layout == NCGlobal.shared.layoutGrid {
+        if !isSearchingMode && layoutForView?.layout == NCGlobal.shared.layoutGrid {
             groupByField = "classFile"
         } else {
             groupByField = "name"
@@ -1046,7 +1054,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
                     providers: self.providers,
                     searchResults: self.searchResults)
             } update: { account, id, searchResult, metadatas in
-                guard let metadatas = metadatas, metadatas.count > 0, self.appDelegate.isSearchingMode , let searchResult = searchResult else { return }
+                guard let metadatas = metadatas, metadatas.count > 0, self.isSearchingMode , let searchResult = searchResult else { return }
                 NCOperationQueue.shared.unifiedSearchAddSection(collectionViewCommon: self, metadatas: metadatas, searchResult: searchResult)
             } completion: { account, error in
                 self.refreshControl.endRefreshing()
@@ -1059,7 +1067,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
                     self.refreshControl.endRefreshing()
                     self.collectionView.reloadData()
                 }
-                guard let metadatas = metadatas, error == .success, self.appDelegate.isSearchingMode else { return }
+                guard let metadatas = metadatas, error == .success, self.isSearchingMode else { return }
                 self.dataSource = NCDataSource(
                     metadatas: metadatas,
                     account: self.appDelegate.account,
@@ -1491,7 +1499,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
         cell.hideButtonMore(false)
         cell.titleInfoTrailingDefault()
 
-        if appDelegate.isSearchingMode {
+        if isSearchingMode {
             cell.fileTitleLabel?.text = metadata.fileName
             cell.fileTitleLabel?.lineBreakMode = .byTruncatingTail
             if metadata.name == NCGlobal.shared.appName {
@@ -1642,7 +1650,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
         }
 
         // Separator
-        if collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1 || appDelegate.isSearchingMode {
+        if collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1 || isSearchingMode {
             cell.cellSeparatorView?.isHidden = true
         } else {
             cell.cellSeparatorView?.isHidden = false
@@ -1665,7 +1673,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
         cell.setAccessibility(label: metadata.fileNameView + ", " + (cell.fileInfoLabel?.text ?? ""), value: a11yValues.joined(separator: ", "))
 
         // Color string find in search
-        if appDelegate.isSearchingMode, let literalSearch = self.literalSearch, let title = cell.fileTitleLabel?.text {
+        if isSearchingMode, let literalSearch = self.literalSearch, let title = cell.fileTitleLabel?.text {
             let longestWordRange = (title.lowercased() as NSString).range(of: literalSearch)
             let attributedString = NSMutableAttributedString(string: title, attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 15)])
             attributedString.setAttributes([NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 15), NSAttributedString.Key.foregroundColor : UIColor.systemBlue], range: longestWordRange)
@@ -1694,7 +1702,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
                 }
 
                 header.delegate = self
-                if headerMenuButtonsCommand && !appDelegate.isSearchingMode {
+                if headerMenuButtonsCommand && !isSearchingMode {
                     header.setButtonsCommand(heigt: NCGlobal.shared.heightButtonsCommand, imageButton1: UIImage(named: "addImage"), titleButton1: NSLocalizedString("_upload_", comment: ""), imageButton2: UIImage(named: "folder"), titleButton2: NSLocalizedString("_create_folder_", comment: ""), imageButton3: UIImage(named: "scan"), titleButton3: NSLocalizedString("_scan_", comment: ""))
                 } else {
                     header.setButtonsCommand(heigt: 0)
@@ -1749,11 +1757,11 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             footer.buttonIsHidden(true)
             footer.hideActivityIndicatorSection()
 
-            if appDelegate.isSearchingMode {
+            if isSearchingMode {
                 if sections > 1 && section != sections - 1 {
                     footer.separatorIsHidden(false)
                 }
-                if appDelegate.isSearchingMode && isPaginated && metadatasCount > 0 {
+                if isSearchingMode && isPaginated && metadatasCount > 0 {
                     footer.buttonIsHidden(false)
                 }
                 if unifiedSearchInProgress {
@@ -1779,7 +1787,7 @@ extension NCCollectionViewCommon: UICollectionViewDelegateFlowLayout {
 
         var size: CGFloat = 0
 
-        if headerMenuButtonsCommand && !appDelegate.isSearchingMode {
+        if headerMenuButtonsCommand && !isSearchingMode {
             size += NCGlobal.shared.heightButtonsCommand
         }
         if headerMenuButtonsView {
@@ -1795,12 +1803,12 @@ extension NCCollectionViewCommon: UICollectionViewDelegateFlowLayout {
 
         if let richWorkspaceText = richWorkspaceText, !headerRichWorkspaceDisable {
             let trimmed = richWorkspaceText.trimmingCharacters(in: .whitespaces)
-            if trimmed.count > 0 && !appDelegate.isSearchingMode {
+            if trimmed.count > 0 && !isSearchingMode {
                 headerRichWorkspace = UIScreen.main.bounds.size.height / 6
             }
         }
 
-        if appDelegate.isSearchingMode || layoutForView?.layout == NCGlobal.shared.layoutGrid || dataSource.numberOfSections() > 1 {
+        if isSearchingMode || layoutForView?.layout == NCGlobal.shared.layoutGrid || dataSource.numberOfSections() > 1 {
             if section == 0 {
                 return (getHeaderHeight(), headerRichWorkspace, NCGlobal.shared.heightSection)
             } else {
@@ -1833,7 +1841,7 @@ extension NCCollectionViewCommon: UICollectionViewDelegateFlowLayout {
             size.height += NCGlobal.shared.heightFooter
         }
 
-        if appDelegate.isSearchingMode && isPaginated && metadatasCount > 0 {
+        if isSearchingMode && isPaginated && metadatasCount > 0 {
             size.height += NCGlobal.shared.heightFooterButton
         }
 

+ 28 - 17
iOSClient/Main/NCFunctionCenter.swift

@@ -308,22 +308,35 @@ import Photos
                 let error = NKError(errorCode: NCGlobal.shared.errorFileNotSaved, errorDescription: "_access_photo_not_enabled_msg_")
                 return NCContentPresenter.shared.messageNotification("_access_photo_not_enabled_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
             }
-            if metadata.classFile == NKCommon.typeClassFile.image.rawValue, let image = UIImage(contentsOfFile: fileNamePath) {
-                UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.saveAlbum(_:didFinishSavingWithError:contextInfo:)), nil)
-            } else if metadata.classFile == NKCommon.typeClassFile.video.rawValue, UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(fileNamePath) {
-                UISaveVideoAtPathToSavedPhotosAlbum(fileNamePath, self, #selector(self.saveAlbum(_:didFinishSavingWithError:contextInfo:)), nil)
-            } else {
-                let error = NKError(errorCode: NCGlobal.shared.errorFileNotSaved, errorDescription: "_file_not_saved_cameraroll_")
-                NCContentPresenter.shared.messageNotification("_save_selected_files_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
-            }
-        }
-    }
 
-    @objc private func saveAlbum(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
-
-        if error != nil {
-            let error = NKError(errorCode: NCGlobal.shared.errorFileNotSaved, errorDescription: "_file_not_saved_cameraroll_")
-            NCContentPresenter.shared.messageNotification("_save_selected_files_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+            let errorSave = NKError(errorCode: NCGlobal.shared.errorFileNotSaved, errorDescription: "_file_not_saved_cameraroll_")
+
+            do {
+                if metadata.classFile == NKCommon.typeClassFile.image.rawValue {
+                    let data = try Data(contentsOf: URL(fileURLWithPath: fileNamePath))
+                    PHPhotoLibrary.shared().performChanges({
+                        let assetRequest = PHAssetCreationRequest.forAsset()
+                        assetRequest.addResource(with: .photo, data: data, options: nil)
+                    }) { (success, error) in
+                        if !success {
+                            NCContentPresenter.shared.messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+                        }
+                    }
+                } else if metadata.classFile == NKCommon.typeClassFile.video.rawValue {
+                    PHPhotoLibrary.shared().performChanges({
+                        PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: fileNamePath))
+                    }) { (success, error) in
+                        if !success {
+                            NCContentPresenter.shared.messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+                        }
+                    }
+                } else {
+                    NCContentPresenter.shared.messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+                    return
+                }
+            } catch {
+                NCContentPresenter.shared.messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+            }
         }
     }
 
@@ -462,8 +475,6 @@ import Photos
 
     func openFileViewInFolder(serverUrl: String, fileNameBlink: String?, fileNameOpen: String?) {
 
-        appDelegate.isSearchingMode = false
-        
         DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
             var topNavigationController: UINavigationController?
             var pushServerUrl = NCUtilityFileSystem.shared.getHomeServer(urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId)

+ 39 - 40
iOSClient/Networking/NCNetworking.swift

@@ -129,11 +129,8 @@ import Photos
     }
 
     func authenticationChallenge(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
-
-        if checkTrustedChallenge(session, didReceive: challenge) {
-            completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
-        } else {
-            completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil)
+        DispatchQueue.global().async {
+            self.checkTrustedChallenge(session, didReceive: challenge, completionHandler: completionHandler)
         }
     }
 
@@ -158,7 +155,7 @@ import Photos
 
     // MARK: - Pinning check
 
-    private func checkTrustedChallenge(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge) -> Bool {
+    private func checkTrustedChallenge(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
 
         let protectionSpace: URLProtectionSpace = challenge.protectionSpace
         let directoryCertificate = CCUtility.getDirectoryCerificates()!
@@ -166,14 +163,6 @@ import Photos
         let certificateSavedPath = directoryCertificate + "/" + host + ".der"
         var isTrusted: Bool
 
-        #if !EXTENSION
-        defer {
-            if !isTrusted {
-                DispatchQueue.main.async { (UIApplication.shared.delegate as? AppDelegate)?.trustCertificateError(host: host) }
-            }
-        }
-        #endif
-
         if let serverTrust: SecTrust = protectionSpace.serverTrust, let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
 
             // extarct certificate txt
@@ -197,8 +186,15 @@ import Photos
         } else {
             isTrusted = false
         }
-        
-        return isTrusted
+
+        if isTrusted {
+            completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
+        } else {
+            #if !EXTENSION
+            DispatchQueue.main.async { (UIApplication.shared.delegate as? AppDelegate)?.trustCertificateError(host: host) }
+            #endif
+            completionHandler(URLSession.AuthChallengeDisposition.performDefaultHandling, nil)
+        }
     }
 
     func writeCertificate(host: String) {
@@ -207,9 +203,8 @@ import Photos
         let certificateAtPath = directoryCertificate + "/" + host + ".tmp"
         let certificateToPath = directoryCertificate + "/" + host + ".der"
 
-        if !NCUtilityFileSystem.shared.moveFile(atPath: certificateAtPath, toPath: certificateToPath) {
-            let error = NKError(errorCode: NCGlobal.shared.errorCreationFile, errorDescription: "_error_creation_file_")
-            NCContentPresenter.shared.showError(error: error, priority: .max)
+        if !NCUtilityFileSystem.shared.copyFile(atPath: certificateAtPath, toPath: certificateToPath) {
+            NKCommon.shared.writeLog("[ERROR] Write certificare error")
         }
     }
     
@@ -221,7 +216,7 @@ import Photos
         let x509cert = d2i_X509_bio(mem, nil)
 
         if x509cert == nil {
-            print("[LOG] OpenSSL couldn't parse X509 Certificate")
+            NKCommon.shared.writeLog("[ERROR] OpenSSL couldn't parse X509 Certificate")
         } else {
             // save details
             if FileManager.default.fileExists(atPath: certNamePathTXT) {
@@ -1006,16 +1001,34 @@ import Photos
 
     func createFolder(assets: [PHAsset], selector: String, useSubFolder: Bool, account: String, urlBase: String, userId: String) -> Bool {
 
-        let serverUrl = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: urlBase, userId: userId, account: account)
-        let fileName =  NCManageDatabase.shared.getAccountAutoUploadFileName()
         let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: urlBase, userId: userId, account: account)
-        var result = createFolderWithSemaphore(fileName: fileName, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId)
+        let serverUrlBase = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: urlBase, userId: userId, account: account)
+        let fileNameBase =  NCManageDatabase.shared.getAccountAutoUploadFileName()
+
+        func createFolder(fileName: String, serverUrl: String) -> Bool {
+            var result: Bool = false
+            let semaphore = DispatchSemaphore(value: 0)
+            NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId, overwrite: true) { error in
+                if error == .success { result = true }
+                semaphore.signal()
+            }
+            semaphore.wait()
+            return result
+        }
+
+        var result = createFolder(fileName: fileNameBase, serverUrl: serverUrlBase)
 
         if useSubFolder && result {
             for dateSubFolder in createNameSubFolder(assets: assets) {
-                let fileName = (dateSubFolder as NSString).lastPathComponent
-                let serverUrl = ((autoUploadPath + "/" + dateSubFolder) as NSString).deletingLastPathComponent
-                result = createFolderWithSemaphore(fileName: fileName, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId)
+                let yearMonth = dateSubFolder.split(separator: "/")
+                guard let year = yearMonth.first else { break }
+                guard let month = yearMonth.last else { break }
+                let serverUrlYear = autoUploadPath
+                let serverUrlMonth = autoUploadPath + "/" + year
+                result = createFolder(fileName: String(year), serverUrl: serverUrlYear)
+                if result {
+                    result = createFolder(fileName: String(month), serverUrl: serverUrlMonth)
+                }
                 if !result { break }
             }
         }
@@ -1023,20 +1036,6 @@ import Photos
         return result
     }
 
-    private func createFolderWithSemaphore(fileName: String, serverUrl: String, account: String, urlBase: String, userId: String) -> Bool {
-
-        var result: Bool = false
-        let semaphore = DispatchSemaphore(value: 0)
-
-        NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: account, urlBase: urlBase, userId: userId, overwrite: true) { error in
-            if error == .success { result = true }
-            semaphore.signal()
-        }
-        semaphore.wait()
-
-        return result
-    }
-
     func createNameSubFolder(assets: [PHAsset]) -> [String] {
 
         var datesSubFolder: [String] = []

+ 73 - 52
iOSClient/Networking/NCNetworkingProcessUpload.swift

@@ -25,6 +25,7 @@ import UIKit
 import NextcloudKit
 import Photos
 import JGProgressHUD
+import RealmSwift
 
 class NCNetworkingProcessUpload: NSObject {
     public static let shared: NCNetworkingProcessUpload = {
@@ -32,12 +33,43 @@ class NCNetworkingProcessUpload: NSObject {
         return instance
     }()
 
-    var timerProcess: Timer?
+    private let appDelegate = UIApplication.shared.delegate as! AppDelegate
+    private var notificationToken: NotificationToken?
+    private var timerProcess: Timer?
+    private var pauseProcess: Bool = false
+
+    func observeTableMetadata() {
+        let realm = try! Realm()
+        let results = realm.objects(tableMetadata.self).filter("session != '' || sessionError != ''")
+        notificationToken = results.observe { [weak self] (changes: RealmCollectionChange) in
+            switch changes {
+            case .initial:
+                print("Initial")
+            case .update(_, let deletions, let insertions, let modifications):
+                if (deletions.count > 0 || insertions.count > 0 || modifications.count > 0) {
+                    self?.invalidateObserveTableMetadata()
+                    self?.start(completition: { items in
+                        print("[LOG] PROCESS-UPLOAD-OBSERVE \(items)")
+                        DispatchQueue.main.async {
+                            self?.observeTableMetadata()
+                        }
+                    })
+                }
+            case .error(let error):
+                NKCommon.shared.writeLog("[ERROR] Could not write to TableMetadata: \(error)")
+            }
+        }
+    }
+
+    func invalidateObserveTableMetadata() {
+        notificationToken?.invalidate()
+        notificationToken = nil
+    }
 
     func startTimer() {
         DispatchQueue.main.async {
             self.timerProcess?.invalidate()
-            self.timerProcess = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.processTimer), userInfo: nil, repeats: true)
+            self.timerProcess = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.processTimer), userInfo: nil, repeats: true)
         }
     }
 
@@ -47,19 +79,21 @@ class NCNetworkingProcessUpload: NSObject {
         }
     }
 
-    @objc func processTimer() {
-        process { _ in }
+    @objc private func processTimer() {
+        start { items in
+            print("[LOG] PROCESS-UPLOAD-TIMER \(items)")
+        }
     }
 
-    func process(completition: @escaping (_ items: Int) -> Void) {
-
-        guard let account = NCManageDatabase.shared.getActiveAccount() else { return }
+    func start(completition: @escaping (_ items: Int) -> Void) {
 
-        stopTimer()
+        if appDelegate.account.isEmpty || pauseProcess {
+            return completition(0)
+        } else {
+            pauseProcess = true
+        }
 
-        let appDelegate = UIApplication.shared.delegate as! AppDelegate
         let applicationState = UIApplication.shared.applicationState
-        let isPasscodePresented = appDelegate.isPasscodePresented()
         let queue = DispatchQueue.global()
         var maxConcurrentOperationUpload = 10
         let viewController = appDelegate.window?.rootViewController
@@ -67,17 +101,15 @@ class NCNetworkingProcessUpload: NSObject {
 
         queue.async {
 
-            let metadatasUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status == %d OR status == %d", NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading))
+            let metadatasUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND (status == %d OR status == %d)", self.appDelegate.account, NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading))
             let isWiFi = NCNetworking.shared.networkReachability == NKCommon.typeReachability.reachableEthernetOrWiFi
             var counterUpload: Int = 0
             let sessionSelectors = [NCGlobal.shared.selectorUploadFileNODelete, NCGlobal.shared.selectorUploadFile, NCGlobal.shared.selectorUploadAutoUpload, NCGlobal.shared.selectorUploadAutoUploadAll]
 
             counterUpload = metadatasUpload.count
 
-            print("[LOG] PROCESS-UPLOAD \(counterUpload)")
-
             // Update Badge
-            let counterBadge = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status == %d OR status == %d OR status == %d", NCGlobal.shared.metadataStatusWaitUpload, NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading))
+            let counterBadge = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND (status == %d OR status == %d OR status == %d)", self.appDelegate.account, NCGlobal.shared.metadataStatusWaitUpload, NCGlobal.shared.metadataStatusInUpload, NCGlobal.shared.metadataStatusUploading))
             NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateBadgeNumber, userInfo: ["counter":counterBadge.count])
 
             NCNetworking.shared.getOcIdInBackgroundSession(queue: queue, completion: { listOcId in
@@ -85,19 +117,13 @@ class NCNetworkingProcessUpload: NSObject {
                 for sessionSelector in sessionSelectors where counterUpload < maxConcurrentOperationUpload {
 
                     let limit = maxConcurrentOperationUpload - counterUpload
-                    let metadatas = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "sessionSelector == %@ AND status == %d", sessionSelector, NCGlobal.shared.metadataStatusWaitUpload), page: 1, limit: limit, sorted: "date", ascending: true)
+                    let metadatas = NCManageDatabase.shared.getAdvancedMetadatas(predicate: NSPredicate(format: "account == %@ AND sessionSelector == %@ AND status == %d", self.appDelegate.account, sessionSelector, NCGlobal.shared.metadataStatusWaitUpload), page: 1, limit: limit, sorted: "date", ascending: true)
                     if metadatas.count > 0 {
                         NKCommon.shared.writeLog("[INFO] PROCESS-UPLOAD find \(metadatas.count) items")
                     }
 
                     for metadata in metadatas where counterUpload < maxConcurrentOperationUpload {
 
-                        // Different account
-                        if account.account != metadata.account {
-                            NKCommon.shared.writeLog("[INFO] Process auto upload skipped file: \(metadata.serverUrl)/\(metadata.fileNameView) on account: \(metadata.account), because the actual account is \(account.account).")
-                            continue
-                        }
-
                         // Is already in upload background? skipped
                         if listOcId.contains(metadata.ocId) {
                             NKCommon.shared.writeLog("[INFO] Process auto upload skipped file: \(metadata.serverUrl)/\(metadata.fileNameView), because is already in session.")
@@ -147,49 +173,44 @@ class NCNetworkingProcessUpload: NSObject {
 
                 // No upload available ? --> Retry Upload in Error
                 if counterUpload == 0 {
-                    let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "status == %d", NCGlobal.shared.metadataStatusUploadError))
+                    let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND status == %d", self.appDelegate.account, NCGlobal.shared.metadataStatusUploadError))
                     for metadata in metadatas {
                         NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, session: NCNetworking.shared.sessionIdentifierBackground, sessionError: "", sessionTaskIdentifier: 0, status: NCGlobal.shared.metadataStatusWaitUpload)
                     }
-                }
 
-                // verify delete Asset Local Identifiers in auto upload (DELETE Photos album)
-                if applicationState == .active && counterUpload == 0 && !isPasscodePresented {
-                    self.deleteAssetLocalIdentifiers(account: account.account) {
-                        self.startTimer()
+                    // verify delete Asset Local Identifiers in auto upload (DELETE Photos album)
+                    if applicationState == .active && metadatas.isEmpty && !self.appDelegate.isPasscodePresented() {
+                        self.deleteAssetLocalIdentifiers {
+                            self.pauseProcess = false
+                        }
+                    } else {
+                        self.pauseProcess = false
                     }
-                } else if applicationState == .active {
-                    self.startTimer()
+                } else {
+                    self.pauseProcess = false
                 }
+
                 completition(counterUpload)
             })
         }
     }
 
-    private func deleteAssetLocalIdentifiers(account: String, completition: @escaping () -> Void) {
+    private func deleteAssetLocalIdentifiers(completition: @escaping () -> Void) {
 
-        DispatchQueue.main.async {
-            let metadatasSessionUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND session CONTAINS[cd] %@", account, "upload"))
-            if !metadatasSessionUpload.isEmpty {
-                completition()
-                return
-            }
-            let localIdentifiers = NCManageDatabase.shared.getAssetLocalIdentifiersUploaded(account: account)
-            if localIdentifiers.isEmpty {
-                completition()
-                return
-            }
-            let assets = PHAsset.fetchAssets(withLocalIdentifiers: localIdentifiers, options: nil)
-
-            PHPhotoLibrary.shared().performChanges({
-                PHAssetChangeRequest.deleteAssets(assets as NSFastEnumeration)
-            }, completionHandler: { _, _ in
-                DispatchQueue.main.async {
-                    NCManageDatabase.shared.clearAssetLocalIdentifiers(localIdentifiers, account: account)
-                    completition()
-                }
-            })
-        }
+        let metadatasSessionUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND session CONTAINS[cd] %@", appDelegate.account, "upload"))
+        if !metadatasSessionUpload.isEmpty { return completition() }
+
+        let localIdentifiers = NCManageDatabase.shared.getAssetLocalIdentifiersUploaded(account: appDelegate.account)
+        if localIdentifiers.isEmpty { return completition() }
+
+        let assets = PHAsset.fetchAssets(withLocalIdentifiers: localIdentifiers, options: nil)
+
+        PHPhotoLibrary.shared().performChanges({
+            PHAssetChangeRequest.deleteAssets(assets as NSFastEnumeration)
+        }, completionHandler: { _, _ in
+            NCManageDatabase.shared.clearAssetLocalIdentifiers(localIdentifiers, account: self.appDelegate.account)
+            completition()
+        })
     }
 
     // MARK: -

+ 0 - 1
iOSClient/Networking/NCService.swift

@@ -201,7 +201,6 @@ class NCService: NSObject {
                         if let shares = shares, !shares.isEmpty {
                             NCManageDatabase.shared.addShare(account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, shares: shares)
                         }
-                        self.appDelegate.shares = NCManageDatabase.shared.getTableShares(account: account)
                     }
                 }
             }

+ 6 - 4
iOSClient/RichWorkspace/NCViewerRichWorkspaceWebView.swift

@@ -103,10 +103,12 @@ class NCViewerRichWorkspaceWebView: UIViewController, WKNavigationDelegate, WKSc
     // MARK: -
 
     public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
-        if let serverTrust = challenge.protectionSpace.serverTrust {
-            completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
-        } else {
-            completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil)
+        DispatchQueue.global().async {
+            if let serverTrust = challenge.protectionSpace.serverTrust {
+                completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
+            } else {
+                completionHandler(URLSession.AuthChallengeDisposition.useCredential, nil)
+            }
         }
     }
 

+ 0 - 4
iOSClient/Select/NCSelect.swift

@@ -80,8 +80,6 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent
     private var listLayout: NCListLayout!
     private var gridLayout: NCGridLayout!
 
-    private var shares: [tableShare]?
-
     private var backgroundImageView = UIImageView()
 
     private var activeAccount: tableAccount!
@@ -185,8 +183,6 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent
         }
 
         loadDatasource(withLoadFolder: true)
-
-        shares = NCManageDatabase.shared.getTableShares(account: activeAccount.account, serverUrl: serverUrl)
     }
 
     override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

+ 1 - 0
iOSClient/Share/Advanced/NCShareAdvancePermission.swift

@@ -157,6 +157,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
         case .expirationDate:
             let cell = tableView.cellForRow(at: indexPath) as? NCShareDateCell
             cell?.textField.becomeFirstResponder()
+            cell?.checkMaximumDate(account: metadata.account)
         case .password:
             guard share.password.isEmpty else {
                 share.password = ""

+ 50 - 4
iOSClient/Share/Advanced/NCShareCells.swift

@@ -262,16 +262,16 @@ class NCShareToggleCell: UITableViewCell {
 class NCShareDateCell: UITableViewCell {
     let picker = UIDatePicker()
     let textField = UITextField()
-
+    var shareType: Int
     var onReload: (() -> Void)?
 
     init(share: NCTableShareable) {
+        self.shareType = share.shareType
         super.init(style: .value1, reuseIdentifier: "shareExpDate")
+
         picker.datePickerMode = .date
         picker.minimumDate = Date()
-        if #available(iOS 13.4, *) {
-            picker.preferredDatePickerStyle = .wheels
-        }
+        picker.preferredDatePickerStyle = .wheels
         picker.action(for: .valueChanged) { datePicker in
             guard let datePicker = datePicker as? UIDatePicker else { return }
             self.detailTextLabel?.text = DateFormatter.shareExpDate.string(from: datePicker.date)
@@ -301,4 +301,50 @@ class NCShareDateCell: UITableViewCell {
     required public init?(coder: NSCoder) {
         fatalError("init(coder:) has not been implemented")
     }
+
+    func checkMaximumDate(account: String) {
+        let defaultExpDays = defaultExpirationDays(account: account)
+        if defaultExpDays > 0 && isExpireDateEnforced(account: account) {
+            let enforcedInSecs = TimeInterval(defaultExpDays * 24 * 60 * 60)
+            self.picker.maximumDate = Date().advanced(by: enforcedInSecs)
+        }
+    }
+
+    private func isExpireDateEnforced(account: String) -> Bool {
+        switch self.shareType {
+        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)
+        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)
+        case NCShareCommon.shared.SHARE_TYPE_REMOTE,
+            NCShareCommon.shared.SHARE_TYPE_REMOTE_GROUP:
+            return NCManageDatabase.shared.getCapabilitiesServerBool(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingRemoteExpireDateEnforced, exists: false)
+        default:
+            return false
+        }
+    }
+
+    private func defaultExpirationDays(account: String) -> Int {
+        switch self.shareType {
+        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)
+        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)
+        case NCShareCommon.shared.SHARE_TYPE_REMOTE,
+            NCShareCommon.shared.SHARE_TYPE_REMOTE_GROUP:
+            return NCManageDatabase.shared.getCapabilitiesServerInt(account: account, elements: NCElementsJSON.shared.capabilitiesFileSharingRemoteExpireDateDays)
+        default:
+            return 0
+        }
+    }
 }

+ 0 - 3
iOSClient/Share/NCShareNetworking.swift

@@ -53,7 +53,6 @@ class NCShareNetworking: NSObject {
 
             if error == .success, let shares = shares {
                 NCManageDatabase.shared.addShare(account: self.metadata.account, urlBase: self.metadata.urlBase, userId: self.metadata.userId, shares: shares)
-                self.appDelegate.shares = NCManageDatabase.shared.getTableShares(account: self.metadata.account)
             } else {
                 NCContentPresenter.shared.showError(error: error)
             }
@@ -77,7 +76,6 @@ class NCShareNetworking: NSObject {
             if error == .success, let share = share {
                 option.idShare = share.idShare
                 NCManageDatabase.shared.addShare(account: self.metadata.account, urlBase: self.metadata.urlBase, userId: self.metadata.userId, shares: [share])
-                self.appDelegate.shares = NCManageDatabase.shared.getTableShares(account: self.metadata.account)
                 if option.hasChanges(comparedTo: share) {
                     self.updateShare(option: option)
                 }
@@ -107,7 +105,6 @@ class NCShareNetworking: NSObject {
             NCActivityIndicator.shared.stop()
             if error == .success, let share = share {
                 NCManageDatabase.shared.addShare(account: self.metadata.account, urlBase: self.metadata.urlBase, userId: self.metadata.userId, shares: [share])
-                self.appDelegate.shares = NCManageDatabase.shared.getTableShares(account: self.metadata.account)
                 self.delegate?.readShareCompleted()
             } else {
                 NCContentPresenter.shared.showError(error: error)

+ 0 - 1
iOSClient/Shares/NCShares.swift

@@ -102,7 +102,6 @@ class NCShares: NCCollectionViewCommon {
                 if let shares = shares, !shares.isEmpty {
                     NCManageDatabase.shared.addShare(account: self.appDelegate.account, urlBase: self.appDelegate.urlBase, userId: self.appDelegate.userId, shares: shares)
                 }
-                self.appDelegate.shares = NCManageDatabase.shared.getTableShares(account: account)
                 self.reloadDataSource()
 
             } else {

BIN
iOSClient/Supporting Files/af.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/an.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ar.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ast.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/az.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/be.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/bg_BG.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/bn_BD.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/br.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/bs.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ca.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/cs-CZ.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/cy_GB.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/da.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/de.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/el.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/en-GB.lproj/Localizable.strings


+ 1 - 1
iOSClient/Supporting Files/en.lproj/Localizable.strings

@@ -897,7 +897,7 @@
 "_description_lockscreenwidget_" = "Keep an eye on available space and recent activity";
 "_no_items_"                = "No items";
 "_check_back_later_"        = "Check back later";
-"_exporting_video_"         = "Exporting video … Tap to cancel";
+"_exporting_video_"         = "Exporting video … Tap to cancel.";
 
 // Video
 "_select_trace_"            = "Select the trace";

BIN
iOSClient/Supporting Files/eo.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-419.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-AR.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-CL.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-CO.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-CR.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-DO.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-EC.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-GT.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-HN.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-MX.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-NI.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-PA.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-PE.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-PR.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-PY.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-SV.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es-UY.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/es.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/et_EE.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/eu.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/fa.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/fi-FI.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/fo.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/fr.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/gd.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/gl.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/he.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/hi_IN.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/hr.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/hsb.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/hu.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/hy.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ia.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/id.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ig.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/is.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/it.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ja-JP.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ka-GE.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ka.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/kab.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/km.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/kn.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ko.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/la.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/lb.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/lo.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/lt_LT.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/lv.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/mk.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/mn.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/mr.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ms_MY.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/my.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/nb-NO.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ne.lproj/Localizable.strings


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