From 7b6a19ed74f5ccb77215ff8ac45472ed61fe90a9 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 29 Jan 2026 14:51:46 +0100 Subject: [PATCH 1/9] code Signed-off-by: Marino Faggiana --- iOSClient/Login/NCLogin.swift | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index 64f4fa5425..f51096a067 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -375,21 +375,38 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { // MARK: - QRCode func dismissQRCode(_ value: String?, metadataType: String?) { - guard var value = value else { return } + guard let value else { + return + } let protocolLogin = NCBrandOptions.shared.webLoginAutenticationProtocol + "login/" - if value.hasPrefix(protocolLogin) && value.contains("user:") && value.contains("password:") && value.contains("server:") { - value = value.replacingOccurrences(of: protocolLogin, with: "") - let valueArray = value.components(separatedBy: "&") - if valueArray.count == 3 { - let user = valueArray[0].replacingOccurrences(of: "user:", with: "") - let password = valueArray[1].replacingOccurrences(of: "password:", with: "") - let urlBase = valueArray[2].replacingOccurrences(of: "server:", with: "") + let protocolLoginOneTime = NCBrandOptions.shared.webLoginAutenticationProtocol + "onetime-login/" + var parameters: String = "" + + if value.hasPrefix(protocolLogin) { + parameters = value.replacingOccurrences(of: protocolLogin, with: "") + } else if value.hasPrefix(protocolLoginOneTime) { + parameters = value.replacingOccurrences(of: protocolLoginOneTime, with: "") + } else { + return + } + + if parameters.contains("user:"), parameters.contains("password:"), parameters.contains("server:") { + let parametersArray = parameters.components(separatedBy: "&") + if parametersArray.count == 3 { + let user = parametersArray[0].replacingOccurrences(of: "user:", with: "") + let password = parametersArray[1].replacingOccurrences(of: "password:", with: "") + let urlBase = parametersArray[2].replacingOccurrences(of: "server:", with: "") let serverUrl = urlBase + "/remote.php/dav" loginButton.isEnabled = false NextcloudKit.shared.checkServer(serverUrl: serverUrl) { _, error in self.loginButton.isEnabled = true if error == .success { - self.createAccount(urlBase: urlBase, user: user, password: password) + if value.hasPrefix(protocolLogin) { + self.createAccount(urlBase: urlBase, user: user, password: password) + + } else if value.hasPrefix(protocolLoginOneTime) { + + } } else { let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) From 88c46aa33561170d60c0812d29d4793758445890 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 29 Jan 2026 16:39:50 +0100 Subject: [PATCH 2/9] code Signed-off-by: Marino Faggiana --- iOSClient/Login/NCLogin.swift | 57 ++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index f51096a067..ca2b1e2b9b 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -378,6 +378,22 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { guard let value else { return } + + func getParameters(parameters: String) -> (server: String?, user: String?, password: String?) { + guard parameters.contains("user:"), + parameters.contains("password:"), + parameters.contains("server:") else { + return(nil, nil, nil) + } + let parametersArray = parameters.components(separatedBy: "&") + + let user = parametersArray[0].replacingOccurrences(of: "user:", with: "") + let password = parametersArray[1].replacingOccurrences(of: "password:", with: "") + let server = parametersArray[2].replacingOccurrences(of: "server:", with: "") + + return(server, user, password) + } + let protocolLogin = NCBrandOptions.shared.webLoginAutenticationProtocol + "login/" let protocolLoginOneTime = NCBrandOptions.shared.webLoginAutenticationProtocol + "onetime-login/" var parameters: String = "" @@ -390,28 +406,27 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { return } - if parameters.contains("user:"), parameters.contains("password:"), parameters.contains("server:") { - let parametersArray = parameters.components(separatedBy: "&") - if parametersArray.count == 3 { - let user = parametersArray[0].replacingOccurrences(of: "user:", with: "") - let password = parametersArray[1].replacingOccurrences(of: "password:", with: "") - let urlBase = parametersArray[2].replacingOccurrences(of: "server:", with: "") - let serverUrl = urlBase + "/remote.php/dav" - loginButton.isEnabled = false - NextcloudKit.shared.checkServer(serverUrl: serverUrl) { _, error in - self.loginButton.isEnabled = true - if error == .success { - if value.hasPrefix(protocolLogin) { - self.createAccount(urlBase: urlBase, user: user, password: password) - - } else if value.hasPrefix(protocolLoginOneTime) { - - } - } else { - let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: error.errorDescription, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) - self.present(alertController, animated: true) + guard parameters.contains("user:"), + parameters.contains("password:"), + parameters.contains("server:") else { + return + } + let parametersArray = parameters.components(separatedBy: "&") + let user = parametersArray[0].replacingOccurrences(of: "user:", with: "") + let password = parametersArray[1].replacingOccurrences(of: "password:", with: "") + let server = parametersArray[2].replacingOccurrences(of: "server:", with: "") + + if value.hasPrefix(protocolLogin) { + self.createAccount(urlBase: server, user: user, password: password) + } else if value.hasPrefix(protocolLoginOneTime) { + NextcloudKit.shared.getAppPasswordOnetime(url: server, user: user, onetimeToken: password) { token, _, error in + if error == .success, let token { + self.createAccount(urlBase: server, user: user, password: token) + } else { + Task { + await showErrorBanner(controller: self.controller, text: error.errorDescription) } + self.dismiss(animated: true, completion: nil) } } } From 68620add40a142461070944de43fc13d05416b0d Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 10:08:35 +0100 Subject: [PATCH 3/9] Auto-MKCol (#3963) * added new header Signed-off-by: Marino Faggiana * test Signed-off-by: Marino Faggiana --------- Signed-off-by: Marino Faggiana --- iOSClient/NCGlobal.swift | 2 ++ iOSClient/Networking/NCNetworking+Upload.swift | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index 93aa8c217d..b6c5f21d76 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -52,6 +52,8 @@ final class NCGlobal: Sendable { let nextcloudVersion28: Int = 28 let nextcloudVersion30: Int = 30 let nextcloudVersion31: Int = 31 + let nextcloudVersion32: Int = 32 + let nextcloudVersion33: Int = 33 let nextcloudVersionFuture: Int = 99999 diff --git a/iOSClient/Networking/NCNetworking+Upload.swift b/iOSClient/Networking/NCNetworking+Upload.swift index 2c4c89826c..4aae22072f 100644 --- a/iOSClient/Networking/NCNetworking+Upload.swift +++ b/iOSClient/Networking/NCNetworking+Upload.swift @@ -27,8 +27,16 @@ extension NCNetworking { size: Int64, response: AFDataResponse?, error: NKError) { + // let capabilities = await NKCapabilities.shared.getCapabilities(for: account) + // let autoMkcol = capabilities.serverVersionMajor >= NCGlobal.shared.nextcloudVersion33 let options = NKRequestOptions(customHeader: customHeaders, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue) - let results = await NextcloudKit.shared.uploadAsync(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, dateCreationFile: creationDate, dateModificationFile: dateModificationFile, account: account, options: options) { request in + let results = await NextcloudKit.shared.uploadAsync(serverUrlFileName: serverUrlFileName, + fileNameLocalPath: fileNameLocalPath, + dateCreationFile: creationDate, + dateModificationFile: dateModificationFile, + autoMkcol: true, + account: account, + options: options) { request in requestHandler(request) } taskHandler: { task in Task { @@ -175,6 +183,8 @@ extension NCNetworking { taskHandler: @escaping (_ task: URLSessionUploadTask?) -> Void = { _ in }, start: @escaping () -> Void = { }) async -> NKError { + // let capabilities = await NKCapabilities.shared.getCapabilities(for: metadata.account) + // let autoMkcol = capabilities.serverVersionMajor >= NCGlobal.shared.nextcloudVersion33 let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileName: metadata.fileName, userId: metadata.userId, @@ -191,6 +201,7 @@ extension NCNetworking { fileNameLocalPath: fileNameLocalPath, dateCreationFile: metadata.creationDate as Date, dateModificationFile: metadata.date as Date, + autoMkcol: true, account: metadata.account, sessionIdentifier: metadata.session) From 26f2d0c3e0962018e3869921173df6d2c44ef972 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 12:01:56 +0100 Subject: [PATCH 4/9] Message error (#3964) * fix timer Signed-off-by: Marino Faggiana * added errorCode Signed-off-by: Marino Faggiana * shownErrors Signed-off-by: Marino Faggiana * fix Signed-off-by: Marino Faggiana --------- Signed-off-by: Marino Faggiana --- iOSClient/Account/NCAccount.swift | 2 +- iOSClient/Activity/NCActivity.swift | 8 ++-- .../Activity/NCActivityTableViewCell.swift | 2 +- iOSClient/AppDelegate.swift | 4 +- .../UIAlertController+Extension.swift | 4 +- iOSClient/Files/NCFiles.swift | 8 ++-- iOSClient/GUI/Lucid Banner/BannerView.swift | 38 +++++++++++++++---- .../GUI/Lucid Banner/HudBannerView.swift | 4 +- iOSClient/Login/NCLogin.swift | 2 +- iOSClient/Login/NCLoginProvider.swift | 4 +- ...ionViewCommon+CollectionViewDelegate.swift | 4 +- .../NCCollectionViewCommon.swift | 8 ++-- iOSClient/Main/Create/NCCreate.swift | 4 +- iOSClient/Main/NCDragDrop.swift | 6 +-- iOSClient/Main/NCMainTabBarController.swift | 4 +- iOSClient/Main/NCPickerViewController.swift | 6 +-- iOSClient/Menu/NCContextMenu.swift | 31 +++++++-------- iOSClient/Menu/NCViewerContextMenu.swift | 2 +- iOSClient/NCAppStateManager.swift | 8 ++++ .../Networking/NCNetworking+ServerError.swift | 2 +- .../NCNetworking+TransferDelegate.swift | 12 +++--- .../Networking/NCNetworking+Upload.swift | 2 +- .../Networking/NCNetworking+WebDAV.swift | 2 +- iOSClient/Notification/NCNotification.swift | 4 +- .../RichWorkspace/NCRichWorkspaceCommon.swift | 8 ++-- .../RichWorkspace/NCViewerRichWorkspace.swift | 2 +- .../Scan document/NCUploadScanDocument.swift | 2 +- iOSClient/SceneDelegate.swift | 10 ++--- iOSClient/Select/NCSelect.swift | 2 +- .../Advanced/NCSettingsAdvancedModel.swift | 2 +- .../NCTermOfServiceModel.swift | 2 +- iOSClient/Transfers/NCTransfersModel.swift | 2 +- iOSClient/Trash/NCTrash+Networking.swift | 12 +++--- iOSClient/Utility/MigrationMultiDomains.swift | 2 +- iOSClient/Viewer/NCViewer.swift | 4 +- .../NCPlayer/NCPlayerToolBar.swift | 2 +- .../Viewer/NCViewerProviderContextMenu.swift | 4 +- .../NCViewerRichDocument.swift | 9 +++-- 38 files changed, 132 insertions(+), 102 deletions(-) diff --git a/iOSClient/Account/NCAccount.swift b/iOSClient/Account/NCAccount.swift index c392cc099f..dd13742efe 100644 --- a/iOSClient/Account/NCAccount.swift +++ b/iOSClient/Account/NCAccount.swift @@ -194,7 +194,7 @@ class NCAccount: NSObject { return } - await showErrorBanner(controller: controller, text: "_account_unauthorized_") + await showErrorBanner(controller: controller, text: "_account_unauthorized_", errorCode: NCGlobal.shared.errorUnauthorized401) let resultsWipe = await NextcloudKit.shared.getRemoteWipeStatusAsync(serverUrl: tblAccount.urlBase, token: token, account: account) { task in Task { diff --git a/iOSClient/Activity/NCActivity.swift b/iOSClient/Activity/NCActivity.swift index 5cf38ebbe9..6c1f6b70f3 100644 --- a/iOSClient/Activity/NCActivity.swift +++ b/iOSClient/Activity/NCActivity.swift @@ -84,7 +84,7 @@ class NCActivity: UIViewController, NCSharePagingContent { self.loadComments() } else { Task { - await showErrorBanner(controller: self.tabBarController, text: error.errorDescription) + await showErrorBanner(controller: self.tabBarController, text: error.errorDescription, errorCode: error.errorCode) } } } @@ -439,7 +439,7 @@ extension NCActivity { self.database.addComments(comments, account: metadata.account, objectId: metadata.fileId) } else if error.errorCode != NCGlobal.shared.errorResourceNotFound { Task { - await showErrorBanner(controller: self.tabBarController, text: error.errorDescription) + await showErrorBanner(controller: self.tabBarController, text: error.errorDescription, errorCode: error.errorCode) } } @@ -579,7 +579,7 @@ extension NCActivity: NCShareCommentsCellDelegate { self.loadComments() } else { Task {@MainActor in - await showErrorBanner(controller: self.tabBarController, text: error.errorDescription) + await showErrorBanner(controller: self.tabBarController, text: error.errorDescription, errorCode: error.errorCode) } } } @@ -611,7 +611,7 @@ extension NCActivity: NCShareCommentsCellDelegate { self.loadComments() } else { Task { - await showErrorBanner(controller: self.tabBarController, text: error.errorDescription) + await showErrorBanner(controller: self.tabBarController, text: error.errorDescription, errorCode: error.errorCode) } } } diff --git a/iOSClient/Activity/NCActivityTableViewCell.swift b/iOSClient/Activity/NCActivityTableViewCell.swift index d94e80ce13..84e5da2890 100644 --- a/iOSClient/Activity/NCActivityTableViewCell.swift +++ b/iOSClient/Activity/NCActivityTableViewCell.swift @@ -85,7 +85,7 @@ extension NCActivityTableViewCell: UICollectionViewDelegate { (responder as? UIViewController)!.navigationController?.pushViewController(viewController, animated: true) } else { Task { - await showErrorBanner(controller: viewController.controller, text: "_trash_file_not_found_") + await showErrorBanner(controller: viewController.controller, text: "_trash_file_not_found_", errorCode: 0) } } } diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index 226fd9162a..01ab3d99e8 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -378,7 +378,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD return } - try? await Task.sleep(nanoseconds: 1_000_000_000) + try? await Task.sleep(for: .seconds(1)) let tblAccounts = await NCManageDatabase.shared.getAllTableAccountAsync() for tblAccount in tblAccounts { @@ -406,7 +406,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD if app == NCGlobal.shared.termsOfServiceName { Task { await NCNetworking.shared.transferDispatcher.notifyAllDelegatesAsync { delegate in - try? await Task.sleep(nanoseconds: 500_000_000) + try? await Task.sleep(for: .seconds(0.5)) delegate.transferReloadDataSource(serverUrl: nil, requestData: true, status: nil) } } diff --git a/iOSClient/Extensions/UIAlertController+Extension.swift b/iOSClient/Extensions/UIAlertController+Extension.swift index 93799b81cb..e775ce1ee5 100644 --- a/iOSClient/Extensions/UIAlertController+Extension.swift +++ b/iOSClient/Extensions/UIAlertController+Extension.swift @@ -62,10 +62,10 @@ extension UIAlertController { if createFolderResults.error == .success { let error = await NCNetworkingE2EEMarkFolder().markFolderE2ee(account: session.account, serverUrlFileName: serverUrlFileName, userId: session.userId) if error != .success { - await showErrorBanner(scene: scene, text: error.errorDescription) + await showErrorBanner(scene: scene, text: error.errorDescription, errorCode: error.errorCode) } } else { - await showErrorBanner(scene: scene, text: createFolderResults.error.errorDescription) + await showErrorBanner(scene: scene, text: createFolderResults.error.errorDescription, errorCode: createFolderResults.error.errorCode) } } } else if isDirectoryEncrypted { diff --git a/iOSClient/Files/NCFiles.swift b/iOSClient/Files/NCFiles.swift index 334118babe..0abb5a8221 100644 --- a/iOSClient/Files/NCFiles.swift +++ b/iOSClient/Files/NCFiles.swift @@ -321,11 +321,11 @@ class NCFiles: NCCollectionViewCommon { await showInfoBanner(controller: self.controller, text: "Metadata not found") let error = await NCNetworkingE2EE().uploadMetadata(serverUrl: serverUrl, account: account) if error != .success { - await showErrorBanner(controller: self.controller, text: error.errorDescription) + await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) } } else { // show error - await showErrorBanner(controller: self.controller, text: error.errorDescription) + await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) } return(metadatas, error, reloadRequired) @@ -343,14 +343,14 @@ class NCFiles: NCCollectionViewCommon { let error = await NCNetworkingE2EE().uploadMetadata(serverUrl: serverUrl, updateVersionV1V2: true, account: account) if error != .success { - await showErrorBanner(controller: self.controller, text: error.errorDescription) + await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) } NCActivityIndicator.shared.stop() } } else { // Client Diagnostic await self.database.addDiagnosticAsync(account: account, issue: NCGlobal.shared.diagnosticIssueE2eeErrors) - await showErrorBanner(controller: self.controller, text: error.errorDescription) + await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) } return (metadatas, error, reloadRequired) diff --git a/iOSClient/GUI/Lucid Banner/BannerView.swift b/iOSClient/GUI/Lucid Banner/BannerView.swift index 5afbb8fc8c..f2b3010575 100644 --- a/iOSClient/GUI/Lucid Banner/BannerView.swift +++ b/iOSClient/GUI/Lucid Banner/BannerView.swift @@ -159,7 +159,8 @@ func showErrorBannerActiveScenes(title: String = "_error_", footnote: String? = nil, foregroundColor: UIColor = .white, backgroundColor: UIColor = .red, - sleepBefore: Double = 1) async { + sleepBefore: Double = 1, + errorCode: Int) async { for scene in UIApplication.shared.foregroundActiveScenes { await showErrorBanner(scene: scene, title: title, @@ -167,7 +168,8 @@ func showErrorBannerActiveScenes(title: String = "_error_", footnote: footnote, foregroundColor: foregroundColor, backgroundColor: backgroundColor, - sleepBefore: sleepBefore) + sleepBefore: sleepBefore, + errorCode: errorCode) } } @@ -178,14 +180,16 @@ func showErrorBanner(controller: UITabBarController?, footnote: String? = nil, foregroundColor: UIColor = .white, backgroundColor: UIColor = .red, - sleepBefore: Double = 1) async { + sleepBefore: Double = 1, + errorCode: Int) async { let scene = SceneManager.shared.getWindow(controller: controller)?.windowScene await showErrorBanner(scene: scene, text: text, footnote: footnote, foregroundColor: foregroundColor, backgroundColor: backgroundColor, - sleepBefore: sleepBefore) + sleepBefore: sleepBefore, + errorCode: errorCode) } @MainActor @@ -195,14 +199,16 @@ func showErrorBanner(sceneIdentifier: String?, footnote: String? = nil, foregroundColor: UIColor = .white, backgroundColor: UIColor = .red, - sleepBefore: Double = 1) async { + sleepBefore: Double = 1, + errorCode: Int) async { await showErrorBanner(controller: SceneManager.shared.getController(sceneIdentifier: sceneIdentifier), title: title, text: text, footnote: footnote, foregroundColor: foregroundColor, backgroundColor: backgroundColor, - sleepBefore: sleepBefore) + sleepBefore: sleepBefore, + errorCode: errorCode) } #endif @@ -214,12 +220,28 @@ func showErrorBanner(scene: UIWindowScene?, footnote: String? = nil, foregroundColor: UIColor = .white, backgroundColor: UIColor = .red, - sleepBefore: Double = 1) async { - try? await Task.sleep(nanoseconds: UInt64(sleepBefore * 1e9)) + sleepBefore: Double = 1, + errorCode: Int) async { #if !EXTENSION + // Prevent repeated display of the same user-facing error during the current foreground session. + // If this error code has already been shown, do nothing. + // Otherwise, record it and allow the UX notification to be displayed once. + if shownErrors.contains(errorCode) { + return + } else { + // Coalesce user-facing errors across the current foreground session. + // The same error code is shown to the user only once. + // Error 507 (insufficient storage) is recorded to avoid repeated UX notifications + // for subsequent uploads failing for the same reason. + if errorCode == 507 { + shownErrors.insert(errorCode) + } + } let scene = scene ?? UIApplication.shared.mainAppWindow?.windowScene #endif + try? await Task.sleep(for: .seconds(sleepBefore)) + let payload = LucidBannerPayload( title: NSLocalizedString(title, comment: ""), subtitle: NSLocalizedString(text, comment: ""), diff --git a/iOSClient/GUI/Lucid Banner/HudBannerView.swift b/iOSClient/GUI/Lucid Banner/HudBannerView.swift index 6eb8a1338d..66bfda8249 100644 --- a/iOSClient/GUI/Lucid Banner/HudBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/HudBannerView.swift @@ -275,11 +275,11 @@ private struct HudBannerPreviewWrapper: View { HudBannerView(state: state) .task { for i in 0...100 { - try? await Task.sleep(nanoseconds: 45_000_000) + try? await Task.sleep(for: .milliseconds(45)) state.payload.progress = Double(i) / 100 } - try? await Task.sleep(nanoseconds: 400_000_000) + try? await Task.sleep(for: .seconds(0.4)) state.payload.stage = .success } } diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index ca2b1e2b9b..ab3f12df13 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -438,7 +438,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { self.createAccount(urlBase: urlBase, user: user, password: password) } else { Task { - await showErrorBanner(controller: self.controller, text: error.errorDescription) + await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) } self.dismiss(animated: true, completion: nil) } diff --git a/iOSClient/Login/NCLoginProvider.swift b/iOSClient/Login/NCLoginProvider.swift index 3e3442a060..b56bbab49b 100644 --- a/iOSClient/Login/NCLoginProvider.swift +++ b/iOSClient/Login/NCLoginProvider.swift @@ -64,7 +64,7 @@ class NCLoginProvider: UIViewController { guard let url = URL(string: initialURLString) else { Task { - await showErrorBanner(controller: self.controller, text: "_login_url_error_") + await showErrorBanner(controller: self.controller, text: "_login_url_error_", errorCode: 0) } return } @@ -196,7 +196,7 @@ class NCLoginProvider: UIViewController { try Task.checkCancellation() grantValues = await poll(token: token, endpoint: endpoint, options: options) - try await Task.sleep(nanoseconds: 1_000_000_000) // .seconds() is not supported on iOS 15 yet. + try await Task.sleep(for: .seconds(1)) } while grantValues == nil guard let grantValues else { diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift index 8b18f1e11e..47922b4299 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift @@ -65,7 +65,7 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { if results.nkError == .success || results.afError?.isExplicitlyCancelledError ?? false { print("ok") } else { - await showErrorBanner(scene: scene, text: results.nkError.errorDescription) + await showErrorBanner(scene: scene, text: results.nkError.errorDescription, errorCode: results.nkError.errorCode) } } @@ -118,7 +118,7 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { } } else { Task { - await showErrorBanner(controller: controller, text: "_go_online_") + await showErrorBanner(controller: controller, text: "_go_online_", errorCode: NCGlobal.shared.errorOffline) } } } diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 37b71d071c..898dcdc97c 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -208,7 +208,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, self.refreshControl.endRefreshing() // Wait 1.5 seconds before resetting the button alpha - try? await Task.sleep(nanoseconds: 1_500_000_000) + try? await Task.sleep(for: .seconds(1.5)) self.mainNavigationController?.resetPlusButtonAlpha() } } @@ -627,7 +627,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, } } else { Task { - await showErrorBanner(scene: scene, text: resultsUpload.error.errorDescription) + await showErrorBanner(scene: scene, text: resultsUpload.error.errorDescription, errorCode: resultsUpload.error.errorCode) } } } @@ -748,7 +748,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, } completion: { _, searchResult, metadatas, error in if error != .success { Task { - await showErrorBanner(controller: self.controller, text: error.errorDescription) + await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) } } @@ -919,7 +919,7 @@ extension NCCollectionViewCommon: NCTransferDelegate { Task { if error != .success, error.errorCode != global.errorResourceNotFound { - await showErrorBanner(controller: self.controller, text: error.errorDescription) + await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) } guard session.account == account else { return diff --git a/iOSClient/Main/Create/NCCreate.swift b/iOSClient/Main/Create/NCCreate.swift index 1343959068..7763ea073d 100644 --- a/iOSClient/Main/Create/NCCreate.swift +++ b/iOSClient/Main/Create/NCCreate.swift @@ -41,7 +41,7 @@ class NCCreate: NSObject { } guard results.error == .success, let url = results.url else { Task { - await showErrorBanner(controller: controller, text: results.error.errorDescription) + await showErrorBanner(controller: controller, text: results.error.errorDescription, errorCode: results.error.errorCode) } return } @@ -68,7 +68,7 @@ class NCCreate: NSObject { } guard results.error == .success, let url = results.url else { Task { - await showErrorBanner(controller: controller, text: results.error.errorDescription) + await showErrorBanner(controller: controller, text: results.error.errorDescription, errorCode: results.error.errorCode) } return } diff --git a/iOSClient/Main/NCDragDrop.swift b/iOSClient/Main/NCDragDrop.swift index 7aa59e600a..bba4710240 100644 --- a/iOSClient/Main/NCDragDrop.swift +++ b/iOSClient/Main/NCDragDrop.swift @@ -145,7 +145,7 @@ class NCDragDrop: NSObject { database.addMetadata(metadataForUpload) } catch { Task { - await showErrorBanner(controller: controller, text: error.localizedDescription) + await showErrorBanner(controller: controller, text: error.localizedDescription, errorCode: 0) } return } @@ -235,7 +235,7 @@ class NCDragDrop: NSObject { downloadRequest = request } guard results.nkError == .success else { - await showErrorBanner(scene: scene, text: results.nkError.errorDescription) + await showErrorBanner(scene: scene, text: results.nkError.errorDescription, errorCode: results.nkError.errorCode) break } } @@ -257,7 +257,7 @@ class NCDragDrop: NSObject { uploadRequest = request } guard results.error == .success else { - await showErrorBanner(scene: scene, text: results.error.errorDescription) + await showErrorBanner(scene: scene, text: results.error.errorDescription, errorCode: results.error.errorCode) break } diff --git a/iOSClient/Main/NCMainTabBarController.swift b/iOSClient/Main/NCMainTabBarController.swift index 778a257e61..33ada311a2 100644 --- a/iOSClient/Main/NCMainTabBarController.swift +++ b/iOSClient/Main/NCMainTabBarController.swift @@ -132,10 +132,8 @@ class NCMainTabBarController: UITabBarController { @MainActor private func timerCheck() async { - let nanoseconds: UInt64 = 3_000_000_000 - while !Task.isCancelled { - try? await Task.sleep(nanoseconds: nanoseconds) + try? await Task.sleep(for: .seconds(3)) guard isViewLoaded, view.window != nil else { continue diff --git a/iOSClient/Main/NCPickerViewController.swift b/iOSClient/Main/NCPickerViewController.swift index 5dc78ced7b..5a007289f0 100644 --- a/iOSClient/Main/NCPickerViewController.swift +++ b/iOSClient/Main/NCPickerViewController.swift @@ -60,19 +60,19 @@ class NCPhotosPickerViewController: NSObject { pickerVC?.didExceedMaximumNumberOfSelection = { _ in Task { - await showErrorBanner(controller: self.controller, text: "_limited_dimension_") + await showErrorBanner(controller: self.controller, text: "_limited_dimension_", errorCode: 0) } } pickerVC?.handleNoAlbumPermissions = { _ in Task { - await showErrorBanner(controller: self.controller, text: "_denied_album_") + await showErrorBanner(controller: self.controller, text: "_denied_album_", errorCode: 0) } } pickerVC?.handleNoCameraPermissions = { _ in Task { - await showErrorBanner(controller: self.controller, text: "_denied_camera_") + await showErrorBanner(controller: self.controller, text: "_denied_camera_", errorCode: 0) } } diff --git a/iOSClient/Menu/NCContextMenu.swift b/iOSClient/Menu/NCContextMenu.swift index fe2e5e303c..e08a949b36 100644 --- a/iOSClient/Menu/NCContextMenu.swift +++ b/iOSClient/Menu/NCContextMenu.swift @@ -105,7 +105,7 @@ class NCContextMenu: NSObject { NCNetworking.shared.setStatusWaitFavorite(metadata) { error in if error != .success { Task { - await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription) + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription, errorCode: error.errorCode) } } } @@ -232,7 +232,7 @@ class NCContextMenu: NSObject { userId: metadata.userId ) if error != .success { - await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription) + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription, errorCode: error.errorCode) } } } @@ -272,7 +272,8 @@ class NCContextMenu: NSObject { } else { await showErrorBanner(sceneIdentifier: self.sceneIdentifier, title: "_e2e_error_", - text: results.error.errorDescription) + text: results.error.errorDescription, + errorCode: results.error.errorCode) } } } @@ -336,7 +337,7 @@ class NCContextMenu: NSObject { fileNameNew ) ) != nil { - await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: "_rename_already_exists_") + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: "_rename_already_exists_", errorCode: 0) return } @@ -531,23 +532,23 @@ class NCContextMenu: NSObject { image: iconImage ) { _ in Task { - let response = await NextcloudKit.shared.sendRequestAsync(account: metadata.account, - fileId: metadata.fileId, - filePath: self.utilityFileSystem.getRelativeFilePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId), - url: item.url, - method: item.method, - params: item.params) - - if response.error != .success { - await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: response.error.errorDescription) + let results = await NextcloudKit.shared.sendRequestAsync(account: metadata.account, + fileId: metadata.fileId, + filePath: self.utilityFileSystem.getRelativeFilePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId), + url: item.url, + method: item.method, + params: item.params) + + if results.error != .success { + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: results.error.errorDescription, errorCode: results.error.errorCode) } else { - if let tooltip = response.uiResponse?.ocs.data.tooltip { + if let tooltip = results.uiResponse?.ocs.data.tooltip { NCContentPresenter().showCustomMessage(message: tooltip, type: .success) } else { let baseURL = metadata.urlBase await MainActor.run { - guard let ui = response.uiResponse?.ocs.data.root, let firstRow = ui.rows.first, let child = firstRow.children.first else { return } + guard let ui = results.uiResponse?.ocs.data.root, let firstRow = ui.rows.first, let child = firstRow.children.first else { return } let viewer = ClientIntegrationUIViewer( rows: [.init(element: child.element, title: child.text, urlString: child.url)], diff --git a/iOSClient/Menu/NCViewerContextMenu.swift b/iOSClient/Menu/NCViewerContextMenu.swift index 1b5e13138c..feac02e2e0 100644 --- a/iOSClient/Menu/NCViewerContextMenu.swift +++ b/iOSClient/Menu/NCViewerContextMenu.swift @@ -67,7 +67,7 @@ enum NCViewerContextMenu { NCNetworking.shared.setStatusWaitFavorite(metadata) { error in if error != .success { Task { - await showErrorBanner(controller: controller, text: error.errorDescription) + await showErrorBanner(controller: controller, text: error.errorDescription, errorCode: error.errorCode) } } } diff --git a/iOSClient/NCAppStateManager.swift b/iOSClient/NCAppStateManager.swift index 533e71b2ba..d5221cfa84 100644 --- a/iOSClient/NCAppStateManager.swift +++ b/iOSClient/NCAppStateManager.swift @@ -14,6 +14,9 @@ var isAppInBackground: Bool = true // Global flag indicating whether the app is in maintenanceMode. var maintenanceMode: Bool = false +// Global error code +var shownErrors: Set = [] + /// Singleton responsible for monitoring and managing app state transitions. /// /// This class observes system notifications related to app lifecycle events and updates global flags accordingly: @@ -50,6 +53,11 @@ final class NCAppStateManager { appDelegate?.pushSubscriptionTask?.cancel() appDelegate?.pushSubscriptionTask = nil + // + // Clear the errors + // + shownErrors.removeAll() + nkLog(debug: "Application did enter in background") } } diff --git a/iOSClient/Networking/NCNetworking+ServerError.swift b/iOSClient/Networking/NCNetworking+ServerError.swift index 2047922a95..432cfabd4c 100644 --- a/iOSClient/Networking/NCNetworking+ServerError.swift +++ b/iOSClient/Networking/NCNetworking+ServerError.swift @@ -83,7 +83,7 @@ extension NCNetworking { } else if unauthorizedArray.contains(account) { nkLog(error: "Unauthorized for \(account)") - try? await Task.sleep(nanoseconds: 500_000_000) + try? await Task.sleep(for: .seconds(0.5)) await NCAccount().checkRemoteUser(account: account, controller: controller) /// ToS } else if tosArray.contains(account) { diff --git a/iOSClient/Networking/NCNetworking+TransferDelegate.swift b/iOSClient/Networking/NCNetworking+TransferDelegate.swift index eb527d9522..16e7b07e30 100644 --- a/iOSClient/Networking/NCNetworking+TransferDelegate.swift +++ b/iOSClient/Networking/NCNetworking+TransferDelegate.swift @@ -121,7 +121,7 @@ extension NCNetworking: NCTransferDelegate { NCAskAuthorization().askAuthorizationPhotoLibrary(controller: controller) { hasPermission in guard hasPermission else { Task {@MainActor in - await showErrorBanner(scene: scene, text: "_access_photo_not_enabled_msg_") + await showErrorBanner(scene: scene, text: "_access_photo_not_enabled_msg_", errorCode: 0) } return } @@ -135,7 +135,7 @@ extension NCNetworking: NCTransferDelegate { }) { success, _ in if !success { Task { - await showErrorBanner(scene: scene, text: "_file_not_saved_cameraroll_") + await showErrorBanner(scene: scene, text: "_file_not_saved_cameraroll_", errorCode: 0) } } } @@ -145,19 +145,19 @@ extension NCNetworking: NCTransferDelegate { }) { success, _ in if !success { Task { - await showErrorBanner(scene: scene, text: "_file_not_saved_cameraroll_") + await showErrorBanner(scene: scene, text: "_file_not_saved_cameraroll_", errorCode: 0) } } } } else { Task { - await showErrorBanner(scene: scene, text: "_file_not_saved_cameraroll_") + await showErrorBanner(scene: scene, text: "_file_not_saved_cameraroll_", errorCode: 0) } return } } catch { Task { - await showErrorBanner(scene: scene, text: "_file_not_saved_cameraroll_") + await showErrorBanner(scene: scene, text: "_file_not_saved_cameraroll_", errorCode: 0) } } } @@ -227,7 +227,7 @@ extension NCNetworking: NCTransferDelegate { } guard resultsFile.error == .success, let file = resultsFile.file else { Task { - await showErrorBanner(controller: viewController.tabBarController, text: resultsFile.error.errorDescription) + await showErrorBanner(controller: viewController.tabBarController, text: resultsFile.error.errorDescription, errorCode: resultsFile.error.errorCode) } return } diff --git a/iOSClient/Networking/NCNetworking+Upload.swift b/iOSClient/Networking/NCNetworking+Upload.swift index 4aae22072f..05c295cba1 100644 --- a/iOSClient/Networking/NCNetworking+Upload.swift +++ b/iOSClient/Networking/NCNetworking+Upload.swift @@ -296,7 +296,7 @@ extension NCNetworking { } else if (error.errorCode == self.global.errorBadRequest || error.errorCode == self.global.errorUnsupportedMediaType) && error.errorDescription.localizedCaseInsensitiveContains("virus") { await uploadCancelFile(metadata: metadata) #if !EXTENSION - await showErrorBanner(sceneIdentifier: metadata.sceneIdentifier, text: "_virus_detect_") + await showErrorBanner(sceneIdentifier: metadata.sceneIdentifier, text: "_virus_detect_", errorCode: self.global.errorBadRequest) #endif // Client Diagnostic await NCManageDatabase.shared.addDiagnosticAsync(account: metadata.account, issue: self.global.diagnosticIssueVirusDetected) diff --git a/iOSClient/Networking/NCNetworking+WebDAV.swift b/iOSClient/Networking/NCNetworking+WebDAV.swift index 77a3a4e88a..89c6d80463 100644 --- a/iOSClient/Networking/NCNetworking+WebDAV.swift +++ b/iOSClient/Networking/NCNetworking+WebDAV.swift @@ -533,7 +533,7 @@ extension NCNetworking { Task { let error = await NCNetworkingE2EERename().rename(metadata: metadata, fileNameNew: fileNameNew) if error != .success { - await showErrorBanner(sceneIdentifier: metadata.sceneIdentifier, text: error.errorDescription) + await showErrorBanner(sceneIdentifier: metadata.sceneIdentifier, text: error.errorDescription, errorCode: error.errorCode) } } #endif diff --git a/iOSClient/Notification/NCNotification.swift b/iOSClient/Notification/NCNotification.swift index d1c5825db0..ef99c7bf9d 100644 --- a/iOSClient/Notification/NCNotification.swift +++ b/iOSClient/Notification/NCNotification.swift @@ -254,7 +254,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { self.tableView.reloadData() } else if error != .success { Task { - await showErrorBanner(controller: self.controller, text: error.errorDescription) + await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) } } else { print("[Error] The user has been changed during networking process.") @@ -301,7 +301,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { } } else if error != .success { Task { - await showErrorBanner(controller: self.controller, text: error.errorDescription) + await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) } } else { print("[Error] The user has been changed during networking process.") diff --git a/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift b/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift index 51e965a84e..b19068078f 100644 --- a/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift +++ b/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift @@ -11,7 +11,7 @@ class NCRichWorkspaceCommon: NSObject { func createViewerNextcloudText(serverUrl: String, viewController: UIViewController, controller: NCMainTabBarController?, session: NCSession.Session) { if !NextcloudKit.shared.isNetworkReachable() { Task { - await showErrorBanner(controller: controller, text: "_go_online_") + await showErrorBanner(controller: controller, text: "_go_online_", errorCode: NCGlobal.shared.errorOffline) } return } @@ -41,7 +41,7 @@ class NCRichWorkspaceCommon: NSObject { } } else if error != .success { Task { - await showErrorBanner(controller: controller, text: error.errorDescription) + await showErrorBanner(controller: controller, text: error.errorDescription, errorCode: error.errorCode) } } } @@ -50,7 +50,7 @@ class NCRichWorkspaceCommon: NSObject { func openViewerNextcloudText(serverUrl: String, viewController: UIViewController, controller: NCMainTabBarController?, session: NCSession.Session) { if !NextcloudKit.shared.isNetworkReachable() { Task { - await showErrorBanner(controller: controller, text: "_go_online_") + await showErrorBanner(controller: controller, text: "_go_online_", errorCode: NCGlobal.shared.errorOffline) } return } @@ -82,7 +82,7 @@ class NCRichWorkspaceCommon: NSObject { } } else if error != .success { Task { - await showErrorBanner(controller: controller, text: error.errorDescription) + await showErrorBanner(controller: controller, text: error.errorDescription, errorCode: error.errorCode) } } } diff --git a/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift b/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift index 31d2962dae..abc9f93123 100644 --- a/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift +++ b/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift @@ -47,7 +47,7 @@ import MarkdownKit super.viewDidAppear(animated) Task { - try? await Task.sleep(nanoseconds: 1_500_000_000) + try? await Task.sleep(for: .seconds(1.5)) let resultsReadFile = await NCNetworking.shared.readFileAsync(serverUrlFileName: self.serverUrl, account: session.account) guard resultsReadFile.error == .success, let metadata = resultsReadFile.metadata else { diff --git a/iOSClient/Scan document/NCUploadScanDocument.swift b/iOSClient/Scan document/NCUploadScanDocument.swift index a2a975aebb..143f25fb83 100644 --- a/iOSClient/Scan document/NCUploadScanDocument.swift +++ b/iOSClient/Scan document/NCUploadScanDocument.swift @@ -92,7 +92,7 @@ class NCUploadScanDocument: ObservableObject { for char in self.password.unicodeScalars { if !char.isASCII { Task { - await showErrorBanner(controller: self.controller, text: "_password_ascii_") + await showErrorBanner(controller: self.controller, text: "_password_ascii_", errorCode: 0) } return DispatchQueue.main.async { completion(true) diff --git a/iOSClient/SceneDelegate.swift b/iOSClient/SceneDelegate.swift index 04cbd0ab8d..e7528215ef 100644 --- a/iOSClient/SceneDelegate.swift +++ b/iOSClient/SceneDelegate.swift @@ -278,7 +278,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { return true } group.addTask { - try? await Task.sleep(nanoseconds: 25 * 1_000_000_000) // ~25s + try? await Task.sleep(for: .seconds(25)) return false } return await group.next() ?? false @@ -312,7 +312,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { if url.contains(urlBase?.host ?? "") && userId == tblAccount.userId { await NCAccount().changeAccount(tblAccount.account, userProfile: nil, controller: controller) // wait switch account - try? await Task.sleep(nanoseconds: 1_000_000_000) + try? await Task.sleep(for: .seconds(1)) return tblAccount } } @@ -487,15 +487,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } Task { - try? await Task.sleep(nanoseconds: 1_000_000_000) + try? await Task.sleep(for: .seconds(1)) let num = await NCAutoUpload.shared.initAutoUpload() nkLog(start: "Auto upload with \(num) photo") - try? await Task.sleep(nanoseconds: 1_500_000_000) + try? await Task.sleep(for: .seconds(1.5)) await NCService().startRequestServicesServer(account: account, controller: controller) - try? await Task.sleep(nanoseconds: 2_000_000_000) + try? await Task.sleep(for: .seconds(2)) await NCNetworking.shared.verifyZombie() } diff --git a/iOSClient/Select/NCSelect.swift b/iOSClient/Select/NCSelect.swift index ca3ac46a48..ff9bfbb213 100644 --- a/iOSClient/Select/NCSelect.swift +++ b/iOSClient/Select/NCSelect.swift @@ -221,7 +221,7 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent error: NKError) { if error != .success { Task { - await showErrorBanner(sceneIdentifier: sceneIdentifier, text: error.errorDescription) + await showErrorBanner(sceneIdentifier: sceneIdentifier, text: error.errorDescription, errorCode: error.errorCode) } } diff --git a/iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift b/iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift index e1efc50d8e..4d79b432c3 100644 --- a/iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift +++ b/iOSClient/Settings/Advanced/NCSettingsAdvancedModel.swift @@ -114,7 +114,7 @@ class NCSettingsAdvancedModel: ObservableObject, ViewOnAppearHandling { // Cancel all networking tasks NCNetworking.shared.cancelAllTask() - try? await Task.sleep(nanoseconds: 1_000_000_000) + try? await Task.sleep(for: .seconds(1)) NCNetworking.shared.removeServerErrorAccount(self.session.account) NCManageDatabase.shared.clearDBCache() diff --git a/iOSClient/Terms of service/NCTermOfServiceModel.swift b/iOSClient/Terms of service/NCTermOfServiceModel.swift index daf54df761..334b152b69 100644 --- a/iOSClient/Terms of service/NCTermOfServiceModel.swift +++ b/iOSClient/Terms of service/NCTermOfServiceModel.swift @@ -58,7 +58,7 @@ class NCTermOfServiceModel: ObservableObject { delegate.transferReloadDataSource(serverUrl: nil, requestData: true, status: nil) } } else { - await showErrorBanner(controller: controller, text: error.errorDescription) + await showErrorBanner(controller: controller, text: error.errorDescription, errorCode: error.errorCode) } } self.dismissView = true diff --git a/iOSClient/Transfers/NCTransfersModel.swift b/iOSClient/Transfers/NCTransfersModel.swift index 2e1556a59d..ffc8d68f47 100644 --- a/iOSClient/Transfers/NCTransfersModel.swift +++ b/iOSClient/Transfers/NCTransfersModel.swift @@ -71,7 +71,7 @@ final class TransfersViewModel: ObservableObject, NCMetadataTransfersSuccessDele isLoading = false } - try? await Task.sleep(nanoseconds: 500_000_000) + try? await Task.sleep(for: .seconds(0.5)) } } diff --git a/iOSClient/Trash/NCTrash+Networking.swift b/iOSClient/Trash/NCTrash+Networking.swift index 4b812e9a4a..56d0987cf6 100644 --- a/iOSClient/Trash/NCTrash+Networking.swift +++ b/iOSClient/Trash/NCTrash+Networking.swift @@ -76,7 +76,7 @@ extension NCTrash { func emptyTrash() async { let serverUrlFileName = session.urlBase + "/remote.php/dav/trashbin/" + session.userId + "/trash" - let response = await NextcloudKit.shared.deleteFileOrFolderAsync(serverUrlFileName: serverUrlFileName, account: session.account) { task in + let results = await NextcloudKit.shared.deleteFileOrFolderAsync(serverUrlFileName: serverUrlFileName, account: session.account) { task in Task { let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.session.account, path: serverUrlFileName, @@ -85,8 +85,8 @@ extension NCTrash { } } - if response.error != .success { - await showErrorBanner(controller: self.controller, text: response.error.errorDescription) + if results.error != .success { + await showErrorBanner(controller: self.controller, text: results.error.errorDescription, errorCode: results.error.errorCode) } await self.database.deleteTrashAsync(fileId: nil, account: session.account) await self.reloadDataSource() @@ -98,7 +98,7 @@ extension NCTrash { continue } let serverUrlFileName = result.filePath + result.fileName - let response = await NextcloudKit.shared.deleteFileOrFolderAsync(serverUrlFileName: serverUrlFileName, account: session.account) { task in + let results = await NextcloudKit.shared.deleteFileOrFolderAsync(serverUrlFileName: serverUrlFileName, account: session.account) { task in Task { let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.session.account, path: serverUrlFileName, @@ -106,8 +106,8 @@ extension NCTrash { await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task) } } - if response.error != .success { - await showErrorBanner(controller: self.controller, text: response.error.errorDescription) + if results.error != .success { + await showErrorBanner(controller: self.controller, text: results.error.errorDescription, errorCode: results.error.errorCode) } await self.database.deleteTrashAsync(fileId: fileId, account: session.account) await self.reloadDataSource() diff --git a/iOSClient/Utility/MigrationMultiDomains.swift b/iOSClient/Utility/MigrationMultiDomains.swift index 666e425c83..d09d2b4d1b 100644 --- a/iOSClient/Utility/MigrationMultiDomains.swift +++ b/iOSClient/Utility/MigrationMultiDomains.swift @@ -64,7 +64,7 @@ struct MigrationMultiDomains: View { await performMigrationLogic(ocIds: ocIds) progressText = NSLocalizedString("_finishing_up_", comment: "") - try await Task.sleep(nanoseconds: 500_000_000) + try await Task.sleep(for: .seconds(0.5)) } catch { print("Migration failed: \(error.localizedDescription)") } diff --git a/iOSClient/Viewer/NCViewer.swift b/iOSClient/Viewer/NCViewer.swift index 22421890f9..5729b80ae5 100644 --- a/iOSClient/Viewer/NCViewer.swift +++ b/iOSClient/Viewer/NCViewer.swift @@ -84,7 +84,7 @@ class NCViewer: NSObject { NCActivityIndicator.shared.stop() guard results.error == .success, let url = results.url else { - await showErrorBanner(controller: delegate?.tabBarController as? NCMainTabBarController, text: results.error.errorDescription) + await showErrorBanner(controller: delegate?.tabBarController as? NCMainTabBarController, text: results.error.errorDescription, errorCode: results.error.errorCode) return nil } @@ -138,7 +138,7 @@ class NCViewer: NSObject { NCActivityIndicator.shared.stop() guard results.error == .success, let url = results.url else { - await showErrorBanner(controller: delegate?.tabBarController as? NCMainTabBarController, text: results.error.errorDescription) + await showErrorBanner(controller: delegate?.tabBarController as? NCMainTabBarController, text: results.error.errorDescription, errorCode: results.error.errorCode) return nil } diff --git a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift index 52febd51ac..c9f6e831e4 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift @@ -496,7 +496,7 @@ extension NCPlayerToolBar: NCSelectDelegate { if error == .success { self.addPlaybackSlave(type: type, metadata: metadata) } else if error.errorCode != 200 { - await showErrorBanner(scene: scene, text: error.errorDescription) + await showErrorBanner(scene: scene, text: error.errorDescription, errorCode: error.errorCode) } } } diff --git a/iOSClient/Viewer/NCViewerProviderContextMenu.swift b/iOSClient/Viewer/NCViewerProviderContextMenu.swift index 15393d3006..638da59a3c 100644 --- a/iOSClient/Viewer/NCViewerProviderContextMenu.swift +++ b/iOSClient/Viewer/NCViewerProviderContextMenu.swift @@ -228,7 +228,7 @@ extension NCViewerProviderContextMenu: VLCMediaPlayerDelegate { case .error: NCActivityIndicator.shared.stop() Task { - await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: "_error_something_wrong_") + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: "_error_something_wrong_", errorCode: 0) } print("Played mode: ERROR") case .playing: @@ -286,7 +286,7 @@ extension NCViewerProviderContextMenu: NCTransferDelegate { error: NKError) { if error != .success { Task { - await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription) + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription, errorCode: error.errorCode) } } diff --git a/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift b/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift index cb3d143ddc..4f8f400791 100644 --- a/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift +++ b/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift @@ -252,7 +252,7 @@ class NCViewerRichDocument: UIViewController, WKNavigationDelegate, WKScriptMess } } else { Task { - await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription) + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription, errorCode: error.errorCode) } } }) @@ -314,8 +314,9 @@ class NCViewerRichDocument: UIViewController, WKNavigationDelegate, WKScriptMess self.webView.evaluateJavaScript(functionJS, completionHandler: { _, _ in }) } else { Task { - await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription) - } } + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription, errorCode: error.errorCode) + } + } } } } @@ -336,7 +337,7 @@ class NCViewerRichDocument: UIViewController, WKNavigationDelegate, WKScriptMess self.webView.evaluateJavaScript(functionJS, completionHandler: { _, _ in }) } else { Task { - await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription) + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription, errorCode: error.errorCode) } } } From 7f38c8d6ed29c29b94b0fe866f5d1208fe5f010b Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 12:04:50 +0100 Subject: [PATCH 5/9] fix error message Signed-off-by: Marino Faggiana --- iOSClient/Login/NCLogin.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index ab3f12df13..c234ca3e63 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -424,7 +424,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { self.createAccount(urlBase: server, user: user, password: token) } else { Task { - await showErrorBanner(controller: self.controller, text: error.errorDescription) + await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) } self.dismiss(animated: true, completion: nil) } From acc8bc849835393fc7252879991d0923db03652a Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 12:05:31 +0100 Subject: [PATCH 6/9] cleaning Signed-off-by: Marino Faggiana --- iOSClient/Login/NCLogin.swift | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index c234ca3e63..76599ac485 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -379,21 +379,6 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { return } - func getParameters(parameters: String) -> (server: String?, user: String?, password: String?) { - guard parameters.contains("user:"), - parameters.contains("password:"), - parameters.contains("server:") else { - return(nil, nil, nil) - } - let parametersArray = parameters.components(separatedBy: "&") - - let user = parametersArray[0].replacingOccurrences(of: "user:", with: "") - let password = parametersArray[1].replacingOccurrences(of: "password:", with: "") - let server = parametersArray[2].replacingOccurrences(of: "server:", with: "") - - return(server, user, password) - } - let protocolLogin = NCBrandOptions.shared.webLoginAutenticationProtocol + "login/" let protocolLoginOneTime = NCBrandOptions.shared.webLoginAutenticationProtocol + "onetime-login/" var parameters: String = "" From 7edd28681e117a7414b3f2e88c8b29b7f4d21fe6 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 12:08:12 +0100 Subject: [PATCH 7/9] clean Signed-off-by: Marino Faggiana --- iOSClient/Login/NCLogin.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index 76599ac485..2b76941b60 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -383,10 +383,10 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { let protocolLoginOneTime = NCBrandOptions.shared.webLoginAutenticationProtocol + "onetime-login/" var parameters: String = "" - if value.hasPrefix(protocolLogin) { - parameters = value.replacingOccurrences(of: protocolLogin, with: "") - } else if value.hasPrefix(protocolLoginOneTime) { + if value.hasPrefix(protocolLoginOneTime) { parameters = value.replacingOccurrences(of: protocolLoginOneTime, with: "") + } else if value.hasPrefix(protocolLogin) { + parameters = value.replacingOccurrences(of: protocolLogin, with: "") } else { return } @@ -401,9 +401,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { let password = parametersArray[1].replacingOccurrences(of: "password:", with: "") let server = parametersArray[2].replacingOccurrences(of: "server:", with: "") - if value.hasPrefix(protocolLogin) { - self.createAccount(urlBase: server, user: user, password: password) - } else if value.hasPrefix(protocolLoginOneTime) { + if value.hasPrefix(protocolLoginOneTime) { NextcloudKit.shared.getAppPasswordOnetime(url: server, user: user, onetimeToken: password) { token, _, error in if error == .success, let token { self.createAccount(urlBase: server, user: user, password: token) @@ -414,6 +412,8 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { self.dismiss(animated: true, completion: nil) } } + } else if value.hasPrefix(protocolLogin) { + self.createAccount(urlBase: server, user: user, password: password) } } From bda014e267d4017a99fe2806a058160d0b157ba1 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 12:52:18 +0100 Subject: [PATCH 8/9] move in async Signed-off-by: Marino Faggiana --- iOSClient/Login/NCLogin.swift | 110 ++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index 2b76941b60..e475a33ad7 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -43,6 +43,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { private var p12Data: Data? private var p12Password: String? + private var QRCodeCheck: Bool = false // MARK: - View Life Cycle @@ -221,12 +222,16 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { // AppConfig if let url = configServerUrl { - if let user = self.configUsername, let password = configAppPassword { - return createAccount(urlBase: url, user: user, password: password) - } else if let user = self.configUsername, let password = configPassword { - return getAppPassword(urlBase: url, user: user, password: password) - } else { - urlBase = url + Task { + if let user = self.configUsername, let password = configAppPassword { + await createAccount(urlBase: url, user: user, password: password) + return + } else if let user = self.configUsername, let password = configPassword { + await getAppPassword(urlBase: url, user: user, password: password) + return + } else { + urlBase = url + } } } } @@ -375,62 +380,62 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { // MARK: - QRCode func dismissQRCode(_ value: String?, metadataType: String?) { - guard let value else { - return - } - - let protocolLogin = NCBrandOptions.shared.webLoginAutenticationProtocol + "login/" - let protocolLoginOneTime = NCBrandOptions.shared.webLoginAutenticationProtocol + "onetime-login/" - var parameters: String = "" - - if value.hasPrefix(protocolLoginOneTime) { - parameters = value.replacingOccurrences(of: protocolLoginOneTime, with: "") - } else if value.hasPrefix(protocolLogin) { - parameters = value.replacingOccurrences(of: protocolLogin, with: "") - } else { + guard let value, !QRCodeCheck else { return } + QRCodeCheck = true + Task { @MainActor in + let protocolLogin = NCBrandOptions.shared.webLoginAutenticationProtocol + "login/" + let protocolLoginOneTime = NCBrandOptions.shared.webLoginAutenticationProtocol + "onetime-login/" + var parameters: String = "" + + if value.hasPrefix(protocolLoginOneTime) { + parameters = value.replacingOccurrences(of: protocolLoginOneTime, with: "") + } else if value.hasPrefix(protocolLogin) { + parameters = value.replacingOccurrences(of: protocolLogin, with: "") + } else { + QRCodeCheck = false + return + } - guard parameters.contains("user:"), - parameters.contains("password:"), - parameters.contains("server:") else { - return - } - let parametersArray = parameters.components(separatedBy: "&") - let user = parametersArray[0].replacingOccurrences(of: "user:", with: "") - let password = parametersArray[1].replacingOccurrences(of: "password:", with: "") - let server = parametersArray[2].replacingOccurrences(of: "server:", with: "") - - if value.hasPrefix(protocolLoginOneTime) { - NextcloudKit.shared.getAppPasswordOnetime(url: server, user: user, onetimeToken: password) { token, _, error in - if error == .success, let token { - self.createAccount(urlBase: server, user: user, password: token) + guard parameters.contains("user:"), + parameters.contains("password:"), + parameters.contains("server:") else { + QRCodeCheck = false + return + } + let parametersArray = parameters.components(separatedBy: "&") + let user = parametersArray[0].replacingOccurrences(of: "user:", with: "") + let password = parametersArray[1].replacingOccurrences(of: "password:", with: "") + let server = parametersArray[2].replacingOccurrences(of: "server:", with: "") + + if value.hasPrefix(protocolLoginOneTime) { + let results = await NextcloudKit.shared.getAppPasswordOnetimeAsync(url: server, user: user, onetimeToken: password) + if results.error == .success, let token = results.token { + await createAccount(urlBase: server, user: user, password: token) } else { - Task { - await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) - } - self.dismiss(animated: true, completion: nil) + await showErrorBanner(controller: self.controller, text: results.error.errorDescription, errorCode: results.error.errorCode) + dismiss(animated: true, completion: nil) } + } else if value.hasPrefix(protocolLogin) { + await self.createAccount(urlBase: server, user: user, password: password) } - } else if value.hasPrefix(protocolLogin) { - self.createAccount(urlBase: server, user: user, password: password) } } - private func getAppPassword(urlBase: String, user: String, password: String) { - NextcloudKit.shared.getAppPassword(url: urlBase, user: user, password: password) { token, _, error in - if error == .success, let password = token { - self.createAccount(urlBase: urlBase, user: user, password: password) - } else { - Task { - await showErrorBanner(controller: self.controller, text: error.errorDescription, errorCode: error.errorCode) - } - self.dismiss(animated: true, completion: nil) - } + private func getAppPassword(urlBase: String, user: String, password: String) async { + let results = await NextcloudKit.shared.getAppPasswordAsync(url: urlBase, user: user, password: password) + + if results.error == .success, let password = results.token { + await self.createAccount(urlBase: urlBase, user: user, password: password) + } else { + await showErrorBanner(controller: self.controller, text: results.error.errorDescription, errorCode: results.error.errorCode) + dismiss(animated: true, completion: nil) } } - private func createAccount(urlBase: String, user: String, password: String) { + @MainActor + private func createAccount(urlBase: String, user: String, password: String) async { if self.controller == nil { self.controller = UIApplication.shared.mainAppWindow?.rootViewController as? NCMainTabBarController } @@ -439,9 +444,8 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { NCNetworking.shared.writeCertificate(host: host) } - Task { - await NCAccount().createAccount(viewController: self, urlBase: urlBase, user: user, password: password, controller: self.controller) - } + await NCAccount().createAccount(viewController: self, urlBase: urlBase, user: user, password: password, controller: self.controller) + QRCodeCheck = false } } From e58eaa539d6fd5f9ed05c6992fdc608925c378c3 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 12:54:37 +0100 Subject: [PATCH 9/9] clean Signed-off-by: Marino Faggiana --- iOSClient/Login/NCLogin.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index e475a33ad7..6740efb7c4 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -384,6 +384,7 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { return } QRCodeCheck = true + Task { @MainActor in let protocolLogin = NCBrandOptions.shared.webLoginAutenticationProtocol + "login/" let protocolLoginOneTime = NCBrandOptions.shared.webLoginAutenticationProtocol + "onetime-login/" @@ -445,7 +446,6 @@ class NCLogin: UIViewController, UITextFieldDelegate, NCLoginQRCodeDelegate { } await NCAccount().createAccount(viewController: self, urlBase: urlBase, user: user, password: password, controller: self.controller) - QRCodeCheck = false } }