From 88501571696075a306d83fea0033a27c7beea3a0 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 10:27:03 +0100 Subject: [PATCH 1/4] fix timer Signed-off-by: Marino Faggiana --- iOSClient/AppDelegate.swift | 4 ++-- iOSClient/GUI/Lucid Banner/HudBannerView.swift | 4 ++-- iOSClient/Login/NCLoginProvider.swift | 2 +- .../Collection Common/NCCollectionViewCommon.swift | 2 +- iOSClient/Main/NCMainTabBarController.swift | 4 +--- iOSClient/Networking/NCNetworking+ServerError.swift | 2 +- iOSClient/RichWorkspace/NCViewerRichWorkspace.swift | 2 +- iOSClient/SceneDelegate.swift | 10 +++++----- .../Settings/Advanced/NCSettingsAdvancedModel.swift | 2 +- iOSClient/Transfers/NCTransfersModel.swift | 2 +- iOSClient/Utility/MigrationMultiDomains.swift | 2 +- 11 files changed, 17 insertions(+), 19 deletions(-) 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/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/NCLoginProvider.swift b/iOSClient/Login/NCLoginProvider.swift index 3e3442a060..05a826b988 100644 --- a/iOSClient/Login/NCLoginProvider.swift +++ b/iOSClient/Login/NCLoginProvider.swift @@ -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.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 37b71d071c..2c9cc723ef 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() } } 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/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/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/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/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/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/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)") } From 28061d68a77dfe7417a1791a006e9407711c6dc5 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 11:32:45 +0100 Subject: [PATCH 2/4] added errorCode Signed-off-by: Marino Faggiana --- iOSClient/Account/NCAccount.swift | 2 +- iOSClient/Activity/NCActivity.swift | 8 ++--- .../Activity/NCActivityTableViewCell.swift | 2 +- .../UIAlertController+Extension.swift | 4 +-- iOSClient/Files/NCFiles.swift | 8 ++--- iOSClient/GUI/Lucid Banner/BannerView.swift | 21 ++++++++----- iOSClient/Login/NCLogin.swift | 2 +- iOSClient/Login/NCLoginProvider.swift | 2 +- ...ionViewCommon+CollectionViewDelegate.swift | 4 +-- .../NCCollectionViewCommon.swift | 6 ++-- iOSClient/Main/Create/NCCreate.swift | 4 +-- iOSClient/Main/NCDragDrop.swift | 6 ++-- iOSClient/Main/NCPickerViewController.swift | 6 ++-- iOSClient/Menu/NCContextMenu.swift | 31 ++++++++++--------- iOSClient/Menu/NCViewerContextMenu.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 ++--- .../Scan document/NCUploadScanDocument.swift | 2 +- iOSClient/Select/NCSelect.swift | 2 +- .../NCTermOfServiceModel.swift | 2 +- iOSClient/Trash/NCTrash+Networking.swift | 12 +++---- iOSClient/Viewer/NCViewer.swift | 4 +-- .../NCPlayer/NCPlayerToolBar.swift | 2 +- .../Viewer/NCViewerProviderContextMenu.swift | 4 +-- .../NCViewerRichDocument.swift | 9 +++--- 28 files changed, 91 insertions(+), 82 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/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..b1f4948796 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,7 +220,8 @@ func showErrorBanner(scene: UIWindowScene?, footnote: String? = nil, foregroundColor: UIColor = .white, backgroundColor: UIColor = .red, - sleepBefore: Double = 1) async { + sleepBefore: Double = 1, + errorCode: Int) async { try? await Task.sleep(nanoseconds: UInt64(sleepBefore * 1e9)) #if !EXTENSION let scene = scene ?? UIApplication.shared.mainAppWindow?.windowScene diff --git a/iOSClient/Login/NCLogin.swift b/iOSClient/Login/NCLogin.swift index 64f4fa5425..102698030b 100644 --- a/iOSClient/Login/NCLogin.swift +++ b/iOSClient/Login/NCLogin.swift @@ -406,7 +406,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 05a826b988..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 } 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 2c9cc723ef..898dcdc97c 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -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/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/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/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/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/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/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/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 65d4e6522a03bc15ccd621917e59531137e1ca9c Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 11:41:11 +0100 Subject: [PATCH 3/4] shownErrors Signed-off-by: Marino Faggiana --- iOSClient/GUI/Lucid Banner/BannerView.swift | 15 +++++++++++++++ iOSClient/NCAppStateManager.swift | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/iOSClient/GUI/Lucid Banner/BannerView.swift b/iOSClient/GUI/Lucid Banner/BannerView.swift index b1f4948796..d4fa58fca2 100644 --- a/iOSClient/GUI/Lucid Banner/BannerView.swift +++ b/iOSClient/GUI/Lucid Banner/BannerView.swift @@ -222,6 +222,21 @@ func showErrorBanner(scene: UIWindowScene?, backgroundColor: UIColor = .red, sleepBefore: Double = 1, errorCode: Int) async { + // 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) + } + } + try? await Task.sleep(nanoseconds: UInt64(sleepBefore * 1e9)) #if !EXTENSION let scene = scene ?? UIApplication.shared.mainAppWindow?.windowScene 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") } } From 90395b8e3599066953a2c4de5f83ac7152984bd0 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 30 Jan 2026 12:00:24 +0100 Subject: [PATCH 4/4] fix Signed-off-by: Marino Faggiana --- iOSClient/GUI/Lucid Banner/BannerView.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iOSClient/GUI/Lucid Banner/BannerView.swift b/iOSClient/GUI/Lucid Banner/BannerView.swift index d4fa58fca2..f2b3010575 100644 --- a/iOSClient/GUI/Lucid Banner/BannerView.swift +++ b/iOSClient/GUI/Lucid Banner/BannerView.swift @@ -222,6 +222,7 @@ func showErrorBanner(scene: UIWindowScene?, backgroundColor: UIColor = .red, 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. @@ -236,12 +237,11 @@ func showErrorBanner(scene: UIWindowScene?, shownErrors.insert(errorCode) } } - - try? await Task.sleep(nanoseconds: UInt64(sleepBefore * 1e9)) -#if !EXTENSION 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: ""),