From 727615a8181d825a013feb526e83ebba3c71e3b7 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Tue, 29 Mar 2022 12:52:14 -0400 Subject: [PATCH] Fix crash when providing account actions before own account is loaded --- Tusker/Controllers/MastodonController.swift | 13 ++++ Tusker/Screens/Utilities/Previewing.swift | 71 ++++++++++----------- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/Tusker/Controllers/MastodonController.swift b/Tusker/Controllers/MastodonController.swift index d6a02862..a9263e90 100644 --- a/Tusker/Controllers/MastodonController.swift +++ b/Tusker/Controllers/MastodonController.swift @@ -67,6 +67,19 @@ class MastodonController: ObservableObject { return client.run(request, completion: completion) } + func run(_ request: Request) async throws -> (Result, Pagination?) { + return try await withCheckedThrowingContinuation({ continuation in + client.run(request) { response in + switch response { + case .failure(let error): + continuation.resume(throwing: error) + case .success(let result, let pagination): + continuation.resume(returning: (result, pagination)) + } + } + }) + } + /// - Returns: A tuple of client ID and client secret. func registerApp() async throws -> (String, String) { if let clientID = client.clientID, diff --git a/Tusker/Screens/Utilities/Previewing.swift b/Tusker/Screens/Utilities/Previewing.swift index d7e180bc..2483746c 100644 --- a/Tusker/Screens/Utilities/Previewing.swift +++ b/Tusker/Screens/Utilities/Previewing.swift @@ -48,50 +48,21 @@ extension MenuPreviewProvider { ] } - var actionsSection: [UIMenuElement] = [ + let actionsSection: [UIMenuElement] = [ createAction(identifier: "sendmessage", title: "Send Message", systemImageName: "envelope", handler: { [weak self] (_) in guard let self = self else { return } self.navigationDelegate?.compose(mentioningAcct: account.acct) }), - ] - - if accountID != mastodonController.account.id { - actionsSection.append(UIDeferredMenuElement({ (elementHandler) in - guard let mastodonController = self.mastodonController else { - elementHandler([]) - return - } - let request = Client.getRelationships(accounts: [account.id]) - // talk about callback hell :/ - mastodonController.run(request) { [weak self] (response) in - guard let self = self, - case let .success(results, _) = response, - let relationship = results.first else { - DispatchQueue.main.async { - elementHandler([]) - } - return - } - let following = relationship.following - DispatchQueue.main.async { - let action = self.createAction(identifier: "follow", title: following ? "Unfollow" : "Follow", systemImageName: following ? "person.badge.minus" : "person.badge.plus", handler: { (_) in - let request = (following ? Account.unfollow : Account.follow)(accountID) - mastodonController.run(request) { (response) in - switch response { - case .failure(_): - fatalError() - case let .success(relationship, _): - mastodonController.persistentContainer.addOrUpdate(relationship: relationship) - } - } - }) - elementHandler([ - action - ]) + UIDeferredMenuElement({ (elementHandler) in + Task { @MainActor in + if let action = await self.followAction(for: accountID, mastodonController: mastodonController) { + elementHandler([action]) + } else { + elementHandler([]) } } - })) - } + }) + ] var shareSection = [ openInSafariAction(url: account.url), @@ -267,6 +238,30 @@ extension MenuPreviewProvider { } } + private func followAction(for accountID: String, mastodonController: MastodonController) async -> UIMenuElement? { + guard let ownAccount = try? await mastodonController.getOwnAccount(), + accountID != ownAccount.id else { + return nil + } + let request = Client.getRelationships(accounts: [accountID]) + guard let (relationships, _) = try? await mastodonController.run(request), + let relationship = relationships.first else { + return nil + } + let following = relationship.following + return createAction(identifier: "follow", title: following ? "Unfollow" : "Follow", systemImageName: following ? "person.badge.minus" : "person.badge.plus") { _ in + let request = (following ? Account.unfollow : Account.follow)(accountID) + mastodonController.run(request) { response in + switch response { + case .failure(_): + fatalError() + case .success(let relationship, _): + mastodonController.persistentContainer.addOrUpdate(relationship: relationship) + } + } + } + } + } extension LargeImageViewController: CustomPreviewPresenting {