From 30b49b9e5de871003fd6f22df65aae47aa7d43fc Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 8 Dec 2025 12:34:57 +0100 Subject: [PATCH 01/14] cod Signed-off-by: Marino Faggiana --- Share/NCShareExtension.swift | 2 +- .../GUI/Lucid Banner/UploadBannerView.swift | 6 +- .../E2EE/NCNetworkingE2EEUpload.swift | 60 +++++++------------ .../Networking/NCNetworkingProcess.swift | 11 +++- 4 files changed, 36 insertions(+), 43 deletions(-) diff --git a/Share/NCShareExtension.swift b/Share/NCShareExtension.swift index 5071a1efd3..d3200a1270 100644 --- a/Share/NCShareExtension.swift +++ b/Share/NCShareExtension.swift @@ -420,7 +420,7 @@ extension NCShareExtension { self.counterUploaded += 1 if metadata.isDirectoryE2EE { - error = await NCNetworkingE2EEUpload().upload(metadata: metadata, session: session, controller: self, scene: self.view.window?.windowScene) + error = await NCNetworkingE2EEUpload().upload(metadata: metadata, session: session, controller: self, tokenBanner: self.token) } else if metadata.chunk > 0 { LucidBanner.shared.update( systemImage: "gearshape.arrow.triangle.2.circlepath", diff --git a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift index 8c96c2938a..6975dff3af 100644 --- a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift @@ -216,16 +216,20 @@ func showUploadBanner(scene: UIWindowScene?, vPosition: LucidBanner.VerticalPosition = .center, hAlignment: LucidBanner.HorizontalAlignment = .center, verticalMargin: CGFloat = 0, + blocksTouches: Bool = false, draggable: Bool = false, stage: LucidBanner.Stage? = nil, + policy: LucidBanner.ShowPolicy = .drop, onButtonTap: (() -> Void)? = nil) -> Int { LucidBanner.shared.show( scene: scene, vPosition: vPosition, hAlignment: hAlignment, verticalMargin: verticalMargin, + blocksTouches: blocksTouches, draggable: draggable, - stage: stage + stage: stage, + policy: policy ) { state in UploadBannerView(state: state, onButtonTap: onButtonTap) } diff --git a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift index b6595ed49d..1327e7c1fd 100644 --- a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift +++ b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift @@ -16,13 +16,12 @@ class NCNetworkingE2EEUpload: NSObject { let utility = NCUtility() let database = NCManageDatabase.shared var numChunks: Int = 0 - var bannerToken: Int = 0 var currentUploadTask: Task<(account: String, file: NKFile?, error: NKError), Never>? var request: UploadRequest? @discardableResult @MainActor - func upload(metadata: tableMetadata, session: NCSession.Session? = nil, controller: UIViewController? = nil, scene: UIWindowScene? = nil, externalBannerToken: Int? = nil) async -> NKError { + func upload(metadata: tableMetadata, session: NCSession.Session? = nil, controller: UIViewController? = nil, tokenBanner: Int) async -> NKError { var finalError: NKError = .success var session = session let ocId = metadata.ocIdTransfer @@ -44,6 +43,15 @@ class NCNetworkingE2EEUpload: NSObject { LucidBanner.shared.dismiss() } + LucidBanner.shared.update( + title: NSLocalizedString("_wait_file_encryption_", comment: ""), + subtitle: NSLocalizedString("_e2ee_upload_tip_", comment: ""), + systemImage: "lock.circle.fill", + for: tokenBanner + ) + + LucidBanner.shared.requestRelayout(animated: true) + if let result = await self.database.getMetadataAsync(predicate: NSPredicate(format: "serverUrl == %@ AND fileNameView == %@ AND ocId != %@", metadata.serverUrl, metadata.fileNameView, metadata.ocId)) { metadata.fileName = result.fileName } else { @@ -137,32 +145,6 @@ class NCNetworkingE2EEUpload: NSObject { return finalError } - // BANNER - // - if let externalBannerToken { - bannerToken = externalBannerToken - } else { - bannerToken = showUploadBanner(scene: scene, - vPosition: .bottom, - verticalMargin: 55, - draggable: true, - stage: .init(rawValue: "button"), - onButtonTap: { - if let currentUploadTask = self.currentUploadTask { - currentUploadTask.cancel() - } - if let request = self.request { - request.cancel() - } - LucidBanner.shared.dismiss() - }) - } - - LucidBanner.shared.update(title: NSLocalizedString("_wait_file_encryption_", comment: ""), - subtitle: NSLocalizedString("_e2ee_upload_tip_", comment: ""), - systemImage: "lock.circle.fill", - for: bannerToken) - // SEND NEW METADATA // let sendE2eeError = await sendE2ee(e2eToken: e2eToken, fileId: fileId) @@ -175,7 +157,7 @@ class NCNetworkingE2EEUpload: NSObject { // UPLOAD // - let resultsSendFile = await sendFile(metadata: metadata, e2eToken: e2eToken, controller: controller) + let resultsSendFile = await sendFile(metadata: metadata, e2eToken: e2eToken, controller: controller, tokenBanner: tokenBanner) // UNLOCK // @@ -222,21 +204,21 @@ class NCNetworkingE2EEUpload: NSObject { } @MainActor - private func sendFile(metadata: tableMetadata, e2eToken: String, controller: UIViewController?) async -> (ocId: String?, etag: String?, date: Date?, error: NKError) { + private func sendFile(metadata: tableMetadata, e2eToken: String, controller: UIViewController?, tokenBanner: Int) async -> (ocId: String?, etag: String?, date: Date?, error: NKError) { if metadata.chunk > 0 { LucidBanner.shared.update( title: NSLocalizedString("_wait_file_preparation_", comment: ""), - footnote: "( " + NSLocalizedString("_tap_to_cancel_", comment: "") + " )", systemImage: "gearshape.arrow.triangle.2.circlepath", imageAnimation: .rotate, progress: 0, - for: self.bannerToken) + stage: .init(rawValue: "button"), + for: tokenBanner) 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(progress: progress, for: self.bannerToken) + LucidBanner.shared.update(progress: progress, for: tokenBanner) } } uploadStart: { _ in Task {@MainActor in @@ -245,11 +227,11 @@ class NCNetworkingE2EEUpload: NSObject { systemImage: "arrowshape.up.circle", imageAnimation: .breathe, progress: 0, - for: self.bannerToken) + for: tokenBanner) } } uploadProgressHandler: { _, _, progress in Task {@MainActor in - LucidBanner.shared.update(progress: progress, for: self.bannerToken) + LucidBanner.shared.update(progress: progress, for: tokenBanner) } } assembling: { Task {@MainActor in @@ -259,7 +241,7 @@ class NCNetworkingE2EEUpload: NSObject { systemImage: "tray.and.arrow.down", imageAnimation: .pulsebyLayer, progress: 0, - for: self.bannerToken) + for: tokenBanner) } } @@ -274,11 +256,11 @@ class NCNetworkingE2EEUpload: NSObject { } else { LucidBanner.shared.update( title: NSLocalizedString("_keep_active_for_upload_", comment: ""), - footnote: "( " + NSLocalizedString("_tap_to_cancel_", comment: "") + " )", systemImage: "arrowshape.up.circle", imageAnimation: .breathe, progress: 0, - for: self.bannerToken) + stage: .init(rawValue: "button"), + for: tokenBanner) let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileName: metadata.fileName, @@ -294,7 +276,7 @@ class NCNetworkingE2EEUpload: NSObject { self.request = request } progressHandler: { _, _, fractionCompleted in Task {@MainActor in - LucidBanner.shared.update(progress: fractionCompleted, for: self.bannerToken) + LucidBanner.shared.update(progress: fractionCompleted, for: tokenBanner) } } diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 38d3d43e2e..2ce28d465c 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -359,8 +359,15 @@ actor NCNetworkingProcess { // if metadata.isDirectoryE2EE { let controller = await getController(account: metadata.account, sceneIdentifier: metadata.sceneIdentifier) - await NCNetworkingE2EEUpload().upload(metadata: metadata, controller: controller, scene: SceneManager.shared.getWindow(sceneIdentifier: metadata.sceneIdentifier)?.windowScene) - + let scene = await SceneManager.shared.getWindow(sceneIdentifier: metadata.sceneIdentifier)?.windowScene + let token = await showUploadBanner(scene: scene, + vPosition: .bottom, + verticalMargin: 55, + blocksTouches: true, + draggable: true) + await NCNetworkingE2EEUpload().upload(metadata: metadata, + controller: controller, + tokenBanner: token) // UPLOAD CHUNK // } else if metadata.chunk > 0 { From c7a360249cfd8ff860308426d46abac8f70fd470 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 8 Dec 2025 16:19:46 +0100 Subject: [PATCH 02/14] cod Signed-off-by: Marino Faggiana --- iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift index 1327e7c1fd..198b871cf9 100644 --- a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift +++ b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift @@ -237,9 +237,8 @@ class NCNetworkingE2EEUpload: NSObject { Task {@MainActor in LucidBanner.shared.update( title: NSLocalizedString("_finalizing_wait_", comment: ""), - footnote: "", - systemImage: "tray.and.arrow.down", - imageAnimation: .pulsebyLayer, + systemImage: "gearshape.arrow.triangle.2.circlepath", + imageAnimation: .rotate, progress: 0, for: tokenBanner) } From d02108aaf8b02125dd216c622c32560f8dbabc7d Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 8 Dec 2025 16:38:52 +0100 Subject: [PATCH 03/14] code Signed-off-by: Marino Faggiana --- Share/NCShareExtension.swift | 2 +- .../E2EE/NCNetworkingE2EEUpload.swift | 38 ++++++++++++++----- .../Networking/NCNetworkingProcess.swift | 21 +++++++++- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/Share/NCShareExtension.swift b/Share/NCShareExtension.swift index d3200a1270..32c8af32f1 100644 --- a/Share/NCShareExtension.swift +++ b/Share/NCShareExtension.swift @@ -420,7 +420,7 @@ extension NCShareExtension { self.counterUploaded += 1 if metadata.isDirectoryE2EE { - error = await NCNetworkingE2EEUpload().upload(metadata: metadata, session: session, controller: self, tokenBanner: self.token) + error = await NCNetworkingE2EEUpload().upload(metadata: metadata, session: session, controller: self, stageBanner: nil, tokenBanner: self.token) } else if metadata.chunk > 0 { LucidBanner.shared.update( systemImage: "gearshape.arrow.triangle.2.circlepath", diff --git a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift index 198b871cf9..75b0f84679 100644 --- a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift +++ b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift @@ -16,12 +16,17 @@ class NCNetworkingE2EEUpload: NSObject { let utility = NCUtility() let database = NCManageDatabase.shared var numChunks: Int = 0 - var currentUploadTask: Task<(account: String, file: NKFile?, error: NKError), Never>? - var request: UploadRequest? @discardableResult @MainActor - func upload(metadata: tableMetadata, session: NCSession.Session? = nil, controller: UIViewController? = nil, tokenBanner: Int) async -> NKError { + func upload(metadata: tableMetadata, + session: NCSession.Session? = nil, + controller: UIViewController? = nil, + stageBanner: LucidBanner.Stage?, + tokenBanner: Int, + requestHandle: @escaping (_ request: UploadRequest) -> Void = { _ in }, + currentUploadTask: @escaping (_ task: Task<(account: String, file: NKFile?, error: NKError), Never>?) -> Void = { _ in }) + async -> NKError { var finalError: NKError = .success var session = session let ocId = metadata.ocIdTransfer @@ -157,7 +162,15 @@ class NCNetworkingE2EEUpload: NSObject { // UPLOAD // - let resultsSendFile = await sendFile(metadata: metadata, e2eToken: e2eToken, controller: controller, tokenBanner: tokenBanner) + let resultsSendFile = await sendFile(metadata: metadata, + e2eToken: e2eToken, + controller: controller, + stageBanner: stageBanner, + tokenBanner: tokenBanner) { request in + requestHandle(request) + } currentUploadTask: { task in + currentUploadTask(task) + } // UNLOCK // @@ -204,14 +217,21 @@ class NCNetworkingE2EEUpload: NSObject { } @MainActor - private func sendFile(metadata: tableMetadata, e2eToken: String, controller: UIViewController?, tokenBanner: Int) async -> (ocId: String?, etag: String?, date: Date?, error: NKError) { + private func sendFile(metadata: tableMetadata, + e2eToken: String, + controller: UIViewController?, + stageBanner: LucidBanner.Stage?, + tokenBanner: Int, + requestHandle: @escaping (_ request: UploadRequest) -> Void = { _ in }, + currentUploadTask: @escaping (_ task: Task<(account: String, file: NKFile?, error: NKError), Never>?) -> Void = { _ in }) + async -> (ocId: String?, etag: String?, date: Date?, error: NKError) { if metadata.chunk > 0 { LucidBanner.shared.update( title: NSLocalizedString("_wait_file_preparation_", comment: ""), systemImage: "gearshape.arrow.triangle.2.circlepath", imageAnimation: .rotate, progress: 0, - stage: .init(rawValue: "button"), + stage: stageBanner, for: tokenBanner) let task = Task { () -> (account: String, file: NKFile?, error: NKError) in @@ -246,7 +266,7 @@ class NCNetworkingE2EEUpload: NSObject { return results } - currentUploadTask = task + currentUploadTask(task) let results = await task.value LucidBanner.shared.dismiss() @@ -258,7 +278,7 @@ class NCNetworkingE2EEUpload: NSObject { systemImage: "arrowshape.up.circle", imageAnimation: .breathe, progress: 0, - stage: .init(rawValue: "button"), + stage: stageBanner, for: tokenBanner) let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, @@ -272,7 +292,7 @@ class NCNetworkingE2EEUpload: NSObject { creationDate: metadata.creationDate as Date, dateModificationFile: metadata.date as Date, customHeaders: ["e2e-token": e2eToken]) { request in - self.request = request + requestHandle(request) } progressHandler: { _, _, fractionCompleted in Task {@MainActor in LucidBanner.shared.update(progress: fractionCompleted, for: tokenBanner) diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 2ce28d465c..4db54260ca 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -358,16 +358,33 @@ actor NCNetworkingProcess { // UPLOAD E2EE // if metadata.isDirectoryE2EE { + var currentUploadTask: Task<(account: String, file: NKFile?, error: NKError), Never>? + var request: UploadRequest? let controller = await getController(account: metadata.account, sceneIdentifier: metadata.sceneIdentifier) let scene = await SceneManager.shared.getWindow(sceneIdentifier: metadata.sceneIdentifier)?.windowScene + let token = await showUploadBanner(scene: scene, vPosition: .bottom, verticalMargin: 55, blocksTouches: true, - draggable: true) + onButtonTap: { + if let currentUploadTask { + currentUploadTask.cancel() + } + if let request { + request.cancel() + } + }) + await NCNetworkingE2EEUpload().upload(metadata: metadata, controller: controller, - tokenBanner: token) + stageBanner: .init(rawValue: "button"), + tokenBanner: token) { uploadRequest in + request = uploadRequest + } currentUploadTask: { task in + currentUploadTask = task + } + // UPLOAD CHUNK // } else if metadata.chunk > 0 { From b1a5ee7a6d07c4e5e5af88b9270f1a018d7abc16 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Mon, 8 Dec 2025 16:47:21 +0100 Subject: [PATCH 04/14] cod Signed-off-by: Marino Faggiana --- .../GUI/Lucid Banner/UploadBannerView.swift | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift index 6975dff3af..63b986ca58 100644 --- a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift @@ -111,19 +111,21 @@ struct UploadBannerView: View { .tint(.accentColor) .opacity(state.progress == nil ? 0 : 1) .animation(.easeInOut(duration: 0.2), value: state.progress == nil) - .padding() if isButton { - Button("_cancel_") { - onButtonTap?() + VStack { + Button("_cancel_") { + onButtonTap?() + } + .buttonStyle(.plain) + .padding(.horizontal, 20) + .padding(.vertical, 10) + .background( + Capsule() + .stroke(.primary.opacity(0.2), lineWidth: 1) + ) } - .buttonStyle(.plain) - .padding(.horizontal, 20) - .padding(.vertical, 10) - .background( - Capsule() - .stroke(.primary.opacity(0.2), lineWidth: 1) - ) + .padding(20) } } .padding(.horizontal, 12) @@ -249,7 +251,6 @@ func showUploadBanner(scene: UIWindowScene?, state: LucidBannerState( title: "Downloading …", subtitle: "Keep application active until the transfers are completed …", - footnote: "Touch for cancel", systemImage: "gearshape.arrow.triangle.2.circlepath", imageAnimation: .rotate, progress: 0.4, From c6e4507cbfc6265bfaaad27b9be80a991902877f Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 9 Dec 2025 09:23:27 +0100 Subject: [PATCH 05/14] cod Signed-off-by: Marino Faggiana --- Share/NCShareExtension.swift | 2 +- iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift | 5 ----- iOSClient/Networking/NCNetworkingProcess.swift | 2 ++ 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Share/NCShareExtension.swift b/Share/NCShareExtension.swift index 32c8af32f1..3ee37a5469 100644 --- a/Share/NCShareExtension.swift +++ b/Share/NCShareExtension.swift @@ -364,7 +364,7 @@ extension NCShareExtension { @MainActor func uploadAndExit() async { var error: NKError? - token = showUploadBanner(scene: self.view.window?.windowScene) + token = showUploadBanner(scene: self.view.window?.windowScene, blocksTouches: true) for metadata in self.uploadMetadata { // BANNER diff --git a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift index 75b0f84679..0c087dc984 100644 --- a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift +++ b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift @@ -45,7 +45,6 @@ class NCNetworkingE2EEUpload: NSObject { await self.database.deleteMetadataAsync(id: ocId) } } - LucidBanner.shared.dismiss() } LucidBanner.shared.update( @@ -269,8 +268,6 @@ class NCNetworkingE2EEUpload: NSObject { currentUploadTask(task) let results = await task.value - LucidBanner.shared.dismiss() - return (results.file?.ocId, results.file?.etag, results.file?.date, results.error) } else { LucidBanner.shared.update( @@ -299,8 +296,6 @@ class NCNetworkingE2EEUpload: NSObject { } } - LucidBanner.shared.dismiss() - return (results.ocId, results.etag, results.date, results.error) } } diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 4db54260ca..40f9adcecc 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -385,6 +385,8 @@ actor NCNetworkingProcess { currentUploadTask = task } + await LucidBanner.shared.dismiss() + // UPLOAD CHUNK // } else if metadata.chunk > 0 { From f9ccc42913405f9ff8da045319c2cd670f358520 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 9 Dec 2025 10:36:42 +0100 Subject: [PATCH 06/14] code Signed-off-by: Marino Faggiana --- iOSClient/GUI/Lucid Banner/UploadBannerView.swift | 2 +- iOSClient/Networking/NCNetworkingProcess.swift | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift index 63b986ca58..c738bec85d 100644 --- a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift @@ -125,7 +125,7 @@ struct UploadBannerView: View { .stroke(.primary.opacity(0.2), lineWidth: 1) ) } - .padding(20) + .padding(15) } } .padding(.horizontal, 12) diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 40f9adcecc..53c19be13a 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -385,7 +385,8 @@ actor NCNetworkingProcess { currentUploadTask = task } - await LucidBanner.shared.dismiss() + // wait dismiss banner before open another (loop) + await LucidBanner.shared.dismissAsync() // UPLOAD CHUNK // From 60f016345fc695f1e28db4f605eca1f6a977e7dc Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 9 Dec 2025 10:48:41 +0100 Subject: [PATCH 07/14] code Signed-off-by: Marino Faggiana --- iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift | 1 + iOSClient/Networking/NCNetworkingProcess.swift | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift index 0c087dc984..f8af7e2879 100644 --- a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift +++ b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift @@ -259,6 +259,7 @@ class NCNetworkingE2EEUpload: NSObject { systemImage: "gearshape.arrow.triangle.2.circlepath", imageAnimation: .rotate, progress: 0, + stage: .none, for: tokenBanner) } } diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 53c19be13a..8a3db79070 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -452,10 +452,9 @@ actor NCNetworkingProcess { Task {@MainActor in LucidBanner.shared.update( title: NSLocalizedString("_finalizing_wait_", comment: ""), - footnote: "", - systemImage: "tray.and.arrow.down", - imageAnimation: .pulsebyLayer, - progress: 0, + systemImage: "gearshape.arrow.triangle.2.circlepath", + imageAnimation: .rotate, + stage: .init(rawValue: "none"), for: token) } } From 14ee94bd0814bcb9d41ac948d96d7bc854a830a0 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 9 Dec 2025 15:17:53 +0100 Subject: [PATCH 08/14] removed JGProgressHUD Signed-off-by: Marino Faggiana --- iOSClient/GUI/NCHud.swift | 166 -------------------------------------- 1 file changed, 166 deletions(-) delete mode 100644 iOSClient/GUI/NCHud.swift diff --git a/iOSClient/GUI/NCHud.swift b/iOSClient/GUI/NCHud.swift deleted file mode 100644 index ec2ac7ff01..0000000000 --- a/iOSClient/GUI/NCHud.swift +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-FileCopyrightText: Nextcloud GmbH -// SPDX-FileCopyrightText: 2024 Marino Faggiana -// SPDX-License-Identifier: GPL-3.0-or-later - -import Foundation -import UIKit -import JGProgressHUD - -class NCHud: NSObject { - private let hud = JGProgressHUD() - private var view: UIView? - - public init(_ view: UIView? = nil) { - if let view { - self.view = view - } - super.init() - } - - func indeterminateProgress(view: UIView? = nil, text: String? = nil, detailText: String? = nil) { - DispatchQueue.main.async { - if let view { - self.view = view - } - - self.hud.textLabel.text = text - self.hud.textLabel.textColor = NCBrandColor.shared.iconImageColor - - self.hud.detailTextLabel.text = detailText - self.hud.detailTextLabel.textColor = NCBrandColor.shared.iconImageColor2 - - if let view = self.view { - self.hud.show(in: view) - } - } - } - - func ringProgress(view: UIView? = nil, text: String? = nil, detailText: String? = nil, tapToCancelDetailText: Bool = false, tapOperation: (() -> Void)? = nil) { - DispatchQueue.main.async { - self.hud.tapOnHUDViewBlock = { hud in - if let tapOperation { - tapOperation() - hud.dismiss() - } - } - - if let view { - self.view = view - } - - self.hud.indicatorView = JGProgressHUDRingIndicatorView() - self.hud.progress = 0.0 - - let indicatorView = self.hud.indicatorView as? JGProgressHUDRingIndicatorView - indicatorView?.ringWidth = 1.5 - indicatorView?.ringColor = NCBrandColor.shared.iconImageColor - - self.hud.textLabel.text = text - self.hud.textLabel.textColor = NCBrandColor.shared.iconImageColor - - if tapToCancelDetailText { - self.hud.detailTextLabel.text = NSLocalizedString("_tap_to_cancel_", comment: "") - } else { - self.hud.detailTextLabel.text = detailText - } - self.hud.detailTextLabel.textColor = NCBrandColor.shared.iconImageColor2 - - if let view = self.view { - self.hud.show(in: view) - } - } - } - - func pieProgress(view: UIView? = nil, text: String? = nil, detailText: String? = nil, tapToCancelDetailText: Bool = false, tapOperation: (() -> Void)? = nil) { - DispatchQueue.main.async { - self.hud.tapOnHUDViewBlock = { hud in - if let tapOperation { - tapOperation() - hud.dismiss() - } - } - - if let view { - self.view = view - } - - self.hud.indicatorView = JGProgressHUDPieIndicatorView() - self.hud.progress = 0.0 - - let indicatorView = self.hud.indicatorView as? JGProgressHUDRingIndicatorView - indicatorView?.ringWidth = 1.5 - indicatorView?.ringColor = NCBrandColor.shared.iconImageColor - - self.hud.textLabel.text = text - self.hud.textLabel.textColor = NCBrandColor.shared.iconImageColor - - if tapToCancelDetailText { - self.hud.detailTextLabel.text = NSLocalizedString("_tap_to_cancel_", comment: "") - } else { - self.hud.detailTextLabel.text = detailText - } - self.hud.detailTextLabel.textColor = NCBrandColor.shared.iconImageColor2 - - if let view = self.view { - self.hud.show(in: view) - } - } - } - - func dismiss() { - DispatchQueue.main.async { - self.hud.dismiss() - } - } - - func show() { - DispatchQueue.main.async { - if let view = self.view { - self.hud.show(in: view) - } - } - } - - func progress(num: Float, total: Float) { - DispatchQueue.main.async { - self.hud.progress = num / total - } - } - - func progress(_ progress: Double) { - DispatchQueue.main.async { - self.hud.progress = Float(progress) - } - } - - func success() { - DispatchQueue.main.async { - self.hud.indicatorView = JGProgressHUDSuccessIndicatorView() - self.hud.indicatorView?.tintColor = .green - self.hud.textLabel.text = NSLocalizedString("_success_", comment: "") - self.hud.detailTextLabel.text = nil - self.hud.dismiss(afterDelay: 1.0) - } - } - - func error(text: String?) { - DispatchQueue.main.async { - self.hud.indicatorView = JGProgressHUDErrorIndicatorView() - self.hud.indicatorView?.tintColor = .red - self.hud.textLabel.text = text - self.hud.dismiss(afterDelay: 2.0) - } - } - - func setText(_ text: String?) { - DispatchQueue.main.async { - self.hud.textLabel.text = text - } - } - - func setDetailText(_ detailText: String) { - DispatchQueue.main.async { - self.hud.detailTextLabel.text = detailText - } - } -} From d692d7631f2caacd5ea2a7a42231e75be4f75a40 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 9 Dec 2025 15:18:05 +0100 Subject: [PATCH 09/14] JGProgressHUD Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 55 ------------------- iOSClient/Settings/Acknowledgements.rtf | 13 +---- .../NCPlayer/NCPlayerToolBar.swift | 27 +++++---- 3 files changed, 19 insertions(+), 76 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 82e3b83219..37ac1a48f7 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -101,10 +101,8 @@ F33918C42C7CD8F2002D9AA1 /* FileNameValidator+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33918C32C7CD8F2002D9AA1 /* FileNameValidator+Extensions.swift */; }; F33918C72C7CD8F2002D9AA1 /* FileNameValidator+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33918C32C7CD8F2002D9AA1 /* FileNameValidator+Extensions.swift */; }; F3391B082B4C52C5001C0C4B /* FirebaseDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B072B4C52C5001C0C4B /* FirebaseDatabase */; }; - F3391B0A2B4C52CB001C0C4B /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B092B4C52CB001C0C4B /* JGProgressHUD */; }; F3391B0C2B4C52D5001C0C4B /* SVGKit in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B0B2B4C52D5001C0C4B /* SVGKit */; }; F3391B102B4C52E6001C0C4B /* SVGKit in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B0F2B4C52E6001C0C4B /* SVGKit */; }; - F3391B142B4C52EF001C0C4B /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B132B4C52EF001C0C4B /* JGProgressHUD */; }; F3391B162B4C52F6001C0C4B /* FirebaseDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B152B4C52F6001C0C4B /* FirebaseDatabase */; }; F33D303E2D8B129600531D64 /* AutoUploadUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33D303D2D8B129600531D64 /* AutoUploadUITests.swift */; }; F33EE6E12BF4BDA500CA1A51 /* NIOSSL in Frameworks */ = {isa = PBXBuildFile; productRef = F33EE6E02BF4BDA500CA1A51 /* NIOSSL */; }; @@ -297,7 +295,6 @@ F72AD70F28C24BA1006CB92D /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = F72AD70E28C24BA1006CB92D /* NextcloudKit */; }; F72AD71128C24BBB006CB92D /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = F72AD71028C24BBB006CB92D /* NextcloudKit */; }; F72AD71328C24BCC006CB92D /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = F72AD71228C24BCC006CB92D /* NextcloudKit */; }; - F72CD01227A7E92400E59476 /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F72CD01127A7E92400E59476 /* JGProgressHUD */; }; F72CD63A25C19EBF00F46F9A /* NCAutoUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72CD63925C19EBF00F46F9A /* NCAutoUpload.swift */; }; F72D1007210B6882009C96B7 /* NCPushNotificationEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = F72D1005210B6882009C96B7 /* NCPushNotificationEncryption.m */; }; F72D404923D2082500A97FD0 /* NCViewerNextcloudText.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72D404823D2082500A97FD0 /* NCViewerNextcloudText.swift */; }; @@ -408,7 +405,6 @@ F751247C2C42919C00E63DB8 /* NCPhotoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F751247A2C42919C00E63DB8 /* NCPhotoCell.swift */; }; F751247E2C42919C00E63DB8 /* NCPhotoCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F751247B2C42919C00E63DB8 /* NCPhotoCell.xib */; }; F752BA052E58C05200616A26 /* Maintenance.swift in Sources */ = {isa = PBXBuildFile; fileRef = F752BA042E58C05200616A26 /* Maintenance.swift */; }; - F75379222AE2ADA100C0250E /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F75379212AE2ADA100C0250E /* JGProgressHUD */; }; F753BA93281FD8020015BFB6 /* EasyTipView in Frameworks */ = {isa = PBXBuildFile; productRef = F753BA92281FD8020015BFB6 /* EasyTipView */; }; F755BD9B20594AC7008C5FBB /* NCService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F755BD9A20594AC7008C5FBB /* NCService.swift */; }; F755CB402B8CB13C00CE27E9 /* NCMediaLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = F755CB3F2B8CB13C00CE27E9 /* NCMediaLayout.swift */; }; @@ -419,7 +415,6 @@ F757CC8829E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift in Sources */ = {isa = PBXBuildFile; fileRef = F757CC8129E7F88B00F31428 /* NCManageDatabase+Groupfolders.swift */; }; F757CC8C29E82D0500F31428 /* NCGroupfolders.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F757CC8A29E82D0500F31428 /* NCGroupfolders.storyboard */; }; F757CC8D29E82D0500F31428 /* NCGroupfolders.swift in Sources */ = {isa = PBXBuildFile; fileRef = F757CC8B29E82D0500F31428 /* NCGroupfolders.swift */; }; - F758A01227A7F03E0069468B /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F758A01127A7F03E0069468B /* JGProgressHUD */; }; F758B45A212C564000515F55 /* NCScan.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F758B457212C564000515F55 /* NCScan.storyboard */; }; F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F758B45D212C569C00515F55 /* NCScanCell.swift */; }; F758B460212C56A400515F55 /* NCScan.swift in Sources */ = {isa = PBXBuildFile; fileRef = F758B45F212C56A400515F55 /* NCScan.swift */; }; @@ -732,8 +727,6 @@ F7BF9D842934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BF9D812934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift */; }; F7BF9D852934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BF9D812934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift */; }; F7BF9D872934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BF9D812934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift */; }; - F7BFFD282C8846020029A201 /* NCHud.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BFFD272C8846020029A201 /* NCHud.swift */; }; - F7BFFD2A2C8854200029A201 /* NCHud.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BFFD272C8846020029A201 /* NCHud.swift */; }; F7C1EEA525053A9C00866ACC /* NCCollectionViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C1EEA425053A9C00866ACC /* NCCollectionViewDataSource.swift */; }; F7C30DF6291BC0CA0017149B /* NCNetworkingE2EEUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C30DF5291BC0CA0017149B /* NCNetworkingE2EEUpload.swift */; }; F7C30DF7291BC0D30017149B /* NCNetworkingE2EEUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C30DF5291BC0CA0017149B /* NCNetworkingE2EEUpload.swift */; }; @@ -1682,7 +1675,6 @@ F7BE7C79290ADF16002ABB61 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Intent.strings"; sourceTree = ""; }; F7BE7C7B290ADF16002ABB61 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/Intent.strings"; sourceTree = ""; }; F7BF9D812934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+LayoutForView.swift"; sourceTree = ""; }; - F7BFFD272C8846020029A201 /* NCHud.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCHud.swift; sourceTree = ""; }; F7C1EEA425053A9C00866ACC /* NCCollectionViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCollectionViewDataSource.swift; sourceTree = ""; }; F7C30DF5291BC0CA0017149B /* NCNetworkingE2EEUpload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingE2EEUpload.swift; sourceTree = ""; }; F7C30DF9291BCF790017149B /* NCNetworkingE2EECreateFolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingE2EECreateFolder.swift; sourceTree = ""; }; @@ -1843,7 +1835,6 @@ F37208C22BAB63F0006B5430 /* TagListView in Frameworks */, F3391B162B4C52F6001C0C4B /* FirebaseDatabase in Frameworks */, F37208B62BAB63EF006B5430 /* EasyTipView in Frameworks */, - F3391B142B4C52EF001C0C4B /* JGProgressHUD in Frameworks */, F37208BA2BAB63EF006B5430 /* TLPhotoPicker in Frameworks */, F37208AA2BAB63EE006B5430 /* MarkdownKit in Frameworks */, F3391B102B4C52E6001C0C4B /* SVGKit in Frameworks */, @@ -1866,7 +1857,6 @@ files = ( F3F0419D2B9F7E6E00D5155F /* RealmSwift in Frameworks */, F3391B082B4C52C5001C0C4B /* FirebaseDatabase in Frameworks */, - F3391B0A2B4C52CB001C0C4B /* JGProgressHUD in Frameworks */, F3391B0C2B4C52D5001C0C4B /* SVGKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1892,7 +1882,6 @@ F7B8F6182EAB7516006A70D6 /* JDStatusBarNotification in Frameworks */, F72AD70F28C24BA1006CB92D /* NextcloudKit in Frameworks */, F33EE6E72BF4C02600CA1A51 /* NIOSSL in Frameworks */, - F72CD01227A7E92400E59476 /* JGProgressHUD in Frameworks */, F77CB6A92AA08053000C3CA4 /* OpenSSL in Frameworks */, F760DE092AE66ED00027D78A /* KeychainAccess in Frameworks */, F73ADD2126554F8E0069EA0D /* SwiftEntryKit in Frameworks */, @@ -1915,7 +1904,6 @@ F7A560462AE15D3D00BE8FD6 /* Queuer in Frameworks */, F7B8F6162EAB7503006A70D6 /* JDStatusBarNotification in Frameworks */, F783030D28B4C59A00B84583 /* SwiftEntryKit in Frameworks */, - F75379222AE2ADA100C0250E /* JGProgressHUD in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1950,7 +1938,6 @@ F3A0479E2BD268B500658E7B /* PopupView in Frameworks */, F3374AF82D78B01B002A38F9 /* HeapModule in Frameworks */, F770768E263A8C3400A1BA94 /* FloatingPanel in Frameworks */, - F758A01227A7F03E0069468B /* JGProgressHUD in Frameworks */, F77333882927A72100466E35 /* OpenSSL in Frameworks */, F753BA93281FD8020015BFB6 /* EasyTipView in Frameworks */, F70557B72ED44E2700135623 /* LucidBanner in Frameworks */, @@ -2631,7 +2618,6 @@ F769CA182966EA3C00039397 /* ComponentView.swift */, F768823D2C0DD304001CF441 /* LazyView.swift */, F768823F2C0DD30B001CF441 /* ViewOnAppear.swift */, - F7BFFD272C8846020029A201 /* NCHud.swift */, F75CA1462962F13700B01130 /* NCHUDView.swift */, ); path = GUI; @@ -3421,7 +3407,6 @@ name = NextcloudUITests; packageProductDependencies = ( F3391B0F2B4C52E6001C0C4B /* SVGKit */, - F3391B132B4C52EF001C0C4B /* JGProgressHUD */, F3391B152B4C52F6001C0C4B /* FirebaseDatabase */, F3F0419E2B9F7E7900D5155F /* RealmSwift */, F37208A32BAB63EE006B5430 /* QRCodeReader */, @@ -3465,7 +3450,6 @@ name = NextcloudIntegrationTests; packageProductDependencies = ( F3391B072B4C52C5001C0C4B /* FirebaseDatabase */, - F3391B092B4C52CB001C0C4B /* JGProgressHUD */, F3391B0B2B4C52D5001C0C4B /* SVGKit */, F3F0419C2B9F7E6E00D5155F /* RealmSwift */, ); @@ -3514,7 +3498,6 @@ F72D7EB6263B1207000B3DFC /* MarkdownKit */, F73ADD2026554F8E0069EA0D /* SwiftEntryKit */, F710FC7F277B7D2700AA9FBF /* RealmSwift */, - F72CD01127A7E92400E59476 /* JGProgressHUD */, F72AD70E28C24BA1006CB92D /* NextcloudKit */, F70821D729E59E6D001CA2D7 /* TagListView */, F7F623B62A5EFA0C0022D3D4 /* Gzip */, @@ -3550,7 +3533,6 @@ F783034328B5142B00B84583 /* NextcloudKit */, F787AC0A298BCB540001BB00 /* SVGKitSwift */, F7A560452AE15D3D00BE8FD6 /* Queuer */, - F75379212AE2ADA100C0250E /* JGProgressHUD */, F760DE042AE66EBE0027D78A /* KeychainAccess */, F7160A7C2BE931DE0034DCB3 /* RealmSwift */, F33EE6E22BF4C00700CA1A51 /* NIOSSL */, @@ -3616,7 +3598,6 @@ F76DA962277B760E0082465B /* Queuer */, F76DA968277B77EA0082465B /* DropDown */, F7BB7E4627A18C56009B9F29 /* Parchment */, - F758A01127A7F03E0069468B /* JGProgressHUD */, F753BA92281FD8020015BFB6 /* EasyTipView */, F72AD70C28C24B93006CB92D /* NextcloudKit */, F734B06528E75C0100E180D5 /* TLPhotoPicker */, @@ -3807,7 +3788,6 @@ F76DA967277B77E90082465B /* XCRemoteSwiftPackageReference "DropDown" */, F710FC78277B7CFF00AA9FBF /* XCRemoteSwiftPackageReference "realm-swift" */, F7BB7E4527A18C56009B9F29 /* XCRemoteSwiftPackageReference "Parchment" */, - F72CD01027A7E92400E59476 /* XCRemoteSwiftPackageReference "JGProgressHUD" */, F753BA91281FD8010015BFB6 /* XCRemoteSwiftPackageReference "EasyTipView" */, F783034028B511D200B84583 /* XCRemoteSwiftPackageReference "NextcloudKit" */, F734B06428E75C0100E180D5 /* XCRemoteSwiftPackageReference "TLPhotoPicker" */, @@ -4288,7 +4268,6 @@ F73EF7E22B02266D0087E6E9 /* NCManageDatabase+Trash.swift in Sources */, F77DD6AB2C5CC093009448FB /* NCSession.swift in Sources */, F76D364728A4F8BF00214537 /* NCActivityIndicator.swift in Sources */, - F7BFFD2A2C8854200029A201 /* NCHud.swift in Sources */, F749B654297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */, AF22B208277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.swift in Sources */, F73EF7C22B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */, @@ -4427,7 +4406,6 @@ 370D26AF248A3D7A00121797 /* NCCellProtocol.swift in Sources */, F32FADA92D1176E3007035E2 /* UIButton+Extension.swift in Sources */, F768822C2C0DD1E7001CF441 /* NCPreferences.swift in Sources */, - F7BFFD282C8846020029A201 /* NCHud.swift in Sources */, F71CD6CA2930D7B1006C95C1 /* NCApplicationHandle.swift in Sources */, F3754A7D2CF87D600009312E /* SetupPasscodeView.swift in Sources */, F73EF7D72B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */, @@ -6017,14 +5995,6 @@ version = 10.54.6; }; }; - F72CD01027A7E92400E59476 /* XCRemoteSwiftPackageReference "JGProgressHUD" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/JonasGessner/JGProgressHUD.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.0; - }; - }; F72DA9B225F53E4E00B87DB1 /* XCRemoteSwiftPackageReference "SwiftRichString" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/malcommac/SwiftRichString"; @@ -6234,11 +6204,6 @@ package = F70B86732642CE3B00ED5349 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseDatabase; }; - F3391B092B4C52CB001C0C4B /* JGProgressHUD */ = { - isa = XCSwiftPackageProductDependency; - package = F72CD01027A7E92400E59476 /* XCRemoteSwiftPackageReference "JGProgressHUD" */; - productName = JGProgressHUD; - }; F3391B0B2B4C52D5001C0C4B /* SVGKit */ = { isa = XCSwiftPackageProductDependency; package = F75E57A725BF0D61002B72C2 /* XCRemoteSwiftPackageReference "SVGKit" */; @@ -6249,11 +6214,6 @@ package = F75E57A725BF0D61002B72C2 /* XCRemoteSwiftPackageReference "SVGKit" */; productName = SVGKit; }; - F3391B132B4C52EF001C0C4B /* JGProgressHUD */ = { - isa = XCSwiftPackageProductDependency; - package = F72CD01027A7E92400E59476 /* XCRemoteSwiftPackageReference "JGProgressHUD" */; - productName = JGProgressHUD; - }; F3391B152B4C52F6001C0C4B /* FirebaseDatabase */ = { isa = XCSwiftPackageProductDependency; package = F70B86732642CE3B00ED5349 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; @@ -6474,11 +6434,6 @@ package = F783034028B511D200B84583 /* XCRemoteSwiftPackageReference "NextcloudKit" */; productName = NextcloudKit; }; - F72CD01127A7E92400E59476 /* JGProgressHUD */ = { - isa = XCSwiftPackageProductDependency; - package = F72CD01027A7E92400E59476 /* XCRemoteSwiftPackageReference "JGProgressHUD" */; - productName = JGProgressHUD; - }; F72D7EB6263B1207000B3DFC /* MarkdownKit */ = { isa = XCSwiftPackageProductDependency; package = F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */; @@ -6519,21 +6474,11 @@ package = F76B649A2ADFFAD200014640 /* XCRemoteSwiftPackageReference "LRUCache" */; productName = LRUCache; }; - F75379212AE2ADA100C0250E /* JGProgressHUD */ = { - isa = XCSwiftPackageProductDependency; - package = F72CD01027A7E92400E59476 /* XCRemoteSwiftPackageReference "JGProgressHUD" */; - productName = JGProgressHUD; - }; F753BA92281FD8020015BFB6 /* EasyTipView */ = { isa = XCSwiftPackageProductDependency; package = F753BA91281FD8010015BFB6 /* XCRemoteSwiftPackageReference "EasyTipView" */; productName = EasyTipView; }; - F758A01127A7F03E0069468B /* JGProgressHUD */ = { - isa = XCSwiftPackageProductDependency; - package = F72CD01027A7E92400E59476 /* XCRemoteSwiftPackageReference "JGProgressHUD" */; - productName = JGProgressHUD; - }; F75EAED726D2552E00F4320E /* MarqueeLabel */ = { isa = XCSwiftPackageProductDependency; package = F75EAED626D2552E00F4320E /* XCRemoteSwiftPackageReference "MarqueeLabel" */; diff --git a/iOSClient/Settings/Acknowledgements.rtf b/iOSClient/Settings/Acknowledgements.rtf index e3140d165b..65cecead34 100644 --- a/iOSClient/Settings/Acknowledgements.rtf +++ b/iOSClient/Settings/Acknowledgements.rtf @@ -1,8 +1,8 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2865 +{\rtf1\ansi\ansicpg1252\cocoartf2867 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} -\margl1440\margr1440\vieww25280\viewh28800\viewkind0 +\paperw12240\paperh15840\margl1440\margr1440\vieww25280\viewh28800\viewkind0 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 \f0\fs24 \cf0 \ @@ -196,15 +196,6 @@ Copyright (c) Tim Oliver\ __________________________________\ \ -\f1\b JGProgressHUD -\f0\b0 \ -\ -MIT License\ -\ -Copyright (c) Jonas Gessner\ -__________________________________\ -\ - \f1\b JDStatusBarNotification \f0\b0 \ \ diff --git a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift index fe5618c073..6955dc6f16 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift @@ -11,6 +11,7 @@ import MediaPlayer import MobileVLCKit import FloatingPanel import Alamofire +import LucidBanner class NCPlayerToolBar: UIView { @IBOutlet weak var utilityView: UIView! @@ -38,7 +39,6 @@ class NCPlayerToolBar: UIView { var isFullscreen: Bool = false var playRepeat: Bool = false - private let hud = NCHud() private var ncplayer: NCPlayer? private var metadata: tableMetadata? private let audioSession = AVAudioSession.sharedInstance() @@ -431,12 +431,14 @@ extension NCPlayerToolBar: NCSelectDelegate { func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool, session: NCSession.Session) { if let metadata = metadata, let viewerMediaPage = viewerMediaPage { let fileNameLocalPath = NCUtilityFileSystem().getDirectoryProviderStorageOcId(metadata.ocId, fileName: metadata.fileNameView, userId: metadata.userId, urlBase: metadata.urlBase) + let scene = SceneManager.shared.getWindow(controller: viewerMediaPage.tabBarController)?.windowScene if utilityFileSystem.fileProviderStorageExists(metadata) { addPlaybackSlave(type: type, metadata: metadata) } else { var downloadRequest: DownloadRequest? - hud.ringProgress(view: viewerMediaPage.view, text: NSLocalizedString("_downloading_", comment: ""), tapToCancelDetailText: true) { + let token = showHudBanner(scene: scene, + title: NSLocalizedString("_downloading_", comment: "")) { _, _ in if let request = downloadRequest { request.cancel() } @@ -457,10 +459,13 @@ extension NCPlayerToolBar: NCSelectDelegate { status: self.global.metadataStatusDownloading) } }, progressHandler: { progress in - self.hud.progress(progress.fractionCompleted) + Task {@MainActor in + LucidBanner.shared.update(progress: Double(progress.fractionCompleted), for: token) + } }) { _, etag, _, _, _, _, error in - self.hud.dismiss() Task { + LucidBanner.shared.dismiss() + let ocId = metadata.ocId await self.database.setMetadataSessionAsync(ocId: ocId, session: "", @@ -468,12 +473,14 @@ extension NCPlayerToolBar: NCSelectDelegate { sessionError: "", status: self.global.metadataStatusNormal, etag: etag) - } - if error == .success { - self.hud.success() - self.addPlaybackSlave(type: type, metadata: metadata) - } else if error.errorCode != 200 { - self.hud.error(text: error.errorDescription) + + if error == .success { + self.addPlaybackSlave(type: type, metadata: metadata) + } else if error.errorCode != 200 { + await showErrorBanner(scene: scene, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } } } From d3ac169d3094f614978f2a3c656cc3bff65f69c4 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Tue, 9 Dec 2025 16:08:48 +0100 Subject: [PATCH 10/14] showErrorBanner Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 4 -- iOSClient/Activity/NCActivity.swift | 24 +++++++++-- .../Activity/NCActivityTableViewCell.swift | 6 ++- iOSClient/Files/NCFiles.swift | 22 ++++++++-- .../GUI/Lucid Banner/ErrorBannerView.swift | 10 +++++ .../GUI/Lucid Banner/HudBannerView.swift | 14 +++---- .../NCCollectionViewCommon.swift | 10 ++++- iOSClient/Main/Create/NCCreate.swift | 18 ++++++++- iOSClient/Main/NCDragDrop.swift | 9 ++++- iOSClient/Main/NCPickerViewController.swift | 18 +++++++-- .../NCNetworking+TransferDelegate.swift | 40 +++++++++++++++---- .../NCPlayer/NCPlayerToolBar.swift | 2 +- 12 files changed, 141 insertions(+), 36 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 37ac1a48f7..d6e88b5da0 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -206,7 +206,6 @@ F70557BD2ED44F1800135623 /* UploadBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70557BB2ED44F1800135623 /* UploadBannerView.swift */; }; F70557BE2ED44F1800135623 /* ErrorBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70557BA2ED44F1800135623 /* ErrorBannerView.swift */; }; F70557BF2ED44F1800135623 /* UploadBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70557BB2ED44F1800135623 /* UploadBannerView.swift */; }; - F70557C02ED44F1800135623 /* ErrorBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70557BA2ED44F1800135623 /* ErrorBannerView.swift */; }; F70716E62987F81500E72C1D /* DocumentActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70716E52987F81500E72C1D /* DocumentActionViewController.swift */; }; F70716ED2987F81500E72C1D /* File Provider Extension UI.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = F70716E32987F81500E72C1D /* File Provider Extension UI.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; F70753EB2542A99800972D44 /* NCViewerMediaPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70753EA2542A99800972D44 /* NCViewerMediaPage.swift */; }; @@ -249,7 +248,6 @@ F7148054262ED51000693E51 /* NCListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD4321903CF20088454D /* NCListCell.xib */; }; F714805E262ED52900693E51 /* NCSectionFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD53219047D40088454D /* NCSectionFooter.xib */; }; F714A1472ED84AF90050A43B /* HudBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F714A1462ED84AF00050A43B /* HudBannerView.swift */; }; - F714A1482ED84AF90050A43B /* HudBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F714A1462ED84AF00050A43B /* HudBannerView.swift */; }; F7160A7D2BE931DE0034DCB3 /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F7160A7C2BE931DE0034DCB3 /* RealmSwift */; }; F7160A822BE933390034DCB3 /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F7160A812BE933390034DCB3 /* RealmSwift */; }; F717402D24F699A5000C87D5 /* NCFavorite.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F717402B24F699A5000C87D5 /* NCFavorite.storyboard */; }; @@ -4167,7 +4165,6 @@ F7C30DFB291BCF790017149B /* NCNetworkingE2EECreateFolder.swift in Sources */, F73EF7DA2B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */, F70557BF2ED44F1800135623 /* UploadBannerView.swift in Sources */, - F70557C02ED44F1800135623 /* ErrorBannerView.swift in Sources */, F7817CFB29801A3500FFBC65 /* Data+Extension.swift in Sources */, F72429362AFE39860040AEF3 /* NCLivePhoto.swift in Sources */, AF4BF61F27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */, @@ -4195,7 +4192,6 @@ F798F0E225880608000DAFFD /* UIColor+Extension.swift in Sources */, F7C9B9202B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, F78E2D6829AF02DB0024D4F3 /* Database.swift in Sources */, - F714A1482ED84AF90050A43B /* HudBannerView.swift in Sources */, AA8D31562D41052300FE2775 /* NCManageDatabase+DownloadLimit.swift in Sources */, F711A4DF2AF92CAE00095DD8 /* NCUtility+Date.swift in Sources */, F78295311F962EFA00A572F5 /* NCEndToEndEncryption.m in Sources */, diff --git a/iOSClient/Activity/NCActivity.swift b/iOSClient/Activity/NCActivity.swift index 480421d897..6098a49209 100644 --- a/iOSClient/Activity/NCActivity.swift +++ b/iOSClient/Activity/NCActivity.swift @@ -83,7 +83,11 @@ class NCActivity: UIViewController, NCSharePagingContent { self.commentView?.newCommentField.text?.removeAll() self.loadComments() } else { - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner(controller: self.tabBarController, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } } } @@ -436,7 +440,11 @@ extension NCActivity { if error == .success, let comments = comments { self.database.addComments(comments, account: metadata.account, objectId: metadata.fileId) } else if error.errorCode != NCGlobal.shared.errorResourceNotFound { - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner(controller: self.tabBarController, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } if let disptachGroup = disptachGroup { @@ -574,7 +582,11 @@ extension NCActivity: NCShareCommentsCellDelegate { if error == .success { self.loadComments() } else { - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner(controller: self.tabBarController, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } } })) @@ -604,7 +616,11 @@ extension NCActivity: NCShareCommentsCellDelegate { if error == .success { self.loadComments() } else { - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner(controller: self.tabBarController, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } } } diff --git a/iOSClient/Activity/NCActivityTableViewCell.swift b/iOSClient/Activity/NCActivityTableViewCell.swift index 86edd9f793..2b0db6b02c 100644 --- a/iOSClient/Activity/NCActivityTableViewCell.swift +++ b/iOSClient/Activity/NCActivityTableViewCell.swift @@ -85,7 +85,11 @@ extension NCActivityTableViewCell: UICollectionViewDelegate { (responder as? UIViewController)!.navigationController?.pushViewController(viewController, animated: true) } else { let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_trash_file_not_found_") - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner(controller: viewController.controller, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } } } diff --git a/iOSClient/Files/NCFiles.swift b/iOSClient/Files/NCFiles.swift index 0bcf384c17..565fe12e30 100644 --- a/iOSClient/Files/NCFiles.swift +++ b/iOSClient/Files/NCFiles.swift @@ -321,11 +321,17 @@ class NCFiles: NCCollectionViewCommon { NCContentPresenter().showInfo(description: "Metadata not found") let error = await NCNetworkingE2EE().uploadMetadata(serverUrl: serverUrl, account: account) if error != .success { - NCContentPresenter().showError(error: error) + await showErrorBanner(controller: self.controller, + errorDescription: error.errorDescription, + errorCode: error.errorCode) } } else { // show error - NCContentPresenter().showError(error: results.error) + Task {@MainActor in + await showErrorBanner(controller: self.controller, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } return(metadatas, error, reloadRequired) @@ -343,14 +349,22 @@ class NCFiles: NCCollectionViewCommon { let error = await NCNetworkingE2EE().uploadMetadata(serverUrl: serverUrl, updateVersionV1V2: true, account: account) if error != .success { - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner(controller: self.controller, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } NCActivityIndicator.shared.stop() } } else { // Client Diagnostic await self.database.addDiagnosticAsync(account: account, issue: NCGlobal.shared.diagnosticIssueE2eeErrors) - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner(controller: self.controller, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } return (metadatas, error, reloadRequired) diff --git a/iOSClient/GUI/Lucid Banner/ErrorBannerView.swift b/iOSClient/GUI/Lucid Banner/ErrorBannerView.swift index 3eb2caac2c..0ade336061 100644 --- a/iOSClient/GUI/Lucid Banner/ErrorBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/ErrorBannerView.swift @@ -74,9 +74,19 @@ struct ErrorBannerView: View { // MARK: - Helper +@MainActor +func showErrorBanner(controller: UITabBarController?, errorDescription: String, errorCode: Int, sleepBefore: Double = 1) async { + let scene = SceneManager.shared.getWindow(controller: controller)?.windowScene + await showErrorBanner(scene: scene, errorDescription: errorDescription, errorCode: errorCode, sleepBefore: sleepBefore) +} + @MainActor func showErrorBanner(scene: UIWindowScene?, errorDescription: String, errorCode: Int, sleepBefore: Double = 1) async { try? await Task.sleep(nanoseconds: UInt64(sleepBefore * 1e9)) + var scene = scene + if scene == nil { + scene = UIApplication.shared.mainAppWindow?.windowScene + } LucidBanner.shared.show( scene: scene, diff --git a/iOSClient/GUI/Lucid Banner/HudBannerView.swift b/iOSClient/GUI/Lucid Banner/HudBannerView.swift index 9293095bd2..f35f7f0daf 100644 --- a/iOSClient/GUI/Lucid Banner/HudBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/HudBannerView.swift @@ -160,13 +160,13 @@ struct HudBannerView: View { // MARK: - Helper @MainActor -func showHudBanner( - scene: UIWindowScene?, - title: String? = nil, - subtitle: String? = nil, - onTap: ((_ token: Int, _ stage: String?) -> Void)? = nil -) -> Int { - LucidBanner.shared.show( +func showHudBanner(scene: UIWindowScene?, title: String? = nil, subtitle: String? = nil, onTap: ((_ token: Int, _ stage: String?) -> Void)? = nil) -> Int { + var scene = scene + if scene == nil { + scene = UIApplication.shared.mainAppWindow?.windowScene + } + + return LucidBanner.shared.show( scene: scene, title: title, subtitle: subtitle, diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index db762ea5b8..03b4ad892d 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -356,7 +356,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS Task { if error != .success, error.errorCode != global.errorResourceNotFound { - await showErrorBanner(scene: UIApplication.shared.mainAppWindow?.windowScene, + await showErrorBanner(controller: self.controller, errorDescription: error.errorDescription, errorCode: error.errorCode) } @@ -889,7 +889,13 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } completion: { _, searchResult, metadatas, error in if error != .success { - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner( + controller: self.controller, + errorDescription: error.errorDescription, + errorCode: error.errorCode + ) + } } metadataForSection.unifiedSearchInProgress = false diff --git a/iOSClient/Main/Create/NCCreate.swift b/iOSClient/Main/Create/NCCreate.swift index 0cb2fec5fb..5f812cf2c7 100644 --- a/iOSClient/Main/Create/NCCreate.swift +++ b/iOSClient/Main/Create/NCCreate.swift @@ -39,7 +39,14 @@ class NCCreate: NSObject { } } guard results.error == .success, let url = results.url else { - return NCContentPresenter().showError(error: results.error) + Task {@MainActor in + await showErrorBanner( + controller: controller, + errorDescription: results.error.errorDescription, + errorCode: results.error.errorCode + ) + } + return } let metadata = await NCManageDatabaseCreateMetadata().createMetadataAsync( fileName: fileName, @@ -63,7 +70,14 @@ class NCCreate: NSObject { } } guard results.error == .success, let url = results.url else { - return NCContentPresenter().showError(error: results.error) + Task {@MainActor in + await showErrorBanner( + controller: controller, + errorDescription: results.error.errorDescription, + errorCode: results.error.errorCode + ) + } + return } let metadata = await NCManageDatabaseCreateMetadata().createMetadataAsync( diff --git a/iOSClient/Main/NCDragDrop.swift b/iOSClient/Main/NCDragDrop.swift index e0c2421575..24f0545624 100644 --- a/iOSClient/Main/NCDragDrop.swift +++ b/iOSClient/Main/NCDragDrop.swift @@ -143,7 +143,14 @@ class NCDragDrop: NSObject { database.addMetadata(metadataForUpload) } catch { - NCContentPresenter().showError(error: NKError(error: error)) + Task {@MainActor in + let error = NKError(error: error) + await showErrorBanner( + controller: controller, + errorDescription: error.errorDescription, + errorCode: error.errorCode + ) + } return } } diff --git a/iOSClient/Main/NCPickerViewController.swift b/iOSClient/Main/NCPickerViewController.swift index 0c35c8622e..a44ccfdd8c 100644 --- a/iOSClient/Main/NCPickerViewController.swift +++ b/iOSClient/Main/NCPickerViewController.swift @@ -60,17 +60,29 @@ class NCPhotosPickerViewController: NSObject { pickerVC?.didExceedMaximumNumberOfSelection = { _ in let error = NKError(errorCode: self.global.errorInternalError, errorDescription: "_limited_dimension_") - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner(controller: self.controller, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } pickerVC?.handleNoAlbumPermissions = { _ in let error = NKError(errorCode: self.global.errorInternalError, errorDescription: "_denied_album_") - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner(controller: self.controller, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } pickerVC?.handleNoCameraPermissions = { _ in let error = NKError(errorCode: self.global.errorInternalError, errorDescription: "_denied_camera_") - NCContentPresenter().showError(error: error) + Task {@MainActor in + await showErrorBanner(controller: self.controller, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } } pickerVC?.configure = configure diff --git a/iOSClient/Networking/NCNetworking+TransferDelegate.swift b/iOSClient/Networking/NCNetworking+TransferDelegate.swift index 7d919eaca5..3a51057f66 100644 --- a/iOSClient/Networking/NCNetworking+TransferDelegate.swift +++ b/iOSClient/Networking/NCNetworking+TransferDelegate.swift @@ -48,6 +48,7 @@ extension NCNetworking: NCTransferDelegate { } } guard let controller else { return } + let scene = SceneManager.shared.getWindow(controller: controller)?.windowScene switch selector { case NCGlobal.shared.selectorLoadFileQuickLook: @@ -113,8 +114,13 @@ extension NCNetworking: NCTransferDelegate { NCAskAuthorization().askAuthorizationPhotoLibrary(controller: controller) { hasPermission in guard hasPermission else { - let error = NKError(errorCode: NCGlobal.shared.errorFileNotSaved, errorDescription: "_access_photo_not_enabled_msg_") - return NCContentPresenter().messageNotification("_access_photo_not_enabled_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error) + Task {@MainActor in + let error = NKError(errorCode: NCGlobal.shared.errorFileNotSaved, errorDescription: "_access_photo_not_enabled_msg_") + await showErrorBanner(scene: scene, + errorDescription: error.errorDescription, + errorCode: error.errorCode) + } + return } let errorSave = NKError(errorCode: NCGlobal.shared.errorFileNotSaved, errorDescription: "_file_not_saved_cameraroll_") @@ -127,7 +133,11 @@ extension NCNetworking: NCTransferDelegate { assetRequest.addResource(with: .photo, data: data, options: nil) }) { success, _ in if !success { - NCContentPresenter().messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error) + Task {@MainActor in + await showErrorBanner(scene: scene, + errorDescription: errorSave.errorDescription, + errorCode: errorSave.errorCode) + } } } } else if metadata.isVideo { @@ -135,15 +145,27 @@ extension NCNetworking: NCTransferDelegate { PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: fileNamePath)) }) { success, _ in if !success { - NCContentPresenter().messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error) + Task {@MainActor in + await showErrorBanner(scene: scene, + errorDescription: errorSave.errorDescription, + errorCode: errorSave.errorCode) + } } } } else { - NCContentPresenter().messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error) + Task {@MainActor in + await showErrorBanner(scene: scene, + errorDescription: errorSave.errorDescription, + errorCode: errorSave.errorCode) + } return } } catch { - NCContentPresenter().messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error) + Task {@MainActor in + await showErrorBanner(scene: scene, + errorDescription: errorSave.errorDescription, + errorCode: errorSave.errorCode) + } } } @@ -211,7 +233,11 @@ extension NCNetworking: NCTransferDelegate { } } guard resultsFile.error == .success, let file = resultsFile.file else { - NCContentPresenter().showError(error: resultsFile.error) + Task {@MainActor in + await showErrorBanner(controller: viewController.tabBarController, + errorDescription: resultsFile.error.errorDescription, + errorCode: resultsFile.error.errorCode) + } return } diff --git a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift index 6955dc6f16..4d044ee6e0 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift @@ -438,7 +438,7 @@ extension NCPlayerToolBar: NCSelectDelegate { } else { var downloadRequest: DownloadRequest? let token = showHudBanner(scene: scene, - title: NSLocalizedString("_downloading_", comment: "")) { _, _ in + title: NSLocalizedString("_downloading_", comment: "")) { _, _ in if let request = downloadRequest { request.cancel() } From 9469d7834d86c41bed1d67a77fa8fa45805a337a Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 10 Dec 2025 10:12:13 +0100 Subject: [PATCH 11/14] min-max Signed-off-by: Marino Faggiana --- .../GUI/Lucid Banner/UploadBannerView.swift | 135 ++++++++++++++++-- iOSClient/Main/Create/NCCreate.swift | 2 +- .../Networking/NCNetworkingProcess.swift | 1 + 3 files changed, 125 insertions(+), 13 deletions(-) diff --git a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift index c738bec85d..5df28a2aa5 100644 --- a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift @@ -9,9 +9,13 @@ struct UploadBannerView: View { @ObservedObject var state: LucidBannerState @State var trigger = true let onButtonTap: (() -> Void)? + let allowMinimizeOnTap: Bool - init(state: LucidBannerState, onButtonTap: (() -> Void)? = nil) { + init(state: LucidBannerState, + allowMinimizeOnTap: Bool = false, + onButtonTap: (() -> Void)? = nil) { self.state = state + self.allowMinimizeOnTap = allowMinimizeOnTap self.onButtonTap = onButtonTap } @@ -25,7 +29,14 @@ struct UploadBannerView: View { let isButton = (state.typedStage == .init(rawValue: "button")) containerView(state: state) { - if isSuccess { + if state.isMinimized { + Image(systemName: state.systemImage ?? "arrow.up.circle") + .font(.title3) + if let p = state.progress { + Text("\(Int(p * 100))%") + .font(.footnote.monospacedDigit()) + } + } else if isSuccess { HStack(alignment: .center, spacing: 10) { if #available(iOS 26, *) { Image(systemName: "checkmark") @@ -140,25 +151,37 @@ struct UploadBannerView: View { @ViewBuilder func containerView(state: LucidBannerState, @ViewBuilder _ content: () -> Content) -> some View { let isError = (state.typedStage == .error) + let cornerRadius: CGFloat = 22 + + let contentBase = content() + .contentShape(Rectangle()) + .onTapGesture { + guard allowMinimizeOnTap else { return } + UploadBannerCoordinator.shared.handleTap(state) + } + .onDisappear { + UploadBannerCoordinator.shared.clear() + } if #available(iOS 26, *) { if isError { - content() + contentBase .background( - RoundedRectangle(cornerRadius: 22) + RoundedRectangle(cornerRadius: cornerRadius) .fill(Color.red.opacity(1)) ) - .glassEffect(.regular, in: RoundedRectangle(cornerRadius: 22)) + .glassEffect(.regular, in: RoundedRectangle(cornerRadius: cornerRadius)) } else { - content() - .glassEffect(.regular, in: RoundedRectangle(cornerRadius: 22)) + contentBase + .glassEffect(.regular, in: RoundedRectangle(cornerRadius: cornerRadius)) } } else { let colorBg = isError ? Color.red.opacity(0.9) : Color.white.opacity(0.9) - content() - .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 22.0)) + + contentBase + .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: cornerRadius)) .overlay( - RoundedRectangle(cornerRadius: 22, style: .continuous) + RoundedRectangle(cornerRadius: cornerRadius, style: .continuous) .stroke(colorBg, lineWidth: 0.6) ) .shadow(color: .black.opacity(0.5), radius: 10, x: 0, y: 4) @@ -222,8 +245,10 @@ func showUploadBanner(scene: UIWindowScene?, draggable: Bool = false, stage: LucidBanner.Stage? = nil, policy: LucidBanner.ShowPolicy = .drop, + allowMinimizeOnTap: Bool = false, + minimizePoint: CGPoint? = nil, onButtonTap: (() -> Void)? = nil) -> Int { - LucidBanner.shared.show( + let token = LucidBanner.shared.show( scene: scene, vPosition: vPosition, hAlignment: hAlignment, @@ -233,7 +258,93 @@ func showUploadBanner(scene: UIWindowScene?, stage: stage, policy: policy ) { state in - UploadBannerView(state: state, onButtonTap: onButtonTap) + UploadBannerView(state: state, + allowMinimizeOnTap: allowMinimizeOnTap, + onButtonTap: onButtonTap) + } + + UploadBannerCoordinator.shared.setMinimizePoint(minimizePoint) + UploadBannerCoordinator.shared.register(token: token) + return token +} + +@MainActor +final class UploadBannerCoordinator { + static let shared = UploadBannerCoordinator() + + private var currentToken: Int? + private var originalCenter: CGPoint? + private var minimizePoint: CGPoint? + + func register(token: Int) { + currentToken = token + } + + func clear() { + currentToken = nil + originalCenter = nil + minimizePoint = nil + } + + func setMinimizePoint(_ point: CGPoint?) { + minimizePoint = point + } + + func handleTap(_ state: LucidBannerState) { + guard let token = currentToken else { + return + } + + guard LucidBanner.shared.isAlive(token) else { + clear() + return + } + + if state.isMinimized { + maximize(state: state, token: token) + } else { + minimize(state: state, token: token) + } + } + + private func minimize(state: LucidBannerState, token: Int) { + if let frame = LucidBanner.shared.currentFrameInWindow(for: token) { + originalCenter = CGPoint(x: frame.midX, y: frame.midY) + } + state.isMinimized = true + + LucidBanner.shared.setDraggingEnabled(false, for: token) + LucidBanner.shared.requestRelayout(animated: true) + + if let target = minimizePoint { + LucidBanner.shared.move( + toX: target.x, + y: target.y, + for: token, + animated: true + ) + } + } + + private func maximize(state: LucidBannerState, token: Int) { + state.isMinimized = false + + LucidBanner.shared.setDraggingEnabled(true, for: token) + LucidBanner.shared.requestRelayout(animated: true) + + // Restore + if let center = originalCenter { + LucidBanner.shared.move( + toX: center.x, + y: center.y, + for: token, + animated: true + ) + } else { + LucidBanner.shared.resetPosition(for: token, animated: true) + } + + originalCenter = nil } } diff --git a/iOSClient/Main/Create/NCCreate.swift b/iOSClient/Main/Create/NCCreate.swift index 5f812cf2c7..c2280e256a 100644 --- a/iOSClient/Main/Create/NCCreate.swift +++ b/iOSClient/Main/Create/NCCreate.swift @@ -309,7 +309,7 @@ class NCCreate: NSObject { if let url = exportFileForSharing(from: localFileURL) { exportURLs.append(url) } - } + } } LucidBanner.shared.dismiss() diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 8a3db79070..3879e87e42 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -416,6 +416,7 @@ actor NCNetworkingProcess { verticalMargin: 55, draggable: true, stage: .init(rawValue: "button"), + allowMinimizeOnTap: true, onButtonTap: { if let currentUploadTask { currentUploadTask.cancel() From 1ce639f8740e4e4ceed6930aa705ab9ba9f41301 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 10 Dec 2025 11:44:34 +0100 Subject: [PATCH 12/14] code Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 4 ++ .../Extensions/UIWindowScene+Extension.swift | 29 +++++++++ .../GUI/Lucid Banner/UploadBannerView.swift | 63 +++++++++++++++---- .../Networking/NCNetworkingProcess.swift | 7 +++ 4 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 iOSClient/Extensions/UIWindowScene+Extension.swift diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index d6e88b5da0..70036afa87 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -846,6 +846,7 @@ F7E402332BA89551007E5609 /* NCTrash+Networking.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E402322BA89551007E5609 /* NCTrash+Networking.swift */; }; F7E41316294A19B300839300 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E41315294A19B300839300 /* UIView+Extension.swift */; }; F7E4D9C422ED929B003675FD /* NCShareCommentsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E4D9C322ED929B003675FD /* NCShareCommentsCell.swift */; }; + F7E562A22EE978B100FA2FDF /* UIWindowScene+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E562A12EE9789B00FA2FDF /* UIWindowScene+Extension.swift */; }; F7E742F32EC0A10C00E2362A /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; }; F7E742F42EC0A10C00E2362A /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; }; F7E742F52EC0A3DD00E2362A /* NCManageDatabase+Directory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78A10BE29322E8A008499B8 /* NCManageDatabase+Directory.swift */; }; @@ -1755,6 +1756,7 @@ F7E41315294A19B300839300 /* UIView+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Extension.swift"; sourceTree = ""; }; F7E45E6D21E75BF200579249 /* ja-JP */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ja-JP"; path = "ja-JP.lproj/Localizable.strings"; sourceTree = ""; }; F7E4D9C322ED929B003675FD /* NCShareCommentsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCommentsCell.swift; sourceTree = ""; }; + F7E562A12EE9789B00FA2FDF /* UIWindowScene+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindowScene+Extension.swift"; sourceTree = ""; }; F7E7AEA42BA32C6500512E52 /* NCCollectionViewDownloadThumbnail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCollectionViewDownloadThumbnail.swift; sourceTree = ""; }; F7E7AEA62BA32D0000512E52 /* NCCollectionViewUnifiedSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCollectionViewUnifiedSearch.swift; sourceTree = ""; }; F7E8A390295DC5E0006CB2D0 /* View+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extension.swift"; sourceTree = ""; }; @@ -2801,6 +2803,7 @@ F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */, F7EE66AC2A20B226009AE765 /* UILabel+Extension.swift */, F77BB7492899857B0090FC19 /* UINavigationController+Extension.swift */, + F7E562A12EE9789B00FA2FDF /* UIWindowScene+Extension.swift */, F743C89D2E5B2595000173A9 /* UIScene+Extension.swift */, F77C3F5A2D9BF8B500F3C471 /* UITabBar+Extension.swift */, F77BB747289985270090FC19 /* UITabBarController+Extension.swift */, @@ -4475,6 +4478,7 @@ F7BF9D822934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */, AA8D31662D411FA100FE2775 /* NCShareDateCell.swift in Sources */, F3F442EE2DDE292D00FD701F /* NCMetadataPermissions.swift in Sources */, + F7E562A22EE978B100FA2FDF /* UIWindowScene+Extension.swift in Sources */, F3374A812D64AB9F002A38F9 /* StatusInfo.swift in Sources */, AF7E504E27A2D8FF00B5E4AF /* UIBarButton+Extension.swift in Sources */, AA8D31682D41224800FE2775 /* NCShareToggleCell.swift in Sources */, diff --git a/iOSClient/Extensions/UIWindowScene+Extension.swift b/iOSClient/Extensions/UIWindowScene+Extension.swift new file mode 100644 index 0000000000..f351001620 --- /dev/null +++ b/iOSClient/Extensions/UIWindowScene+Extension.swift @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Nextcloud GmbH +// SPDX-FileCopyrightText: 2025 Marino Faggiana +// SPDX-License-Identifier: GPL-3.0-or-later + +import UIKit + +public extension UIWindowScene { + + /// Returns the top-left coordinate of the UITabBar in this scene, + /// expressed in the coordinate space of the scene's key window. + /// + /// If the scene does not host a UITabBarController as root, + /// or no suitable window is found, the method returns `nil`. + var tabBarTopLeft: CGPoint? { + // Select key window if available, otherwise fallback to the first one. + guard let window = windows.first(where: { $0.isKeyWindow }) ?? windows.first, + let tabBarController = window.rootViewController as? UITabBarController + else { + return nil + } + + let tabBar = tabBarController.tabBar + + // Convert tab bar's bounds to the window coordinate space. + let frameInWindow = tabBar.convert(tabBar.bounds, to: window) + + return CGPoint(x: frameInWindow.minX, y: frameInWindow.minY) + } +} diff --git a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift index 5df28a2aa5..f1bc4e3c9f 100644 --- a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift @@ -30,12 +30,21 @@ struct UploadBannerView: View { containerView(state: state) { if state.isMinimized { - Image(systemName: state.systemImage ?? "arrow.up.circle") - .font(.title3) - if let p = state.progress { - Text("\(Int(p * 100))%") - .font(.footnote.monospacedDigit()) + HStack(spacing: 5) { + Image(systemName: state.systemImage ?? "arrow.up.circle") + .font(.body.weight(.medium)) + .frame(width: 20, height: 20) + + if let p = state.progress { + Text("\(Int(p * 100))%") + .font(.caption2.monospacedDigit()) + .frame(height: 20) + } + } + .padding(.horizontal, 3) + .padding(.vertical, 3) + .clipShape(Capsule()) } else if isSuccess { HStack(alignment: .center, spacing: 10) { if #available(iOS 26, *) { @@ -290,6 +299,27 @@ final class UploadBannerCoordinator { minimizePoint = point } + @MainActor + func moveIfMinimized(to point: CGPoint, animated: Bool = true) { + guard let token = currentToken else { return } + guard LucidBanner.shared.isAlive(token) else { + clear() + return + } + guard let state = LucidBanner.shared.currentState(for: token), + state.isMinimized else { + return + } + + // Move the minimized banner + LucidBanner.shared.move( + toX: point.x, + y: point.y, + for: token, + animated: animated + ) + } + func handleTap(_ state: LucidBannerState) { guard let token = currentToken else { return @@ -351,7 +381,19 @@ final class UploadBannerCoordinator { // MARK: - Preview #Preview { - ZStack { + // Create a mutable preview state + let state = LucidBannerState( + title: "Uploading…", + subtitle: "Minimized style preview", + systemImage: "arrow.up.circle", + imageAnimation: .none, + progress: 0.71, + stage: "button" + ) + + state.isMinimized = true + + return ZStack { LinearGradient( colors: [.white, .gray.opacity(0.1)], startPoint: .top, @@ -359,13 +401,8 @@ final class UploadBannerCoordinator { ) UploadBannerView( - state: LucidBannerState( - title: "Downloading …", - subtitle: "Keep application active until the transfers are completed …", - systemImage: "gearshape.arrow.triangle.2.circlepath", - imageAnimation: .rotate, - progress: 0.4, - stage: "button") + state: state, + allowMinimizeOnTap: true ) .padding() } diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 3879e87e42..949ddf8d1f 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -367,6 +367,7 @@ actor NCNetworkingProcess { vPosition: .bottom, verticalMargin: 55, blocksTouches: true, + minimizePoint: CGPoint(x: 0, y: 0), onButtonTap: { if let currentUploadTask { currentUploadTask.cancel() @@ -410,6 +411,11 @@ actor NCNetworkingProcess { var currentUploadTask: Task<(account: String, file: NKFile?, error: NKError), Never>? var token: Int = 0 let scene = SceneManager.shared.getWindow(sceneIdentifier: metadata.sceneIdentifier)?.windowScene + let tabBarTopLeft = scene?.tabBarTopLeft + let minimizePoint = CGPoint( + x: (tabBarTopLeft?.x ?? 0) + 50, + y: (tabBarTopLeft?.y ?? 0) - 20 + ) token = showUploadBanner(scene: scene, vPosition: .bottom, @@ -417,6 +423,7 @@ actor NCNetworkingProcess { draggable: true, stage: .init(rawValue: "button"), allowMinimizeOnTap: true, + minimizePoint: minimizePoint, onButtonTap: { if let currentUploadTask { currentUploadTask.cancel() From 30a4012a453c43d86a2c7447ed7e74491a94d03b Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 10 Dec 2025 17:39:42 +0100 Subject: [PATCH 13/14] cod Signed-off-by: Marino Faggiana --- Share/NCShareExtension.swift | 2 +- .../GUI/Lucid Banner/ErrorBannerView.swift | 1 + .../GUI/Lucid Banner/HudBannerView.swift | 6 ++--- .../GUI/Lucid Banner/UploadBannerView.swift | 4 +-- ...ionViewCommon+CollectionViewDelegate.swift | 8 +++--- .../E2EE/NCNetworkingE2EEUpload.swift | 4 +-- .../Networking/NCNetworkingProcess.swift | 26 +++++++++---------- .../Utility/NCOperationSaveLivePhoto.swift | 22 ++++++++-------- 8 files changed, 37 insertions(+), 36 deletions(-) diff --git a/Share/NCShareExtension.swift b/Share/NCShareExtension.swift index 3ee37a5469..c9bc162dca 100644 --- a/Share/NCShareExtension.swift +++ b/Share/NCShareExtension.swift @@ -47,7 +47,7 @@ class NCShareExtension: UIViewController { let utility = NCUtility() let global = NCGlobal.shared var maintenanceMode: Bool = false - var token: Int = 0 + var token: Int? // MARK: - View Life Cycle diff --git a/iOSClient/GUI/Lucid Banner/ErrorBannerView.swift b/iOSClient/GUI/Lucid Banner/ErrorBannerView.swift index 0ade336061..6099fc7faf 100644 --- a/iOSClient/GUI/Lucid Banner/ErrorBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/ErrorBannerView.swift @@ -92,6 +92,7 @@ func showErrorBanner(scene: UIWindowScene?, errorDescription: String, errorCode: scene: scene, subtitle: errorDescription, footnote: "(Code: \(errorCode))", + vPosition: .top, autoDismissAfter: NCGlobal.shared.dismissAfterSecond, swipeToDismiss: true, onTap: { _, _ in diff --git a/iOSClient/GUI/Lucid Banner/HudBannerView.swift b/iOSClient/GUI/Lucid Banner/HudBannerView.swift index f35f7f0daf..02b55bb1aa 100644 --- a/iOSClient/GUI/Lucid Banner/HudBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/HudBannerView.swift @@ -160,7 +160,7 @@ struct HudBannerView: View { // MARK: - Helper @MainActor -func showHudBanner(scene: UIWindowScene?, title: String? = nil, subtitle: String? = nil, onTap: ((_ token: Int, _ stage: String?) -> Void)? = nil) -> Int { +func showHudBanner(scene: UIWindowScene?, title: String? = nil, subtitle: String? = nil, onTap: ((_ token: Int?, _ stage: String?) -> Void)? = nil) -> Int? { var scene = scene if scene == nil { scene = UIApplication.shared.mainAppWindow?.windowScene @@ -182,7 +182,7 @@ func showHudBanner(scene: UIWindowScene?, title: String? = nil, subtitle: String @MainActor func completeHudBannerSuccess( - token: Int + token: Int? ) { LucidBanner.shared.update( stage: .success, @@ -194,7 +194,7 @@ func completeHudBannerSuccess( @MainActor func completeHudBannerError( subtitle: String? = nil, - token: Int + token: Int? ) { LucidBanner.shared.update( subtitle: subtitle, diff --git a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift index f1bc4e3c9f..77a7664fa5 100644 --- a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift @@ -256,7 +256,7 @@ func showUploadBanner(scene: UIWindowScene?, policy: LucidBanner.ShowPolicy = .drop, allowMinimizeOnTap: Bool = false, minimizePoint: CGPoint? = nil, - onButtonTap: (() -> Void)? = nil) -> Int { + onButtonTap: (() -> Void)? = nil) -> Int? { let token = LucidBanner.shared.show( scene: scene, vPosition: vPosition, @@ -285,7 +285,7 @@ final class UploadBannerCoordinator { private var originalCenter: CGPoint? private var minimizePoint: CGPoint? - func register(token: Int) { + func register(token: Int?) { currentToken = token } diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift index 28cd6e7c6e..8f3a08f851 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift @@ -28,10 +28,10 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { func downloadFile() async { var downloadRequest: DownloadRequest? let scene = SceneManager.shared.getWindow(controller: self.tabBarController)?.windowScene - var token: Int = 0 + var tokenBanner: Int? await MainActor.run { - token = showHudBanner(scene: scene, - title: NSLocalizedString("_downloading_", comment: "")) { _, _ in + tokenBanner = showHudBanner(scene: scene, + title: NSLocalizedString("_downloading_", comment: "")) { _, _ in if let request = downloadRequest { request.cancel() } @@ -49,7 +49,7 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { downloadRequest = request } progressHandler: { progress in Task {@MainActor in - LucidBanner.shared.update(progress: Double(progress.fractionCompleted), for: token) + LucidBanner.shared.update(progress: Double(progress.fractionCompleted), for: tokenBanner) } } await MainActor.run { diff --git a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift index f8af7e2879..94f0119e95 100644 --- a/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift +++ b/iOSClient/Networking/E2EE/NCNetworkingE2EEUpload.swift @@ -23,7 +23,7 @@ class NCNetworkingE2EEUpload: NSObject { session: NCSession.Session? = nil, controller: UIViewController? = nil, stageBanner: LucidBanner.Stage?, - tokenBanner: Int, + tokenBanner: Int?, requestHandle: @escaping (_ request: UploadRequest) -> Void = { _ in }, currentUploadTask: @escaping (_ task: Task<(account: String, file: NKFile?, error: NKError), Never>?) -> Void = { _ in }) async -> NKError { @@ -220,7 +220,7 @@ class NCNetworkingE2EEUpload: NSObject { e2eToken: String, controller: UIViewController?, stageBanner: LucidBanner.Stage?, - tokenBanner: Int, + tokenBanner: Int?, requestHandle: @escaping (_ request: UploadRequest) -> Void = { _ in }, currentUploadTask: @escaping (_ task: Task<(account: String, file: NKFile?, error: NKError), Never>?) -> Void = { _ in }) async -> (ocId: String?, etag: String?, date: Date?, error: NKError) { diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 949ddf8d1f..7d5829c764 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -409,7 +409,7 @@ actor NCNetworkingProcess { @MainActor func uploadChunk(metadata: tableMetadata) async { var currentUploadTask: Task<(account: String, file: NKFile?, error: NKError), Never>? - var token: Int = 0 + var tokenBanner: Int? let scene = SceneManager.shared.getWindow(sceneIdentifier: metadata.sceneIdentifier)?.windowScene let tabBarTopLeft = scene?.tabBarTopLeft let minimizePoint = CGPoint( @@ -417,14 +417,14 @@ actor NCNetworkingProcess { y: (tabBarTopLeft?.y ?? 0) - 20 ) - token = showUploadBanner(scene: scene, - vPosition: .bottom, - verticalMargin: 55, - draggable: true, - stage: .init(rawValue: "button"), - allowMinimizeOnTap: true, - minimizePoint: minimizePoint, - onButtonTap: { + tokenBanner = showUploadBanner(scene: scene, + vPosition: .bottom, + verticalMargin: 55, + draggable: true, + stage: .init(rawValue: "button"), + allowMinimizeOnTap: true, + minimizePoint: minimizePoint, + onButtonTap: { if let currentUploadTask { currentUploadTask.cancel() } else { @@ -441,7 +441,7 @@ actor NCNetworkingProcess { let results = await NCNetworking.shared.uploadChunkFile(metadata: metadata) { total, counter in Task {@MainActor in let progress = Double(counter) / Double(total) - LucidBanner.shared.update(progress: progress, for: token) + LucidBanner.shared.update(progress: progress, for: tokenBanner) } } uploadStart: { _ in Task {@MainActor in @@ -450,11 +450,11 @@ actor NCNetworkingProcess { systemImage: "arrowshape.up.circle", imageAnimation: .breathe, progress: 0, - for: token) + for: tokenBanner) } } uploadProgressHandler: { _, _, progress in Task {@MainActor in - LucidBanner.shared.update(progress: progress, for: token) + LucidBanner.shared.update(progress: progress, for: tokenBanner) } } assembling: { Task {@MainActor in @@ -463,7 +463,7 @@ actor NCNetworkingProcess { systemImage: "gearshape.arrow.triangle.2.circlepath", imageAnimation: .rotate, stage: .init(rawValue: "none"), - for: token) + for: tokenBanner) } } diff --git a/iOSClient/Utility/NCOperationSaveLivePhoto.swift b/iOSClient/Utility/NCOperationSaveLivePhoto.swift index 7ef2ce5da4..aa55cc6fb0 100644 --- a/iOSClient/Utility/NCOperationSaveLivePhoto.swift +++ b/iOSClient/Utility/NCOperationSaveLivePhoto.swift @@ -12,7 +12,7 @@ class NCOperationSaveLivePhoto: ConcurrentOperation, @unchecked Sendable { var metadataMOV: tableMetadata let utilityFileSystem = NCUtilityFileSystem() var scene: UIWindowScene? - var token: Int = 0 + var tokenBanner: Int? init(metadata: tableMetadata, metadataMOV: tableMetadata, controller: UITabBarController?) { self.metadata = tableMetadata.init(value: metadata) @@ -31,18 +31,18 @@ class NCOperationSaveLivePhoto: ConcurrentOperation, @unchecked Sendable { selector: "") else { return self.finish() } - token = showHudBanner(scene: scene, title: NSLocalizedString("_download_image_", comment: "")) + tokenBanner = showHudBanner(scene: scene, title: NSLocalizedString("_download_image_", comment: "")) let resultsMetadata = await NCNetworking.shared.downloadFile(metadata: metadata) { _ in } progressHandler: { progess in Task {@MainActor in - LucidBanner.shared.update(progress: progess.fractionCompleted, for: self.token) + LucidBanner.shared.update(progress: progess.fractionCompleted, for: self.tokenBanner) } } guard resultsMetadata.nkError == .success else { Task {@MainActor in - completeHudBannerError(subtitle: NSLocalizedString("_livephoto_save_error_", comment: ""), token: token) + completeHudBannerError(subtitle: NSLocalizedString("_livephoto_save_error_", comment: ""), token: self.tokenBanner) } return self.finish() } @@ -50,13 +50,13 @@ class NCOperationSaveLivePhoto: ConcurrentOperation, @unchecked Sendable { let resultsMetadataLive = await NCNetworking.shared.downloadFile(metadata: metadataLive) { _ in } progressHandler: { progess in Task {@MainActor in - LucidBanner.shared.update(progress: progess.fractionCompleted, for: self.token) + LucidBanner.shared.update(progress: progess.fractionCompleted, for: self.tokenBanner) } } guard resultsMetadataLive.nkError == .success else { Task {@MainActor in - completeHudBannerError(subtitle: NSLocalizedString("_livephoto_save_error_", comment: ""), token: self.token) + completeHudBannerError(subtitle: NSLocalizedString("_livephoto_save_error_", comment: ""), token: self.tokenBanner) } return self.finish() } @@ -78,27 +78,27 @@ class NCOperationSaveLivePhoto: ConcurrentOperation, @unchecked Sendable { urlBase: metadataMov.urlBase)) LucidBanner.shared.update(title: NSLocalizedString("_livephoto_save_", comment: ""), - for: self.token) + for: self.tokenBanner) NCLivePhoto.generate(from: fileNameImage, videoURL: fileNameMov, progress: { progress in Task {@MainActor in - LucidBanner.shared.update(progress: progress, for: self.token) + LucidBanner.shared.update(progress: progress, for: self.tokenBanner) } }, completion: { _, resources in if let resources { NCLivePhoto.saveToLibrary(resources) { result in Task {@MainActor in if !result { - completeHudBannerError(subtitle: NSLocalizedString("_livephoto_save_error_", comment: ""), token: self.token) + completeHudBannerError(subtitle: NSLocalizedString("_livephoto_save_error_", comment: ""), token: self.tokenBanner) } else { - completeHudBannerSuccess(token: self.token) + completeHudBannerSuccess(token: self.tokenBanner) } return self.finish() } } } else { Task {@MainActor in - completeHudBannerError(subtitle: NSLocalizedString("_livephoto_save_error_", comment: ""), token: self.token) + completeHudBannerError(subtitle: NSLocalizedString("_livephoto_save_error_", comment: ""), token: self.tokenBanner) return self.finish() } } From abceacf05e5b2dd233ed8a6fffac83d88b8ca274 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 10 Dec 2025 17:54:15 +0100 Subject: [PATCH 14/14] cod Signed-off-by: Marino Faggiana --- iOSClient/GUI/Lucid Banner/UploadBannerView.swift | 3 +++ iOSClient/Networking/NCNetworkingProcess.swift | 7 ++++--- iOSClient/Supporting Files/en.lproj/Localizable.strings | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift index 77a7664fa5..d41b3d38d0 100644 --- a/iOSClient/GUI/Lucid Banner/UploadBannerView.swift +++ b/iOSClient/GUI/Lucid Banner/UploadBannerView.swift @@ -171,6 +171,9 @@ struct UploadBannerView: View { .onDisappear { UploadBannerCoordinator.shared.clear() } + // Hard cap for very large screens (iPad etc.) + .frame(maxWidth: 500) + .frame(maxWidth: .infinity, alignment: .center) if #available(iOS 26, *) { if isError { diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 7d5829c764..a076e5c02c 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -411,10 +411,10 @@ actor NCNetworkingProcess { var currentUploadTask: Task<(account: String, file: NKFile?, error: NKError), Never>? var tokenBanner: Int? let scene = SceneManager.shared.getWindow(sceneIdentifier: metadata.sceneIdentifier)?.windowScene - let tabBarTopLeft = scene?.tabBarTopLeft + let tabBarTopLeft = scene?.tabBarTopLeft ?? CGPoint(x: 0, y: 50) let minimizePoint = CGPoint( - x: (tabBarTopLeft?.x ?? 0) + 50, - y: (tabBarTopLeft?.y ?? 0) - 20 + x: tabBarTopLeft.x + 50, + y: tabBarTopLeft.y - 20 ) tokenBanner = showUploadBanner(scene: scene, @@ -434,6 +434,7 @@ actor NCNetworkingProcess { LucidBanner.shared.update(title: NSLocalizedString("_wait_file_preparation_", comment: ""), subtitle: NSLocalizedString("_large_upload_tip_", comment: ""), + footnote: "( " + NSLocalizedString("_tap_to_min_max_", comment: "") + " )", systemImage: "gearshape.arrow.triangle.2.circlepath", imageAnimation: .rotate) diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 3541c53785..46bf73d7a3 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -23,6 +23,7 @@ "_cancel_" = "Cancel"; "_edit_" = "Edit"; "_tap_to_cancel_" = "Tap to cancel"; +"_tap_to_min_max_" = "Tap to minimize / maximize"; "_cancel_request_" = "Do you want to cancel?"; "_upload_file_" = "Upload file"; "_download_file_" = "Download file";