From 81d5c314faf1bda2d46f387e4ac17b9a51ddd639 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 08:25:47 +0200 Subject: [PATCH 01/22] fix Signed-off-by: Marino Faggiana --- iOSClient/Networking/NCNetworking+Task.swift | 1 - iOSClient/Networking/NCNetworkingProcess.swift | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/iOSClient/Networking/NCNetworking+Task.swift b/iOSClient/Networking/NCNetworking+Task.swift index 62340f83cf..7ca6c50589 100644 --- a/iOSClient/Networking/NCNetworking+Task.swift +++ b/iOSClient/Networking/NCNetworking+Task.swift @@ -61,7 +61,6 @@ extension NCNetworking { func cancelAllTaskForGoInBackground() { cancelAllQueue() - cancelAllDataTask() cancelDownloadTasks() cancelUploadTasks() } diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 3055cd4253..23cb49f02e 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -41,16 +41,16 @@ actor NCNetworkingProcess { NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { [weak self] _ in guard let self else { return } - Task { await self.stopTimer() } + Task { + await self.stopTimer() + } } NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: nil) { [weak self] _ in guard let self else { return } Task { - if !isAppInBackground { - await self.startTimer(interval: self.maxInterval) - } + await self.startTimer(interval: self.maxInterval) } } } From 5e5e629575e47a7b776913a1a45d5e3b2a244f2a Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 08:26:34 +0200 Subject: [PATCH 02/22] build 3 Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 64681acf33..8f0301e11c 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -5872,7 +5872,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = NKUJUXUJ3B; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -5938,7 +5938,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = NKUJUXUJ3B; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; From 49c18e474fa0c64507b3e8030a245f30a456197f Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 09:02:38 +0200 Subject: [PATCH 03/22] cod Signed-off-by: Marino Faggiana --- .../Networking/NCNetworkingProcess.swift | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 23cb49f02e..ec5b0be9a6 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -35,7 +35,9 @@ actor NCNetworkingProcess { NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterPlayerStoppedPlaying), object: nil, queue: nil) { [weak self] _ in guard let self else { return } - Task { await self.setScreenAwake(true) } + Task { + await self.setScreenAwake(true) + } } NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { [weak self] _ in @@ -190,7 +192,9 @@ actor NCNetworkingProcess { let isWiFi = self.networking.networkReachability == NKTypeReachability.reachableEthernetOrWiFi let sessionUploadSelectors = [self.global.selectorUploadFileNODelete, self.global.selectorUploadFile, self.global.selectorUploadAutoUpload] var counterUploading = metadatas.filter { $0.status == self.global.metadataStatusUploading }.count - for sessionSelector in sessionUploadSelectors where counterUploading < httpMaximumConnectionsPerHostInUpload { + for sessionSelector in sessionUploadSelectors { + guard counterUploading < httpMaximumConnectionsPerHostInUpload else { return } + let limitUpload = max(0, httpMaximumConnectionsPerHostInUpload - counterUploading) let filteredUpload = metadatas .filter { $0.sessionSelector == sessionSelector && $0.status == NCGlobal.shared.metadataStatusWaitUpload } @@ -202,14 +206,19 @@ actor NCNetworkingProcess { nkLog(debug: "PROCESS (UPLOAD) find \(metadatasWaitUpload.count) items") } - for metadata in metadatasWaitUpload where counterUploading < httpMaximumConnectionsPerHostInUpload { + for metadata in metadatasWaitUpload { + guard counterUploading < httpMaximumConnectionsPerHostInUpload else { return } let metadatas = await NCCameraRoll().extractCameraRoll(from: metadata) + // no extract photo if metadatas.isEmpty { await self.database.deleteMetadataOcIdAsync(metadata.ocId) } - for metadata in metadatas where counterUploading < httpMaximumConnectionsPerHostInUpload { + for metadata in metadatas { + guard counterUploading < httpMaximumConnectionsPerHostInUpload, + timer != nil else { return } + /// isE2EE let isInDirectoryE2EE = metadata.isDirectoryE2EE /// NO WiFi @@ -277,6 +286,8 @@ actor NCNetworkingProcess { /// let metadatasWaitCreateFolder = metadatas.filter { $0.status == global.metadataStatusWaitCreateFolder }.sorted { $0.serverUrl < $1.serverUrl } for metadata in metadatasWaitCreateFolder { + guard timer != nil else { return .success } + let resultsCreateFolder = await networking.createFolder(fileName: metadata.fileName, serverUrl: metadata.serverUrl, overwrite: true, @@ -307,6 +318,8 @@ actor NCNetworkingProcess { /// let metadatasWaitCopy = metadatas.filter { $0.status == global.metadataStatusWaitCopy }.sorted { $0.serverUrl < $1.serverUrl } for metadata in metadatasWaitCopy { + guard timer != nil else { return .success } + let serverUrlTo = metadata.serverUrlTo let serverUrlFileNameSource = metadata.serverUrl + "/" + metadata.fileName var serverUrlFileNameDestination = serverUrlTo + "/" + metadata.fileName @@ -343,6 +356,8 @@ actor NCNetworkingProcess { /// let metadatasWaitMove = metadatas.filter { $0.status == global.metadataStatusWaitMove }.sorted { $0.serverUrl < $1.serverUrl } for metadata in metadatasWaitMove { + guard timer != nil else { return .success } + let serverUrlTo = metadata.serverUrlTo let serverUrlFileNameSource = metadata.serverUrl + "/" + metadata.fileName let serverUrlFileNameDestination = serverUrlTo + "/" + metadata.fileName @@ -395,6 +410,8 @@ actor NCNetworkingProcess { /// let metadatasWaitFavorite = metadatas.filter { $0.status == global.metadataStatusWaitFavorite }.sorted { $0.serverUrl < $1.serverUrl } for metadata in metadatasWaitFavorite { + guard timer != nil else { return .success } + let session = NCSession.Session(account: metadata.account, urlBase: metadata.urlBase, user: metadata.user, userId: metadata.userId) let fileName = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session) let resultsFavorite = await NextcloudKit.shared.setFavoriteAsync(fileName: fileName, favorite: metadata.favorite, account: metadata.account) @@ -427,6 +444,8 @@ actor NCNetworkingProcess { /// let metadatasWaitRename = metadatas.filter { $0.status == global.metadataStatusWaitRename }.sorted { $0.serverUrl < $1.serverUrl } for metadata in metadatasWaitRename { + guard timer != nil else { return .success } + let serverUrlFileNameSource = metadata.serveUrlFileName let serverUrlFileNameDestination = metadata.serverUrl + "/" + metadata.fileName let resultRename = await NextcloudKit.shared.moveFileOrFolderAsync(serverUrlFileNameSource: serverUrlFileNameSource, serverUrlFileNameDestination: serverUrlFileNameDestination, overwrite: false, account: metadata.account) @@ -456,6 +475,8 @@ actor NCNetworkingProcess { var returnError = NKError() for metadata in metadatasWaitDelete { + guard timer != nil else { return .success } + let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName let resultDelete = await NextcloudKit.shared.deleteFileOrFolderAsync(serverUrlFileName: serverUrlFileName, account: metadata.account) From 960289d276172fd8b22be7bc7de56054d3bf6181 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 09:53:54 +0200 Subject: [PATCH 04/22] cod Signed-off-by: Marino Faggiana --- .../Networking/NCNetworkingProcess.swift | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index ec5b0be9a6..382211d61b 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -158,8 +158,8 @@ actor NCNetworkingProcess { /// ------------------------ WEBDAV let waitWebDav = metadatas.filter { self.global.metadataStatusWaitWebDav.contains($0.status) } if !waitWebDav.isEmpty { - let error = await metadataStatusWaitWebDav(metadatas: Array(waitWebDav)) - if error != .success { + let (status, error) = await metadataStatusWaitWebDav(metadatas: Array(waitWebDav)) + if (error == .cancelled) || (status == global.metadataStatusWaitDelete && error != .success) { return } } @@ -280,13 +280,15 @@ actor NCNetworkingProcess { return } - private func metadataStatusWaitWebDav(metadatas: [tableMetadata]) async -> NKError { + private func metadataStatusWaitWebDav(metadatas: [tableMetadata]) async -> (status: Int?, error: NKError) { /// ------------------------ CREATE FOLDER /// let metadatasWaitCreateFolder = metadatas.filter { $0.status == global.metadataStatusWaitCreateFolder }.sorted { $0.serverUrl < $1.serverUrl } for metadata in metadatasWaitCreateFolder { - guard timer != nil else { return .success } + guard timer != nil else { + return (global.metadataStatusWaitCreateFolder, .cancelled) + } let resultsCreateFolder = await networking.createFolder(fileName: metadata.fileName, serverUrl: metadata.serverUrl, @@ -310,7 +312,7 @@ actor NCNetworkingProcess { } if resultsCreateFolder.error != .success { - return resultsCreateFolder.error + return (global.metadataStatusWaitCreateFolder, resultsCreateFolder.error) } } @@ -318,7 +320,9 @@ actor NCNetworkingProcess { /// let metadatasWaitCopy = metadatas.filter { $0.status == global.metadataStatusWaitCopy }.sorted { $0.serverUrl < $1.serverUrl } for metadata in metadatasWaitCopy { - guard timer != nil else { return .success } + guard timer != nil else { + return (global.metadataStatusWaitCopy, .cancelled) + } let serverUrlTo = metadata.serverUrlTo let serverUrlFileNameSource = metadata.serverUrl + "/" + metadata.fileName @@ -348,7 +352,7 @@ actor NCNetworkingProcess { } if resultCopy.error != .success { - return resultCopy.error + return (global.metadataStatusWaitCopy, resultCopy.error) } } @@ -356,7 +360,9 @@ actor NCNetworkingProcess { /// let metadatasWaitMove = metadatas.filter { $0.status == global.metadataStatusWaitMove }.sorted { $0.serverUrl < $1.serverUrl } for metadata in metadatasWaitMove { - guard timer != nil else { return .success } + guard timer != nil else { + return (global.metadataStatusWaitMove, .cancelled) + } let serverUrlTo = metadata.serverUrlTo let serverUrlFileNameSource = metadata.serverUrl + "/" + metadata.fileName @@ -402,7 +408,7 @@ actor NCNetworkingProcess { } if resultMove.error != .success { - return resultMove.error + return (global.metadataStatusWaitMove, resultMove.error) } } @@ -410,7 +416,9 @@ actor NCNetworkingProcess { /// let metadatasWaitFavorite = metadatas.filter { $0.status == global.metadataStatusWaitFavorite }.sorted { $0.serverUrl < $1.serverUrl } for metadata in metadatasWaitFavorite { - guard timer != nil else { return .success } + guard timer != nil else { + return (global.metadataStatusWaitFavorite, .cancelled) + } let session = NCSession.Session(account: metadata.account, urlBase: metadata.urlBase, user: metadata.user, userId: metadata.userId) let fileName = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session) @@ -436,7 +444,7 @@ actor NCNetworkingProcess { } if resultsFavorite.error != .success { - return resultsFavorite.error + return (global.metadataStatusWaitFavorite, resultsFavorite.error) } } @@ -444,7 +452,9 @@ actor NCNetworkingProcess { /// let metadatasWaitRename = metadatas.filter { $0.status == global.metadataStatusWaitRename }.sorted { $0.serverUrl < $1.serverUrl } for metadata in metadatasWaitRename { - guard timer != nil else { return .success } + guard timer != nil else { + return (global.metadataStatusWaitRename, .cancelled) + } let serverUrlFileNameSource = metadata.serveUrlFileName let serverUrlFileNameDestination = metadata.serverUrl + "/" + metadata.fileName @@ -463,7 +473,7 @@ actor NCNetworkingProcess { } if resultRename.error != .success { - return resultRename.error + return (global.metadataStatusWaitRename, resultRename.error) } } @@ -475,7 +485,9 @@ actor NCNetworkingProcess { var returnError = NKError() for metadata in metadatasWaitDelete { - guard timer != nil else { return .success } + guard timer != nil else { + return (global.metadataStatusWaitDelete, .cancelled) + } let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName let resultDelete = await NextcloudKit.shared.deleteFileOrFolderAsync(serverUrlFileName: serverUrlFileName, account: metadata.account) @@ -513,10 +525,10 @@ actor NCNetworkingProcess { } if returnError != .success { - return returnError + return (global.metadataStatusWaitDelete, returnError) } } - return .success + return (nil, .success) } } From cb469b32e662d748c52b772e9b425f3008ae7a3c Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 09:59:18 +0200 Subject: [PATCH 05/22] cleaning Signed-off-by: Marino Faggiana --- iOSClient/NCGlobal.swift | 2 +- iOSClient/Networking/NCNetworkingProcess.swift | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index a5d80edbc5..6ee684f233 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -238,7 +238,7 @@ final class NCGlobal: Sendable { let metadataStatusUploadingAllMode = [1,2,3] let metadataStatusDownloadingAllMode = [-1, -2, -3] - let metadataStatusInTransfer = [-1, -2, 1, 2] + let metadataStatusForScreenAwake = [-1, -2, 1, 2] let metadataStatusHideInView = [1, 2, 3, 11] let metadataStatusWaitWebDav = [10, 11, 12, 13, 14, 15] diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 382211d61b..2c6ba2a450 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -29,7 +29,9 @@ actor NCNetworkingProcess { NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterPlayerIsPlaying), object: nil, queue: nil) { [weak self] _ in guard let self else { return } - Task { await self.setScreenAwake(false) } + Task { + await self.setScreenAwake(false) + } } NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterPlayerStoppedPlaying), object: nil, queue: nil) { [weak self] _ in @@ -108,10 +110,10 @@ actor NCNetworkingProcess { if let metadatas, !metadatas.isEmpty { let tasks = await networking.getAllDataTask() let hasSyncTask = tasks.contains { $0.taskDescription == global.taskDescriptionSynchronization } - let resultsTransfer = metadatas.filter { global.metadataStatusInTransfer.contains($0.status) } + let resultsScreenAwake = metadatas.filter { global.metadataStatusForScreenAwake.contains($0.status) } if enableControllingScreenAwake { - ScreenAwakeManager.shared.mode = resultsTransfer.isEmpty && !hasSyncTask ? .off : NCKeychain().screenAwakeMode + ScreenAwakeManager.shared.mode = resultsScreenAwake.isEmpty && !hasSyncTask ? .off : NCKeychain().screenAwakeMode } await runMetadataPipelineAsync() From d4e5b89daa3c9bfce5e0b803baedcd6a7fc5f2a4 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 10:12:51 +0200 Subject: [PATCH 06/22] fix Signed-off-by: Marino Faggiana --- iOSClient/Utility/NCCameraRoll.swift | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/iOSClient/Utility/NCCameraRoll.swift b/iOSClient/Utility/NCCameraRoll.swift index 44657484f0..ca989ce2de 100644 --- a/iOSClient/Utility/NCCameraRoll.swift +++ b/iOSClient/Utility/NCCameraRoll.swift @@ -152,11 +152,9 @@ final class NCCameraRoll: CameraRollExtractor { /// - modifyMetadataForUpload: Whether to update metadata for upload and store it in the database /// - Returns: An `ExtractedAsset` containing the updated metadata and path to the extracted file func extractImageVideoFromAssetLocalIdentifier( - metadata originalMetadata: tableMetadata, + metadata: tableMetadata, modifyMetadataForUpload: Bool ) async throws -> ExtractedAsset { - var metadata = originalMetadata.detachedCopy() - // Determine the appropriate chunk size based on the current network connection let chunkSize = NCNetworking.shared.networkReachability == .reachableEthernetOrWiFi ? NCGlobal.shared.chunkSizeMBEthernetOrWiFi @@ -219,10 +217,11 @@ final class NCCameraRoll: CameraRollExtractor { // Optionally update metadata for upload and persist it if modifyMetadataForUpload { - updateMetadataForUpload(&metadata, size: Int(metadata.size), chunkSize: chunkSize) + let metadata = updateMetadataForUpload(metadata: metadata, size: Int(metadata.size), chunkSize: chunkSize) + return ExtractedAsset(metadata: metadata, filePath: filePath) + } else { + return ExtractedAsset(metadata: metadata, filePath: filePath) } - - return ExtractedAsset(metadata: metadata, filePath: filePath) } private func metadataUpdatedFilename(for asset: PHAsset, original: String, ext: String, native: Bool) -> String { @@ -239,14 +238,14 @@ final class NCCameraRoll: CameraRollExtractor { return nil } - private func updateMetadataForUpload(_ metadata: inout tableMetadata, size: Int, chunkSize: Int) { + private func updateMetadataForUpload(metadata: tableMetadata, size: Int, chunkSize: Int) -> tableMetadata { metadata.chunk = size > chunkSize ? chunkSize : 0 metadata.e2eEncrypted = metadata.isDirectoryE2EE if metadata.chunk > 0 || metadata.e2eEncrypted { metadata.session = NCNetworking.shared.sessionUpload } metadata.isExtractFile = true - metadata = self.database.addAndReturnMetadata(metadata) + return self.database.addAndReturnMetadata(metadata) } private func extractImage(asset: PHAsset, ext: String, filePath: String, compatibilityFormat: Bool) async throws { From 469cef4678b8f15dab2092ad72a0c151b212adbc Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 10:21:38 +0200 Subject: [PATCH 07/22] fix Signed-off-by: Marino Faggiana --- iOSClient/Utility/NCCameraRoll.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/iOSClient/Utility/NCCameraRoll.swift b/iOSClient/Utility/NCCameraRoll.swift index ca989ce2de..892940c948 100644 --- a/iOSClient/Utility/NCCameraRoll.swift +++ b/iOSClient/Utility/NCCameraRoll.swift @@ -151,10 +151,7 @@ final class NCCameraRoll: CameraRollExtractor { /// - originalMetadata: Metadata describing the asset /// - modifyMetadataForUpload: Whether to update metadata for upload and store it in the database /// - Returns: An `ExtractedAsset` containing the updated metadata and path to the extracted file - func extractImageVideoFromAssetLocalIdentifier( - metadata: tableMetadata, - modifyMetadataForUpload: Bool - ) async throws -> ExtractedAsset { + func extractImageVideoFromAssetLocalIdentifier(metadata: tableMetadata, modifyMetadataForUpload: Bool) async throws -> ExtractedAsset { // Determine the appropriate chunk size based on the current network connection let chunkSize = NCNetworking.shared.networkReachability == .reachableEthernetOrWiFi ? NCGlobal.shared.chunkSizeMBEthernetOrWiFi From f4afcb1317e0bfb097474fcae9f3d9c30d608c0d Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 10:28:37 +0200 Subject: [PATCH 08/22] fix Signed-off-by: Marino Faggiana --- .../Data/NCManageDatabase+SecurityGuard.swift | 32 +------- .../Networking/NCNetworking+Upload.swift | 75 ++++++++++--------- iOSClient/Networking/NCService.swift | 2 +- 3 files changed, 44 insertions(+), 65 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase+SecurityGuard.swift b/iOSClient/Data/NCManageDatabase+SecurityGuard.swift index 2eb31a1b7a..cb0d993c40 100644 --- a/iOSClient/Data/NCManageDatabase+SecurityGuard.swift +++ b/iOSClient/Data/NCManageDatabase+SecurityGuard.swift @@ -32,20 +32,6 @@ extension NCManageDatabase { // MARK: - Realm write - func addDiagnostic(account: String, issue: String, error: String? = nil, sync: Bool = true) { - performRealmWrite(sync: sync) { realm in - let primaryKey = account + issue + (error ?? "") - - if let result = realm.object(ofType: TableSecurityGuardDiagnostics.self, forPrimaryKey: primaryKey) { - result.counter += 1 - result.oldest = Date().timeIntervalSince1970 - } else { - let table = TableSecurityGuardDiagnostics(account: account, issue: issue, error: error, date: Date()) - realm.add(table) - } - } - } - func addDiagnosticAsync(account: String, issue: String, error: String? = nil) async { @@ -78,23 +64,13 @@ extension NCManageDatabase { // MARK: - Realm read - func existsDiagnostics(account: String) -> Bool { - var exists = false - performRealmRead { realm in + func existsDiagnosticsAsync(account: String) async -> Bool { + let exists: Bool? = await performRealmReadAsync { realm in let results = realm.objects(TableSecurityGuardDiagnostics.self) .filter("account == %@", account) - exists = !results.isEmpty - } - return exists - } - - func getDiagnostics(account: String, issue: String) -> Results? { - var results: Results? - performRealmRead { realm in - results = realm.objects(TableSecurityGuardDiagnostics.self) - .filter("account == %@ AND issue == %@", account, issue) + return !results.isEmpty } - return results + return exists ?? false } func getDiagnosticsAsync(account: String) async -> [TableSecurityGuardDiagnostics]? { diff --git a/iOSClient/Networking/NCNetworking+Upload.swift b/iOSClient/Networking/NCNetworking+Upload.swift index 5e9bf0e727..f5b78a10e2 100644 --- a/iOSClient/Networking/NCNetworking+Upload.swift +++ b/iOSClient/Networking/NCNetworking+Upload.swift @@ -466,40 +466,42 @@ extension NCNetworking { func uploadForbidden(metadata: tableMetadata, error: NKError) { let newFileName = self.utilityFileSystem.createFileName(metadata.fileName, serverUrl: metadata.serverUrl, account: metadata.account) let alertController = UIAlertController(title: error.errorDescription, message: NSLocalizedString("_change_upload_filename_", comment: ""), preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: String(format: NSLocalizedString("_save_file_as_", comment: ""), newFileName), style: .default, handler: { _ in - let atpath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId) + "/" + metadata.fileName - let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId) + "/" + newFileName - self.utilityFileSystem.moveFile(atPath: atpath, toPath: toPath) - self.database.setMetadataSession(ocId: metadata.ocId, - newFileName: newFileName, - sessionTaskIdentifier: 0, - sessionError: "", - status: self.global.metadataStatusWaitUpload, - errorCode: error.errorCode) - })) - alertController.addAction(UIAlertAction(title: NSLocalizedString("_discard_changes_", comment: ""), style: .destructive, handler: { _ in - Task { - await self.uploadCancelFile(metadata: metadata) - } - })) - - // Select UIWindowScene active in serverUrl - var controller = UIApplication.shared.firstWindow?.rootViewController - let windowScenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene } - for windowScene in windowScenes { - if let rootViewController = windowScene.keyWindow?.rootViewController as? NCMainTabBarController, - rootViewController.currentServerUrl() == metadata.serverUrl { - controller = rootViewController - break - } - } - controller?.present(alertController, animated: true) - // Client Diagnostic - self.database.addDiagnostic(account: metadata.account, - issue: self.global.diagnosticIssueProblems, - error: self.global.diagnosticProblemsForbidden) + alertController.addAction(UIAlertAction(title: String(format: NSLocalizedString("_save_file_as_", comment: ""), newFileName), style: .default, handler: { _ in + let atpath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId) + "/" + metadata.fileName + let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId) + "/" + newFileName + self.utilityFileSystem.moveFile(atPath: atpath, toPath: toPath) + self.database.setMetadataSession(ocId: metadata.ocId, + newFileName: newFileName, + sessionTaskIdentifier: 0, + sessionError: "", + status: self.global.metadataStatusWaitUpload, + errorCode: error.errorCode) + })) + alertController.addAction(UIAlertAction(title: NSLocalizedString("_discard_changes_", comment: ""), style: .destructive, handler: { _ in + Task { + await self.uploadCancelFile(metadata: metadata) + } + })) + + // Select UIWindowScene active in serverUrl + var controller = UIApplication.shared.firstWindow?.rootViewController + let windowScenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene } + for windowScene in windowScenes { + if let rootViewController = windowScene.keyWindow?.rootViewController as? NCMainTabBarController, + rootViewController.currentServerUrl() == metadata.serverUrl { + controller = rootViewController + break + } + } + controller?.present(alertController, animated: true) + // Client Diagnostic + Task { + await self.database.addDiagnosticAsync(account: metadata.account, + issue: self.global.diagnosticIssueProblems, + error: self.global.diagnosticProblemsForbidden) + } } func termsOfService(metadata: tableMetadata) { @@ -541,10 +543,11 @@ extension NCNetworking { controller?.present(alertController, animated: true) // Client Diagnostic - self.database.addDiagnostic(account: metadata.account, - issue: self.global.diagnosticIssueProblems, - error: self.global.diagnosticProblemsForbidden, - sync: false) + Task { + await self.database.addDiagnosticAsync(account: metadata.account, + issue: self.global.diagnosticIssueProblems, + error: self.global.diagnosticProblemsForbidden) + } } } } diff --git a/iOSClient/Networking/NCService.swift b/iOSClient/Networking/NCService.swift index 8e8cda3c85..6dd1bfda7a 100644 --- a/iOSClient/Networking/NCService.swift +++ b/iOSClient/Networking/NCService.swift @@ -245,7 +245,7 @@ class NCService: NSObject { func sendClientDiagnosticsRemoteOperation(account: String) async { let capabilities = await NKCapabilities.shared.getCapabilitiesAsync(for: account) guard capabilities.securityGuardDiagnostics, - self.database.existsDiagnostics(account: account) else { + await self.database.existsDiagnosticsAsync(account: account) else { return } From 2dfecc77d5045a502105a7e9099c06a212518322 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 10:38:41 +0200 Subject: [PATCH 09/22] fix Signed-off-by: Marino Faggiana --- iOSClient/Networking/NCNetworking+Upload.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iOSClient/Networking/NCNetworking+Upload.swift b/iOSClient/Networking/NCNetworking+Upload.swift index f5b78a10e2..56a1facb8c 100644 --- a/iOSClient/Networking/NCNetworking+Upload.swift +++ b/iOSClient/Networking/NCNetworking+Upload.swift @@ -403,7 +403,7 @@ extension NCNetworking { if capabilities.termsOfService { termsOfService(metadata: metadata) } else { - uploadForbidden(metadata: metadata, error: error) + await uploadForbidden(metadata: metadata, error: error) } #endif } @@ -463,6 +463,7 @@ extension NCNetworking { } #if !EXTENSION + @MainActor func uploadForbidden(metadata: tableMetadata, error: NKError) { let newFileName = self.utilityFileSystem.createFileName(metadata.fileName, serverUrl: metadata.serverUrl, account: metadata.account) let alertController = UIAlertController(title: error.errorDescription, message: NSLocalizedString("_change_upload_filename_", comment: ""), preferredStyle: .alert) From 124d06ca4d34d806149cf3be2662cc725ef6931f Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 11:02:38 +0200 Subject: [PATCH 10/22] cod Signed-off-by: Marino Faggiana --- .../FileProviderExtension.swift | 2 +- .../Data/NCManageDatabase+Metadata.swift | 47 +++++++++---------- iOSClient/NCImageCache.swift | 43 +++++++++-------- iOSClient/Transfers/NCTransfers.swift | 24 ++++++---- 4 files changed, 60 insertions(+), 56 deletions(-) diff --git a/File Provider Extension/FileProviderExtension.swift b/File Provider Extension/FileProviderExtension.swift index ae13826a6a..c8926c09a0 100644 --- a/File Provider Extension/FileProviderExtension.swift +++ b/File Provider Extension/FileProviderExtension.swift @@ -220,7 +220,7 @@ class FileProviderExtension: NSFileProviderExtension { assert(pathComponents.count > 2) let itemIdentifier = NSFileProviderItemIdentifier(pathComponents[pathComponents.count - 2]) let fileName = pathComponents[pathComponents.count - 1] - guard let metadata = self.database.getMetadataFromOcIdAndocIdTransfer(itemIdentifier.rawValue) else { + guard let metadata = await self.database.getMetadataFromOcIdAndocIdTransferAsync(itemIdentifier.rawValue) else { return } let serverUrlFileName = metadata.serverUrl + "/" + fileName diff --git a/iOSClient/Data/NCManageDatabase+Metadata.swift b/iOSClient/Data/NCManageDatabase+Metadata.swift index bf117f907e..1d5fe2d28a 100644 --- a/iOSClient/Data/NCManageDatabase+Metadata.swift +++ b/iOSClient/Data/NCManageDatabase+Metadata.swift @@ -471,14 +471,6 @@ extension NCManageDatabase { } } - func deleteMetadatas(_ metadatas: [tableMetadata], sync: Bool = true) { - let detached = metadatas.map { $0.detachedCopy() } - - performRealmWrite(sync: sync) { realm in - realm.delete(detached) - } - } - // Asynchronously deletes an array of `tableMetadata` entries from the Realm database. /// - Parameter metadatas: The `tableMetadata` objects to be deleted. func deleteMetadatasAsync(_ metadatas: [tableMetadata]) async { @@ -1017,16 +1009,27 @@ extension NCManageDatabase { func getMetadatasAsync(predicate: NSPredicate, sortedByKeyPath: String, - ascending: Bool = false) async -> [tableMetadata]? { + ascending: Bool = false, + limit: Int? = nil) async -> [tableMetadata]? { return await performRealmReadAsync { realm in - realm.objects(tableMetadata.self) + let results = realm.objects(tableMetadata.self) .filter(predicate) - .sorted(byKeyPath: sortedByKeyPath, ascending: ascending) - .map { $0.detachedCopy() } + .sorted(byKeyPath: sortedByKeyPath, + ascending: ascending) + + if let limit { + let sliced = results.prefix(limit) + return sliced.map { $0.detachedCopy() } + } else { + return results.map { $0.detachedCopy() } + } } } - func getMetadatas(predicate: NSPredicate, numItems: Int, sorted: String, ascending: Bool) -> [tableMetadata] { + func getMetadatas(predicate: NSPredicate, + numItems: Int, + sorted: String, + ascending: Bool) -> [tableMetadata] { return performRealmRead { realm in let results = realm.objects(tableMetadata.self) .filter(predicate) @@ -1058,17 +1061,6 @@ extension NCManageDatabase { } } - func getMetadataFromOcIdAndocIdTransfer(_ ocId: String?) -> tableMetadata? { - guard let ocId else { return nil } - - return performRealmRead { realm in - realm.objects(tableMetadata.self) - .filter("ocId == %@ OR ocIdTransfer == %@", ocId, ocId) - .first - .map { $0.detachedCopy() } - } - } - func getMetadataFromOcIdAndocIdTransferAsync(_ ocId: String?) async -> tableMetadata? { guard let ocId else { return nil @@ -1215,13 +1207,16 @@ extension NCManageDatabase { } ?? [] } - func getMetadatas(predicate: NSPredicate, sortedByKeyPath: String, ascending: Bool, arraySlice: Int) -> [tableMetadata] { + func getMetadatas(predicate: NSPredicate, + sortedByKeyPath: String, + ascending: Bool, + limit: Int) -> [tableMetadata] { return performRealmRead { realm in let results = realm.objects(tableMetadata.self) .filter(predicate) .sorted(byKeyPath: sortedByKeyPath, ascending: ascending) .map { $0.detachedCopy() } - .prefix(arraySlice) + .prefix(limit) return Array(results) } ?? [] } diff --git a/iOSClient/NCImageCache.swift b/iOSClient/NCImageCache.swift index 0f09c5b404..138f9f6fe2 100644 --- a/iOSClient/NCImageCache.swift +++ b/iOSClient/NCImageCache.swift @@ -39,30 +39,31 @@ final class NCImageCache: @unchecked Sendable { NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: nil) { _ in #if !EXTENSION - guard !self.isLoadingCache else { - return - } - self.isDidEnterBackground = false + Task { + guard !self.isLoadingCache else { + return + } + self.isDidEnterBackground = false - var files: [NCFiles] = [] - var cost: Int = 0 + var files: [NCFiles] = [] + var cost: Int = 0 - if let activeTableAccount = NCManageDatabase.shared.getActiveTableAccount(), - NCImageCache.shared.cache.count == 0 { - let session = NCSession.shared.getSession(account: activeTableAccount.account) + if let activeTableAccount = await NCManageDatabase.shared.getActiveTableAccountAsync(), + NCImageCache.shared.cache.count == 0 { + let session = NCSession.shared.getSession(account: activeTableAccount.account) - for mainTabBarController in SceneManager.shared.getControllers() { - if let currentVC = mainTabBarController.selectedViewController as? UINavigationController, - let file = currentVC.visibleViewController as? NCFiles { - files.append(file) + for mainTabBarController in SceneManager.shared.getControllers() { + if let currentVC = await mainTabBarController.selectedViewController as? UINavigationController, + let file = await currentVC.visibleViewController as? NCFiles { + files.append(file) + } } - } - DispatchQueue.global().async { self.isLoadingCache = true - /// MEDIA - if let metadatas = NCManageDatabase.shared.getResultsMetadatas(predicate: self.getMediaPredicate(filterLivePhotoFile: true, session: session, showOnlyImages: false, showOnlyVideos: false), sortedByKeyPath: "datePhotosOriginal", freeze: true)?.prefix(self.countLimit) { + // MEDIA + let predicate = self.getMediaPredicate(filterLivePhotoFile: true, session: session, showOnlyImages: false, showOnlyVideos: false) + if let metadatas = await NCManageDatabase.shared.getMetadatasAsync(predicate: predicate, sortedByKeyPath: "datePhotosOriginal", limit: self.countLimit) { autoreleasepool { self.cache.removeAllValues() @@ -79,11 +80,12 @@ final class NCImageCache: @unchecked Sendable { } } - /// FILE + // FILE if !self.isDidEnterBackground { - for file in files where !file.serverUrl.isEmpty { + for file in files where await !file.serverUrl.isEmpty { + let serverUrl = await file.serverUrl NCNetworking.shared.notifyAllDelegates { delegate in - delegate.transferReloadData(serverUrl: file.serverUrl, status: nil) + delegate.transferReloadData(serverUrl: serverUrl, status: nil) } } } @@ -91,6 +93,7 @@ final class NCImageCache: @unchecked Sendable { self.isLoadingCache = false } } + #endif } } diff --git a/iOSClient/Transfers/NCTransfers.swift b/iOSClient/Transfers/NCTransfers.swift index 6b6168e27d..6015b979d7 100644 --- a/iOSClient/Transfers/NCTransfers.swift +++ b/iOSClient/Transfers/NCTransfers.swift @@ -77,8 +77,12 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate { // MARK: TAP EVENT override func tapMoreGridItem(with ocId: String, ocIdTransfer: String, image: UIImage?, sender: Any) { - guard let metadata = self.database.getMetadataFromOcIdAndocIdTransfer(ocIdTransfer) else { return } - NCNetworking.shared.cancelTask(metadata: metadata) + Task { + guard let metadata = await self.database.getMetadataFromOcIdAndocIdTransferAsync(ocIdTransfer) else { + return + } + NCNetworking.shared.cancelTask(metadata: metadata) + } } override func longPressMoreListItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { @@ -101,13 +105,15 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate { override func longPressListItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { if gestureRecognizer.state != .began { return } - if let metadata = self.database.getMetadataFromOcIdAndocIdTransfer(ocIdTransfer) { - metadataTemp = metadata - let touchPoint = gestureRecognizer.location(in: collectionView) - becomeFirstResponder() - let startTaskItem = UIMenuItem(title: NSLocalizedString("_force_start_", comment: ""), action: #selector(startTask(_:))) - UIMenuController.shared.menuItems = [startTaskItem] - UIMenuController.shared.showMenu(from: collectionView, rect: CGRect(x: touchPoint.x, y: touchPoint.y, width: 0, height: 0)) + Task { + if let metadata = await self.database.getMetadataFromOcIdAndocIdTransferAsync(ocIdTransfer) { + metadataTemp = metadata + let touchPoint = gestureRecognizer.location(in: collectionView) + becomeFirstResponder() + let startTaskItem = UIMenuItem(title: NSLocalizedString("_force_start_", comment: ""), action: #selector(startTask(_:))) + UIMenuController.shared.menuItems = [startTaskItem] + UIMenuController.shared.showMenu(from: collectionView, rect: CGRect(x: touchPoint.x, y: touchPoint.y, width: 0, height: 0)) + } } } From 5efc74c5f374cc76504eb0f99b6fc2e2f1362e0d Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 11:15:04 +0200 Subject: [PATCH 11/22] fix Signed-off-by: Marino Faggiana --- iOSClient/Networking/NCNetworkingProcess.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 2c6ba2a450..77db267269 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -68,6 +68,9 @@ actor NCNetworkingProcess { } func startTimer(interval: TimeInterval) async { + guard !isAppInBackground else { + return + } await stopTimer() lastUsedInterval = interval From 589cf8d621c3cafaef587656c47aa7fd8b6fd8d9 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 11:19:21 +0200 Subject: [PATCH 12/22] fix Signed-off-by: Marino Faggiana --- iOSClient/NCAppStateManager.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iOSClient/NCAppStateManager.swift b/iOSClient/NCAppStateManager.swift index c48bb0abe1..1aee802dc0 100644 --- a/iOSClient/NCAppStateManager.swift +++ b/iOSClient/NCAppStateManager.swift @@ -35,6 +35,8 @@ final class NCAppStateManager { } NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { _ in + isAppInBackground = true + nkLog(debug: "Application did enter in background") } } From f9db64c843022f39296548923f417de8a2846668 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 11:38:18 +0200 Subject: [PATCH 13/22] fix Signed-off-by: Marino Faggiana --- iOSClient/Networking/NCNetworkingProcess.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 77db267269..41e7ad0dcd 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -68,9 +68,13 @@ actor NCNetworkingProcess { } func startTimer(interval: TimeInterval) async { - guard !isAppInBackground else { + let isActive = await MainActor.run { + UIApplication.shared.applicationState == .active + } + guard isActive else { return } + await stopTimer() lastUsedInterval = interval @@ -79,7 +83,9 @@ actor NCNetworkingProcess { newTimer.setEventHandler { [weak self] in guard let self else { return } - Task { await self.handleTimerTick() } + Task { + await self.handleTimerTick() + } } timer = newTimer From 5f4001f468765d17ed978f3d62e4c96de303d73f Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 11:39:24 +0200 Subject: [PATCH 14/22] Revert "remove appsuspending" This reverts commit 2e083aae521a59a5cba4df59b97b5a96c4975670. Signed-off-by: Marino Faggiana # Conflicts: # iOSClient/Data/NCManageDatabase.swift # iOSClient/NCAppStateManager.swift --- iOSClient/AppDelegate.swift | 2 + iOSClient/Data/NCManageDatabase.swift | 47 +++++++++++++++++++ iOSClient/NCAppStateManager.swift | 9 ++++ .../NCBackgroundLocationUploadManager.swift | 1 + 4 files changed, 59 insertions(+) diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index 8a265100a8..a0de047455 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -190,6 +190,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } // Open Realm + isAppSuspending = false // now you can read/write in Realm if database.openRealmBackground() { scheduleAppRefresh() } else { @@ -222,6 +223,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } // Open Realm + isAppSuspending = false // now you can read/write in Realm if database.openRealmBackground() { scheduleAppProcessing() } else { diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index fb06594132..4086c8c116 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/iOSClient/Data/NCManageDatabase.swift @@ -200,7 +200,14 @@ final class NCManageDatabase: @unchecked Sendable { @discardableResult func performRealmRead(_ block: @escaping (Realm) throws -> T?, sync: Bool = true, completion: ((T?) -> Void)? = nil) -> T? { +<<<<<<< HEAD let isOnRealmQueue = DispatchQueue.getSpecific(key: NCManageDatabase.realmQueueKey) != nil +======= + guard !isAppSuspending else { + completion?(nil) + return nil + } +>>>>>>> parent of 2e083aae52 (remove appsuspending) if sync { if isOnRealmQueue { @@ -241,7 +248,14 @@ final class NCManageDatabase: @unchecked Sendable { } func performRealmWrite(sync: Bool = true, _ block: @escaping (Realm) throws -> Void) { +<<<<<<< HEAD let isOnRealmQueue = DispatchQueue.getSpecific(key: NCManageDatabase.realmQueueKey) != nil +======= + guard !isAppSuspending + else { + return + } +>>>>>>> parent of 2e083aae52 (remove appsuspending) let executionBlock: @Sendable () -> Void = { autoreleasepool { @@ -273,6 +287,23 @@ final class NCManageDatabase: @unchecked Sendable { func performRealmReadAsync(_ block: @escaping (Realm) throws -> T?) async -> T? { await withCheckedContinuation { continuation in realmQueue.async { +<<<<<<< HEAD +======= + var didResume = false + defer { + if !didResume { + continuation.resume(returning: nil) + } + } + + if isAppSuspending { + // App is suspending — don't execute the block + continuation.resume(returning: nil) + didResume = true + return + } + +>>>>>>> parent of 2e083aae52 (remove appsuspending) autoreleasepool { do { let realm = try Realm() @@ -290,6 +321,22 @@ final class NCManageDatabase: @unchecked Sendable { func performRealmWriteAsync(_ block: @escaping (Realm) throws -> Void) async { await withCheckedContinuation { continuation in realmQueue.async { +<<<<<<< HEAD +======= + var didResume = false + defer { + if !didResume { + continuation.resume() + } + } + + if isAppSuspending { + continuation.resume() + didResume = true + return + } + +>>>>>>> parent of 2e083aae52 (remove appsuspending) autoreleasepool { do { let realm = try Realm() diff --git a/iOSClient/NCAppStateManager.swift b/iOSClient/NCAppStateManager.swift index 1aee802dc0..5c638f9c3a 100644 --- a/iOSClient/NCAppStateManager.swift +++ b/iOSClient/NCAppStateManager.swift @@ -8,6 +8,9 @@ import NextcloudKit /// Global flag indicating whether the app has ever become active since launch. var hasBecomeActiveOnce: Bool = false +/// Global flag used to control Realm write/read operations during app suspension. +var isAppSuspending: Bool = false + /// Global flag indicating whether the app is currently in background mode. var isAppInBackground: Bool = true @@ -16,6 +19,7 @@ var isAppInBackground: Bool = true /// This class observes system notifications related to app lifecycle events and updates global flags accordingly: /// /// - `hasBecomeActiveOnce`: set to `true` the first time the app enters foreground. +/// - `isAppSuspending`: set to `true` when the app enters background (useful to safely close Realm writes). /// - `isAppInBackground`: indicates whether the app is currently running in background. /// /// Additionally, it logs lifecycle transitions using `nkLog(debug:)`. @@ -25,6 +29,7 @@ final class NCAppStateManager { private init() { NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: nil) { _ in hasBecomeActiveOnce = true + isAppSuspending = false isAppInBackground = false nkLog(debug: "Application will enter in foreground") @@ -35,6 +40,10 @@ final class NCAppStateManager { } NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { _ in +<<<<<<< HEAD +======= + isAppSuspending = true +>>>>>>> parent of 2e083aae52 (remove appsuspending) isAppInBackground = true nkLog(debug: "Application did enter in background") diff --git a/iOSClient/Networking/NCBackgroundLocationUploadManager.swift b/iOSClient/Networking/NCBackgroundLocationUploadManager.swift index 74c9b76430..bb145e2352 100644 --- a/iOSClient/Networking/NCBackgroundLocationUploadManager.swift +++ b/iOSClient/Networking/NCBackgroundLocationUploadManager.swift @@ -111,6 +111,7 @@ class NCBackgroundLocationUploadManager: NSObject, CLLocationManagerDelegate { } // Open Realm + isAppSuspending = false // now you can read/write in Realm if database.openRealmBackground() { let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! let location = locations.last From 2bd3d60f2a8dd1aa17d085cbf873a38f5a4f237f Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 11:53:18 +0200 Subject: [PATCH 15/22] fix Signed-off-by: Marino Faggiana --- iOSClient/Data/NCManageDatabase.swift | 55 +++++++-------------------- iOSClient/NCAppStateManager.swift | 3 -- 2 files changed, 13 insertions(+), 45 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index 4086c8c116..8172865c83 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/iOSClient/Data/NCManageDatabase.swift @@ -200,14 +200,11 @@ final class NCManageDatabase: @unchecked Sendable { @discardableResult func performRealmRead(_ block: @escaping (Realm) throws -> T?, sync: Bool = true, completion: ((T?) -> Void)? = nil) -> T? { -<<<<<<< HEAD - let isOnRealmQueue = DispatchQueue.getSpecific(key: NCManageDatabase.realmQueueKey) != nil -======= guard !isAppSuspending else { completion?(nil) return nil } ->>>>>>> parent of 2e083aae52 (remove appsuspending) + let isOnRealmQueue = DispatchQueue.getSpecific(key: NCManageDatabase.realmQueueKey) != nil if sync { if isOnRealmQueue { @@ -248,14 +245,11 @@ final class NCManageDatabase: @unchecked Sendable { } func performRealmWrite(sync: Bool = true, _ block: @escaping (Realm) throws -> Void) { -<<<<<<< HEAD - let isOnRealmQueue = DispatchQueue.getSpecific(key: NCManageDatabase.realmQueueKey) != nil -======= guard !isAppSuspending else { return } ->>>>>>> parent of 2e083aae52 (remove appsuspending) + let isOnRealmQueue = DispatchQueue.getSpecific(key: NCManageDatabase.realmQueueKey) != nil let executionBlock: @Sendable () -> Void = { autoreleasepool { @@ -285,25 +279,13 @@ final class NCManageDatabase: @unchecked Sendable { // MARK: - performRealmRead async/await, performRealmWrite async/await func performRealmReadAsync(_ block: @escaping (Realm) throws -> T?) async -> T? { - await withCheckedContinuation { continuation in - realmQueue.async { -<<<<<<< HEAD -======= - var didResume = false - defer { - if !didResume { - continuation.resume(returning: nil) - } - } - - if isAppSuspending { - // App is suspending — don't execute the block - continuation.resume(returning: nil) - didResume = true - return - } + // Skip execution if app is suspending + guard !isAppSuspending else { + return nil + } ->>>>>>> parent of 2e083aae52 (remove appsuspending) + return await withCheckedContinuation { continuation in + realmQueue.async { autoreleasepool { do { let realm = try Realm() @@ -319,24 +301,13 @@ final class NCManageDatabase: @unchecked Sendable { } func performRealmWriteAsync(_ block: @escaping (Realm) throws -> Void) async { + // App is suspending — don't execute the block + if isAppSuspending { + return + } + await withCheckedContinuation { continuation in realmQueue.async { -<<<<<<< HEAD -======= - var didResume = false - defer { - if !didResume { - continuation.resume() - } - } - - if isAppSuspending { - continuation.resume() - didResume = true - return - } - ->>>>>>> parent of 2e083aae52 (remove appsuspending) autoreleasepool { do { let realm = try Realm() diff --git a/iOSClient/NCAppStateManager.swift b/iOSClient/NCAppStateManager.swift index 5c638f9c3a..2a947aead0 100644 --- a/iOSClient/NCAppStateManager.swift +++ b/iOSClient/NCAppStateManager.swift @@ -40,10 +40,7 @@ final class NCAppStateManager { } NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { _ in -<<<<<<< HEAD -======= isAppSuspending = true ->>>>>>> parent of 2e083aae52 (remove appsuspending) isAppInBackground = true nkLog(debug: "Application did enter in background") From 30411b6a98afec3b8574079e147f2b5bf3cde293 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 15:10:17 +0200 Subject: [PATCH 16/22] clean Signed-off-by: Marino Faggiana --- iOSClient/AppDelegate.swift | 2 -- iOSClient/Data/NCManageDatabase.swift | 7 ++++++- .../Networking/NCBackgroundLocationUploadManager.swift | 1 - iOSClient/Networking/NCNetworkingProcess.swift | 4 +++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index a0de047455..8a265100a8 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -190,7 +190,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } // Open Realm - isAppSuspending = false // now you can read/write in Realm if database.openRealmBackground() { scheduleAppRefresh() } else { @@ -223,7 +222,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } // Open Realm - isAppSuspending = false // now you can read/write in Realm if database.openRealmBackground() { scheduleAppProcessing() } else { diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index 8172865c83..1080b72aed 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/iOSClient/Data/NCManageDatabase.swift @@ -96,6 +96,9 @@ final class NCManageDatabase: @unchecked Sendable { let dirGroup = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroup) let databaseFileUrl = dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + databaseName) + // now you can read/write in Realm + isAppSuspending = false + Realm.Configuration.defaultConfiguration = Realm.Configuration(fileURL: databaseFileUrl, schemaVersion: databaseSchemaVersion, migrationBlock: { migration, oldSchemaVersion in @@ -200,6 +203,7 @@ final class NCManageDatabase: @unchecked Sendable { @discardableResult func performRealmRead(_ block: @escaping (Realm) throws -> T?, sync: Bool = true, completion: ((T?) -> Void)? = nil) -> T? { + // Skip execution if app is suspending guard !isAppSuspending else { completion?(nil) return nil @@ -245,6 +249,7 @@ final class NCManageDatabase: @unchecked Sendable { } func performRealmWrite(sync: Bool = true, _ block: @escaping (Realm) throws -> Void) { + // Skip execution if app is suspending guard !isAppSuspending else { return @@ -301,7 +306,7 @@ final class NCManageDatabase: @unchecked Sendable { } func performRealmWriteAsync(_ block: @escaping (Realm) throws -> Void) async { - // App is suspending — don't execute the block + // Skip execution if app is suspending if isAppSuspending { return } diff --git a/iOSClient/Networking/NCBackgroundLocationUploadManager.swift b/iOSClient/Networking/NCBackgroundLocationUploadManager.swift index bb145e2352..74c9b76430 100644 --- a/iOSClient/Networking/NCBackgroundLocationUploadManager.swift +++ b/iOSClient/Networking/NCBackgroundLocationUploadManager.swift @@ -111,7 +111,6 @@ class NCBackgroundLocationUploadManager: NSObject, CLLocationManagerDelegate { } // Open Realm - isAppSuspending = false // now you can read/write in Realm if database.openRealmBackground() { let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! let location = locations.last diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 41e7ad0dcd..159d2a34b4 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -234,7 +234,9 @@ actor NCNetworkingProcess { let isInDirectoryE2EE = metadata.isDirectoryE2EE /// NO WiFi if !isWiFi && metadata.session == networking.sessionUploadBackgroundWWan { continue } - if isAppInBackground && (isInDirectoryE2EE || metadata.chunk > 0) { continue } + if isAppInBackground && (isInDirectoryE2EE || metadata.chunk > 0) { + continue + } await self.database.setMetadataStatusAsync(ocId: metadata.ocId, status: global.metadataStatusUploading) From 7fa903e57f3f97c8d2d21bfba0c553b77f96fe09 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 15:27:52 +0200 Subject: [PATCH 17/22] rename Signed-off-by: Marino Faggiana --- iOSClient/SceneDelegate.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/iOSClient/SceneDelegate.swift b/iOSClient/SceneDelegate.swift index f1181ca762..15e25bcc46 100644 --- a/iOSClient/SceneDelegate.swift +++ b/iOSClient/SceneDelegate.swift @@ -29,12 +29,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { self.window?.overrideUserInterfaceStyle = NCKeychain().appearanceInterfaceStyle } - if let activeTableAccount = self.database.getActiveTableAccount() { - nkLog(debug: "Account active \(activeTableAccount.account)") + if let activeTblAccount = self.database.getActiveTableAccount() { + nkLog(debug: "Account active \(activeTblAccount.account)") - NCBrandColor.shared.settingThemingColor(account: activeTableAccount.account) Task { - await NCNetworkingProcess.shared.setCurrentAccount(activeTableAccount.account) + await NCNetworkingProcess.shared.setCurrentAccount(activeTblAccount.account) } for tableAccount in self.database.getAllTableAccount() { NextcloudKit.shared.appendSession(account: tableAccount.account, @@ -57,7 +56,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController { SceneManager.shared.register(scene: scene, withRootViewController: controller) /// Set the ACCOUNT - controller.account = activeTableAccount.account + controller.account = activeTblAccount.account /// window?.rootViewController = controller window?.makeKeyAndVisible() From 02be57c9007a58e51dd0ff7f4c87fa7c24dcf4ae Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 15:54:27 +0200 Subject: [PATCH 18/22] theming Signed-off-by: Marino Faggiana --- .../Collection Common/NCCollectionViewCommon.swift | 11 ++++------- iOSClient/SceneDelegate.swift | 4 ++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 22a073ed0e..50098bd2f1 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -244,7 +244,10 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS let dropInteraction = UIDropInteraction(delegate: self) self.navigationController?.navigationItem.leftBarButtonItems?.first?.customView?.addInteraction(dropInteraction) - NotificationCenter.default.addObserver(self, selector: #selector(changeTheming(_:)), name: NSNotification.Name(rawValue: global.notificationCenterChangeTheming), object: nil) + NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: self.global.notificationCenterChangeTheming), object: nil, queue: .main) { [weak self] _ in + guard let self else { return } + self.collectionView.reloadData() + } DispatchQueue.main.async { self.collectionView?.collectionViewLayout.invalidateLayout() @@ -528,12 +531,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS self.resetPlusButtonAlpha() } - @objc func changeTheming(_ notification: NSNotification) { - Task { - await self.reloadDataSource() - } - } - @objc func closeRichWorkspaceWebView() { Task { await self.reloadDataSource() diff --git a/iOSClient/SceneDelegate.swift b/iOSClient/SceneDelegate.swift index 15e25bcc46..979a7fbdc4 100644 --- a/iOSClient/SceneDelegate.swift +++ b/iOSClient/SceneDelegate.swift @@ -31,6 +31,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { if let activeTblAccount = self.database.getActiveTableAccount() { nkLog(debug: "Account active \(activeTblAccount.account)") + // set capabilities + self.database.applyCachedCapabilitiesBlocking(account: activeTblAccount.account) + // set theming color + NCBrandColor.shared.settingThemingColor(account: activeTblAccount.account) Task { await NCNetworkingProcess.shared.setCurrentAccount(activeTblAccount.account) From dd2c619b6df58d131d863fc3978281c52e1cd6d2 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 15:55:59 +0200 Subject: [PATCH 19/22] clean Signed-off-by: Marino Faggiana --- iOSClient/Data/NCManageDatabase.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index 1080b72aed..7f546313a0 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/iOSClient/Data/NCManageDatabase.swift @@ -110,12 +110,11 @@ final class NCManageDatabase: @unchecked Sendable { if let url = realm.configuration.fileURL { nkLog(start: "Realm is located at: \(url.path)") } + return true } catch { nkLog(error: "Realm error: \(error)") return false } - - return true } private func openRealmAppex() { From f38c7caaf325f97f52fa161a47a08f1951877690 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 16:00:44 +0200 Subject: [PATCH 20/22] async Signed-off-by: Marino Faggiana --- iOSClient/Data/NCManageDatabase+Account.swift | 37 +++++++++++++++++++ iOSClient/Networking/NCAutoUpload.swift | 4 +- .../NCNetworking+Recommendations.swift | 2 +- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase+Account.swift b/iOSClient/Data/NCManageDatabase+Account.swift index 0e0b993a1d..49fee902b8 100644 --- a/iOSClient/Data/NCManageDatabase+Account.swift +++ b/iOSClient/Data/NCManageDatabase+Account.swift @@ -518,6 +518,21 @@ extension NCManageDatabase { } ?? NCBrandOptions.shared.folderDefaultAutoUpload } + func getAccountAutoUploadFileNameAsync(account: String) async -> String { + let result: String? = await performRealmReadAsync { realm in + guard let record = realm.objects(tableAccount.self) + .filter("account == %@", account) + .first + else { + return nil + } + + return record.autoUploadFileName.isEmpty ? nil : record.autoUploadFileName + } + + return result ?? NCBrandOptions.shared.folderDefaultAutoUpload + } + func getAccountAutoUploadDirectory(session: NCSession.Session) -> String { return getAccountAutoUploadDirectory(account: session.account, urlBase: session.urlBase, userId: session.userId) } @@ -535,6 +550,21 @@ extension NCManageDatabase { } ?? homeServer } + func getAccountAutoUploadDirectoryAsync(account: String, urlBase: String, userId: String) async -> String { + let homeServer = utilityFileSystem.getHomeServer(urlBase: urlBase, userId: userId) + + let directory: String? = await performRealmReadAsync { realm in + realm.objects(tableAccount.self) + .filter("account == %@", account) + .first? + .autoUploadDirectory + } + + return directory.flatMap { dir in + (dir.isEmpty || dir.contains("/webdav")) ? homeServer : dir + } ?? homeServer + } + func getAccountAutoUploadServerUrlBase(session: NCSession.Session) -> String { return getAccountAutoUploadServerUrlBase(account: session.account, urlBase: session.urlBase, userId: session.userId) } @@ -546,6 +576,13 @@ extension NCManageDatabase { return folderPhotos } + func getAccountAutoUploadServerUrlBaseAsync(account: String, urlBase: String, userId: String) async -> String { + let cameraFileName = await self.getAccountAutoUploadFileNameAsync(account: account) + let cameraDirectory = await self.getAccountAutoUploadDirectoryAsync(account: account, urlBase: urlBase, userId: userId) + let folderPhotos = utilityFileSystem.stringAppendServerUrl(cameraDirectory, addFileName: cameraFileName) + return folderPhotos + } + func getAccountAutoUploadSubfolderGranularity() -> Int { performRealmRead { realm in realm.objects(tableAccount.self) diff --git a/iOSClient/Networking/NCAutoUpload.swift b/iOSClient/Networking/NCAutoUpload.swift index fb70b6933b..10f2c4893f 100644 --- a/iOSClient/Networking/NCAutoUpload.swift +++ b/iOSClient/Networking/NCAutoUpload.swift @@ -57,7 +57,7 @@ class NCAutoUpload: NSObject { private func uploadAssets(controller: NCMainTabBarController? = nil, tblAccount: tableAccount, assets: [PHAsset], fileNames: [String]) async -> Int { let session = NCSession.shared.getSession(account: tblAccount.account) - let autoUploadServerUrlBase = self.database.getAccountAutoUploadServerUrlBase(account: tblAccount.account, urlBase: tblAccount.urlBase, userId: tblAccount.userId) + let autoUploadServerUrlBase = await self.database.getAccountAutoUploadServerUrlBaseAsync(account: tblAccount.account, urlBase: tblAccount.urlBase, userId: tblAccount.userId) var metadatas: [tableMetadata] = [] let formatCompatibility = NCKeychain().formatCompatibility let keychainLivePhoto = NCKeychain().livePhoto @@ -155,7 +155,7 @@ class NCAutoUpload: NSObject { guard hasPermission else { return (nil, nil) } - let autoUploadServerUrlBase = self.database.getAccountAutoUploadServerUrlBase(account: tblAccount.account, urlBase: tblAccount.urlBase, userId: tblAccount.userId) + let autoUploadServerUrlBase = await self.database.getAccountAutoUploadServerUrlBaseAsync(account: tblAccount.account, urlBase: tblAccount.urlBase, userId: tblAccount.userId) var mediaPredicates: [NSPredicate] = [] var datePredicates: [NSPredicate] = [] let fetchOptions = PHFetchOptions() diff --git a/iOSClient/Networking/NCNetworking+Recommendations.swift b/iOSClient/Networking/NCNetworking+Recommendations.swift index fe21ade295..f8fd2fc0aa 100644 --- a/iOSClient/Networking/NCNetworking+Recommendations.swift +++ b/iOSClient/Networking/NCNetworking+Recommendations.swift @@ -40,8 +40,8 @@ extension NCNetworking { } } } - await self.database.createRecommendedFilesAsync(account: session.account, recommendations: recommendationsToInsert) + await self.database.createRecommendedFilesAsync(account: session.account, recommendations: recommendationsToInsert) await collectionView.reloadData() } } From bf870ddaaf1fb52c1e9243bda49b0892ff74b06e Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 16:09:07 +0200 Subject: [PATCH 21/22] async Signed-off-by: Marino Faggiana --- iOSClient/Data/NCManageDatabase+Account.swift | 4 ++++ .../Data/NCManageDatabase+AutoUpload.swift | 18 +++++++++++++++--- .../AutoUpload/NCAutoUploadModel.swift | 5 ++--- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase+Account.swift b/iOSClient/Data/NCManageDatabase+Account.swift index 49fee902b8..4ad7f94746 100644 --- a/iOSClient/Data/NCManageDatabase+Account.swift +++ b/iOSClient/Data/NCManageDatabase+Account.swift @@ -569,6 +569,10 @@ extension NCManageDatabase { return getAccountAutoUploadServerUrlBase(account: session.account, urlBase: session.urlBase, userId: session.userId) } + func getAccountAutoUploadServerUrlBaseAsync(session: NCSession.Session) async -> String { + return await getAccountAutoUploadServerUrlBaseAsync(account: session.account, urlBase: session.urlBase, userId: session.userId) + } + func getAccountAutoUploadServerUrlBase(account: String, urlBase: String, userId: String) -> String { let cameraFileName = self.getAccountAutoUploadFileName(account: account) let cameraDirectory = self.getAccountAutoUploadDirectory(account: account, urlBase: urlBase, userId: userId) diff --git a/iOSClient/Data/NCManageDatabase+AutoUpload.swift b/iOSClient/Data/NCManageDatabase+AutoUpload.swift index 4b70f4d71a..e2bab0e8ba 100644 --- a/iOSClient/Data/NCManageDatabase+AutoUpload.swift +++ b/iOSClient/Data/NCManageDatabase+AutoUpload.swift @@ -57,7 +57,8 @@ extension NCManageDatabase { // MARK: - Realm Read - func fetchSkipFileNames(account: String, autoUploadServerUrlBase: String) async -> Set { + func fetchSkipFileNames(account: String, + autoUploadServerUrlBase: String) async -> Set { let result: Set? = await performRealmReadAsync { realm in let metadatas = realm.objects(tableMetadata.self) .filter("account == %@ AND autoUploadServerUrlBase == %@ AND status IN %@", account, autoUploadServerUrlBase, NCGlobal.shared.metadataStatusUploadingAllMode) @@ -78,7 +79,8 @@ extension NCManageDatabase { /// - account: The account identifier. /// - autoUploadServerUrlBase: The server base URL for auto-upload. /// - Returns: The most recent upload `Date`, or `nil` if no entry exists. - func fetchLastAutoUploadedDateAsync(account: String, autoUploadServerUrlBase: String) async -> Date? { + func fetchLastAutoUploadedDateAsync(account: String, + autoUploadServerUrlBase: String) async -> Date? { await performRealmReadAsync { realm in realm.objects(tableAutoUploadTransfer.self) .filter("account == %@ AND serverUrlBase == %@", account, autoUploadServerUrlBase) @@ -87,11 +89,21 @@ extension NCManageDatabase { } } - func existsAutoUpload(account: String, autoUploadServerUrlBase: String) -> Bool { + func existsAutoUpload(account: String, + autoUploadServerUrlBase: String) -> Bool { return performRealmRead { realm in realm.objects(tableAutoUploadTransfer.self) .filter("account == %@ AND serverUrlBase == %@", account, autoUploadServerUrlBase) .first != nil } ?? false } + + func existsAutoUploadAsync(account: String, + autoUploadServerUrlBase: String) async -> Bool { + return await performRealmReadAsync { realm in + realm.objects(tableAutoUploadTransfer.self) + .filter("account == %@ AND serverUrlBase == %@", account, autoUploadServerUrlBase) + .first != nil + } ?? false + } } diff --git a/iOSClient/Settings/AutoUpload/NCAutoUploadModel.swift b/iOSClient/Settings/AutoUpload/NCAutoUploadModel.swift index 01b7dc7db3..25b5157e67 100644 --- a/iOSClient/Settings/AutoUpload/NCAutoUploadModel.swift +++ b/iOSClient/Settings/AutoUpload/NCAutoUploadModel.swift @@ -241,9 +241,8 @@ class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling { func deleteAutoUploadTransfer() { Task { - let autoUploadServerUrlBase = NCManageDatabase.shared.getAccountAutoUploadServerUrlBase(session: session) - await NCManageDatabase.shared.deleteAutoUploadTransferAsync(account: session.account, - autoUploadServerUrlBase: autoUploadServerUrlBase) + let autoUploadServerUrlBase = await NCManageDatabase.shared.getAccountAutoUploadServerUrlBaseAsync(session: session) + await NCManageDatabase.shared.deleteAutoUploadTransferAsync(account: session.account, autoUploadServerUrlBase: autoUploadServerUrlBase) } } From 30535ffa65d07050855876c3d7882b79811f684a Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 6 Jul 2025 16:12:06 +0200 Subject: [PATCH 22/22] remove old code Signed-off-by: Marino Faggiana --- iOSClient/Networking/NCNetworkingProcess.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/iOSClient/Networking/NCNetworkingProcess.swift b/iOSClient/Networking/NCNetworkingProcess.swift index 159d2a34b4..aba932ef98 100644 --- a/iOSClient/Networking/NCNetworkingProcess.swift +++ b/iOSClient/Networking/NCNetworkingProcess.swift @@ -141,7 +141,6 @@ actor NCNetworkingProcess { private func removeUploadedAssetsIfNeeded() async { guard NCKeychain().removePhotoCameraRoll, - !isAppInBackground, let localIdentifiers = await self.database.getAssetLocalIdentifiersUploadedAsync(), !localIdentifiers.isEmpty else { return @@ -234,9 +233,6 @@ actor NCNetworkingProcess { let isInDirectoryE2EE = metadata.isDirectoryE2EE /// NO WiFi if !isWiFi && metadata.session == networking.sessionUploadBackgroundWWan { continue } - if isAppInBackground && (isInDirectoryE2EE || metadata.chunk > 0) { - continue - } await self.database.setMetadataStatusAsync(ocId: metadata.ocId, status: global.metadataStatusUploading)