Convert renameFeed and renameFolder to async await.

This commit is contained in:
Brent Simmons 2024-03-27 17:49:09 -07:00
parent a7ba7e3b4a
commit 6ad90583a4
18 changed files with 263 additions and 107 deletions

View File

@ -631,8 +631,9 @@ public enum FetchType {
delegate.moveFeed(for: self, with: feed, from: from, to: to, completion: completion)
}
public func renameFeed(_ feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
delegate.renameFeed(for: self, with: feed, to: name, completion: completion)
public func renameFeed(_ feed: Feed, to name: String) async throws {
try await delegate.renameFeed(for: self, with: feed, to: name)
}
public func restoreFeed(_ feed: Feed, container: Container) async throws {
@ -649,11 +650,13 @@ public enum FetchType {
delegate.removeFolder(for: self, with: folder, completion: completion)
}
public func renameFolder(_ folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
delegate.renameFolder(for: self, with: folder, to: name, completion: completion)
public func renameFolder(_ folder: Folder, to name: String) async throws {
try await delegate.renameFolder(for: self, with: folder, to: name)
}
public func restoreFolder(_ folder: Folder) async throws {
try await delegate.restoreFolder(for: self, folder: folder)
}

View File

@ -33,11 +33,11 @@ import Secrets
func importOPML(for account:Account, opmlFile: URL) async throws
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, Error>) -> Void)
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, Error>) -> Void)
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void)
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> 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, Error>) -> Void)
func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void)
func moveFeed(for account: Account, with feed: Feed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void)

View File

