Compare commits
No commits in common. "7883b04618a2e05164a107fc042376140840c19a" and "2cfc0cf28adda2f8c99715cc7cd0f362e8fe0800" have entirely different histories.
7883b04618
...
2cfc0cf28a
|
@ -18,7 +18,6 @@ public class Relationship: Decodable {
|
||||||
public let followRequested: Bool
|
public let followRequested: Bool
|
||||||
public let domainBlocking: Bool
|
public let domainBlocking: Bool
|
||||||
public let showingReblogs: Bool
|
public let showingReblogs: Bool
|
||||||
public let endorsed: Bool?
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case id
|
case id
|
||||||
|
@ -30,6 +29,5 @@ public class Relationship: Decodable {
|
||||||
case followRequested = "requested"
|
case followRequested = "requested"
|
||||||
case domainBlocking = "domain_blocking"
|
case domainBlocking = "domain_blocking"
|
||||||
case showingReblogs = "showing_reblogs"
|
case showingReblogs = "showing_reblogs"
|
||||||
case endorsed
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,6 @@
|
||||||
D6BC9DD7232D7811002CA326 /* TimelinesPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC9DD6232D7811002CA326 /* TimelinesPageViewController.swift */; };
|
D6BC9DD7232D7811002CA326 /* TimelinesPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC9DD6232D7811002CA326 /* TimelinesPageViewController.swift */; };
|
||||||
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */; };
|
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */; };
|
||||||
D6BED174212667E900F02DA0 /* TimelineStatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BED173212667E900F02DA0 /* TimelineStatusTableViewCell.swift */; };
|
D6BED174212667E900F02DA0 /* TimelineStatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BED173212667E900F02DA0 /* TimelineStatusTableViewCell.swift */; };
|
||||||
D6C143DA253510F4007DC240 /* ComposeContentWarningTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C143D9253510F4007DC240 /* ComposeContentWarningTextField.swift */; };
|
|
||||||
D6C693EF216192C2007D6A6D /* TuskerNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */; };
|
D6C693EF216192C2007D6A6D /* TuskerNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */; };
|
||||||
D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693FB2162FE6F007D6A6D /* LoadingViewController.swift */; };
|
D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693FB2162FE6F007D6A6D /* LoadingViewController.swift */; };
|
||||||
D6C693FE2162FEEA007D6A6D /* UIViewController+Children.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */; };
|
D6C693FE2162FEEA007D6A6D /* UIViewController+Children.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */; };
|
||||||
|
@ -261,7 +260,6 @@
|
||||||
D6D4DDF0212518A200E1C4BB /* TuskerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D4DDEF212518A200E1C4BB /* TuskerUITests.swift */; };
|
D6D4DDF0212518A200E1C4BB /* TuskerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D4DDEF212518A200E1C4BB /* TuskerUITests.swift */; };
|
||||||
D6DD353D22F28CD000A9563A /* ContentWarningCopyMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */; };
|
D6DD353D22F28CD000A9563A /* ContentWarningCopyMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */; };
|
||||||
D6DD353F22F502EC00A9563A /* Preferences+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */; };
|
D6DD353F22F502EC00A9563A /* Preferences+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */; };
|
||||||
D6DF95C12533F5DE0027A9B6 /* RelationshipMO.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DF95C02533F5DE0027A9B6 /* RelationshipMO.swift */; };
|
|
||||||
D6DFC69E242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */; };
|
D6DFC69E242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */; };
|
||||||
D6DFC6A0242C4CCC00ACC392 /* WeakArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */; };
|
D6DFC6A0242C4CCC00ACC392 /* WeakArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */; };
|
||||||
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0DC8D216EDF1E00369478 /* Previewing.swift */; };
|
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0DC8D216EDF1E00369478 /* Previewing.swift */; };
|
||||||
|
@ -568,7 +566,6 @@
|
||||||
D6BC9DD6232D7811002CA326 /* TimelinesPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinesPageViewController.swift; sourceTree = "<group>"; };
|
D6BC9DD6232D7811002CA326 /* TimelinesPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinesPageViewController.swift; sourceTree = "<group>"; };
|
||||||
D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsViewController.swift; sourceTree = "<group>"; };
|
D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsViewController.swift; sourceTree = "<group>"; };
|
||||||
D6BED173212667E900F02DA0 /* TimelineStatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStatusTableViewCell.swift; sourceTree = "<group>"; };
|
D6BED173212667E900F02DA0 /* TimelineStatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStatusTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D6C143D9253510F4007DC240 /* ComposeContentWarningTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeContentWarningTextField.swift; sourceTree = "<group>"; };
|
|
||||||
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TuskerNavigationDelegate.swift; sourceTree = "<group>"; };
|
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TuskerNavigationDelegate.swift; sourceTree = "<group>"; };
|
||||||
D6C693FB2162FE6F007D6A6D /* LoadingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingViewController.swift; sourceTree = "<group>"; };
|
D6C693FB2162FE6F007D6A6D /* LoadingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingViewController.swift; sourceTree = "<group>"; };
|
||||||
D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Children.swift"; sourceTree = "<group>"; };
|
D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Children.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -597,7 +594,6 @@
|
||||||
D6D4DDF1212518A200E1C4BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
D6D4DDF1212518A200E1C4BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentWarningCopyMode.swift; sourceTree = "<group>"; };
|
D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentWarningCopyMode.swift; sourceTree = "<group>"; };
|
||||||
D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preferences+Notification.swift"; sourceTree = "<group>"; };
|
D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preferences+Notification.swift"; sourceTree = "<group>"; };
|
||||||
D6DF95C02533F5DE0027A9B6 /* RelationshipMO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelationshipMO.swift; sourceTree = "<group>"; };
|
|
||||||
D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
||||||
D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakArray.swift; sourceTree = "<group>"; };
|
D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakArray.swift; sourceTree = "<group>"; };
|
||||||
D6E0DC8D216EDF1E00369478 /* Previewing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Previewing.swift; sourceTree = "<group>"; };
|
D6E0DC8D216EDF1E00369478 /* Previewing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Previewing.swift; sourceTree = "<group>"; };
|
||||||
|
@ -897,7 +893,6 @@
|
||||||
D6370B9A24421FF30092A7FF /* Tusker.xcdatamodeld */,
|
D6370B9A24421FF30092A7FF /* Tusker.xcdatamodeld */,
|
||||||
D60E2F232442372B005F8713 /* StatusMO.swift */,
|
D60E2F232442372B005F8713 /* StatusMO.swift */,
|
||||||
D60E2F252442372B005F8713 /* AccountMO.swift */,
|
D60E2F252442372B005F8713 /* AccountMO.swift */,
|
||||||
D6DF95C02533F5DE0027A9B6 /* RelationshipMO.swift */,
|
|
||||||
D60E2F2D244248BF005F8713 /* MastodonCachePersistentStore.swift */,
|
D60E2F2D244248BF005F8713 /* MastodonCachePersistentStore.swift */,
|
||||||
);
|
);
|
||||||
path = CoreData;
|
path = CoreData;
|
||||||
|
@ -1006,7 +1001,6 @@
|
||||||
D62275A524F1C81800B82A16 /* ComposeReplyView.swift */,
|
D62275A524F1C81800B82A16 /* ComposeReplyView.swift */,
|
||||||
D62275A724F1CA2800B82A16 /* ComposeReplyContentView.swift */,
|
D62275A724F1CA2800B82A16 /* ComposeReplyContentView.swift */,
|
||||||
D6E4267625327FB400C02E1C /* ComposeAutocompleteView.swift */,
|
D6E4267625327FB400C02E1C /* ComposeAutocompleteView.swift */,
|
||||||
D6C143D9253510F4007DC240 /* ComposeContentWarningTextField.swift */,
|
|
||||||
);
|
);
|
||||||
path = Compose;
|
path = Compose;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1843,7 +1837,6 @@
|
||||||
D677284C24ECBE9100C732D3 /* ComposeAvatarImageView.swift in Sources */,
|
D677284C24ECBE9100C732D3 /* ComposeAvatarImageView.swift in Sources */,
|
||||||
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */,
|
D6BC9DDA232D8BE5002CA326 /* SearchResultsViewController.swift in Sources */,
|
||||||
D627FF7F217E95E000CC0648 /* DraftTableViewCell.swift in Sources */,
|
D627FF7F217E95E000CC0648 /* DraftTableViewCell.swift in Sources */,
|
||||||
D6DF95C12533F5DE0027A9B6 /* RelationshipMO.swift in Sources */,
|
|
||||||
D6AEBB4A23216F0400E5038B /* UnfollowAccountActivity.swift in Sources */,
|
D6AEBB4A23216F0400E5038B /* UnfollowAccountActivity.swift in Sources */,
|
||||||
D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */,
|
D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */,
|
||||||
D6D3FDE024F41B8400FF50A5 /* ComposeContainerView.swift in Sources */,
|
D6D3FDE024F41B8400FF50A5 /* ComposeContainerView.swift in Sources */,
|
||||||
|
@ -1863,7 +1856,6 @@
|
||||||
D622757424EDF1CD00B82A16 /* ComposeAttachmentsList.swift in Sources */,
|
D622757424EDF1CD00B82A16 /* ComposeAttachmentsList.swift in Sources */,
|
||||||
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */,
|
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */,
|
||||||
D6BED174212667E900F02DA0 /* TimelineStatusTableViewCell.swift in Sources */,
|
D6BED174212667E900F02DA0 /* TimelineStatusTableViewCell.swift in Sources */,
|
||||||
D6C143DA253510F4007DC240 /* ComposeContentWarningTextField.swift in Sources */,
|
|
||||||
0427033822B30F5F000D31B6 /* BehaviorPrefsView.swift in Sources */,
|
0427033822B30F5F000D31B6 /* BehaviorPrefsView.swift in Sources */,
|
||||||
D627943923A553B600D38C68 /* UnbookmarkStatusActivity.swift in Sources */,
|
D627943923A553B600D38C68 /* UnbookmarkStatusActivity.swift in Sources */,
|
||||||
D64D0AAD2128D88B005A6F37 /* LocalData.swift in Sources */,
|
D64D0AAD2128D88B005A6F37 /* LocalData.swift in Sources */,
|
||||||
|
|
|
@ -29,13 +29,10 @@ class FollowAccountActivity: AccountActivity {
|
||||||
|
|
||||||
let request = Account.follow(account.id)
|
let request = Account.follow(account.id)
|
||||||
mastodonController.run(request) { (response) in
|
mastodonController.run(request) { (response) in
|
||||||
switch response {
|
if case .failure(_) = response {
|
||||||
case .failure(_):
|
|
||||||
// todo: display error message
|
// todo: display error message
|
||||||
UINotificationFeedbackGenerator().notificationOccurred(.error)
|
UINotificationFeedbackGenerator().notificationOccurred(.error)
|
||||||
fatalError()
|
fatalError()
|
||||||
case let .success(relationship, _):
|
|
||||||
self.mastodonController.persistentContainer.addOrUpdate(relationship: relationship)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,10 @@ class UnfollowAccountActivity: AccountActivity {
|
||||||
|
|
||||||
let request = Account.unfollow(account.id)
|
let request = Account.unfollow(account.id)
|
||||||
mastodonController.run(request) { (response) in
|
mastodonController.run(request) { (response) in
|
||||||
switch response {
|
if case .failure(_) = response {
|
||||||
case .failure(_):
|
|
||||||
// todo: display error message
|
// todo: display error message
|
||||||
UINotificationFeedbackGenerator().notificationOccurred(.error)
|
UINotificationFeedbackGenerator().notificationOccurred(.error)
|
||||||
fatalError()
|
fatalError()
|
||||||
case let .success(relationship, _):
|
|
||||||
self.mastodonController.persistentContainer.addOrUpdate(relationship: relationship)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
||||||
|
|
||||||
let statusSubject = PassthroughSubject<String, Never>()
|
let statusSubject = PassthroughSubject<String, Never>()
|
||||||
let accountSubject = PassthroughSubject<String, Never>()
|
let accountSubject = PassthroughSubject<String, Never>()
|
||||||
let relationshipSubject = PassthroughSubject<String, Never>()
|
|
||||||
|
|
||||||
init(for accountInfo: LocalData.UserAccountInfo?, transient: Bool = false) {
|
init(for accountInfo: LocalData.UserAccountInfo?, transient: Bool = false) {
|
||||||
if transient {
|
if transient {
|
||||||
|
@ -137,40 +136,6 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func relationship(forAccount id: String, in context: NSManagedObjectContext? = nil) -> RelationshipMO? {
|
|
||||||
let context = context ?? viewContext
|
|
||||||
let request: NSFetchRequest<RelationshipMO> = RelationshipMO.fetchRequest()
|
|
||||||
request.predicate = NSPredicate(format: "accountID = %@", id)
|
|
||||||
request.fetchLimit = 1
|
|
||||||
if let result = try? context.fetch(request), let relationship = result.first {
|
|
||||||
return relationship
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
private func upsert(relationship: Relationship) -> RelationshipMO {
|
|
||||||
if let relationshipMO = self.relationship(forAccount: relationship.id, in: self.backgroundContext) {
|
|
||||||
relationshipMO.updateFrom(apiRelationship: relationship, container: self)
|
|
||||||
return relationshipMO
|
|
||||||
} else {
|
|
||||||
let relationshipMO = RelationshipMO(apiRelationship: relationship, container: self, context: self.backgroundContext)
|
|
||||||
return relationshipMO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func addOrUpdate(relationship: Relationship, completion: ((RelationshipMO) -> Void)? = nil) {
|
|
||||||
backgroundContext.perform {
|
|
||||||
let relationshipMO = self.upsert(relationship: relationship)
|
|
||||||
if self.backgroundContext.hasChanges {
|
|
||||||
try! self.backgroundContext.save()
|
|
||||||
}
|
|
||||||
completion?(relationshipMO)
|
|
||||||
self.relationshipSubject.send(relationship.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func addAll(accounts: [Account], completion: (() -> Void)? = nil) {
|
func addAll(accounts: [Account], completion: (() -> Void)? = nil) {
|
||||||
backgroundContext.perform {
|
backgroundContext.perform {
|
||||||
accounts.forEach { self.upsert(account: $0, incrementReferenceCount: true) }
|
accounts.forEach { self.upsert(account: $0, incrementReferenceCount: true) }
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
//
|
|
||||||
// RelationshipMO.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 10/11/20.
|
|
||||||
// Copyright © 2020 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import CoreData
|
|
||||||
import Pachyderm
|
|
||||||
|
|
||||||
@objc(RelationshipMO)
|
|
||||||
public final class RelationshipMO: NSManagedObject {
|
|
||||||
|
|
||||||
@nonobjc public class func fetchRequest() -> NSFetchRequest<RelationshipMO> {
|
|
||||||
return NSFetchRequest<RelationshipMO>(entityName: "Relationship")
|
|
||||||
}
|
|
||||||
|
|
||||||
@NSManaged public var accountID: String
|
|
||||||
@NSManaged public var blocking: Bool
|
|
||||||
@NSManaged public var domainBlocking: Bool
|
|
||||||
@NSManaged public var endorsed: Bool
|
|
||||||
@NSManaged public var followedBy: Bool
|
|
||||||
@NSManaged public var following: Bool
|
|
||||||
@NSManaged public var muting: Bool
|
|
||||||
@NSManaged public var mutingNotifications: Bool
|
|
||||||
@NSManaged public var requested: Bool
|
|
||||||
@NSManaged public var showingReblogs: Bool
|
|
||||||
@NSManaged public var account: AccountMO?
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension RelationshipMO {
|
|
||||||
convenience init(apiRelationship relationship: Relationship, container: MastodonCachePersistentStore, context: NSManagedObjectContext) {
|
|
||||||
self.init(context: context)
|
|
||||||
self.updateFrom(apiRelationship: relationship, container: container)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateFrom(apiRelationship relationship: Relationship, container: MastodonCachePersistentStore) {
|
|
||||||
guard let context = managedObjectContext else {
|
|
||||||
// we have been deleted, don't bother updating
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.accountID = relationship.id
|
|
||||||
self.blocking = relationship.blocking
|
|
||||||
self.domainBlocking = relationship.domainBlocking
|
|
||||||
self.endorsed = relationship.endorsed ?? false
|
|
||||||
self.followedBy = relationship.followedBy
|
|
||||||
self.following = relationship.following
|
|
||||||
self.muting = relationship.muting
|
|
||||||
self.mutingNotifications = relationship.mutingNotifications
|
|
||||||
self.requested = relationship.followRequested
|
|
||||||
self.showingReblogs = relationship.showingReblogs
|
|
||||||
|
|
||||||
self.account = container.account(for: relationship.id, in: context)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17507" systemVersion="19G2021" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19D76" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||||
<entity name="Account" representedClassName="AccountMO" syncable="YES">
|
<entity name="Account" representedClassName="AccountMO" syncable="YES">
|
||||||
<attribute name="acct" attributeType="String"/>
|
<attribute name="acct" attributeType="String"/>
|
||||||
<attribute name="avatar" attributeType="URI"/>
|
<attribute name="avatar" attributeType="URI"/>
|
||||||
|
@ -20,26 +20,12 @@
|
||||||
<attribute name="url" attributeType="URI"/>
|
<attribute name="url" attributeType="URI"/>
|
||||||
<attribute name="username" attributeType="String"/>
|
<attribute name="username" attributeType="String"/>
|
||||||
<relationship name="movedTo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Account"/>
|
<relationship name="movedTo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Account"/>
|
||||||
<relationship name="relationship" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Relationship" inverseName="account" inverseEntity="Relationship"/>
|
|
||||||
<uniquenessConstraints>
|
<uniquenessConstraints>
|
||||||
<uniquenessConstraint>
|
<uniquenessConstraint>
|
||||||
<constraint value="id"/>
|
<constraint value="id"/>
|
||||||
</uniquenessConstraint>
|
</uniquenessConstraint>
|
||||||
</uniquenessConstraints>
|
</uniquenessConstraints>
|
||||||
</entity>
|
</entity>
|
||||||
<entity name="Relationship" representedClassName="RelationshipMO" syncable="YES">
|
|
||||||
<attribute name="accountID" optional="YES" attributeType="String"/>
|
|
||||||
<attribute name="blocking" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="domainBlocking" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="endorsed" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="followedBy" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="following" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="muting" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="mutingNotifications" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="requested" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
|
||||||
<attribute name="showingReblogs" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
|
||||||
<relationship name="account" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Account" inverseName="relationship" inverseEntity="Account"/>
|
|
||||||
</entity>
|
|
||||||
<entity name="Status" representedClassName="StatusMO" syncable="YES">
|
<entity name="Status" representedClassName="StatusMO" syncable="YES">
|
||||||
<attribute name="applicationName" optional="YES" attributeType="String"/>
|
<attribute name="applicationName" optional="YES" attributeType="String"/>
|
||||||
<attribute name="attachmentsData" attributeType="Binary"/>
|
<attribute name="attachmentsData" attributeType="Binary"/>
|
||||||
|
@ -73,8 +59,7 @@
|
||||||
</uniquenessConstraints>
|
</uniquenessConstraints>
|
||||||
</entity>
|
</entity>
|
||||||
<elements>
|
<elements>
|
||||||
<element name="Account" positionX="169.21875" positionY="78.9609375" width="128" height="343"/>
|
<element name="Account" positionX="169.21875" positionY="78.9609375" width="128" height="328"/>
|
||||||
<element name="Status" positionX="-63" positionY="-18" width="128" height="418"/>
|
<element name="Status" positionX="-63" positionY="-18" width="128" height="418"/>
|
||||||
<element name="Relationship" positionX="63" positionY="135" width="128" height="208"/>
|
|
||||||
</elements>
|
</elements>
|
||||||
</model>
|
</model>
|
|
@ -73,7 +73,7 @@ struct ComposeAutocompleteMentionsView: View {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
ForEach(accounts, id: \.id) { (account) in
|
ForEach(accounts, id: \.id) { (account) in
|
||||||
Button {
|
Button {
|
||||||
uiState.autocompleteHandler?.autocomplete(with: "@\(account.acct)")
|
uiState.autocompleteHandler?.autocomplete(with: "@\(account.acct) ")
|
||||||
} label: {
|
} label: {
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
ComposeAvatarImageView(url: account.avatar)
|
ComposeAvatarImageView(url: account.avatar)
|
||||||
|
@ -210,7 +210,7 @@ struct ComposeAutocompleteEmojisView: View {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
ForEach(emojis, id: \.shortcode) { (emoji) in
|
ForEach(emojis, id: \.shortcode) { (emoji) in
|
||||||
Button {
|
Button {
|
||||||
uiState.autocompleteHandler?.autocomplete(with: ":\(emoji.shortcode):")
|
uiState.autocompleteHandler?.autocomplete(with: ":\(emoji.shortcode): ")
|
||||||
} label: {
|
} label: {
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
CustomEmojiImageView(emoji: emoji)
|
CustomEmojiImageView(emoji: emoji)
|
||||||
|
@ -266,7 +266,7 @@ struct ComposeAutocompleteHashtagsView: View {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
ForEach(hashtags, id: \.name) { (hashtag) in
|
ForEach(hashtags, id: \.name) { (hashtag) in
|
||||||
Button {
|
Button {
|
||||||
uiState.autocompleteHandler?.autocomplete(with: "#\(hashtag.name)")
|
uiState.autocompleteHandler?.autocomplete(with: "#\(hashtag.name) ")
|
||||||
} label: {
|
} label: {
|
||||||
Text(verbatim: "#\(hashtag.name)")
|
Text(verbatim: "#\(hashtag.name)")
|
||||||
.foregroundColor(Color(UIColor.label))
|
.foregroundColor(Color(UIColor.label))
|
||||||
|
|
|
@ -1,163 +0,0 @@
|
||||||
//
|
|
||||||
// ComposeContentWarningTextField.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 10/12/20.
|
|
||||||
// Copyright © 2020 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ComposeContentWarningTextField: UIViewRepresentable {
|
|
||||||
typealias UIViewType = UITextField
|
|
||||||
|
|
||||||
@Binding var text: String
|
|
||||||
|
|
||||||
@EnvironmentObject private var uiState: ComposeUIState
|
|
||||||
|
|
||||||
func makeUIView(context: Context) -> UITextField {
|
|
||||||
let view = UITextField()
|
|
||||||
|
|
||||||
view.placeholder = "Write your warning here"
|
|
||||||
view.borderStyle = .roundedRect
|
|
||||||
|
|
||||||
view.delegate = context.coordinator
|
|
||||||
view.addTarget(context.coordinator, action: #selector(Coordinator.didChange(_:)), for: .editingChanged)
|
|
||||||
|
|
||||||
context.coordinator.textField = view
|
|
||||||
context.coordinator.uiState = uiState
|
|
||||||
context.coordinator.text = $text
|
|
||||||
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUIView(_ uiView: UITextField, context: Context) {
|
|
||||||
uiView.text = text
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeCoordinator() -> Coordinator {
|
|
||||||
return Coordinator()
|
|
||||||
}
|
|
||||||
|
|
||||||
class Coordinator: NSObject, UITextFieldDelegate, ComposeAutocompleteHandler {
|
|
||||||
weak var textField: UITextField?
|
|
||||||
var text: Binding<String>!
|
|
||||||
var uiState: ComposeUIState!
|
|
||||||
|
|
||||||
@objc func didChange(_ textField: UITextField) {
|
|
||||||
text.wrappedValue = textField.text ?? ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func textFieldDidBeginEditing(_ textField: UITextField) {
|
|
||||||
uiState.autocompleteHandler = self
|
|
||||||
updateAutocompleteState(textField: textField)
|
|
||||||
}
|
|
||||||
|
|
||||||
func textFieldDidEndEditing(_ textField: UITextField) {
|
|
||||||
uiState.autocompleteHandler = nil
|
|
||||||
updateAutocompleteState(textField: textField)
|
|
||||||
}
|
|
||||||
|
|
||||||
func textFieldDidChangeSelection(_ textField: UITextField) {
|
|
||||||
updateAutocompleteState(textField: textField)
|
|
||||||
}
|
|
||||||
|
|
||||||
func autocomplete(with string: String) {
|
|
||||||
guard let textField = textField,
|
|
||||||
let text = textField.text,
|
|
||||||
let selectedRange = textField.selectedTextRange,
|
|
||||||
let lastWordStartIndex = findAutocompleteLastWord(textField: textField) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let distanceToEnd = textField.offset(from: selectedRange.start, to: textField.endOfDocument)
|
|
||||||
|
|
||||||
let selectedRangeStartUTF16 = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start)
|
|
||||||
let characterBeforeCursorIndex = text.utf16.index(text.startIndex, offsetBy: selectedRangeStartUTF16)
|
|
||||||
|
|
||||||
let insertSpace: Bool
|
|
||||||
if text.distance(from: characterBeforeCursorIndex, to: text.endIndex) > 0 {
|
|
||||||
let charAfterCursor = text[text.index(after: characterBeforeCursorIndex)]
|
|
||||||
insertSpace = charAfterCursor != " " && charAfterCursor != "\n"
|
|
||||||
} else {
|
|
||||||
insertSpace = true
|
|
||||||
}
|
|
||||||
let string = insertSpace ? string + " " : string
|
|
||||||
|
|
||||||
textField.text!.replaceSubrange(lastWordStartIndex..<characterBeforeCursorIndex, with: string)
|
|
||||||
didChange(textField)
|
|
||||||
|
|
||||||
// keep the cursor at the same position in the text, immediately after what was inserted
|
|
||||||
let newCursorPosition = textField.position(from: textField.endOfDocument, offset: -distanceToEnd)!
|
|
||||||
textField.selectedTextRange = textField.textRange(from: newCursorPosition, to: newCursorPosition)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateAutocompleteState(textField: UITextField) {
|
|
||||||
guard let selectedRange = textField.selectedTextRange,
|
|
||||||
let text = textField.text,
|
|
||||||
let lastWordStartIndex = findAutocompleteLastWord(textField: textField) else {
|
|
||||||
uiState.autocompleteState = nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if lastWordStartIndex > text.startIndex {
|
|
||||||
let c = text[text.index(before: lastWordStartIndex)]
|
|
||||||
if isPermittedForAutocomplete(c) || c == ":" {
|
|
||||||
uiState.autocompleteState = nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let selectedRangeStartUTF16 = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start)
|
|
||||||
let cursorIndex = text.utf16.index(text.startIndex, offsetBy: selectedRangeStartUTF16)
|
|
||||||
|
|
||||||
if lastWordStartIndex >= text.startIndex {
|
|
||||||
let lastWord = text[lastWordStartIndex..<cursorIndex]
|
|
||||||
let exceptFirst = lastWord[lastWord.index(after: lastWord.startIndex)...]
|
|
||||||
|
|
||||||
if lastWord.first == ":" {
|
|
||||||
uiState.autocompleteState = .emoji(String(exceptFirst))
|
|
||||||
} else {
|
|
||||||
uiState.autocompleteState = nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uiState.autocompleteState = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func isPermittedForAutocomplete(_ c: Character) -> Bool {
|
|
||||||
return (c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || (c >= "0" && c <= "9") || c == "_"
|
|
||||||
}
|
|
||||||
|
|
||||||
private func findAutocompleteLastWord(textField: UITextField) -> String.Index? {
|
|
||||||
guard textField.isFirstResponder,
|
|
||||||
let selectedRange = textField.selectedTextRange,
|
|
||||||
selectedRange.isEmpty,
|
|
||||||
let text = textField.text,
|
|
||||||
!text.isEmpty else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let selectedRangeStartUTF16 = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start)
|
|
||||||
let cursorIndex = text.utf16.index(text.startIndex, offsetBy: selectedRangeStartUTF16)
|
|
||||||
|
|
||||||
var lastWordStartIndex = text.index(before: cursorIndex)
|
|
||||||
while true {
|
|
||||||
let c = text[lastWordStartIndex]
|
|
||||||
|
|
||||||
if !isPermittedForAutocomplete(c) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if lastWordStartIndex > text.startIndex {
|
|
||||||
lastWordStartIndex = text.index(before: lastWordStartIndex)
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastWordStartIndex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -114,7 +114,8 @@ struct ComposeView: View {
|
||||||
header
|
header
|
||||||
|
|
||||||
if draft.contentWarningEnabled {
|
if draft.contentWarningEnabled {
|
||||||
ComposeContentWarningTextField(text: $draft.contentWarning)
|
TextField("Write your warning here", text: $draft.contentWarning)
|
||||||
|
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||||
}
|
}
|
||||||
|
|
||||||
MainComposeTextView(
|
MainComposeTextView(
|
||||||
|
@ -129,7 +130,6 @@ struct ComposeView: View {
|
||||||
.padding([.top, .bottom], -8)
|
.padding([.top, .bottom], -8)
|
||||||
}
|
}
|
||||||
.padding(stackPadding)
|
.padding(stackPadding)
|
||||||
.padding(.bottom, uiState.autocompleteState != nil ? 46 : nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var header: some View {
|
private var header: some View {
|
||||||
|
|
|
@ -218,13 +218,11 @@ struct MainComposeWrappedTextView: UIViewRepresentable {
|
||||||
uiState.delegate?.keyboardDidHide(accessoryView: textView!.inputAccessoryView!, notification: notification)
|
uiState.delegate?.keyboardDidHide(accessoryView: textView!.inputAccessoryView!, notification: notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
func textViewDidBeginEditing(_ textView: UITextView) {
|
func textViewDidEndEditing(_ textView: UITextView) {
|
||||||
uiState.autocompleteHandler = self
|
|
||||||
updateAutocompleteState()
|
updateAutocompleteState()
|
||||||
}
|
}
|
||||||
|
|
||||||
func textViewDidEndEditing(_ textView: UITextView) {
|
func textViewDidBeginEditing(_ textView: UITextView) {
|
||||||
uiState.autocompleteHandler = nil
|
|
||||||
updateAutocompleteState()
|
updateAutocompleteState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,24 +237,10 @@ struct MainComposeWrappedTextView: UIViewRepresentable {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let distanceToEnd = text.utf16.count - textView.selectedRange.upperBound
|
|
||||||
|
|
||||||
let characterBeforeCursorIndex = text.utf16.index(text.startIndex, offsetBy: textView.selectedRange.upperBound)
|
let characterBeforeCursorIndex = text.utf16.index(text.startIndex, offsetBy: textView.selectedRange.upperBound)
|
||||||
|
|
||||||
let insertSpace: Bool
|
|
||||||
if text.distance(from: characterBeforeCursorIndex, to: text.endIndex) > 0 {
|
|
||||||
let charAfterCursor = text[text.index(after: characterBeforeCursorIndex)]
|
|
||||||
insertSpace = charAfterCursor != " " && charAfterCursor != "\n"
|
|
||||||
} else {
|
|
||||||
insertSpace = true
|
|
||||||
}
|
|
||||||
let string = insertSpace ? string + " " : string
|
|
||||||
|
|
||||||
textView.text.replaceSubrange(lastWordStartIndex..<characterBeforeCursorIndex, with: string)
|
textView.text.replaceSubrange(lastWordStartIndex..<characterBeforeCursorIndex, with: string)
|
||||||
self.textViewDidChange(textView)
|
self.textViewDidChange(textView)
|
||||||
|
|
||||||
// keep the cursor at the same position in the text, immediately after what was inserted
|
|
||||||
textView.selectedRange = NSRange(location: textView.text.utf16.count - distanceToEnd, length: 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateAutocompleteState() {
|
private func updateAutocompleteState() {
|
||||||
|
@ -328,7 +312,7 @@ struct MainComposeWrappedTextView: UIViewRepresentable {
|
||||||
var lastWordStartIndex = text.index(before: characterBeforeCursorIndex)
|
var lastWordStartIndex = text.index(before: characterBeforeCursorIndex)
|
||||||
var foundFirstAtSign = false
|
var foundFirstAtSign = false
|
||||||
while true {
|
while true {
|
||||||
let c = text[lastWordStartIndex]
|
let c = textView.text[lastWordStartIndex]
|
||||||
|
|
||||||
if !isPermittedForAutocomplete(c) {
|
if !isPermittedForAutocomplete(c) {
|
||||||
if foundFirstAtSign {
|
if foundFirstAtSign {
|
||||||
|
|
|
@ -71,13 +71,7 @@ extension MenuPreviewProvider {
|
||||||
elementHandler([
|
elementHandler([
|
||||||
self.createAction(identifier: "follow", title: following ? "Unfollow" : "Follow", systemImageName: following ? "person.badge.minus" : "person.badge.plus", handler: { (_) in
|
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)
|
let request = (following ? Account.unfollow : Account.follow)(accountID)
|
||||||
mastodonController.run(request) { (response) in
|
mastodonController.run(request) { (_) in
|
||||||
switch response {
|
|
||||||
case .failure(_):
|
|
||||||
fatalError()
|
|
||||||
case let .success(relationship, _):
|
|
||||||
mastodonController.persistentContainer.addOrUpdate(relationship: relationship)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|
|
@ -23,11 +23,7 @@ class ProfileHeaderView: UIView {
|
||||||
return nib.instantiate(withOwner: nil, options: nil).first as! ProfileHeaderView
|
return nib.instantiate(withOwner: nil, options: nil).first as! ProfileHeaderView
|
||||||
}
|
}
|
||||||
|
|
||||||
weak var delegate: ProfileHeaderViewDelegate? {
|
weak var delegate: ProfileHeaderViewDelegate?
|
||||||
didSet {
|
|
||||||
createObservers()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var mastodonController: MastodonController! { delegate?.apiController }
|
var mastodonController: MastodonController! { delegate?.apiController }
|
||||||
|
|
||||||
@IBOutlet weak var headerImageView: UIImageView!
|
@IBOutlet weak var headerImageView: UIImageView!
|
||||||
|
@ -45,10 +41,10 @@ class ProfileHeaderView: UIView {
|
||||||
|
|
||||||
var accountID: String!
|
var accountID: String!
|
||||||
|
|
||||||
private var avatarRequest: ImageCache.Request?
|
var avatarRequest: ImageCache.Request?
|
||||||
private var headerRequest: ImageCache.Request?
|
var headerRequest: ImageCache.Request?
|
||||||
|
|
||||||
private var cancellables = [AnyCancellable]()
|
private var accountUpdater: Cancellable?
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
avatarRequest?.cancel()
|
avatarRequest?.cancel()
|
||||||
|
@ -78,22 +74,6 @@ class ProfileHeaderView: UIView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createObservers() {
|
|
||||||
cancellables = []
|
|
||||||
|
|
||||||
mastodonController.persistentContainer.accountSubject
|
|
||||||
.filter { [weak self] in $0 == self?.accountID }
|
|
||||||
.receive(on: DispatchQueue.main)
|
|
||||||
.sink { [weak self] in self?.updateUI(for: $0) }
|
|
||||||
.store(in: &cancellables)
|
|
||||||
|
|
||||||
mastodonController.persistentContainer.relationshipSubject
|
|
||||||
.filter { [weak self] in $0 == self?.accountID }
|
|
||||||
.receive(on: DispatchQueue.main)
|
|
||||||
.sink { [weak self] (_) in self?.updateRelationship() }
|
|
||||||
.store(in: &cancellables)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUI(for accountID: String) {
|
func updateUI(for accountID: String) {
|
||||||
self.accountID = accountID
|
self.accountID = accountID
|
||||||
|
|
||||||
|
@ -131,9 +111,6 @@ class ProfileHeaderView: UIView {
|
||||||
|
|
||||||
// don't show relationship label for the user's own account
|
// don't show relationship label for the user's own account
|
||||||
if accountID != mastodonController.account?.id {
|
if accountID != mastodonController.account?.id {
|
||||||
// while fetching the most up-to-date, show the current data (if any)
|
|
||||||
updateRelationship()
|
|
||||||
|
|
||||||
let request = Client.getRelationships(accounts: [accountID])
|
let request = Client.getRelationships(accounts: [accountID])
|
||||||
mastodonController.run(request) { [weak self] (response) in
|
mastodonController.run(request) { [weak self] (response) in
|
||||||
guard let self = self,
|
guard let self = self,
|
||||||
|
@ -141,7 +118,9 @@ class ProfileHeaderView: UIView {
|
||||||
let relationship = results.first else {
|
let relationship = results.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.mastodonController.persistentContainer.addOrUpdate(relationship: relationship)
|
DispatchQueue.main.async {
|
||||||
|
self.followsYouLabel.isHidden = !relationship.followedBy
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,14 +152,13 @@ class ProfileHeaderView: UIView {
|
||||||
|
|
||||||
nameLabel.heightAnchor.constraint(equalTo: valueTextView.heightAnchor).isActive = true
|
nameLabel.heightAnchor.constraint(equalTo: valueTextView.heightAnchor).isActive = true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private func updateRelationship() {
|
|
||||||
guard let relationship = mastodonController.persistentContainer.relationship(forAccount: accountID) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
followsYouLabel.isHidden = !relationship.followedBy
|
if accountUpdater == nil {
|
||||||
|
accountUpdater = mastodonController.persistentContainer.accountSubject
|
||||||
|
.filter { [weak self] in $0 == self?.accountID }
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
|
.sink { [weak self] in self?.updateUI(for: $0) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func updateUIForPreferences() {
|
@objc private func updateUIForPreferences() {
|
||||||
|
|
Loading…
Reference in New Issue