From cc33cf18f239e2be8606e691a28994539eb39c3c Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 30 Oct 2022 18:54:14 -0400 Subject: [PATCH] Workaround for follow menu item never resolving on macOS See #198 --- .../MastodonCachePersistentStore.swift | 15 ++++--- Tusker/Screens/Utilities/Previewing.swift | 45 ++++++++++++++----- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/Tusker/CoreData/MastodonCachePersistentStore.swift b/Tusker/CoreData/MastodonCachePersistentStore.swift index fe867c48..b54281c5 100644 --- a/Tusker/CoreData/MastodonCachePersistentStore.swift +++ b/Tusker/CoreData/MastodonCachePersistentStore.swift @@ -179,20 +179,21 @@ class MastodonCachePersistentStore: NSPersistentContainer { } @discardableResult - private func upsert(relationship: Relationship) -> RelationshipMO { - if let relationshipMO = self.relationship(forAccount: relationship.id, in: self.backgroundContext) { + private func upsert(relationship: Relationship, in context: NSManagedObjectContext) -> RelationshipMO { + if let relationshipMO = self.relationship(forAccount: relationship.id, in: context) { relationshipMO.updateFrom(apiRelationship: relationship, container: self) return relationshipMO } else { - let relationshipMO = RelationshipMO(apiRelationship: relationship, container: self, context: self.backgroundContext) + let relationshipMO = RelationshipMO(apiRelationship: relationship, container: self, context: context) return relationshipMO } } - func addOrUpdate(relationship: Relationship, completion: ((RelationshipMO) -> Void)? = nil) { - backgroundContext.perform { - let relationshipMO = self.upsert(relationship: relationship) - self.save(context: self.backgroundContext) + func addOrUpdate(relationship: Relationship, in context: NSManagedObjectContext? = nil, completion: ((RelationshipMO) -> Void)? = nil) { + let context = context ?? backgroundContext + context.perform { + let relationshipMO = self.upsert(relationship: relationship, in: context) + self.save(context: context) completion?(relationshipMO) self.relationshipSubject.send(relationship.id) } diff --git a/Tusker/Screens/Utilities/Previewing.swift b/Tusker/Screens/Utilities/Previewing.swift index 207144e7..57ff74cf 100644 --- a/Tusker/Screens/Utilities/Previewing.swift +++ b/Tusker/Screens/Utilities/Previewing.swift @@ -60,12 +60,23 @@ extension MenuActionProvider { draft.visibility = .direct self.navigationDelegate?.compose(editing: draft) }), - UIDeferredMenuElement.uncached({ (elementHandler) in - Task { @MainActor in - if let action = await self.followAction(for: accountID, mastodonController: mastodonController) { - elementHandler([action]) - } else { - elementHandler([]) + UIDeferredMenuElement.uncached({ @MainActor elementHandler in + let relationship = Task { + await self.fetchRelationship(accountID: accountID, mastodonController: mastodonController) + } + // workaround for #198, may result in showing outdated relationship, so only do so where necessary + if ProcessInfo.processInfo.isiOSAppOnMac, + let mo = mastodonController.persistentContainer.relationship(forAccount: accountID), + let action = self.followAction(for: mo, mastodonController: mastodonController) { + elementHandler([action]) + } else { + Task { @MainActor in + if let relationship = await relationship.value, + let action = self.followAction(for: relationship, mastodonController: mastodonController) { + elementHandler([action]) + } else { + elementHandler([]) + } } } }) @@ -381,16 +392,26 @@ extension MenuActionProvider { }) } - private func followAction(for accountID: String, mastodonController: MastodonController) async -> UIMenuElement? { - guard let ownAccount = try? await mastodonController.getOwnAccount(), - accountID != ownAccount.id else { + private func fetchRelationship(accountID: String, mastodonController: MastodonController) async -> RelationshipMO? { + let req = Client.getRelationships(accounts: [accountID]) + guard let (relationships, _) = try? await mastodonController.run(req), + let r = relationships.first else { return nil } - let request = Client.getRelationships(accounts: [accountID]) - guard let (relationships, _) = try? await mastodonController.run(request), - let relationship = relationships.first else { + return await withCheckedContinuation { continuation in + mastodonController.persistentContainer.addOrUpdate(relationship: r, in: mastodonController.persistentContainer.viewContext) { mo in + continuation.resume(returning: mo) + } + } + } + + @MainActor + private func followAction(for relationship: RelationshipMO, mastodonController: MastodonController) -> UIMenuElement? { + guard let ownAccount = mastodonController.account, + relationship.accountID != ownAccount.id else { return nil } + let accountID = relationship.accountID 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)