@ -254,7 +254,22 @@ enum CloudKitAccountDelegateError: LocalizedError {
createRSSFeed(for: account, url: url, editedName: editedName, container: container, validateFeed: validateFeed, completion: completion)
}
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
func renameFeed(for account: Account, with feed: Feed, to name: String) async throws {
try await withCheckedThrowingContinuation { continuation in
self.renameFeed(for: account, with: feed, to: name) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
let editedName = name.isEmpty ? nil : name
refreshProgress.addToNumberOfTasksAndRemaining(1)
accountZone.renameFeed(feed, editedName: editedName) { result in
@ -370,7 +385,22 @@ enum CloudKitAccountDelegateError: LocalizedError {
}
}
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
func renameFolder(for account: Account, with folder: Folder, to name: String) async throws {
try await withCheckedThrowingContinuation { continuation in
self.renameFolder(for: account, with: folder, to: name) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
refreshProgress.addToNumberOfTasksAndRemaining(1)
accountZone.renameFolder(folder, to: name) { result in
self.refreshProgress.completeTask()

View File

@ -189,9 +189,13 @@ import Core
// MARK: - Renamable
public func rename(to newName: String, completion: @escaping (Result<Void, Error>) -> Void) {
guard let account = account else { return }
account.renameFeed(self, to: newName, completion: completion)
public func rename(to newName: String) async throws {
guard let account else {
return
}
try await account.renameFeed(self, to: newName)
}
// MARK: - UnreadCountProvider

View File

@ -347,7 +347,22 @@ final class FeedbinAccountDelegate: AccountDelegate {
return folder
}
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
func renameFolder(for account: Account, with folder: Folder, to name: String) async throws {
try await withCheckedThrowingContinuation { continuation in
self.renameFolder(for: account, with: folder, to: name) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
guard folder.hasAtLeastOneFeed() else {
folder.name = name
@ -469,7 +484,22 @@ final class FeedbinAccountDelegate: AccountDelegate {
}
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
func renameFeed(for account: Account, with feed: Feed, to name: String) async throws {
try await withCheckedThrowingContinuation { continuation in
self.renameFeed(for: account, with: feed, to: name) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
// This error should never happen
guard let subscriptionID = feed.externalID else {
@ -1152,17 +1182,19 @@ private extension FeedbinAccountDelegate {
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 {
account.renameFeed(feed, to: name) { result in
switch result {
case .success:
Task { @MainActor in
do {
try await account.renameFeed(feed, to: name)
self.initialFeedDownload(account: account, feed: feed, completion: completion)
case .failure(let error):
} catch {
completion(.failure(error))
}
}
} else {
@ -1172,9 +1204,7 @@ private extension FeedbinAccountDelegate {
completion(.failure(error))
}
}
}
}
func initialFeedDownload( account: Account, feed: Feed, completion: @escaping (Result<Feed, Error>) -> Void) {

View File

@ -343,7 +343,22 @@ final class FeedlyAccountDelegate: AccountDelegate {
}
}
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
func renameFolder(for account: Account, with folder: Folder, to name: String) async throws {
try await withCheckedThrowingContinuation { continuation in
self.renameFolder(for: account, with: folder, to: name) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
guard let id = folder.externalID else {
return DispatchQueue.main.async {
completion(.failure(FeedlyAccountDelegateError.unableToRenameFolder(folder.nameForDisplay, name)))
@ -422,6 +437,21 @@ final class FeedlyAccountDelegate: AccountDelegate {
}
}
func renameFeed(for account: Account, with feed: Feed, to name: String) async throws {
try await withCheckedThrowingContinuation { continuation in
self.renameFeed(for: account, with: feed, to: name) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
let folderCollectionIds = account.folders?.filter { $0.has(feed) }.compactMap { $0.externalID }
guard let collectionIds = folderCollectionIds, let collectionId = collectionIds.first else {

View File

@ -53,9 +53,13 @@ import Core
// MARK: - Renamable
public func rename(to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
guard let account = account else { return }
account.renameFolder(self, to: name, completion: completion)
public func rename(to name: String) async throws {
guard let account else {
return
}
try await account.renameFolder(self, to: name)
}
// MARK: - Init

View File

@ -91,9 +91,9 @@ final class LocalAccountDelegate: AccountDelegate {
createRSSFeed(for: account, url: url, editedName: name, container: container, completion: completion)
}
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
func renameFeed(for account: Account, with feed: Feed, to name: String) async throws {
feed.editedName = name
completion(.success(()))
}
func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
@ -125,9 +125,9 @@ final class LocalAccountDelegate: AccountDelegate {
return folder
}
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
func renameFolder(for account: Account, with folder: Folder, to name: String) async throws {
folder.name = name
completion(.success(()))
}
func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result<Void, Error>) -> Void) {

View File

@ -443,11 +443,12 @@ extension NewsBlurAccountDelegate {
switch result {
case .success:
if let name = name {
account.renameFeed(feed, to: name) { result in
switch result {
case .success:
Task { @MainActor in
do {
try await account.renameFeed(feed, to: name)
self.initialFeedDownload(account: account, feed: feed, completion: completion)
case .failure(let error):
} catch {
completion(.failure(error))
}
}

View File

@ -430,7 +430,22 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
}
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> ()) {
func renameFolder(for account: Account, with folder: Folder, to name: String) async throws {
try await withCheckedThrowingContinuation { continuation in
self.renameFolder(for: account, with: folder, to: name) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> ()) {
guard let folderToRename = folder.name else {
completion(.failure(NewsBlurError.invalidParameter))
return
@ -504,7 +519,22 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
}
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> ()) {
func renameFeed(for account: Account, with feed: Feed, to name: String) async throws {
try await withCheckedThrowingContinuation { continuation in
self.renameFeed(for: account, with: feed, to: name) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> ()) {
guard let feedID = feed.externalID else {
completion(.failure(NewsBlurError.invalidParameter))
return

View File

@ -349,7 +349,22 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
return folder
}
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
func renameFolder(for account: Account, with folder: Folder, to name: String) async throws {
try await withCheckedThrowingContinuation { continuation in
self.renameFolder(for: account, with: folder, to: name) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
refreshProgress.addToNumberOfTasksAndRemaining(1)
caller.renameTag(oldName: folder.name ?? "", newName: name) { result in
@ -488,8 +503,23 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
}
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
func renameFeed(for account: Account, with feed: Feed, to name: String) async throws {
try await withCheckedThrowingContinuation { continuation in
self.renameFeed(for: account, with: feed, to: name) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
// This error should never happen
guard let subscriptionID = feed.externalID else {
completion(.failure(ReaderAPIAccountDelegateError.invalidParameter))

View File

@ -17,7 +17,8 @@ public protocol Renamable {
/// - to: The new name for the object.
/// - completion: A block called when the renaming completes or fails.
/// - result: The result of the renaming.
func rename(to: String, completion: @escaping (_ result: Result<Void, Error>) -> Void)
@MainActor func rename(to: String) async throws
}

View File

@ -203,20 +203,22 @@ private extension FeedInspectorViewController {
}
func renameFeedIfNecessary() {
guard let feed = feed,
guard let feed,
let account = feed.account,
let nameTextField = nameTextField,
feed.nameForDisplay != nameTextField.stringValue else {
let newName = nameTextField?.stringValue,
feed.nameForDisplay != newName else {
return
}
account.renameFeed(feed, to: nameTextField.stringValue) { [weak self] result in
if case .failure(let error) = result {
self?.presentError(error)
} else {
self?.windowTitle = feed.nameForDisplay
Task { @MainActor in
do {
try await account.renameFeed(feed, to: newName)
self.windowTitle = feed.nameForDisplay
} catch {
self.presentError(error)
}
}
}
}

View File

@ -107,18 +107,20 @@ private extension FolderInspectorViewController {
func renameFolderIfNecessary() {
guard let folder = folder,
let account = folder.account,
let nameTextField = nameTextField,
folder.nameForDisplay != nameTextField.stringValue else {
let newName = nameTextField?.stringValue,
!newName.isEmpty,
folder.nameForDisplay != newName else {
return
}
account.renameFolder(folder, to: nameTextField.stringValue) { [weak self] result in
if case .failure(let error) = result {
self?.presentError(error)
} else {
self?.windowTitle = folder.nameForDisplay
Task { @MainActor in
do {
try await account.renameFolder(folder, to: newName)
self.windowTitle = folder.nameForDisplay
} catch {
self.presentError(error)
}
}
}
}

View File

@ -10,7 +10,7 @@ import AppKit
protocol RenameWindowControllerDelegate {
@MainActor func renameWindowController(_ windowController: RenameWindowController, didRenameObject: Any, withNewName: String)
@MainActor func renameWindowController(_ windowController: RenameWindowController, didRenameObject: Any, withNewName: String) async
}
final class RenameWindowController: NSWindowController {
@ -54,7 +54,11 @@ final class RenameWindowController: NSWindowController {
guard let representedObject = representedObject else {
return
}
delegate?.renameWindowController(self, didRenameObject: representedObject, withNewName: newTitleTextField.stringValue)
Task { @MainActor in
await delegate?.renameWindowController(self, didRenameObject: representedObject, withNewName: newTitleTextField.stringValue)
}
window?.sheetParent?.endSheet(window!, returnCode: .OK)
}

View File

@ -171,26 +171,16 @@ extension SidebarViewController {
extension SidebarViewController: RenameWindowControllerDelegate {
func renameWindowController(_ windowController: RenameWindowController, didRenameObject object: Any, withNewName name: String) {
func renameWindowController(_ windowController: RenameWindowController, didRenameObject object: Any, withNewName name: String) async {
if let feed = object as? Feed {
feed.rename(to: name) { result in
switch result {
case .success:
break
case .failure(let error):
NSApplication.shared.presentError(error)
}
}
} else if let folder = object as? Folder {
folder.rename(to: name) { result in
switch result {
case .success:
break
case .failure(let error):
NSApplication.shared.presentError(error)
}
}
guard let renamableItem = object as? Renamable else {
return
}
do {
try await renamableItem.rename(to: name)
} catch {
NSApplication.shared.presentError(error)
}
}
}

View File

@ -1139,59 +1139,51 @@ private extension SidebarViewController {
func rename(indexPath: IndexPath) {
guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? SidebarItem else { return }
guard let sidebarItem = coordinator.nodeFor(indexPath)?.representedObject as? SidebarItem else {
return
}
let formatString = NSLocalizedString("Rename “%@”", comment: "Rename feed")
let title = NSString.localizedStringWithFormat(formatString as NSString, feed.nameForDisplay) as String
let title = NSString.localizedStringWithFormat(formatString as NSString, sidebarItem.nameForDisplay) as String
let alertController = UIAlertController(title: title, message: nil, preferredStyle: .alert)
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
alertController.addAction(UIAlertAction(title: cancelTitle, style: .cancel))
let renameTitle = NSLocalizedString("Rename", comment: "Rename")
let renameAction = UIAlertAction(title: renameTitle, style: .default) { [weak self] action in
guard let name = alertController.textFields?[0].text, !name.isEmpty else {
return
}
if let feed = feed as? Feed {
feed.rename(to: name) { result in
switch result {
case .success:
break
case .failure(let error):
self?.presentError(error)
}
}
} else if let folder = feed as? Folder {
folder.rename(to: name) { result in
switch result {
case .success:
break
case .failure(let error):
Task { @MainActor in
if let renamableItem = sidebarItem as? Renamable {
do {
try await renamableItem.rename(to: name)
} catch {
self?.presentError(error)
}
}
}
}
alertController.addAction(renameAction)
alertController.preferredAction = renameAction
alertController.addTextField() { textField in
textField.text = feed.nameForDisplay
textField.text = sidebarItem.nameForDisplay
textField.placeholder = NSLocalizedString("Name", comment: "Name")
}
self.present(alertController, animated: true) {
}
}
func delete(indexPath: IndexPath) {
guard let feed = coordinator.nodeFor(indexPath)?.representedObject as? SidebarItem else { return }

View File

@ -62,7 +62,10 @@ class FeedInspectorViewController: UITableViewController {
if nameTextField.text != feed.nameForDisplay {
let nameText = nameTextField.text ?? ""
let newName = nameText.isEmpty ? (feed.name ?? NSLocalizedString("Untitled", comment: "Feed name")) : nameText
feed.rename(to: newName) { _ in }
Task { @MainActor in
try? await feed.rename(to: newName)
}
}
}