From c5441bddc317434b775e9344d4131c437bb5331c Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Thu, 28 Mar 2024 08:24:35 -0700 Subject: [PATCH] Convert addFeed to async await. --- Account/Sources/Account/Account.swift | 5 +- Account/Sources/Account/AccountDelegate.swift | 2 +- .../CloudKit/CloudKitAccountDelegate.swift | 17 ++++- .../Feedbin/FeedbinAccountDelegate.swift | 62 ++++++++++--------- .../Feedly/FeedlyAccountDelegate.swift | 27 ++++++-- .../LocalAccount/LocalAccountDelegate.swift | 6 +- .../NewsBlurAccountDelegate+Internal.swift | 27 +++----- .../NewsBlur/NewsBlurAccountDelegate.swift | 26 ++++++-- .../ReaderAPI/ReaderAPIAccountDelegate.swift | 60 +++++++++--------- .../Sidebar/SidebarOutlineDataSource.swift | 32 ++++------ iOS/Feeds/FeedsViewController+Drop.swift | 20 +++--- 11 files changed, 163 insertions(+), 121 deletions(-) diff --git a/Account/Sources/Account/Account.swift b/Account/Sources/Account/Account.swift index e80c63bd6..47530ffb0 100644 --- a/Account/Sources/Account/Account.swift +++ b/Account/Sources/Account/Account.swift @@ -607,8 +607,9 @@ public enum FetchType { return feed } - public func addFeed(_ feed: Feed, to container: Container, completion: @escaping (Result) -> Void) { - delegate.addFeed(for: self, with: feed, to: container, completion: completion) + public func addFeed(_ feed: Feed, to container: Container) async throws { + + try await delegate.addFeed(for: self, with: feed, to: container) } public func createFeed(url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result) -> Void) { diff --git a/Account/Sources/Account/AccountDelegate.swift b/Account/Sources/Account/AccountDelegate.swift index 09c1e594c..0f5d5a073 100644 --- a/Account/Sources/Account/AccountDelegate.swift +++ b/Account/Sources/Account/AccountDelegate.swift @@ -38,7 +38,7 @@ import Secrets 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 - func addFeed(for account: Account, with: Feed, to container: Container, completion: @escaping (Result) -> Void) + func addFeed(for account: Account, with: Feed, to container: Container) async throws func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result) -> Void) func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result) -> Void) diff --git a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift index ee80b3e42..60de2cd5a 100644 --- a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift +++ b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift @@ -321,7 +321,22 @@ enum CloudKitAccountDelegateError: LocalizedError { } } - func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> Void) { + func addFeed(for account: Account, with feed: Feed, to container: any Container) async throws { + + try await withCheckedThrowingContinuation { continuation in + + self.addFeed(for: account, with: feed, to: container) { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + + private func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> Void) { refreshProgress.addToNumberOfTasksAndRemaining(1) accountZone.addFeed(feed, to: container) { result in self.refreshProgress.completeTask() diff --git a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift index 27ec23c12..7e1cd57eb 100644 --- a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift @@ -564,7 +564,22 @@ final class FeedbinAccountDelegate: AccountDelegate { } } - func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> Void) { + func addFeed(for account: Account, with feed: Feed, to container: any Container) async throws { + + try await withCheckedThrowingContinuation { continuation in + + self.addFeed(for: account, with: feed, to: container) { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + + private func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> Void) { if let folder = container as? Folder, let feedID = Int(feed.feedID) { refreshProgress.addToNumberOfTasksAndRemaining(1) @@ -614,11 +629,13 @@ final class FeedbinAccountDelegate: AccountDelegate { private func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result) -> Void) { if let existingFeed = account.existingFeed(withURL: feed.url) { - account.addFeed(existingFeed, to: container) { result in - switch result { - case .success: + + Task { @MainActor in + + do { + try await account.addFeed(existingFeed, to: container) completion(.success(())) - case .failure(let error): + } catch { completion(.failure(error)) } } @@ -632,9 +649,8 @@ final class FeedbinAccountDelegate: AccountDelegate { } } } - } - + func restoreFolder(for account: Account, folder: Folder) async throws { try await withCheckedThrowingContinuation { continuation in @@ -1190,34 +1206,22 @@ private extension FeedbinAccountDelegate { } func createFeed( account: Account, subscription sub: FeedbinSubscription, name: String?, container: Container, completion: @escaping (Result) -> Void) { - - DispatchQueue.main.async { - + + Task { @MainActor in + let feed = account.createFeed(with: sub.name, url: sub.url, feedID: String(sub.feedID), homePageURL: sub.homePageURL) feed.externalID = String(sub.subscriptionID) feed.iconURL = sub.jsonFeed?.icon feed.faviconURL = sub.jsonFeed?.favicon - account.addFeed(feed, to: container) { result in - switch result { - case .success: - if let name = name { - - Task { @MainActor in - do { - try await account.renameFeed(feed, to: name) - self.initialFeedDownload(account: account, feed: feed, completion: completion) - } catch { - completion(.failure(error)) - - } - } - } else { - self.initialFeedDownload(account: account, feed: feed, completion: completion) - } - case .failure(let error): - completion(.failure(error)) + do { + try await account.addFeed(feed, to: container) + if let name { + try await self.renameFeed(for: account, with: feed, to: name) } + self.initialFeedDownload(account: account, feed: feed, completion: completion) + } catch { + completion(.failure(error)) } } } diff --git a/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift b/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift index 5cd0812e4..36efd4ceb 100644 --- a/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift +++ b/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift @@ -494,7 +494,22 @@ final class FeedlyAccountDelegate: AccountDelegate { feed.editedName = name } - @MainActor func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> Void) { + func addFeed(for account: Account, with feed: Feed, to container: any Container) async throws { + + try await withCheckedThrowingContinuation { continuation in + + self.addFeed(for: account, with: feed, to: container) { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + + func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> Void) { do { guard let credentials = credentials else { @@ -594,12 +609,14 @@ final class FeedlyAccountDelegate: AccountDelegate { } private func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result) -> Void) { + if let existingFeed = account.existingFeed(withURL: feed.url) { - account.addFeed(existingFeed, to: container) { result in - switch result { - case .success: + + Task { @MainActor in + do { + try await account.addFeed(existingFeed, to: container) completion(.success(())) - case .failure(let error): + } catch { completion(.failure(error)) } } diff --git a/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift b/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift index 3d0fff3ab..6e44f4e40 100644 --- a/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift +++ b/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift @@ -107,11 +107,11 @@ final class LocalAccountDelegate: AccountDelegate { completion(.success(())) } - func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> Void) { + func addFeed(for account: Account, with feed: Feed, to container: any Container) async throws { + container.addFeed(feed) - completion(.success(())) } - + func restoreFeed(for account: Account, feed: Feed, container: any Container) async throws { container.addFeed(feed) diff --git a/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift b/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift index 189c00ad0..bfc5fba53 100644 --- a/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift +++ b/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift @@ -434,30 +434,19 @@ extension NewsBlurAccountDelegate { return } - DispatchQueue.main.async { + Task { @MainActor in let feed = account.createFeed(with: feed.name, url: feed.feedURL, feedID: String(feed.feedID), homePageURL: feed.homePageURL) feed.externalID = String(feed.feedID) feed.faviconURL = feed.faviconURL - account.addFeed(feed, to: container) { result in - switch result { - case .success: - if let name = name { - - Task { @MainActor in - do { - try await account.renameFeed(feed, to: name) - self.initialFeedDownload(account: account, feed: feed, completion: completion) - } catch { - completion(.failure(error)) - } - } - } else { - self.initialFeedDownload(account: account, feed: feed, completion: completion) - } - case .failure(let error): - completion(.failure(error)) + do { + try await account.addFeed(feed, to: container) + if let name { + try await self.renameFeed(for: account, with: feed, to: name) } + self.initialFeedDownload(account: account, feed: feed, completion: completion) + } catch { + completion(.failure(error)) } } } diff --git a/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift b/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift index 7d0c7fcc7..b62a0d8cc 100644 --- a/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift +++ b/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift @@ -576,7 +576,22 @@ final class NewsBlurAccountDelegate: AccountDelegate { } } - func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> ()) { + func addFeed(for account: Account, with feed: Feed, to container: any Container) async throws { + + try await withCheckedThrowingContinuation { continuation in + + self.addFeed(for: account, with: feed, to: container) { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + + private func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> ()) { guard let folder = container as? Folder else { DispatchQueue.main.async { if let account = container as? Account { @@ -643,11 +658,12 @@ final class NewsBlurAccountDelegate: AccountDelegate { private func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result) -> ()) { if let existingFeed = account.existingFeed(withURL: feed.url) { - account.addFeed(existingFeed, to: container) { result in - switch result { - case .success: + Task { @MainActor in + + do { + try await account.addFeed(existingFeed, to: container) completion(.success(())) - case .failure(let error): + } catch { completion(.failure(error)) } } diff --git a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift index 3fef5b871..37f27d701 100644 --- a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift +++ b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift @@ -618,7 +618,22 @@ final class ReaderAPIAccountDelegate: AccountDelegate { } } - func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> Void) { + func addFeed(for account: Account, with feed: Feed, to container: any Container) async throws { + + try await withCheckedThrowingContinuation { continuation in + + self.addFeed(for: account, with: feed, to: container) { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + + private func addFeed(for account: Account, with feed: Feed, to container: Container, completion: @escaping (Result) -> Void) { if let folder = container as? Folder, let feedExternalID = feed.externalID { refreshProgress.addToNumberOfTasksAndRemaining(1) caller.createTagging(subscriptionID: feedExternalID, tagName: folder.name ?? "") { result in @@ -666,11 +681,12 @@ final class ReaderAPIAccountDelegate: AccountDelegate { private func restoreFeed(for account: Account, feed: Feed, container: Container, completion: @escaping (Result) -> Void) { if let existingFeed = account.existingFeed(withURL: feed.url) { - account.addFeed(existingFeed, to: container) { result in - switch result { - case .success: + Task { @MainActor in + + do { + try await account.addFeed(existingFeed, to: container) completion(.success(())) - case .failure(let error): + } catch { completion(.failure(error)) } } @@ -1086,34 +1102,22 @@ private extension ReaderAPIAccountDelegate { } func createFeed( account: Account, subscription sub: ReaderAPISubscription, name: String?, container: Container, completion: @escaping (Result) -> Void) { - - DispatchQueue.main.async { - + + Task { @MainActor in + let feed = account.createFeed(with: sub.name, url: sub.url, feedID: String(sub.feedID), homePageURL: sub.homePageURL) feed.externalID = String(sub.feedID) - - account.addFeed(feed, to: container) { result in - switch result { - case .success: - if let name = name { - self.renameFeed(for: account, with: feed, to: name) { result in - switch result { - case .success: - self.initialFeedDownload(account: account, feed: feed, completion: completion) - case .failure(let error): - completion(.failure(error)) - } - } - } else { - self.initialFeedDownload(account: account, feed: feed, completion: completion) - } - case .failure(let error): - completion(.failure(error)) + + do { + try await account.addFeed(feed, to: container) + if let name { + try await self.renameFeed(for: account, with: feed, to: name) } + self.initialFeedDownload(account: account, feed: feed, completion: completion) + } catch { + completion(.failure(error)) } - } - } func initialFeedDownload( account: Account, feed: Feed, completion: @escaping (Result) -> Void) { diff --git a/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift b/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift index bc9424190..43bdb8c76 100644 --- a/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift +++ b/Mac/MainWindow/Sidebar/SidebarOutlineDataSource.swift @@ -308,17 +308,16 @@ private extension SidebarOutlineDataSource { } return localDragOperation(parentNode: parentNode) } - + func copyFeedInAccount(node: Node, to parentNode: Node) { guard let feed = node.representedObject as? Feed, let destination = parentNode.representedObject as? Container else { return } - - destination.account?.addFeed(feed, to: destination) { result in - switch result { - case .success: - break - case .failure(let error): + + Task { @MainActor in + do { + try await destination.account?.addFeed(feed, to: destination) + } catch { NSApplication.shared.presentError(error) } } @@ -351,11 +350,11 @@ private extension SidebarOutlineDataSource { } if let existingFeed = destinationAccount.existingFeed(withURL: feed.url) { - destinationAccount.addFeed(existingFeed, to: destinationContainer) { result in - switch result { - case .success: - break - case .failure(let error): + + Task { @MainActor in + do { + try await destinationAccount.addFeed(existingFeed, to: destinationContainer) + } catch { NSApplication.shared.presentError(error) } } @@ -437,14 +436,7 @@ private extension SidebarOutlineDataSource { for feed in folder.topLevelFeeds { if let existingFeed = destinationAccount.existingFeed(withURL: feed.url) { - destinationAccount.addFeed(existingFeed, to: destinationFolder) { result in - switch result { - case .success: - break - case .failure(let error): - NSApplication.shared.presentError(error) - } - } + try await destinationAccount.addFeed(existingFeed, to: destinationFolder) } else { destinationAccount.createFeed(url: feed.url, name: feed.nameForDisplay, container: destinationFolder, validateFeed: false) { result in switch result { diff --git a/iOS/Feeds/FeedsViewController+Drop.swift b/iOS/Feeds/FeedsViewController+Drop.swift index adfdca028..3cc91c5dc 100644 --- a/iOS/Feeds/FeedsViewController+Drop.swift +++ b/iOS/Feeds/FeedsViewController+Drop.swift @@ -116,13 +116,16 @@ extension SidebarViewController: UITableViewDropDelegate { } func moveFeedBetweenAccounts(feed: Feed, sourceContainer: Container, destinationContainer: Container) { - + if let existingFeed = destinationContainer.account?.existingFeed(withURL: feed.url) { - + BatchUpdate.shared.start() - destinationContainer.account?.addFeed(existingFeed, to: destinationContainer) { result in - switch result { - case .success: + + Task { @MainActor in + + do { + try await destinationContainer.account?.addFeed(existingFeed, to: destinationContainer) + sourceContainer.account?.removeFeed(feed, from: sourceContainer) { result in BatchUpdate.shared.end() switch result { @@ -132,14 +135,15 @@ extension SidebarViewController: UITableViewDropDelegate { self.presentError(error) } } - case .failure(let error): + + } catch { BatchUpdate.shared.end() self.presentError(error) } } - + } else { - + BatchUpdate.shared.start() destinationContainer.account?.createFeed(url: feed.url, name: feed.editedName, container: destinationContainer, validateFeed: false) { result in switch result {