Workaround for follow menu item never resolving on macOS

See #198
This commit is contained in:
Shadowfacts 2022-10-30 18:54:14 -04:00
parent c5921bc4cb
commit cc33cf18f2
2 changed files with 41 additions and 19 deletions

View File

@ -179,20 +179,21 @@ class MastodonCachePersistentStore: NSPersistentContainer {
} }
@discardableResult @discardableResult
private func upsert(relationship: Relationship) -> RelationshipMO { private func upsert(relationship: Relationship, in context: NSManagedObjectContext) -> RelationshipMO {
if let relationshipMO = self.relationship(forAccount: relationship.id, in: self.backgroundContext) { if let relationshipMO = self.relationship(forAccount: relationship.id, in: context) {
relationshipMO.updateFrom(apiRelationship: relationship, container: self) relationshipMO.updateFrom(apiRelationship: relationship, container: self)
return relationshipMO return relationshipMO
} else { } else {
let relationshipMO = RelationshipMO(apiRelationship: relationship, container: self, context: self.backgroundContext) let relationshipMO = RelationshipMO(apiRelationship: relationship, container: self, context: context)
return relationshipMO return relationshipMO
} }
} }
func addOrUpdate(relationship: Relationship, completion: ((RelationshipMO) -> Void)? = nil) { func addOrUpdate(relationship: Relationship, in context: NSManagedObjectContext? = nil, completion: ((RelationshipMO) -> Void)? = nil) {
backgroundContext.perform { let context = context ?? backgroundContext
let relationshipMO = self.upsert(relationship: relationship) context.perform {
self.save(context: self.backgroundContext) let relationshipMO = self.upsert(relationship: relationship, in: context)
self.save(context: context)
completion?(relationshipMO) completion?(relationshipMO)
self.relationshipSubject.send(relationship.id) self.relationshipSubject.send(relationship.id)
} }

View File

@ -60,12 +60,23 @@ extension MenuActionProvider {
draft.visibility = .direct draft.visibility = .direct
self.navigationDelegate?.compose(editing: draft) self.navigationDelegate?.compose(editing: draft)
}), }),
UIDeferredMenuElement.uncached({ (elementHandler) in UIDeferredMenuElement.uncached({ @MainActor elementHandler in
Task { @MainActor in let relationship = Task {
if let action = await self.followAction(for: accountID, mastodonController: mastodonController) { await self.fetchRelationship(accountID: accountID, mastodonController: mastodonController)
elementHandler([action]) }
} else { // workaround for #198, may result in showing outdated relationship, so only do so where necessary
elementHandler([]) 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? { private func fetchRelationship(accountID: String, mastodonController: MastodonController) async -> RelationshipMO? {
guard let ownAccount = try? await mastodonController.getOwnAccount(), let req = Client.getRelationships(accounts: [accountID])
accountID != ownAccount.id else { guard let (relationships, _) = try? await mastodonController.run(req),
let r = relationships.first else {
return nil return nil
} }
let request = Client.getRelationships(accounts: [accountID]) return await withCheckedContinuation { continuation in
guard let (relationships, _) = try? await mastodonController.run(request), mastodonController.persistentContainer.addOrUpdate(relationship: r, in: mastodonController.persistentContainer.viewContext) { mo in
let relationship = relationships.first else { 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 return nil
} }
let accountID = relationship.accountID
let following = relationship.following let following = relationship.following
return createAction(identifier: "follow", title: following ? "Unfollow" : "Follow", systemImageName: following ? "person.badge.minus" : "person.badge.plus") { _ in 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) let request = (following ? Account.unfollow : Account.follow)(accountID)