diff --git a/Account/Sources/Account/Account.swift b/Account/Sources/Account/Account.swift index 606d3c994..e80c63bd6 100644 --- a/Account/Sources/Account/Account.swift +++ b/Account/Sources/Account/Account.swift @@ -646,8 +646,9 @@ public enum FetchType { try await delegate.createFolder(for: self, name: name) } - public func removeFolder(_ folder: Folder, completion: @escaping (Result) -> Void) { - delegate.removeFolder(for: self, with: folder, completion: completion) + public func removeFolder(_ folder: Folder) async throws { + + try await delegate.removeFolder(for: self, with: folder) } public func renameFolder(_ folder: Folder, to name: String) async throws { @@ -1020,7 +1021,7 @@ public enum FetchType { } } - func removeFolder(_ folder: Folder) { + func removeFolder(folder: Folder) { folders?.remove(folder) structureDidChange() postChildrenDidChangeNotification() diff --git a/Account/Sources/Account/AccountDelegate.swift b/Account/Sources/Account/AccountDelegate.swift index de45a7ac1..09c1e594c 100644 --- a/Account/Sources/Account/AccountDelegate.swift +++ b/Account/Sources/Account/AccountDelegate.swift @@ -34,7 +34,7 @@ import Secrets func createFolder(for account: Account, name: String) async throws -> Folder func renameFolder(for account: Account, with folder: Folder, to name: String) async throws - func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) + func removeFolder(for account: Account, with folder: Folder) async throws func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result) -> Void) func renameFeed(for account: Account, with feed: Feed, to name: String) async throws diff --git a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift index f81f4c452..ee80b3e42 100644 --- a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift +++ b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift @@ -415,8 +415,23 @@ enum CloudKitAccountDelegateError: LocalizedError { } } - func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) { - + func removeFolder(for account: Account, with folder: Folder) async throws { + + try await withCheckedThrowingContinuation { continuation in + + self.removeFolder(for: account, with: folder) { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + + private func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) { + refreshProgress.addToNumberOfTasksAndRemaining(2) accountZone.findFeedExternalIDs(for: folder) { result in self.refreshProgress.completeTask() @@ -450,7 +465,7 @@ enum CloudKitAccountDelegateError: LocalizedError { self.refreshProgress.completeTask() switch result { case .success: - account.removeFolder(folder) + account.removeFolder(folder: folder) completion(.success(())) case .failure(let error): completion(.failure(error)) @@ -858,7 +873,7 @@ private extension CloudKitAccountDelegate { if case CloudKitZoneError.userDeletedZone = error { account.removeFeeds(account.topLevelFeeds) for folder in account.folders ?? Set() { - account.removeFolder(folder) + account.removeFolder(folder: folder) } } } diff --git a/Account/Sources/Account/CloudKit/CloudKitAccountZoneDelegate.swift b/Account/Sources/Account/CloudKit/CloudKitAccountZoneDelegate.swift index 5eb2857be..19c82585d 100644 --- a/Account/Sources/Account/CloudKit/CloudKitAccountZoneDelegate.swift +++ b/Account/Sources/Account/CloudKit/CloudKitAccountZoneDelegate.swift @@ -132,7 +132,7 @@ import CloudKitExtras func removeContainer(_ externalID: String) { if let folder = account?.existingFolder(withExternalID: externalID) { - account?.removeFolder(folder) + account?.removeFolder(folder: folder) } } } diff --git a/Account/Sources/Account/CloudKit/CloudKitSendStatusOperation.swift b/Account/Sources/Account/CloudKit/CloudKitSendStatusOperation.swift index 55d377829..a82a17013 100644 --- a/Account/Sources/Account/CloudKit/CloudKitSendStatusOperation.swift +++ b/Account/Sources/Account/CloudKit/CloudKitSendStatusOperation.swift @@ -174,7 +174,7 @@ private extension CloudKitSendStatusOperation { if case CloudKitZoneError.userDeletedZone = error { account.removeFeeds(account.topLevelFeeds) for folder in account.folders ?? Set() { - account.removeFolder(folder) + account.removeFolder(folder: folder) } } } diff --git a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift index 3bf478b5c..27ec23c12 100644 --- a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift @@ -389,11 +389,26 @@ final class FeedbinAccountDelegate: AccountDelegate { } - func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) { + func removeFolder(for account: Account, with folder: Folder) async throws { + + try await withCheckedThrowingContinuation { continuation in + + self.removeFolder(for: account, with: folder) { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + + private func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) { // Feedbin uses tags and if at least one feed isn't tagged, then the folder doesn't exist on their system guard folder.hasAtLeastOneFeed() else { - account.removeFolder(folder) + account.removeFolder(folder: folder) completion(.success(())) return } @@ -446,7 +461,7 @@ final class FeedbinAccountDelegate: AccountDelegate { } group.notify(queue: DispatchQueue.main) { - account.removeFolder(folder) + account.removeFolder(folder: folder) completion(.success(())) } @@ -930,7 +945,7 @@ private extension FeedbinAccountDelegate { account.addFeed(feed) clearFolderRelationship(for: feed, withFolderName: folder.name ?? "") } - account.removeFolder(folder) + account.removeFolder(folder: folder) } } } diff --git a/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift b/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift index d20c3724b..5cd0812e4 100644 --- a/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift +++ b/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift @@ -381,7 +381,22 @@ final class FeedlyAccountDelegate: AccountDelegate { folder.name = name } - func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) { + func removeFolder(for account: Account, with folder: Folder) async throws { + + try await withCheckedThrowingContinuation { continuation in + + self.removeFolder(for: account, with: folder) { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + + private func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) { guard let id = folder.externalID else { return DispatchQueue.main.async { completion(.failure(FeedlyAccountDelegateError.unableToRemoveFolder(folder.nameForDisplay))) @@ -396,7 +411,7 @@ final class FeedlyAccountDelegate: AccountDelegate { switch result { case .success: - account.removeFolder(folder) + account.removeFolder(folder: folder) completion(.success(())) case .failure(let error): completion(.failure(error)) diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyMirrorCollectionsAsFoldersOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyMirrorCollectionsAsFoldersOperation.swift index 376459ff6..b720a26be 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyMirrorCollectionsAsFoldersOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyMirrorCollectionsAsFoldersOperation.swift @@ -54,7 +54,7 @@ final class FeedlyMirrorCollectionsAsFoldersOperation: FeedlyOperation, FeedlyFe if !foldersWithoutCollections.isEmpty { for unmatched in foldersWithoutCollections { - account.removeFolder(unmatched) + account.removeFolder(folder: unmatched) } os_log(.debug, log: log, "Removed %i folders: %@", foldersWithoutCollections.count, foldersWithoutCollections.map { $0.externalID ?? $0.nameForDisplay }) diff --git a/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift b/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift index 5fea4ce27..3d0fff3ab 100644 --- a/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift +++ b/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift @@ -130,12 +130,13 @@ final class LocalAccountDelegate: AccountDelegate { folder.name = name } - func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) { - account.removeFolder(folder) - completion(.success(())) + func removeFolder(for account: Account, with folder: Folder) async throws { + + account.removeFolder(folder: folder) } - + func restoreFolder(for account: Account, folder: Folder) async throws { + account.addFolder(folder) } diff --git a/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift b/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift index 65846f7c8..189c00ad0 100644 --- a/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift +++ b/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift @@ -54,7 +54,7 @@ extension NewsBlurAccountDelegate { account.addFeed(feed) clearFolderRelationship(for: feed, withFolderName: folder.name ?? "") } - account.removeFolder(folder) + account.removeFolder(folder: folder) } } } diff --git a/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift b/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift index c0db2e6df..7d0c7fcc7 100644 --- a/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift +++ b/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift @@ -470,7 +470,22 @@ final class NewsBlurAccountDelegate: AccountDelegate { folder.name = name } - func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> ()) { + func removeFolder(for account: Account, with folder: Folder) async throws { + + try await withCheckedThrowingContinuation { continuation in + + self.removeFolder(for: account, with: folder) { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + + private func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> ()) { guard let folderToRemove = folder.name else { completion(.failure(NewsBlurError.invalidParameter)) return @@ -492,7 +507,7 @@ final class NewsBlurAccountDelegate: AccountDelegate { switch result { case .success: - account.removeFolder(folder) + account.removeFolder(folder: folder) completion(.success(())) case .failure(let error): completion(.failure(error)) diff --git a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift index a24acacdd..3fef5b871 100644 --- a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift +++ b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift @@ -386,7 +386,22 @@ final class ReaderAPIAccountDelegate: AccountDelegate { } - func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) { + func removeFolder(for account: Account, with folder: Folder) async throws { + + try await withCheckedThrowingContinuation { continuation in + + self.removeFolder(for: account, with: folder) { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + + private func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) { let group = DispatchGroup() @@ -437,13 +452,13 @@ final class ReaderAPIAccountDelegate: AccountDelegate { group.notify(queue: DispatchQueue.main) { if self.variant == .theOldReader { - account.removeFolder(folder) + account.removeFolder(folder: folder) completion(.success(())) } else { self.caller.deleteTag(folder: folder) { result in switch result { case .success: - account.removeFolder(folder) + account.removeFolder(folder: folder) completion(.success(())) case .failure(let error): completion(.failure(error)) @@ -872,7 +887,7 @@ private extension ReaderAPIAccountDelegate { account.addFeed(feed) clearFolderRelationship(for: feed, folderExternalID: folder.externalID) } - account.removeFolder(folder) + account.removeFolder(folder: folder) } } } diff --git a/Mac/Scriptability/Account+Scriptability.swift b/Mac/Scriptability/Account+Scriptability.swift index 682c939f6..2bc40ba49 100644 --- a/Mac/Scriptability/Account+Scriptability.swift +++ b/Mac/Scriptability/Account+Scriptability.swift @@ -68,23 +68,24 @@ import Core } @MainActor func deleteElement(_ element:ScriptingObject) { - if let scriptableFolder = element as? ScriptableFolder { - BatchUpdate.shared.perform { - account.removeFolder(scriptableFolder.folder) { result in - } - } - } else if let scriptableFeed = element as? ScriptableFeed { - BatchUpdate.shared.perform { - var container: Container? = nil - if let scriptableFolder = scriptableFeed.container as? ScriptableFolder { - container = scriptableFolder.folder - } else { - container = account - } - account.removeFeed(scriptableFeed.feed, from: container!) { result in - } - } - } + // TODO: fix this +// if let scriptableFolder = element as? ScriptableFolder { +// BatchUpdate.shared.perform { +// account.removeFolder(scriptableFolder.folder) { result in +// } +// } +// } else if let scriptableFeed = element as? ScriptableFeed { +// BatchUpdate.shared.perform { +// var container: Container? = nil +// if let scriptableFolder = scriptableFeed.container as? ScriptableFolder { +// container = scriptableFolder.folder +// } else { +// container = account +// } +// account.removeFeed(scriptableFeed.feed, from: container!) { result in +// } +// } +// } } @objc(isLocationRequiredToCreateForKey:) diff --git a/Shared/Commands/DeleteCommand.swift b/Shared/Commands/DeleteCommand.swift index a151a2db5..8057d3351 100644 --- a/Shared/Commands/DeleteCommand.swift +++ b/Shared/Commands/DeleteCommand.swift @@ -143,30 +143,36 @@ import Core } func delete(completion: @escaping () -> Void) { - + if let feed = feed { - + guard let container = path.resolveContainer() else { completion() return } - + BatchUpdate.shared.start() account?.removeFeed(feed, from: container) { result in BatchUpdate.shared.end() completion() self.checkResult(result) } - + } else if let folder = folder { - + BatchUpdate.shared.start() - account?.removeFolder(folder) { result in - BatchUpdate.shared.end() - completion() - self.checkResult(result) + + Task { @MainActor in + do { + try await account?.removeFolder(folder) + BatchUpdate.shared.end() + completion() + } catch { + BatchUpdate.shared.end() + completion() + self.errorHandler(error) + } } - } }