From dc6b0e2f1ca487a080da70791a1c7cd32ca623ff Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 26 Jan 2026 12:02:24 +0100 Subject: [PATCH 01/10] code Signed-off-by: Marino Faggiana --- iOSClient/GUI/Lucid Banner/BannerView.swift | 15 +++------------ iOSClient/Networking/NCNetworking+Upload.swift | 4 +++- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/iOSClient/GUI/Lucid Banner/BannerView.swift b/iOSClient/GUI/Lucid Banner/BannerView.swift index cc7fd54c40..02c3b0afc8 100644 --- a/iOSClient/GUI/Lucid Banner/BannerView.swift +++ b/iOSClient/GUI/Lucid Banner/BannerView.swift @@ -19,10 +19,7 @@ func showBanner(scene: UIWindowScene?, vPosition: LucidBanner.VerticalPosition = .top, backgroundColor: UIColor) async { #if !EXTENSION - var scene = scene - if scene == nil { - scene = UIApplication.shared.mainAppWindow?.windowScene - } + let scene = scene ?? UIApplication.shared.mainAppWindow?.windowScene #endif let payload = LucidBannerPayload( title: NSLocalizedString(title ?? "", comment: ""), @@ -102,10 +99,7 @@ func showInfoBanner(scene: UIWindowScene?, foregroundColor: UIColor = .label, backgroundColor: UIColor = .systemBackground) async { #if !EXTENSION - var scene = scene - if scene == nil { - scene = UIApplication.shared.mainAppWindow?.windowScene - } + let scene = scene ?? UIApplication.shared.mainAppWindow?.windowScene #endif let payload = LucidBannerPayload( @@ -192,10 +186,7 @@ func showErrorBanner(scene: UIWindowScene?, sleepBefore: Double = 1) async { try? await Task.sleep(nanoseconds: UInt64(sleepBefore * 1e9)) #if !EXTENSION - var scene = scene - if scene == nil { - scene = UIApplication.shared.mainAppWindow?.windowScene - } + let scene = scene ?? UIApplication.shared.mainAppWindow?.windowScene #endif let payload = LucidBannerPayload( diff --git a/iOSClient/Networking/NCNetworking+Upload.swift b/iOSClient/Networking/NCNetworking+Upload.swift index 93ea6b9597..2c4c89826c 100644 --- a/iOSClient/Networking/NCNetworking+Upload.swift +++ b/iOSClient/Networking/NCNetworking+Upload.swift @@ -284,7 +284,9 @@ extension NCNetworking { await uploadCancelFile(metadata: metadata) } else if (error.errorCode == self.global.errorBadRequest || error.errorCode == self.global.errorUnsupportedMediaType) && error.errorDescription.localizedCaseInsensitiveContains("virus") { await uploadCancelFile(metadata: metadata) - NCContentPresenter().showError(error: NKError(errorCode: error.errorCode, errorDescription: "_virus_detect_")) + #if !EXTENSION + await showErrorBanner(sceneIdentifier: metadata.sceneIdentifier, text: "_virus_detect_") + #endif // Client Diagnostic await NCManageDatabase.shared.addDiagnosticAsync(account: metadata.account, issue: self.global.diagnosticIssueVirusDetected) } else if error.errorCode == self.global.errorForbidden { From 2abb8fbc7ae87b79b825c47fd988eddd4d654c36 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 26 Jan 2026 12:13:15 +0100 Subject: [PATCH 02/10] showError Signed-off-by: Marino Faggiana --- iOSClient/Networking/NCNetworking+WebDAV.swift | 2 +- iOSClient/Notification/NCNotification.swift | 8 ++++++-- iOSClient/Select/NCSelect.swift | 4 +++- iOSClient/Trash/NCTrash+Networking.swift | 4 ++-- iOSClient/Viewer/NCViewerProviderContextMenu.swift | 9 ++++++--- .../NCViewerRichDocument.swift | 14 +++++++++----- 6 files changed, 27 insertions(+), 14 deletions(-) diff --git a/iOSClient/Networking/NCNetworking+WebDAV.swift b/iOSClient/Networking/NCNetworking+WebDAV.swift index 48d0dc2ba6..77a3a4e88a 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 { - NCContentPresenter().showError(error: error) + await showErrorBanner(sceneIdentifier: metadata.sceneIdentifier, text: error.errorDescription) } } #endif diff --git a/iOSClient/Notification/NCNotification.swift b/iOSClient/Notification/NCNotification.swift index 26b1de2981..d1c5825db0 100644 --- a/iOSClient/Notification/NCNotification.swift +++ b/iOSClient/Notification/NCNotification.swift @@ -253,7 +253,9 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { } self.tableView.reloadData() } else if error != .success { - NCContentPresenter().showError(error: error) + Task { + await showErrorBanner(controller: self.controller, text: error.errorDescription) + } } else { print("[Error] The user has been changed during networking process.") } @@ -298,7 +300,9 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { self.dismiss(animated: true) } } else if error != .success { - NCContentPresenter().showError(error: error) + Task { + await showErrorBanner(controller: self.controller, text: error.errorDescription) + } } else { print("[Error] The user has been changed during networking process.") } diff --git a/iOSClient/Select/NCSelect.swift b/iOSClient/Select/NCSelect.swift index 15cd58d26b..3b086d6c4c 100644 --- a/iOSClient/Select/NCSelect.swift +++ b/iOSClient/Select/NCSelect.swift @@ -219,7 +219,9 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent destination: String?, error: NKError) { if error != .success { - NCContentPresenter().showError(error: error) + Task { + await showErrorBanner(sceneIdentifier: sceneIdentifier, text: error.errorDescription) + } } Task { @MainActor in diff --git a/iOSClient/Trash/NCTrash+Networking.swift b/iOSClient/Trash/NCTrash+Networking.swift index 39aedb4fab..4b812e9a4a 100644 --- a/iOSClient/Trash/NCTrash+Networking.swift +++ b/iOSClient/Trash/NCTrash+Networking.swift @@ -86,7 +86,7 @@ extension NCTrash { } if response.error != .success { - NCContentPresenter().showError(error: response.error) + await showErrorBanner(controller: self.controller, text: response.error.errorDescription) } await self.database.deleteTrashAsync(fileId: nil, account: session.account) await self.reloadDataSource() @@ -107,7 +107,7 @@ extension NCTrash { } } if response.error != .success { - NCContentPresenter().showError(error: response.error) + await showErrorBanner(controller: self.controller, text: response.error.errorDescription) } await self.database.deleteTrashAsync(fileId: fileId, account: session.account) await self.reloadDataSource() diff --git a/iOSClient/Viewer/NCViewerProviderContextMenu.swift b/iOSClient/Viewer/NCViewerProviderContextMenu.swift index db5a3c7841..15393d3006 100644 --- a/iOSClient/Viewer/NCViewerProviderContextMenu.swift +++ b/iOSClient/Viewer/NCViewerProviderContextMenu.swift @@ -227,8 +227,9 @@ extension NCViewerProviderContextMenu: VLCMediaPlayerDelegate { print("Played mode: ENDED") case .error: NCActivityIndicator.shared.stop() - let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_error_something_wrong_") - NCContentPresenter().showError(error: error, priority: .max) + Task { + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: "_error_something_wrong_") + } print("Played mode: ERROR") case .playing: NCActivityIndicator.shared.stop() @@ -284,7 +285,9 @@ extension NCViewerProviderContextMenu: NCTransferDelegate { destination: String?, error: NKError) { if error != .success { - NCContentPresenter().showError(error: error) + Task { + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription) + } } Task {@MainActor in diff --git a/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift b/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift index 40215c7214..89287cedaf 100644 --- a/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift +++ b/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift @@ -250,8 +250,9 @@ class NCViewerRichDocument: UIViewController, WKNavigationDelegate, WKScriptMess self.documentController?.presentOptionsMenu(from: CGRect.zero, in: self.view, animated: true) } } else { - - NCContentPresenter().showError(error: error) + Task { + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription) + } } }) } @@ -311,8 +312,9 @@ class NCViewerRichDocument: UIViewController, WKNavigationDelegate, WKScriptMess let functionJS = "OCA.RichDocuments.documentsMain.postAsset('\(metadata.fileNameView)', '\(url)')" self.webView.evaluateJavaScript(functionJS, completionHandler: { _, _ in }) } else { - NCContentPresenter().showError(error: error) - } + Task { + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription) + } } } } } @@ -332,7 +334,9 @@ class NCViewerRichDocument: UIViewController, WKNavigationDelegate, WKScriptMess let functionJS = "OCA.RichDocuments.documentsMain.postAsset('\(metadata.fileNameView)', '\(url)')" self.webView.evaluateJavaScript(functionJS, completionHandler: { _, _ in }) } else { - NCContentPresenter().showError(error: error) + Task { + await showErrorBanner(sceneIdentifier: self.sceneIdentifier, text: error.errorDescription) + } } } } From 157cda7845a3787e3d4dea08657be7b56f81c16d Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 26 Jan 2026 12:49:55 +0100 Subject: [PATCH 03/10] showError Signed-off-by: Marino Faggiana --- Share/NCShareExtension.swift | 2 +- .../UIAlertController+Extension.swift | 5 +++-- iOSClient/GUI/Lucid Banner/BannerView.swift | 16 ---------------- iOSClient/Main/NCMainNavigationController.swift | 17 ++++++++++++++--- .../Media/NCMediaNavigationController.swift | 1 + .../RichWorkspace/NCRichWorkspaceCommon.swift | 6 ++++-- iOSClient/Select/NCSelect.swift | 1 + .../Select/NCSelectOpen+SelectDelegate.swift | 1 + iOSClient/Viewer/NCViewer.swift | 4 ++-- .../NCPlayer/NCPlayerToolBar.swift | 2 ++ .../NCViewerRichDocument.swift | 1 + 11 files changed, 30 insertions(+), 26 deletions(-) diff --git a/Share/NCShareExtension.swift b/Share/NCShareExtension.swift index 6d2b368a6d..c2885ce92e 100644 --- a/Share/NCShareExtension.swift +++ b/Share/NCShareExtension.swift @@ -272,7 +272,7 @@ class NCShareExtension: UIViewController { guard let capabilities = NCNetworking.shared.capabilities[session.account] else { return } - let alertController = UIAlertController.createFolder(serverUrl: serverUrl, session: session, capabilities: capabilities) { error in + let alertController = UIAlertController.createFolder(serverUrl: serverUrl, session: session, capabilities: capabilities, scene: self.view.window?.windowScene) { error in if error == .success { Task { await self.loadFolder() diff --git a/iOSClient/Extensions/UIAlertController+Extension.swift b/iOSClient/Extensions/UIAlertController+Extension.swift index 542abad2ab..93799b81cb 100644 --- a/iOSClient/Extensions/UIAlertController+Extension.swift +++ b/iOSClient/Extensions/UIAlertController+Extension.swift @@ -37,6 +37,7 @@ extension UIAlertController { markE2ee: Bool = false, sceneIdentifier: String? = nil, capabilities: NKCapabilities.Capabilities, + scene: UIWindowScene? = nil, completion: ((_ error: NKError) -> Void)? = nil) -> UIAlertController { let alertController = UIAlertController(title: NSLocalizedString("_create_folder_", comment: ""), message: nil, preferredStyle: .alert) let isDirectoryEncrypted = NCUtilityFileSystem().isDirectoryE2EE(serverUrl: serverUrl, urlBase: session.urlBase, userId: session.userId, account: session.account) @@ -61,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 { - NCContentPresenter().showError(error: error) + await showErrorBanner(scene: scene, text: error.errorDescription) } } else { - NCContentPresenter().showError(error: createFolderResults.error) + await showErrorBanner(scene: scene, text: createFolderResults.error.errorDescription) } } } else if isDirectoryEncrypted { diff --git a/iOSClient/GUI/Lucid Banner/BannerView.swift b/iOSClient/GUI/Lucid Banner/BannerView.swift index 02c3b0afc8..0d3630da2c 100644 --- a/iOSClient/GUI/Lucid Banner/BannerView.swift +++ b/iOSClient/GUI/Lucid Banner/BannerView.swift @@ -160,22 +160,6 @@ func showErrorBanner(sceneIdentifier: String?, #endif -@MainActor -func showErrorBanner(title: String = "_error_", - text: String, - footnote: String? = nil, - foregroundColor: UIColor = .white, - backgroundColor: UIColor = .red, - sleepBefore: Double = 1) async { - await showErrorBanner(scene: nil, - title: title, - text: text, - footnote: footnote, - foregroundColor: foregroundColor, - backgroundColor: backgroundColor, - sleepBefore: sleepBefore) -} - @MainActor func showErrorBanner(scene: UIWindowScene?, title: String = "_error_", diff --git a/iOSClient/Main/NCMainNavigationController.swift b/iOSClient/Main/NCMainNavigationController.swift index 07a189ae1c..e7e889874d 100644 --- a/iOSClient/Main/NCMainNavigationController.swift +++ b/iOSClient/Main/NCMainNavigationController.swift @@ -294,7 +294,12 @@ class NCMainNavigationController: UINavigationController, UINavigationController menuActionElement.append(UIAction(title: titleCreateFolder, image: imageCreateFolder) { _ in DispatchQueue.main.async { - let alertController = UIAlertController.createFolder(serverUrl: serverUrl, session: session, sceneIdentifier: controller.sceneIdentifier, capabilities: capabilities) + let alertController = UIAlertController.createFolder( + serverUrl: serverUrl, + session: session, + sceneIdentifier: controller.sceneIdentifier, + capabilities: capabilities, + scene: SceneManager.shared.getWindow(controller: self.controller)?.windowScene) controller.present(alertController, animated: true, completion: nil) } }) @@ -307,7 +312,13 @@ class NCMainNavigationController: UINavigationController, UINavigationController menuE2EEElement.append(UIAction(title: NSLocalizedString("_create_folder_e2ee_", comment: ""), image: NCImageCache.shared.getFolderEncrypted(account: session.account)) { _ in DispatchQueue.main.async { - let alertController = UIAlertController.createFolder(serverUrl: serverUrl, session: session, markE2ee: true, sceneIdentifier: controller.sceneIdentifier, capabilities: capabilities) + let alertController = UIAlertController.createFolder( + serverUrl: serverUrl, + session: session, + markE2ee: true, + sceneIdentifier: controller.sceneIdentifier, + capabilities: capabilities, + scene: SceneManager.shared.getWindow(controller: self.controller)?.windowScene) controller.present(alertController, animated: true, completion: nil) } }) @@ -329,7 +340,7 @@ class NCMainNavigationController: UINavigationController, UINavigationController session.account, serverUrl, NCGlobal.shared.fileNameRichWorkspace.lowercased())) == nil { - richWorkspaceCommon.createViewerNextcloudText(serverUrl: serverUrl, viewController: viewController, session: session) + richWorkspaceCommon.createViewerNextcloudText(serverUrl: serverUrl, viewController: viewController, controller: self.controller, session: session) } else { richWorkspaceCommon.openViewerNextcloudText(serverUrl: serverUrl, viewController: viewController, session: session) } diff --git a/iOSClient/Media/NCMediaNavigationController.swift b/iOSClient/Media/NCMediaNavigationController.swift index bc9636fe18..47fb92a4ce 100644 --- a/iOSClient/Media/NCMediaNavigationController.swift +++ b/iOSClient/Media/NCMediaNavigationController.swift @@ -95,6 +95,7 @@ class NCMediaNavigationController: NCMainNavigationController { viewController.typeOfCommandView = .select viewController.type = "mediaFolder" viewController.session = self.session + viewController.controller = self.controller self.present(navigationController, animated: true) }) ]) diff --git a/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift b/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift index c255e743db..229dc2be6a 100644 --- a/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift +++ b/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift @@ -8,7 +8,7 @@ import NextcloudKit class NCRichWorkspaceCommon: NSObject { let utilityFileSystem = NCUtilityFileSystem() - func createViewerNextcloudText(serverUrl: String, viewController: UIViewController, session: NCSession.Session) { + func createViewerNextcloudText(serverUrl: String, viewController: UIViewController, controller: NCMainTabBarController?, session: NCSession.Session) { if !NextcloudKit.shared.isNetworkReachable() { let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_go_online_") NCContentPresenter().showError(error: error) @@ -39,7 +39,9 @@ class NCRichWorkspaceCommon: NSObject { viewController.present(viewerRichWorkspaceWebView, animated: true, completion: nil) } } else if error != .success { - NCContentPresenter().showError(error: error) + Task { + await showErrorBanner(controller: controller, text: error.errorDescription) + } } } } diff --git a/iOSClient/Select/NCSelect.swift b/iOSClient/Select/NCSelect.swift index 3b086d6c4c..ca3ac46a48 100644 --- a/iOSClient/Select/NCSelect.swift +++ b/iOSClient/Select/NCSelect.swift @@ -61,6 +61,7 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent var titleCurrentFolder = NCBrandOptions.shared.brand var serverUrl = "" var session: NCSession.Session! + var controller: NCMainTabBarController? // ------------------------------------------------------------- private var dataSourceTask: URLSessionTask? diff --git a/iOSClient/Select/NCSelectOpen+SelectDelegate.swift b/iOSClient/Select/NCSelectOpen+SelectDelegate.swift index 61ed275a32..f88347deec 100644 --- a/iOSClient/Select/NCSelectOpen+SelectDelegate.swift +++ b/iOSClient/Select/NCSelectOpen+SelectDelegate.swift @@ -67,6 +67,7 @@ final class NCSelectOpen: NCSelectDelegate { vc.items = copyItems vc.serverUrl = serverUrl vc.session = session + vc.controller = controller vc.navigationItem.backButtonTitle = vc.titleCurrentFolder listViewController.insert(vc, at: 0) diff --git a/iOSClient/Viewer/NCViewer.swift b/iOSClient/Viewer/NCViewer.swift index 51ad31a170..22421890f9 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 { - NCContentPresenter().showError(error: results.error) + await showErrorBanner(controller: delegate?.tabBarController as? NCMainTabBarController, text: results.error.errorDescription) return nil } @@ -138,7 +138,7 @@ class NCViewer: NSObject { NCActivityIndicator.shared.stop() guard results.error == .success, let url = results.url else { - NCContentPresenter().showError(error: results.error) + await showErrorBanner(controller: delegate?.tabBarController as? NCMainTabBarController, text: results.error.errorDescription) return nil } diff --git a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift index dbd2a33cea..52febd51ac 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift @@ -365,6 +365,7 @@ extension NCPlayerToolBar { viewController.type = "subtitle" viewController.serverUrl = metadata.serverUrl viewController.session = NCSession.shared.getSession(account: metadata.account) + viewController.controller = nil self.viewerMediaPage?.present(navigationController, animated: true, completion: nil) } @@ -430,6 +431,7 @@ extension NCPlayerToolBar { viewController.type = "audio" viewController.serverUrl = metadata.serverUrl viewController.session = NCSession.shared.getSession(account: metadata.account) + viewController.controller = nil self.viewerMediaPage?.present(navigationController, animated: true, completion: nil) } diff --git a/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift b/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift index 89287cedaf..cb3d143ddc 100644 --- a/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift +++ b/iOSClient/Viewer/NCViewerRichdocument/NCViewerRichDocument.swift @@ -169,6 +169,7 @@ class NCViewerRichDocument: UIViewController, WKNavigationDelegate, WKScriptMess viewController.includeImages = true viewController.type = "" viewController.session = session + viewController.controller = self.tabBarController as? NCMainTabBarController self.present(navigationController, animated: true, completion: nil) } From a7cba3845acdc43e27e2e6c98157a1358f14b3b7 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 26 Jan 2026 14:16:59 +0100 Subject: [PATCH 04/10] code Signed-off-by: Marino Faggiana --- iOSClient/Main/NCMainNavigationController.swift | 2 +- .../RichWorkspace/NCRichWorkspaceCommon.swift | 17 +++++++++++------ .../RichWorkspace/NCViewerRichWorkspace.swift | 5 ++++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/iOSClient/Main/NCMainNavigationController.swift b/iOSClient/Main/NCMainNavigationController.swift index e7e889874d..edf171945f 100644 --- a/iOSClient/Main/NCMainNavigationController.swift +++ b/iOSClient/Main/NCMainNavigationController.swift @@ -342,7 +342,7 @@ class NCMainNavigationController: UINavigationController, UINavigationController NCGlobal.shared.fileNameRichWorkspace.lowercased())) == nil { richWorkspaceCommon.createViewerNextcloudText(serverUrl: serverUrl, viewController: viewController, controller: self.controller, session: session) } else { - richWorkspaceCommon.openViewerNextcloudText(serverUrl: serverUrl, viewController: viewController, session: session) + richWorkspaceCommon.openViewerNextcloudText(serverUrl: serverUrl, viewController: viewController, controller: controller, session: session) } } } diff --git a/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift b/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift index 229dc2be6a..51e965a84e 100644 --- a/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift +++ b/iOSClient/RichWorkspace/NCRichWorkspaceCommon.swift @@ -10,8 +10,9 @@ class NCRichWorkspaceCommon: NSObject { func createViewerNextcloudText(serverUrl: String, viewController: UIViewController, controller: NCMainTabBarController?, session: NCSession.Session) { if !NextcloudKit.shared.isNetworkReachable() { - let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_go_online_") - NCContentPresenter().showError(error: error) + Task { + await showErrorBanner(controller: controller, text: "_go_online_") + } return } @@ -46,10 +47,12 @@ class NCRichWorkspaceCommon: NSObject { } } - func openViewerNextcloudText(serverUrl: String, viewController: UIViewController, session: NCSession.Session) { + func openViewerNextcloudText(serverUrl: String, viewController: UIViewController, controller: NCMainTabBarController?, session: NCSession.Session) { if !NextcloudKit.shared.isNetworkReachable() { - let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_go_online_") - return NCContentPresenter().showError(error: error) + Task { + await showErrorBanner(controller: controller, text: "_go_online_") + } + return } if let metadata = NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView LIKE[c] %@", @@ -78,7 +81,9 @@ class NCRichWorkspaceCommon: NSObject { viewController.present(viewerRichWorkspaceWebView, animated: true, completion: nil) } } else if error != .success { - NCContentPresenter().showError(error: error) + Task { + await showErrorBanner(controller: controller, text: error.errorDescription) + } } } } else { diff --git a/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift b/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift index 48d47a98f6..31d2962dae 100644 --- a/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift +++ b/iOSClient/RichWorkspace/NCViewerRichWorkspace.swift @@ -73,6 +73,9 @@ import MarkdownKit } @IBAction func editItemAction(_ sender: Any) { - richWorkspaceCommon.openViewerNextcloudText(serverUrl: serverUrl, viewController: self, session: session) + richWorkspaceCommon.openViewerNextcloudText(serverUrl: serverUrl, + viewController: self, + controller: delegate?.tabBarController as? NCMainTabBarController, + session: session) } } From c93ad42196daf24845e4466efda2a093a7a311ab Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 26 Jan 2026 16:29:16 +0100 Subject: [PATCH 05/10] code Signed-off-by: Marino Faggiana --- .../Extensions/UIApplication+Extension.swift | 7 ++ iOSClient/GUI/Lucid Banner/BannerView.swift | 73 +++++++++++++++---- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/iOSClient/Extensions/UIApplication+Extension.swift b/iOSClient/Extensions/UIApplication+Extension.swift index 1ec1e3f269..8c1f44c929 100644 --- a/iOSClient/Extensions/UIApplication+Extension.swift +++ b/iOSClient/Extensions/UIApplication+Extension.swift @@ -52,4 +52,11 @@ extension UIApplication { requestSceneSessionDestruction(windowScene.session, options: options, errorHandler: nil) } } + + /// Returns all foreground-active window scenes. + var foregroundActiveScenes: [UIWindowScene] { + connectedScenes + .compactMap { $0 as? UIWindowScene } + .filter { $0.activationState == .foregroundActive } + } } diff --git a/iOSClient/GUI/Lucid Banner/BannerView.swift b/iOSClient/GUI/Lucid Banner/BannerView.swift index 0d3630da2c..bbd960e68b 100644 --- a/iOSClient/GUI/Lucid Banner/BannerView.swift +++ b/iOSClient/GUI/Lucid Banner/BannerView.swift @@ -6,6 +6,31 @@ import SwiftUI import LucidBanner // MARK: - Show Banner +#if !EXTENSION +@MainActor +func showBannerActiveScenes(title: String?, + subtitle: String? = nil, + footnote: String? = nil, + textColor: UIColor, + image: String?, + imageAnimation: LucidBanner.LucidBannerAnimationStyle, + imageColor: UIColor, + vPosition: LucidBanner.VerticalPosition = .top, + backgroundColor: UIColor) async { + for scene in UIApplication.shared.foregroundActiveScenes { + await showBanner(scene: scene, + title: title, + subtitle: subtitle, + footnote: footnote, + textColor: textColor, + image: image, + imageAnimation: imageAnimation, + imageColor: imageColor, + vPosition: vPosition, + backgroundColor: backgroundColor) + } +} +#endif @MainActor func showBanner(scene: UIWindowScene?, @@ -45,6 +70,22 @@ func showBanner(scene: UIWindowScene?, // MARK: - Show Info #if !EXTENSION +@MainActor +func showInfoBannerActiveScenes(title: String = "_error_", + text: String, + footnote: String? = nil, + foregroundColor: UIColor = .label, + backgroundColor: UIColor = .systemBackground) async { + for scene in UIApplication.shared.foregroundActiveScenes { + await showInfoBanner(scene: scene, + title: title, + text: text, + footnote: footnote, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor) + } +} + @MainActor func showInfoBanner(controller: UITabBarController?, title: String = "_info_", @@ -77,20 +118,6 @@ func showInfoBanner(sceneIdentifier: String?, #endif -@MainActor -func showInfoBanner(title: String = "_error_", - text: String, - footnote: String? = nil, - foregroundColor: UIColor = .label, - backgroundColor: UIColor = .systemBackground) async { - await showInfoBanner(scene: nil, - title: title, - text: text, - footnote: footnote, - foregroundColor: foregroundColor, - backgroundColor: backgroundColor) -} - @MainActor func showInfoBanner(scene: UIWindowScene?, title: String = "_info_", @@ -124,6 +151,24 @@ func showInfoBanner(scene: UIWindowScene?, // MARK: - Show Error #if !EXTENSION +@MainActor +func showErrorBannerActiveScenes(title: String = "_error_", + text: String, + footnote: String? = nil, + foregroundColor: UIColor = .white, + backgroundColor: UIColor = .red, + sleepBefore: Double = 1) async { + for scene in UIApplication.shared.foregroundActiveScenes { + await showErrorBanner(scene: scene, + title: title, + text: text, + footnote: footnote, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + sleepBefore: sleepBefore) + } +} + @MainActor func showErrorBanner(controller: UITabBarController?, title: String = "_error_", From 249c54b2cd0e549c8905431c2b56b270582a3527 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 26 Jan 2026 16:30:08 +0100 Subject: [PATCH 06/10] code Signed-off-by: Marino Faggiana --- .../NCNetworking+NextcloudKitDelegate.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/iOSClient/Networking/NCNetworking+NextcloudKitDelegate.swift b/iOSClient/Networking/NCNetworking+NextcloudKitDelegate.swift index 54044417c0..5a7b798ffb 100644 --- a/iOSClient/Networking/NCNetworking+NextcloudKitDelegate.swift +++ b/iOSClient/Networking/NCNetworking+NextcloudKitDelegate.swift @@ -15,16 +15,16 @@ extension NCNetworking { lastReachability = true } else { if lastReachability { - let scene = SceneManager.shared.getWindow(sceneIdentifier: sceneIdentifier)?.windowScene Task { - await showBanner(scene: scene, - title: NSLocalizedString("_info_", comment: ""), - subtitle: NSLocalizedString("_network_not_available_", comment: ""), - textColor: .white, - image: "wifi.exclamationmark.circle", - imageAnimation: .bounce, - imageColor: .white, - backgroundColor: UIColor.lightGray.withAlphaComponent(0.75)) + await showBannerActiveScenes( + title: NSLocalizedString("_info_", comment: ""), + subtitle: NSLocalizedString("_network_not_available_", comment: ""), + textColor: .white, + image: "wifi.exclamationmark.circle", + imageAnimation: .bounce, + imageColor: .white, + backgroundColor: UIColor.lightGray.withAlphaComponent(0.75) + ) } } lastReachability = false From 9e7e753142a3ab9916ab860a9ee1295cb118c6c7 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 27 Jan 2026 09:17:49 +0100 Subject: [PATCH 07/10] code Signed-off-by: Marino Faggiana --- Share/NCShareExtension.swift | 21 ++++++++----------- .../GUI/Lucid Banner/UploadBannerView.swift | 1 + 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Share/NCShareExtension.swift b/Share/NCShareExtension.swift index c2885ce92e..dbdfc14171 100644 --- a/Share/NCShareExtension.swift +++ b/Share/NCShareExtension.swift @@ -368,15 +368,16 @@ extension NCShareExtension { @MainActor func uploadAndExit() async { var error: NKError? - let payload = LucidBannerPayload(backgroundColor: Color(.systemBackground), + let payload = LucidBannerPayload(stage: .button, + backgroundColor: Color(.systemBackground), vPosition: .center, - verticalMargin: 0, - blocksTouches: true, - draggable: false) + blocksTouches: true) token = showUploadBanner(scene: self.view.window?.windowScene, payload: payload, - allowMinimizeOnTap: false - ) + allowMinimizeOnTap: false, + onButtonTap: { + self.cancel(with: .cancel) + }) for metadata in self.uploadMetadata { // BANNER @@ -447,8 +448,7 @@ extension NCShareExtension { let task = Task { () -> (account: String, file: NKFile?, error: NKError) in let results = await NCNetworking.shared.uploadChunkFile(metadata: metadata) { total, counter in Task {@MainActor in - let progress = Double(counter) / Double(total) - LucidBanner.shared.update(payload: LucidBannerPayload.Update(progress: progress), for: self.token) + LucidBanner.shared.update(payload: LucidBannerPayload.Update(progress: Double(counter) / Double(total)), for: self.token) } } uploadStart: { _ in Task {@MainActor in @@ -460,10 +460,7 @@ extension NCShareExtension { } } uploadProgressHandler: { _, _, progress in Task {@MainActor in - LucidBanner.shared.update( - payload: LucidBannerPayload.Update(progress: progress), - for: self.token) - LucidBanner.shared.update(payload: payload, for: self.token) + LucidBanner.shared.update(payload: LucidBannerPayload.Update(progress: progress), for: self.token) } } assembling: { Task {@MainActor in diff --git a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift index 34b6e8caf1..6ea23349e2 100644 --- a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift @@ -180,6 +180,7 @@ struct UploadBannerView: View { .tint(.accentColor) .opacity(state.payload.progress == nil ? 0 : 1) .animation(.easeInOut(duration: 0.2), value: state.payload.progress == nil) + .padding(.horizontal, 5) if isButton { VStack { From 44b3160dd9da83a8e1c0b08a2f8c954a1c17a1b3 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 27 Jan 2026 09:29:52 +0100 Subject: [PATCH 08/10] fix Signed-off-by: Marino Faggiana --- Share/NCShareExtension.swift | 1 + iOSClient/Main/NCDragDrop.swift | 4 ++-- iOSClient/Networking/NCNetworkingProcess.swift | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Share/NCShareExtension.swift b/Share/NCShareExtension.swift index dbdfc14171..3a353491da 100644 --- a/Share/NCShareExtension.swift +++ b/Share/NCShareExtension.swift @@ -371,6 +371,7 @@ extension NCShareExtension { let payload = LucidBannerPayload(stage: .button, backgroundColor: Color(.systemBackground), vPosition: .center, + horizontalMargin: 20, blocksTouches: true) token = showUploadBanner(scene: self.view.window?.windowScene, payload: payload, diff --git a/iOSClient/Main/NCDragDrop.swift b/iOSClient/Main/NCDragDrop.swift index b9c2fe86a3..7aa59e600a 100644 --- a/iOSClient/Main/NCDragDrop.swift +++ b/iOSClient/Main/NCDragDrop.swift @@ -198,8 +198,8 @@ class NCDragDrop: NSObject { let payload = LucidBannerPayload(stage: nil, backgroundColor: Color(.systemBackground), - vPosition: .bottom, - verticalMargin: 55, + vPosition: .center, + horizontalMargin: 20, blocksTouches: false, draggable: false) let token = showUploadBanner(scene: scene, diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index df336eee6f..823b27ff78 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -394,7 +394,7 @@ actor NCNetworkingProcess { let payload = LucidBannerPayload(backgroundColor: Color(.systemBackground), vPosition: .center, - verticalMargin: 0, + horizontalMargin: 20, blocksTouches: true, draggable: false) let token = await showUploadBanner(scene: scene, @@ -448,7 +448,8 @@ actor NCNetworkingProcess { payload: LucidBannerPayload(stage: .button, backgroundColor: Color(.systemBackground), vPosition: .bottom, - verticalMargin: 55, + horizontalMargin: 20, + verticalMargin: 80, blocksTouches: false, draggable: true), allowMinimizeOnTap: true, From b851dc6eb1494c378bab1873960bfdfefb759353 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 27 Jan 2026 09:49:48 +0100 Subject: [PATCH 09/10] fix Signed-off-by: Marino Faggiana --- Share/NCShareExtension.swift | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Share/NCShareExtension.swift b/Share/NCShareExtension.swift index 3a353491da..ed47c84328 100644 --- a/Share/NCShareExtension.swift +++ b/Share/NCShareExtension.swift @@ -173,9 +173,12 @@ class NCShareExtension: UIViewController { // MARK: - - func cancel(with error: NCShareExtensionError) { - // make sure no uploads are continued - extensionContext?.cancelRequest(withError: error) + func cancel(with error: NCShareExtensionError? = nil) { + if let error { + extensionContext?.cancelRequest(withError: error) + } else { + self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil) + } } func showAlert(title: String = "_error_", description: String, onDismiss: (() -> Void)? = nil) { @@ -264,7 +267,7 @@ class NCShareExtension: UIViewController { // MARK: ACTION @IBAction func actionCancel(_ sender: UIBarButtonItem) { - cancel(with: .cancel) + cancel() } @objc func actionCreateFolder(_ sender: Any?) { @@ -377,7 +380,7 @@ extension NCShareExtension { payload: payload, allowMinimizeOnTap: false, onButtonTap: { - self.cancel(with: .cancel) + self.cancel() }) for metadata in self.uploadMetadata { @@ -407,7 +410,7 @@ extension NCShareExtension { } LucidBanner.shared.dismiss(after: 2) { - self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil) + self.cancel() } } From 9b5de0dff64e0640a67fcb5d3e1bf695f8ade30b Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 27 Jan 2026 09:58:18 +0100 Subject: [PATCH 10/10] code Signed-off-by: Marino Faggiana --- iOSClient/GUI/Lucid Banner/BannerView.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iOSClient/GUI/Lucid Banner/BannerView.swift b/iOSClient/GUI/Lucid Banner/BannerView.swift index bbd960e68b..5afbb8fc8c 100644 --- a/iOSClient/GUI/Lucid Banner/BannerView.swift +++ b/iOSClient/GUI/Lucid Banner/BannerView.swift @@ -138,6 +138,8 @@ func showInfoBanner(scene: UIWindowScene?, textColor: Color(uiColor: foregroundColor), imageColor: Color(uiColor: NCBrandColor.shared.customer), vPosition: .top, + horizontalMargin: 20, + verticalMargin: 10, autoDismissAfter: NCGlobal.shared.dismissAfterSecond, swipeToDismiss: true, ) @@ -227,6 +229,8 @@ func showErrorBanner(scene: UIWindowScene?, textColor: Color(uiColor: foregroundColor), imageColor: .white, vPosition: .top, + horizontalMargin: 20, + verticalMargin: 10, autoDismissAfter: NCGlobal.shared.dismissAfterSecond, swipeToDismiss: true, )