From 378e116b5cf5e41f2f44e55a70178ffdf9f181b7 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Tue, 10 Oct 2023 21:21:52 -0700 Subject: [PATCH] Convert AccountDelegate.createFolder to async/await. --- Account/Sources/Account/Account.swift | 4 +- Account/Sources/Account/AccountDelegate.swift | 2 +- .../FeedbinAccountDelegate.swift | 12 +++--- .../LocalAccountDelegate.swift | 12 +++--- .../NewsBlurAccountDelegate.swift | 42 ++++++++++--------- .../ReaderAPIAccountDelegate.swift | 12 +++--- .../CloudKit/CloudKitAccountDelegate.swift | 29 +++++++------ .../Feedly/FeedlyAccountDelegate.swift | 32 +++++++------- .../AddFolder/AddFolderWindowController.swift | 9 ++-- .../Sidebar/SidebarOutlineDataSource.swift | 8 ++-- Mac/Scriptability/Folder+Scriptability.swift | 17 ++++---- 11 files changed, 95 insertions(+), 84 deletions(-) diff --git a/Account/Sources/Account/Account.swift b/Account/Sources/Account/Account.swift index 3f27c6b22..03b8d1a39 100644 --- a/Account/Sources/Account/Account.swift +++ b/Account/Sources/Account/Account.swift @@ -634,8 +634,8 @@ public enum FetchType { delegate.restoreFeed(for: self, feed: feed, container: container, completion: completion) } - public func addFolder(_ name: String, completion: @escaping (Result) -> Void) { - delegate.createFolder(for: self, name: name, completion: completion) + public func addFolder(_ name: String) async throws -> Folder { + try await delegate.createFolder(for: self, name: name) } public func removeFolder(_ folder: Folder, completion: @escaping (Result) -> Void) { diff --git a/Account/Sources/Account/AccountDelegate.swift b/Account/Sources/Account/AccountDelegate.swift index 1c4629b83..aac87ca5d 100644 --- a/Account/Sources/Account/AccountDelegate.swift +++ b/Account/Sources/Account/AccountDelegate.swift @@ -32,7 +32,7 @@ import Secrets func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result) -> Void) - func createFolder(for account: Account, name: String, completion: @escaping (Result) -> Void) + func createFolder(for account: Account, name: String) async throws -> Folder func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result) -> Void) func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> Void) diff --git a/Account/Sources/Account/AccountDelegates/FeedbinAccountDelegate.swift b/Account/Sources/Account/AccountDelegates/FeedbinAccountDelegate.swift index 8a1760d93..72c407ce2 100644 --- a/Account/Sources/Account/AccountDelegates/FeedbinAccountDelegate.swift +++ b/Account/Sources/Account/AccountDelegates/FeedbinAccountDelegate.swift @@ -282,11 +282,13 @@ public enum FeedbinAccountDelegateError: String, Error { } - func createFolder(for account: Account, name: String, completion: @escaping (Result) -> Void) { - if let folder = account.ensureFolder(with: name) { - completion(.success(folder)) - } else { - completion(.failure(FeedbinAccountDelegateError.invalidParameter)) + func createFolder(for account: Account, name: String) async throws -> Folder { + try await withCheckedThrowingContinuation { continuation in + if let folder = account.ensureFolder(with: name) { + continuation.resume(returning: folder) + } else { + continuation.resume(throwing: FeedbinAccountDelegateError.invalidParameter) + } } } diff --git a/Account/Sources/Account/AccountDelegates/LocalAccountDelegate.swift b/Account/Sources/Account/AccountDelegates/LocalAccountDelegate.swift index f3608dcc0..f521f0887 100644 --- a/Account/Sources/Account/AccountDelegates/LocalAccountDelegate.swift +++ b/Account/Sources/Account/AccountDelegates/LocalAccountDelegate.swift @@ -163,11 +163,13 @@ final class LocalAccountDelegate: AccountDelegate, Logging { completion(.success(())) } - func createFolder(for account: Account, name: String, completion: @escaping (Result) -> Void) { - if let folder = account.ensureFolder(with: name) { - completion(.success(folder)) - } else { - completion(.failure(FeedbinAccountDelegateError.invalidParameter)) + func createFolder(for account: Account, name: String) async throws -> Folder { + try await withCheckedThrowingContinuation { continuation in + if let folder = account.ensureFolder(with: name) { + continuation.resume(returning: folder) + } else { + continuation.resume(throwing: FeedbinAccountDelegateError.invalidParameter) + } } } diff --git a/Account/Sources/Account/AccountDelegates/NewsBlurAccountDelegate.swift b/Account/Sources/Account/AccountDelegates/NewsBlurAccountDelegate.swift index 7e3a2bb86..28467cca0 100644 --- a/Account/Sources/Account/AccountDelegates/NewsBlurAccountDelegate.swift +++ b/Account/Sources/Account/AccountDelegates/NewsBlurAccountDelegate.swift @@ -352,21 +352,23 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging { completion(.success(())) } - func createFolder(for account: Account, name: String, completion: @escaping (Result) -> ()) { + func createFolder(for account: Account, name: String) async throws -> Folder { self.refreshProgress.addToNumberOfTasksAndRemaining(1) - caller.addFolder(named: name) { result in - self.refreshProgress.completeTask() + return try await withCheckedThrowingContinuation { continuation in + caller.addFolder(named: name) { result in + self.refreshProgress.completeTask() - switch result { - case .success(): - if let folder = account.ensureFolder(with: name) { - completion(.success(folder)) - } else { - completion(.failure(NewsBlurError.invalidParameter)) + switch result { + case .success(): + if let folder = account.ensureFolder(with: name) { + continuation.resume(returning: folder) + } else { + continuation.resume(throwing: NewsBlurError.invalidParameter) + } + case .failure(let error): + continuation.resume(throwing: error) } - case .failure(let error): - completion(.failure(error)) } } } @@ -584,12 +586,11 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging { } let group = DispatchGroup() - group.enter() - createFolder(for: account, name: folderName) { result in - group.leave() - switch result { - case .success(let folder): + + Task { @MainActor in + do { + let folder = try await createFolder(for: account, name: folderName) for feed in feedsToRestore { group.enter() self.restoreFeed(for: account, feed: feed, container: folder) { result in @@ -598,12 +599,15 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging { case .success: break case .failure(let error): - self.logger.error("Restore folder feed error: \(error.localizedDescription, privacy: .public)") + self.logger.error("Restore folder feed error: \(error.localizedDescription, privacy: .public)") } } } - case .failure(let error): - self.logger.error("Restore folder feed error: \(error.localizedDescription, privacy: .public)") + group.leave() + + } catch { + self.logger.error("Restore folder feed error: \(error.localizedDescription, privacy: .public)") + group.leave() } } diff --git a/Account/Sources/Account/AccountDelegates/ReaderAPIAccountDelegate.swift b/Account/Sources/Account/AccountDelegates/ReaderAPIAccountDelegate.swift index d7723ec69..49011cd99 100644 --- a/Account/Sources/Account/AccountDelegates/ReaderAPIAccountDelegate.swift +++ b/Account/Sources/Account/AccountDelegates/ReaderAPIAccountDelegate.swift @@ -290,11 +290,13 @@ public enum ReaderAPIAccountDelegateError: LocalizedError { func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result) -> Void) { } - func createFolder(for account: Account, name: String, completion: @escaping (Result) -> Void) { - if let folder = account.ensureFolder(with: name) { - completion(.success(folder)) - } else { - completion(.failure(ReaderAPIAccountDelegateError.invalidParameter)) + func createFolder(for account: Account, name: String) async throws -> Folder { + try await withCheckedThrowingContinuation { continuation in + if let folder = account.ensureFolder(with: name) { + continuation.resume(returning: folder) + } else { + continuation.resume(throwing: ReaderAPIAccountDelegateError.invalidParameter) + } } } diff --git a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift index 1815c419b..8d29be67c 100644 --- a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift +++ b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift @@ -286,21 +286,24 @@ final class CloudKitAccountDelegate: AccountDelegate, Logging { } } - func createFolder(for account: Account, name: String, completion: @escaping (Result) -> Void) { + func createFolder(for account: Account, name: String) async throws -> Folder { refreshProgress.addToNumberOfTasksAndRemaining(1) - accountZone.createFolder(name: name) { result in - self.refreshProgress.completeTask() - switch result { - case .success(let externalID): - if let folder = account.ensureFolder(with: name) { - folder.externalID = externalID - completion(.success(folder)) - } else { - completion(.failure(FeedbinAccountDelegateError.invalidParameter)) + + return try await withCheckedThrowingContinuation { continuation in + accountZone.createFolder(name: name) { result in + self.refreshProgress.completeTask() + switch result { + case .success(let externalID): + if let folder = account.ensureFolder(with: name) { + folder.externalID = externalID + continuation.resume(returning: folder) + } else { + continuation.resume(throwing: FeedbinAccountDelegateError.invalidParameter) + } + case .failure(let error): + self.processAccountError(account, error) + continuation.resume(throwing: error) } - case .failure(let error): - self.processAccountError(account, error) - completion(.failure(error)) } } } diff --git a/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift b/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift index 62de5cf96..584cd667d 100644 --- a/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift +++ b/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift @@ -244,25 +244,27 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging { } } - func createFolder(for account: Account, name: String, completion: @escaping (Result) -> Void) { - + func createFolder(for account: Account, name: String) async throws -> Folder { + let progress = refreshProgress progress.addToNumberOfTasksAndRemaining(1) - caller.createCollection(named: name) { result in - progress.completeTask() - - switch result { - case .success(let collection): - if let folder = account.ensureFolder(with: collection.label) { - folder.externalID = collection.id - completion(.success(folder)) - } else { - // Is the name empty? Or one of the global resource names? - completion(.failure(FeedlyAccountDelegateError.unableToAddFolder(name))) + return try await withCheckedThrowingContinuation { continuation in + caller.createCollection(named: name) { result in + progress.completeTask() + + switch result { + case .success(let collection): + if let folder = account.ensureFolder(with: collection.label) { + folder.externalID = collection.id + continuation.resume(returning: folder) + } else { + // Is the name empty? Or one of the global resource names? + continuation.resume(throwing: FeedlyAccountDelegateError.unableToAddFolder(name)) + } + case .failure(let error): + continuation.resume(throwing: error) } - case .failure(let error): - completion(.failure(error)) } } } diff --git a/Mac/MainWindow/AddFolder/AddFolderWindowController.swift b/Mac/MainWindow/AddFolder/AddFolderWindowController.swift index 08cc50310..cb792c08e 100644 --- a/Mac/MainWindow/AddFolder/AddFolderWindowController.swift +++ b/Mac/MainWindow/AddFolder/AddFolderWindowController.swift @@ -100,11 +100,10 @@ private extension AddFolderWindowController { return } - account.addFolder(folderName) { result in - switch result { - case .success: - break - case .failure(let error): + Task { @MainActor in + do { + try await account.addFolder(folderName) + } catch { NSApplication.shared.presentError(error) } } diff --git a/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift b/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift index 662c6f80b..86b65d8bf 100644 --- a/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift +++ b/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift @@ -440,9 +440,9 @@ private extension SidebarOutlineDataSource { return } - destinationAccount.addFolder(folder.name ?? "") { result in - switch result { - case .success(let destinationFolder): + Task { @MainActor in + do { + let destinationFolder = try await destinationAccount.addFolder(folder.name ?? "") for feed in folder.topLevelFeeds { if let existingFeed = destinationAccount.existingFeed(withURL: feed.url) { destinationAccount.addFeed(existingFeed, to: destinationFolder) { result in @@ -464,7 +464,7 @@ private extension SidebarOutlineDataSource { } } } - case .failure(let error): + } catch { NSApplication.shared.presentError(error) } } diff --git a/Mac/Scriptability/Folder+Scriptability.swift b/Mac/Scriptability/Folder+Scriptability.swift index 6f88fd49d..8fd7e8ebf 100644 --- a/Mac/Scriptability/Folder+Scriptability.swift +++ b/Mac/Scriptability/Folder+Scriptability.swift @@ -82,16 +82,13 @@ class ScriptableFolder: NSObject, UniqueIdScriptingObject, ScriptingObjectContai return } - - account.addFolder(name) { result in - switch result { - case .success(let folder): - let scriptableAccount = ScriptableAccount(account) - let scriptableFolder = ScriptableFolder(folder, container:scriptableAccount) - command.resumeExecution(withResult:scriptableFolder.objectSpecifier) - case .failure: - command.resumeExecution(withResult:nil) - } + do { + let folder = try await account.addFolder(name) + let scriptableAccount = ScriptableAccount(account) + let scriptableFolder = ScriptableFolder(folder, container:scriptableAccount) + command.resumeExecution(withResult:scriptableFolder.objectSpecifier) + } catch { + command.resumeExecution(withResult:nil) } }