From 0255483f976d8c9f494a92f7ca6cdcc7dbfa5883 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 5 Jan 2020 19:54:28 -0500 Subject: [PATCH] Make MastodonCache specific to each API controller See #16 --- .../FollowAccountActivity.swift | 2 +- .../UnfollowAccountActivity.swift | 2 +- .../BookmarkStatusActivity.swift | 2 +- .../Status Activities/PinStatusActivity.swift | 2 +- .../UnbookmarkStatusActivity.swift | 2 +- .../UnpinStatusActivity.swift | 2 +- Tusker/Controllers/MastodonController.swift | 4 +- Tusker/MastodonCache.swift | 62 ++++++++++--------- .../AccountListTableViewController.swift | 2 +- .../BookmarksTableViewController.swift | 16 ++--- .../Compose/ComposeViewController.swift | 8 +-- .../ConversationTableViewController.swift | 14 ++--- .../EditListAccountsViewController.swift | 2 +- .../NotificationsTableViewController.swift | 34 +++++----- .../Profile/ProfileTableViewController.swift | 30 ++++----- .../Search/SearchResultsViewController.swift | 12 ++-- ...ActionAccountListTableViewController.swift | 8 +-- .../TimelineTableViewController.swift | 12 ++-- Tusker/Screens/Utilities/Previewing.swift | 8 ++- Tusker/TuskerNavigationDelegate.swift | 4 +- .../Account Cell/AccountTableViewCell.swift | 4 +- .../AttachmentsContainerView.swift | 8 +-- ...ActionNotificationGroupTableViewCell.swift | 13 ++-- ...FollowNotificationGroupTableViewCell.swift | 10 +-- ...llowRequestNotificationTableViewCell.swift | 4 +- .../ProfileHeaderTableViewCell.swift | 8 +-- .../Status/BaseStatusTableViewCell.swift | 41 +++++++----- .../ConversationMainStatusTableViewCell.swift | 2 +- .../Status/TimelineStatusTableViewCell.swift | 32 ++++++---- Tusker/Views/StatusContentLabel.swift | 12 ++-- Tusker/XCallbackURL/XCBActions.swift | 14 ++--- 31 files changed, 200 insertions(+), 176 deletions(-) diff --git a/Tusker/Activities/Account Activities/FollowAccountActivity.swift b/Tusker/Activities/Account Activities/FollowAccountActivity.swift index 7beb3523..ae89aa7e 100644 --- a/Tusker/Activities/Account Activities/FollowAccountActivity.swift +++ b/Tusker/Activities/Account Activities/FollowAccountActivity.swift @@ -30,7 +30,7 @@ class FollowAccountActivity: AccountActivity { let request = Account.follow(account.id) mastodonController.run(request) { (response) in if case let .success(relationship, _) = response { - MastodonCache.add(relationship: relationship) + self.mastodonController.cache.add(relationship: relationship) } else { // todo: display error message UINotificationFeedbackGenerator().notificationOccurred(.error) diff --git a/Tusker/Activities/Account Activities/UnfollowAccountActivity.swift b/Tusker/Activities/Account Activities/UnfollowAccountActivity.swift index 344387d7..493923d7 100644 --- a/Tusker/Activities/Account Activities/UnfollowAccountActivity.swift +++ b/Tusker/Activities/Account Activities/UnfollowAccountActivity.swift @@ -30,7 +30,7 @@ class UnfollowAccountActivity: AccountActivity { let request = Account.unfollow(account.id) mastodonController.run(request) { (response) in if case let .success(relationship, _) = response { - MastodonCache.add(relationship: relationship) + self.mastodonController.cache.add(relationship: relationship) } else { // todo: display error message UINotificationFeedbackGenerator().notificationOccurred(.error) diff --git a/Tusker/Activities/Status Activities/BookmarkStatusActivity.swift b/Tusker/Activities/Status Activities/BookmarkStatusActivity.swift index 8c64f007..585f3471 100644 --- a/Tusker/Activities/Status Activities/BookmarkStatusActivity.swift +++ b/Tusker/Activities/Status Activities/BookmarkStatusActivity.swift @@ -29,7 +29,7 @@ class BookmarkStatusActivity: StatusActivity { let request = Status.bookmark(status) mastodonController.run(request) { (response) in if case let .success(status, _) = response { - MastodonCache.add(status: status) + self.mastodonController.cache.add(status: status) } else { // todo: display error message UINotificationFeedbackGenerator().notificationOccurred(.error) diff --git a/Tusker/Activities/Status Activities/PinStatusActivity.swift b/Tusker/Activities/Status Activities/PinStatusActivity.swift index 3714a453..40ef6cfd 100644 --- a/Tusker/Activities/Status Activities/PinStatusActivity.swift +++ b/Tusker/Activities/Status Activities/PinStatusActivity.swift @@ -28,7 +28,7 @@ class PinStatusActivity: StatusActivity { let request = Status.pin(status) mastodonController.run(request) { (response) in if case let .success(status, _) = response { - MastodonCache.add(status: status) + self.mastodonController.cache.add(status: status) } else { // todo: display error message UINotificationFeedbackGenerator().notificationOccurred(.error) diff --git a/Tusker/Activities/Status Activities/UnbookmarkStatusActivity.swift b/Tusker/Activities/Status Activities/UnbookmarkStatusActivity.swift index be22c5e1..8cce299b 100644 --- a/Tusker/Activities/Status Activities/UnbookmarkStatusActivity.swift +++ b/Tusker/Activities/Status Activities/UnbookmarkStatusActivity.swift @@ -29,7 +29,7 @@ class UnbookmarkStatusActivity: StatusActivity { let request = Status.unbookmark(status) mastodonController.run(request) { (response) in if case let .success(status, _) = response { - MastodonCache.add(status: status) + self.mastodonController.cache.add(status: status) } else { // todo: display error message UINotificationFeedbackGenerator().notificationOccurred(.error) diff --git a/Tusker/Activities/Status Activities/UnpinStatusActivity.swift b/Tusker/Activities/Status Activities/UnpinStatusActivity.swift index cbb717cb..a22df120 100644 --- a/Tusker/Activities/Status Activities/UnpinStatusActivity.swift +++ b/Tusker/Activities/Status Activities/UnpinStatusActivity.swift @@ -28,7 +28,7 @@ class UnpinStatusActivity: StatusActivity { let request = Status.unpin(status) mastodonController.run(request) { (response) in if case let .success(status, _) = response { - MastodonCache.add(status: status) + self.mastodonController.cache.add(status: status) } else { // todo: display error message UINotificationFeedbackGenerator().notificationOccurred(.error) diff --git a/Tusker/Controllers/MastodonController.swift b/Tusker/Controllers/MastodonController.swift index a916d777..59aa82a6 100644 --- a/Tusker/Controllers/MastodonController.swift +++ b/Tusker/Controllers/MastodonController.swift @@ -14,6 +14,8 @@ class MastodonController { @available(*, deprecated, message: "Use dependency injection to obtain an instance") static let shared = MastodonController() + private(set) lazy var cache = MastodonCache(mastodonController: self) + private var client: Client! var account: Account! @@ -68,7 +70,7 @@ class MastodonController { run(request) { response in guard case let .success(account, _) = response else { fatalError() } self.account = account - MastodonCache.add(account: account) + self.cache.add(account: account) completion?(account) } } diff --git a/Tusker/MastodonCache.swift b/Tusker/MastodonCache.swift index 1ac5eddf..0c22b4e2 100644 --- a/Tusker/MastodonCache.swift +++ b/Tusker/MastodonCache.swift @@ -12,22 +12,26 @@ import Pachyderm class MastodonCache { - private static var statuses = CachedDictionary(name: "Statuses") - private static var accounts = CachedDictionary(name: "Accounts") - private static var relationships = CachedDictionary(name: "Relationships") - private static var notifications = CachedDictionary(name: "Notifications") + private var statuses = CachedDictionary(name: "Statuses") + private var accounts = CachedDictionary(name: "Accounts") + private var relationships = CachedDictionary(name: "Relationships") + private var notifications = CachedDictionary(name: "Notifications") - static let statusSubject = PassthroughSubject() - static let accountSubject = PassthroughSubject() + let statusSubject = PassthroughSubject() + let accountSubject = PassthroughSubject() - static var mastodonController: MastodonController { .shared } + let mastodonController: MastodonController + + init(mastodonController: MastodonController) { + self.mastodonController = mastodonController + } // MARK: - Statuses - static func status(for id: String) -> Status? { + func status(for id: String) -> Status? { return statuses[id] } - static func set(status: Status, for id: String) { + func set(status: Status, for id: String) { statuses[id] = status add(account: status.account) if let reblog = status.reblog { @@ -38,66 +42,66 @@ class MastodonCache { statusSubject.send(status) } - static func status(for id: String, completion: @escaping (Status?) -> Void) { + func status(for id: String, completion: @escaping (Status?) -> Void) { let request = Client.getStatus(id: id) mastodonController.run(request) { response in guard case let .success(status, _) = response else { completion(nil) return } - set(status: status, for: id) + self.set(status: status, for: id) completion(status) } } - static func add(status: Status) { + func add(status: Status) { set(status: status, for: status.id) } - static func addAll(statuses: [Status]) { + func addAll(statuses: [Status]) { statuses.forEach(add) } // MARK: - Accounts - static func account(for id: String) -> Account? { + func account(for id: String) -> Account? { return accounts[id] } - static func set(account: Account, for id: String) { + func set(account: Account, for id: String) { accounts[id] = account accountSubject.send(account) } - static func account(for id: String, completion: @escaping (Account?) -> Void) { + func account(for id: String, completion: @escaping (Account?) -> Void) { let request = Client.getAccount(id: id) mastodonController.run(request) { response in guard case let .success(account, _) = response else { completion(nil) return } - set(account: account, for: account.id) + self.set(account: account, for: account.id) completion(account) } } - static func add(account: Account) { + func add(account: Account) { set(account: account, for: account.id) } - static func addAll(accounts: [Account]) { + func addAll(accounts: [Account]) { accounts.forEach(add) } // MARK: - Relationships - static func relationship(for id: String) -> Relationship? { + func relationship(for id: String) -> Relationship? { return relationships[id] } - static func set(relationship: Relationship, id: String) { + func set(relationship: Relationship, id: String) { relationships[id] = relationship } - static func relationship(for id: String, completion: @escaping (Relationship?) -> Void) { + func relationship(for id: String, completion: @escaping (Relationship?) -> Void) { let request = Client.getRelationships(accounts: [id]) mastodonController.run(request) { response in guard case let .success(relationships, _) = response, @@ -105,33 +109,33 @@ class MastodonCache { completion(nil) return } - set(relationship: relationship, id: relationship.id) + self.set(relationship: relationship, id: relationship.id) completion(relationship) } } - static func add(relationship: Relationship) { + func add(relationship: Relationship) { set(relationship: relationship, id: relationship.id) } - static func addAll(relationships: [Relationship]) { + func addAll(relationships: [Relationship]) { relationships.forEach(add) } // MARK: - Notifications - static func notification(for id: String) -> Pachyderm.Notification? { + func notification(for id: String) -> Pachyderm.Notification? { return notifications[id] } - static func set(notification: Pachyderm.Notification, id: String) { + func set(notification: Pachyderm.Notification, id: String) { notifications[id] = notification } - static func add(notification: Pachyderm.Notification) { + func add(notification: Pachyderm.Notification) { set(notification: notification, id: notification.id) } - static func addAll(notifications: [Pachyderm.Notification]) { + func addAll(notifications: [Pachyderm.Notification]) { notifications.forEach(add) } diff --git a/Tusker/Screens/Account List/AccountListTableViewController.swift b/Tusker/Screens/Account List/AccountListTableViewController.swift index 36fe72e2..c001a316 100644 --- a/Tusker/Screens/Account List/AccountListTableViewController.swift +++ b/Tusker/Screens/Account List/AccountListTableViewController.swift @@ -53,8 +53,8 @@ class AccountListTableViewController: EnhancedTableViewController { guard let cell = tableView.dequeueReusableCell(withIdentifier: accountCell, for: indexPath) as? AccountTableViewCell else { fatalError() } let id = accountIDs[indexPath.row] - cell.updateUI(accountID: id) cell.delegate = self + cell.updateUI(accountID: id) return cell } diff --git a/Tusker/Screens/Bookmarks/BookmarksTableViewController.swift b/Tusker/Screens/Bookmarks/BookmarksTableViewController.swift index a4370c05..ce83ee9a 100644 --- a/Tusker/Screens/Bookmarks/BookmarksTableViewController.swift +++ b/Tusker/Screens/Bookmarks/BookmarksTableViewController.swift @@ -51,7 +51,7 @@ class BookmarksTableViewController: EnhancedTableViewController { let request = Client.getBookmarks() mastodonController.run(request) { (response) in guard case let .success(statuses, pagination) = response else { fatalError() } - MastodonCache.addAll(statuses: statuses) + self.mastodonController.cache.addAll(statuses: statuses) self.statuses.append(contentsOf: statuses.map { ($0.id, .unknown) }) self.newer = pagination?.newer self.older = pagination?.older @@ -89,7 +89,7 @@ class BookmarksTableViewController: EnhancedTableViewController { mastodonController.run(request) { (response) in guard case let .success(newStatuses, pagination) = response else { fatalError() } self.older = pagination?.older - MastodonCache.addAll(statuses: newStatuses) + self.mastodonController.cache.addAll(statuses: newStatuses) self.statuses.append(contentsOf: newStatuses.map { ($0.id, .unknown) }) } } @@ -105,7 +105,7 @@ class BookmarksTableViewController: EnhancedTableViewController { override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let cellConfig = (tableView.cellForRow(at: indexPath) as? TableViewSwipeActionProvider)?.trailingSwipeActionsConfiguration() - guard let status = MastodonCache.status(for: statuses[indexPath.row].id) else { + guard let status = mastodonController.cache.status(for: statuses[indexPath.row].id) else { return cellConfig } @@ -113,7 +113,7 @@ class BookmarksTableViewController: EnhancedTableViewController { let request = Status.unbookmark(status) self.mastodonController.run(request) { (response) in guard case let .success(newStatus, _) = response else { fatalError() } - MastodonCache.add(status: newStatus) + self.mastodonController.cache.add(status: newStatus) self.statuses.remove(at: indexPath.row) } } @@ -131,13 +131,13 @@ class BookmarksTableViewController: EnhancedTableViewController { } override func getSuggestedContextMenuActions(tableView: UITableView, indexPath: IndexPath, point: CGPoint) -> [UIAction] { - guard let status = MastodonCache.status(for: statuses[indexPath.row].id) else { return [] } + guard let status = mastodonController.cache.status(for: statuses[indexPath.row].id) else { return [] } return [ UIAction(title: NSLocalizedString("Unbookmark", comment: "unbookmark action title"), image: UIImage(systemName: "bookmark.fill"), identifier: .init("unbookmark"), discoverabilityTitle: nil, attributes: [], state: .off, handler: { (_) in let request = Status.unbookmark(status) self.mastodonController.run(request) { (response) in guard case let .success(newStatus, _) = response else { fatalError() } - MastodonCache.add(status: newStatus) + self.mastodonController.cache.add(status: newStatus) self.statuses.remove(at: indexPath.row) } }) @@ -158,7 +158,7 @@ extension BookmarksTableViewController: StatusTableViewCellDelegate { extension BookmarksTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths { - guard let status = MastodonCache.status(for: statuses[indexPath.row].id) else { continue } + guard let status = mastodonController.cache.status(for: statuses[indexPath.row].id) else { continue } ImageCache.avatars.get(status.account.avatar, completion: nil) for attachment in status.attachments where attachment.kind == .image { ImageCache.attachments.get(attachment.url, completion: nil) @@ -168,7 +168,7 @@ extension BookmarksTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths { - guard let status = MastodonCache.status(for: statuses[indexPath.row].id) else { continue } + guard let status = mastodonController.cache.status(for: statuses[indexPath.row].id) else { continue } ImageCache.avatars.cancel(status.account.avatar) for attachment in status.attachments where attachment.kind == .image { ImageCache.attachments.cancel(attachment.url) diff --git a/Tusker/Screens/Compose/ComposeViewController.swift b/Tusker/Screens/Compose/ComposeViewController.swift index 07a68169..a6fc85d0 100644 --- a/Tusker/Screens/Compose/ComposeViewController.swift +++ b/Tusker/Screens/Compose/ComposeViewController.swift @@ -70,7 +70,7 @@ class ComposeViewController: UIViewController { self.mastodonController = mastodonController self.inReplyToID = inReplyToID - if let inReplyToID = inReplyToID, let inReplyTo = MastodonCache.status(for: inReplyToID) { + if let inReplyToID = inReplyToID, let inReplyTo = mastodonController.cache.status(for: inReplyToID) { accountsToMention = [inReplyTo.account.acct] + inReplyTo.mentions.map { $0.acct } } else if let mentioningAcct = mentioningAcct { accountsToMention = [mentioningAcct] @@ -146,13 +146,13 @@ class ComposeViewController: UIViewController { } if let inReplyToID = inReplyToID { - if let status = MastodonCache.status(for: inReplyToID) { + if let status = mastodonController.cache.status(for: inReplyToID) { updateInReplyTo(inReplyTo: status) } else { let loadingVC = LoadingViewController() embedChild(loadingVC) - MastodonCache.status(for: inReplyToID) { (status) in + mastodonController.cache.status(for: inReplyToID) { (status) in guard let status = status else { return } DispatchQueue.main.async { self.updateInReplyTo(inReplyTo: status) @@ -514,7 +514,7 @@ class ComposeViewController: UIViewController { self.mastodonController.run(request) { (response) in guard case let .success(status, _) = response else { fatalError() } self.postedStatus = status - MastodonCache.add(status: status) + self.mastodonController.cache.add(status: status) if let draft = self.currentDraft { DraftsManager.shared.remove(draft) diff --git a/Tusker/Screens/Conversation/ConversationTableViewController.swift b/Tusker/Screens/Conversation/ConversationTableViewController.swift index 31bbc061..b225840d 100644 --- a/Tusker/Screens/Conversation/ConversationTableViewController.swift +++ b/Tusker/Screens/Conversation/ConversationTableViewController.swift @@ -58,14 +58,14 @@ class ConversationTableViewController: EnhancedTableViewController { statuses = [(mainStatusID, mainStatusState)] - guard let mainStatus = MastodonCache.status(for: mainStatusID) else { fatalError("Missing cached status \(mainStatusID)") } + guard let mainStatus = mastodonController.cache.status(for: mainStatusID) else { fatalError("Missing cached status \(mainStatusID)") } let request = Status.getContext(mainStatus) mastodonController.run(request) { response in guard case let .success(context, _) = response else { fatalError() } let parents = self.getDirectParents(of: mainStatus, from: context.ancestors) - MastodonCache.addAll(statuses: parents) - MastodonCache.addAll(statuses: context.descendants) + self.mastodonController.cache.addAll(statuses: parents) + self.mastodonController.cache.addAll(statuses: context.descendants) self.statuses = parents.map { ($0.id, .unknown) } + self.statuses + context.descendants.map { ($0.id, .unknown) } let indexPath = IndexPath(row: parents.count, section: 0) DispatchQueue.main.async { @@ -104,14 +104,14 @@ class ConversationTableViewController: EnhancedTableViewController { guard let cell = tableView.dequeueReusableCell(withIdentifier: "mainStatusCell", for: indexPath) as? ConversationMainStatusTableViewCell else { fatalError() } cell.selectionStyle = .none cell.showStatusAutomatically = showStatusesAutomatically - cell.updateUI(statusID: id, state: state) cell.delegate = self + cell.updateUI(statusID: id, state: state) return cell } else { guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? TimelineStatusTableViewCell else { fatalError() } cell.showStatusAutomatically = showStatusesAutomatically - cell.updateUI(statusID: id, state: state) cell.delegate = self + cell.updateUI(statusID: id, state: state) return cell } } @@ -169,7 +169,7 @@ extension ConversationTableViewController: StatusTableViewCellDelegate { extension ConversationTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths { - guard let status = MastodonCache.status(for: statuses[indexPath.row].id) else { continue } + guard let status = mastodonController.cache.status(for: statuses[indexPath.row].id) else { continue } ImageCache.avatars.get(status.account.avatar, completion: nil) for attachment in status.attachments { ImageCache.attachments.get(attachment.url, completion: nil) @@ -179,7 +179,7 @@ extension ConversationTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths { - guard let status = MastodonCache.status(for: statuses[indexPath.row].id) else { continue } + guard let status = mastodonController.cache.status(for: statuses[indexPath.row].id) else { continue } ImageCache.avatars.cancel(status.account.avatar) for attachment in status.attachments { ImageCache.attachments.cancel(attachment.url) diff --git a/Tusker/Screens/Lists/EditListAccountsViewController.swift b/Tusker/Screens/Lists/EditListAccountsViewController.swift index 796c58f4..be46daf8 100644 --- a/Tusker/Screens/Lists/EditListAccountsViewController.swift +++ b/Tusker/Screens/Lists/EditListAccountsViewController.swift @@ -80,7 +80,7 @@ class EditListAccountsViewController: EnhancedTableViewController { self.nextRange = pagination?.older - MastodonCache.addAll(accounts: accounts) + self.mastodonController.cache.addAll(accounts: accounts) var snapshot = self.dataSource.snapshot() snapshot.deleteSections([.accounts]) diff --git a/Tusker/Screens/Notifications/NotificationsTableViewController.swift b/Tusker/Screens/Notifications/NotificationsTableViewController.swift index 4bee64b2..ce87c5a5 100644 --- a/Tusker/Screens/Notifications/NotificationsTableViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsTableViewController.swift @@ -67,9 +67,9 @@ class NotificationsTableViewController: EnhancedTableViewController { self.groups.append(contentsOf: groups) - MastodonCache.addAll(notifications: notifications) - MastodonCache.addAll(statuses: notifications.compactMap { $0.status }) - MastodonCache.addAll(accounts: notifications.map { $0.account }) + self.mastodonController.cache.addAll(notifications: notifications) + self.mastodonController.cache.addAll(statuses: notifications.compactMap { $0.status }) + self.mastodonController.cache.addAll(accounts: notifications.map { $0.account }) self.newer = pagination?.newer self.older = pagination?.older @@ -92,31 +92,31 @@ class NotificationsTableViewController: EnhancedTableViewController { switch group.kind { case .mention: - guard let notification = MastodonCache.notification(for: group.notificationIDs.first!), + guard let notification = mastodonController.cache.notification(for: group.notificationIDs.first!), let cell = tableView.dequeueReusableCell(withIdentifier: statusCell, for: indexPath) as? TimelineStatusTableViewCell else { fatalError() } - cell.updateUI(statusID: notification.status!.id, state: group.statusState!) cell.delegate = self + cell.updateUI(statusID: notification.status!.id, state: group.statusState!) return cell case .favourite, .reblog: guard let cell = tableView.dequeueReusableCell(withIdentifier: actionGroupCell, for: indexPath) as? ActionNotificationGroupTableViewCell else { fatalError() } - cell.updateUI(group: group) cell.delegate = self + cell.updateUI(group: group) return cell case .follow: guard let cell = tableView.dequeueReusableCell(withIdentifier: followGroupCell, for: indexPath) as? FollowNotificationGroupTableViewCell else { fatalError() } - cell.updateUI(group: group) cell.delegate = self + cell.updateUI(group: group) return cell case .followRequest: - guard let notification = MastodonCache.notification(for: group.notificationIDs.first!), + guard let notification = mastodonController.cache.notification(for: group.notificationIDs.first!), let cell = tableView.dequeueReusableCell(withIdentifier: followRequestCell, for: indexPath) as? FollowRequestNotificationTableViewCell else { fatalError() } - cell.updateUI(notification: notification) cell.delegate = self + cell.updateUI(notification: notification) return cell } } @@ -135,9 +135,9 @@ class NotificationsTableViewController: EnhancedTableViewController { self.groups.append(contentsOf: groups) - MastodonCache.addAll(notifications: newNotifications) - MastodonCache.addAll(statuses: newNotifications.compactMap { $0.status }) - MastodonCache.addAll(accounts: newNotifications.map { $0.account }) + self.mastodonController.cache.addAll(notifications: newNotifications) + self.mastodonController.cache.addAll(statuses: newNotifications.compactMap { $0.status }) + self.mastodonController.cache.addAll(accounts: newNotifications.map { $0.account }) self.older = pagination?.older } @@ -207,9 +207,9 @@ class NotificationsTableViewController: EnhancedTableViewController { self.groups.insert(contentsOf: groups, at: 0) - MastodonCache.addAll(notifications: newNotifications) - MastodonCache.addAll(statuses: newNotifications.compactMap { $0.status }) - MastodonCache.addAll(accounts: newNotifications.map { $0.account }) + self.mastodonController.cache.addAll(notifications: newNotifications) + self.mastodonController.cache.addAll(statuses: newNotifications.compactMap { $0.status }) + self.mastodonController.cache.addAll(accounts: newNotifications.map { $0.account }) self.newer = pagination?.newer @@ -237,7 +237,7 @@ extension NotificationsTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths { for notificationID in groups[indexPath.row].notificationIDs { - guard let notification = MastodonCache.notification(for: notificationID) else { continue } + guard let notification = mastodonController.cache.notification(for: notificationID) else { continue } ImageCache.avatars.get(notification.account.avatar, completion: nil) } } @@ -246,7 +246,7 @@ extension NotificationsTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths { for notificationID in groups[indexPath.row].notificationIDs { - guard let notification = MastodonCache.notification(for: notificationID) else { continue } + guard let notification = mastodonController.cache.notification(for: notificationID) else { continue } ImageCache.avatars.cancel(notification.account.avatar) } } diff --git a/Tusker/Screens/Profile/ProfileTableViewController.swift b/Tusker/Screens/Profile/ProfileTableViewController.swift index e6b1d4b3..2e58f49e 100644 --- a/Tusker/Screens/Profile/ProfileTableViewController.swift +++ b/Tusker/Screens/Profile/ProfileTableViewController.swift @@ -73,12 +73,12 @@ class ProfileTableViewController: EnhancedTableViewController { tableView.prefetchDataSource = self if let accountID = accountID { - if MastodonCache.account(for: accountID) != nil { + if mastodonController.cache.account(for: accountID) != nil { updateAccountUI() } else { loadingVC = LoadingViewController() embedChild(loadingVC!) - MastodonCache.account(for: accountID) { (account) in + mastodonController.cache.account(for: accountID) { (account) in guard account != nil else { let alert = UIAlertController(title: "Something Went Wrong", message: "Couldn't load the selected account", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (_) in @@ -112,14 +112,14 @@ class ProfileTableViewController: EnhancedTableViewController { getStatuses(onlyPinned: true) { (response) in guard case let .success(statuses, _) = response else { fatalError() } - MastodonCache.addAll(statuses: statuses) + self.mastodonController.cache.addAll(statuses: statuses) self.pinnedStatuses = statuses.map { ($0.id, .unknown) } } getStatuses() { response in guard case let .success(statuses, pagination) = response else { fatalError() } - MastodonCache.addAll(statuses: statuses) + self.mastodonController.cache.addAll(statuses: statuses) self.timelineSegments.append(statuses.map { ($0.id, .unknown) }) self.older = pagination?.older @@ -128,7 +128,7 @@ class ProfileTableViewController: EnhancedTableViewController { } @objc func updateUIForPreferences() { - guard let account = MastodonCache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") } + guard let account = mastodonController.cache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") } navigationItem.title = account.realDisplayName } @@ -138,7 +138,7 @@ class ProfileTableViewController: EnhancedTableViewController { } func sendMessageMentioning() { - guard let account = MastodonCache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") } + guard let account = mastodonController.cache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") } let vc = UINavigationController(rootViewController: ComposeViewController(mentioningAcct: account.acct, mastodonController: mastodonController)) present(vc, animated: true) } @@ -152,7 +152,7 @@ class ProfileTableViewController: EnhancedTableViewController { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if section == 0 { - return accountID == nil || MastodonCache.account(for: accountID) == nil ? 0 : 1 + return accountID == nil || mastodonController.cache.account(for: accountID) == nil ? 0 : 1 } else if section == 1 { return pinnedStatuses.count } else { @@ -172,14 +172,14 @@ class ProfileTableViewController: EnhancedTableViewController { guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? TimelineStatusTableViewCell else { fatalError() } let (id, state) = pinnedStatuses[indexPath.row] cell.showPinned = true - cell.updateUI(statusID: id, state: state) cell.delegate = self + cell.updateUI(statusID: id, state: state) return cell default: guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? TimelineStatusTableViewCell else { fatalError() } let (id, state) = timelineSegments[indexPath.section - 2][indexPath.row] - cell.updateUI(statusID: id, state: state) cell.delegate = self + cell.updateUI(statusID: id, state: state) return cell } } @@ -193,7 +193,7 @@ class ProfileTableViewController: EnhancedTableViewController { getStatuses(for: older) { response in guard case let .success(newStatuses, pagination) = response else { fatalError() } - MastodonCache.addAll(statuses: newStatuses) + self.mastodonController.cache.addAll(statuses: newStatuses) self.timelineSegments[indexPath.section - 2].append(contentsOf: newStatuses.map { ($0.id, .unknown) }) self.older = pagination?.older @@ -219,7 +219,7 @@ class ProfileTableViewController: EnhancedTableViewController { getStatuses(for: newer) { response in guard case let .success(newStatuses, pagination) = response else { fatalError() } - MastodonCache.addAll(statuses: newStatuses) + self.mastodonController.cache.addAll(statuses: newStatuses) self.timelineSegments[0].insert(contentsOf: newStatuses.map { ($0.id, .unknown) }, at: 0) self.newer = pagination?.newer @@ -248,9 +248,9 @@ extension ProfileTableViewController: StatusTableViewCellDelegate { extension ProfileTableViewController: ProfileHeaderTableViewCellDelegate { func showMoreOptions() { - let account = MastodonCache.account(for: accountID)! + let account = mastodonController.cache.account(for: accountID)! - MastodonCache.relationship(for: account.id) { [weak self] (relationship) in + mastodonController.cache.relationship(for: account.id) { [weak self] (relationship) in guard let self = self else { return } var customActivities: [UIActivity] = [OpenInSafariActivity()] @@ -272,7 +272,7 @@ extension ProfileTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths where indexPath.section > 1 { let statusID = timelineSegments[indexPath.section - 2][indexPath.row].id - guard let status = MastodonCache.status(for: statusID) else { continue } + guard let status = mastodonController.cache.status(for: statusID) else { continue } ImageCache.avatars.get(status.account.avatar, completion: nil) for attachment in status.attachments { ImageCache.attachments.get(attachment.url, completion: nil) @@ -283,7 +283,7 @@ extension ProfileTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths where indexPath.section > 1 { let statusID = timelineSegments[indexPath.section - 2][indexPath.row].id - guard let status = MastodonCache.status(for: statusID) else { continue } + guard let status = mastodonController.cache.status(for: statusID) else { continue } ImageCache.avatars.cancel(status.account.avatar) for attachment in status.attachments { ImageCache.attachments.cancel(attachment.url) diff --git a/Tusker/Screens/Search/SearchResultsViewController.swift b/Tusker/Screens/Search/SearchResultsViewController.swift index 45e97c4b..9c973461 100644 --- a/Tusker/Screens/Search/SearchResultsViewController.swift +++ b/Tusker/Screens/Search/SearchResultsViewController.swift @@ -65,18 +65,18 @@ class SearchResultsViewController: EnhancedTableViewController { switch item { case let .account(id): let cell = tableView.dequeueReusableCell(withIdentifier: accountCell, for: indexPath) as! AccountTableViewCell - cell.updateUI(accountID: id) cell.delegate = self + cell.updateUI(accountID: id) return cell case let .hashtag(tag): let cell = tableView.dequeueReusableCell(withIdentifier: hashtagCell, for: indexPath) as! HashtagTableViewCell - cell.updateUI(hashtag: tag) cell.delegate = self + cell.updateUI(hashtag: tag) return cell case let .status(id, state): let cell = tableView.dequeueReusableCell(withIdentifier: statusCell, for: indexPath) as! TimelineStatusTableViewCell - cell.updateUI(statusID: id, state: state) cell.delegate = self + cell.updateUI(statusID: id, state: state) return cell } }) @@ -136,7 +136,7 @@ class SearchResultsViewController: EnhancedTableViewController { if self.onlySections.contains(.accounts) && !results.accounts.isEmpty { snapshot.appendSections([.accounts]) snapshot.appendItems(results.accounts.map { .account($0.id) }, toSection: .accounts) - MastodonCache.addAll(accounts: results.accounts) + self.mastodonController.cache.addAll(accounts: results.accounts) } if self.onlySections.contains(.hashtags) && !results.hashtags.isEmpty { snapshot.appendSections([.hashtags]) @@ -145,8 +145,8 @@ class SearchResultsViewController: EnhancedTableViewController { if self.onlySections.contains(.statuses) && !results.statuses.isEmpty { snapshot.appendSections([.statuses]) snapshot.appendItems(results.statuses.map { .status($0.id, .unknown) }, toSection: .statuses) - MastodonCache.addAll(statuses: results.statuses) - MastodonCache.addAll(accounts: results.statuses.map { $0.account }) + self.mastodonController.cache.addAll(statuses: results.statuses) + self.mastodonController.cache.addAll(accounts: results.statuses.map { $0.account }) } self.dataSource.apply(snapshot) } diff --git a/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift index e0d9195c..dd60518c 100644 --- a/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift +++ b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift @@ -73,7 +73,7 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController { if accountIDs == nil { // account IDs haven't been set, so perform a request to load them - guard let status = MastodonCache.status(for: statusID) else { + guard let status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") } @@ -82,7 +82,7 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController { let request = actionType == .favorite ? Status.getFavourites(status) : Status.getReblogs(status) mastodonController.run(request) { (response) in guard case let .success(accounts, _) = response else { fatalError() } - MastodonCache.addAll(accounts: accounts) + self.mastodonController.cache.addAll(accounts: accounts) DispatchQueue.main.async { self.accountIDs = accounts.map { $0.id } self.tableView.tableFooterView = nil @@ -116,14 +116,14 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController { switch indexPath.section { case 0: guard let cell = tableView.dequeueReusableCell(withIdentifier: statusCell, for: indexPath) as? TimelineStatusTableViewCell else { fatalError() } - cell.updateUI(statusID: statusID, state: statusState) cell.delegate = self + cell.updateUI(statusID: statusID, state: statusState) return cell case 1: guard let accountIDs = accountIDs, let cell = tableView.dequeueReusableCell(withIdentifier: accountCell, for: indexPath) as? AccountTableViewCell else { fatalError() } - cell.updateUI(accountID: accountIDs[indexPath.row]) cell.delegate = self + cell.updateUI(accountID: accountIDs[indexPath.row]) return cell default: fatalError("Invalid section \(indexPath.section)") diff --git a/Tusker/Screens/Timeline/TimelineTableViewController.swift b/Tusker/Screens/Timeline/TimelineTableViewController.swift index 93362925..c94b45d2 100644 --- a/Tusker/Screens/Timeline/TimelineTableViewController.swift +++ b/Tusker/Screens/Timeline/TimelineTableViewController.swift @@ -65,7 +65,7 @@ class TimelineTableViewController: EnhancedTableViewController { let request = Client.getStatuses(timeline: timeline) mastodonController.run(request) { response in guard case let .success(statuses, pagination) = response else { fatalError() } - MastodonCache.addAll(statuses: statuses) + self.mastodonController.cache.addAll(statuses: statuses) self.timelineSegments.insert(statuses.map { ($0.id, .unknown) }, at: 0) self.newer = pagination?.newer self.older = pagination?.older @@ -87,8 +87,8 @@ class TimelineTableViewController: EnhancedTableViewController { guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? TimelineStatusTableViewCell else { fatalError() } let (id, state) = timelineSegments[indexPath.section][indexPath.row] - cell.updateUI(statusID: id, state: state) cell.delegate = self + cell.updateUI(statusID: id, state: state) return cell } @@ -104,7 +104,7 @@ class TimelineTableViewController: EnhancedTableViewController { mastodonController.run(request) { response in guard case let .success(newStatuses, pagination) = response else { fatalError() } self.older = pagination?.older - MastodonCache.addAll(statuses: newStatuses) + self.mastodonController.cache.addAll(statuses: newStatuses) self.timelineSegments[self.timelineSegments.count - 1].append(contentsOf: newStatuses.map { ($0.id, .unknown) }) } } @@ -129,7 +129,7 @@ class TimelineTableViewController: EnhancedTableViewController { mastodonController.run(request) { response in guard case let .success(newStatuses, pagination) = response else { fatalError() } self.newer = pagination?.newer - MastodonCache.addAll(statuses: newStatuses) + self.mastodonController.cache.addAll(statuses: newStatuses) self.timelineSegments[0].insert(contentsOf: newStatuses.map { ($0.id, .unknown) }, at: 0) DispatchQueue.main.async { self.refreshControl?.endRefreshing() @@ -159,7 +159,7 @@ extension TimelineTableViewController: StatusTableViewCellDelegate { extension TimelineTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths { - guard let status = MastodonCache.status(for: statusID(for: indexPath)) else { continue } + guard let status = mastodonController.cache.status(for: statusID(for: indexPath)) else { continue } ImageCache.avatars.get(status.account.avatar, completion: nil) for attachment in status.attachments { ImageCache.attachments.get(attachment.url, completion: nil) @@ -169,7 +169,7 @@ extension TimelineTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths { - guard let status = MastodonCache.status(for: statusID(for: indexPath)) else { continue } + guard let status = mastodonController.cache.status(for: statusID(for: indexPath)) else { continue } ImageCache.avatars.cancel(status.account.avatar) for attachment in status.attachments { ImageCache.attachments.cancel(attachment.url) diff --git a/Tusker/Screens/Utilities/Previewing.swift b/Tusker/Screens/Utilities/Previewing.swift index 2c20e4e7..346d78a3 100644 --- a/Tusker/Screens/Utilities/Previewing.swift +++ b/Tusker/Screens/Utilities/Previewing.swift @@ -22,8 +22,11 @@ protocol MenuPreviewProvider { extension MenuPreviewProvider { + private var mastodonController: MastodonController? { navigationDelegate?.apiController } + func actionsForProfile(accountID: String) -> [UIAction] { - guard let account = MastodonCache.account(for: accountID) else { return [] } + guard let mastodonController = mastodonController, + let account = mastodonController.cache.account(for: accountID) else { return [] } return [ createAction(identifier: "openinsafari", title: "Open in Safari", systemImageName: "safari", handler: { (_) in self.navigationDelegate?.selected(url: account.url) @@ -53,7 +56,8 @@ extension MenuPreviewProvider { } func actionsForStatus(statusID: String) -> [UIAction] { - guard let status = MastodonCache.status(for: statusID) else { return [] } + guard let mastodonController = mastodonController, + let status = mastodonController.cache.status(for: statusID) else { return [] } return [ createAction(identifier: "reply", title: "Reply", systemImageName: "arrowshape.turn.up.left", handler: { (_) in self.navigationDelegate?.reply(to: statusID) diff --git a/Tusker/TuskerNavigationDelegate.swift b/Tusker/TuskerNavigationDelegate.swift index 2530ed17..f7b04f20 100644 --- a/Tusker/TuskerNavigationDelegate.swift +++ b/Tusker/TuskerNavigationDelegate.swift @@ -194,7 +194,7 @@ extension TuskerNavigationDelegate where Self: UIViewController { } private func moreOptions(forStatus statusID: String) -> UIViewController { - guard let status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") } + guard let status = apiController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") } guard let url = status.url else { fatalError("Missing url for status \(statusID)") } var customActivites: [UIActivity] = [OpenInSafariActivity()] @@ -213,7 +213,7 @@ extension TuskerNavigationDelegate where Self: UIViewController { } private func moreOptions(forAccount accountID: String) -> UIViewController { - guard let account = MastodonCache.account(for: accountID) else { fatalError("Missing cached account \(accountID)") } + guard let account = apiController.cache.account(for: accountID) else { fatalError("Missing cached account \(accountID)") } return moreOptions(forURL: account.url) } diff --git a/Tusker/Views/Account Cell/AccountTableViewCell.swift b/Tusker/Views/Account Cell/AccountTableViewCell.swift index 861b6b8a..00d92346 100644 --- a/Tusker/Views/Account Cell/AccountTableViewCell.swift +++ b/Tusker/Views/Account Cell/AccountTableViewCell.swift @@ -32,7 +32,7 @@ class AccountTableViewCell: UITableViewCell { @objc func updateUIForPrefrences() { avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView) - guard let account = MastodonCache.account(for: accountID) else { + guard let account = mastodonController.cache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") } displayNameLabel.text = account.realDisplayName @@ -40,7 +40,7 @@ class AccountTableViewCell: UITableViewCell { func updateUI(accountID: String) { self.accountID = accountID - guard let account = MastodonCache.account(for: accountID) else { + guard let account = mastodonController.cache.account(for: accountID) else { fatalError("Missing cached account \(accountID)") } diff --git a/Tusker/Views/Attachments/AttachmentsContainerView.swift b/Tusker/Views/Attachments/AttachmentsContainerView.swift index 015f069e..5ca7deb9 100644 --- a/Tusker/Views/Attachments/AttachmentsContainerView.swift +++ b/Tusker/Views/Attachments/AttachmentsContainerView.swift @@ -37,8 +37,6 @@ class AttachmentsContainerView: UIView { createBlurView() createHideButton() - - NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil) } func getAttachmentView(for attachment: Attachment) -> AttachmentView? { @@ -176,11 +174,7 @@ class AttachmentsContainerView: UIView { self.isHidden = true } - updateUIForPreferences() - } - - @objc func updateUIForPreferences() { - contentHidden = Preferences.shared.blurAllMedia || (MastodonCache.status(for: statusID)?.sensitive ?? false) + contentHidden = Preferences.shared.blurAllMedia || status.sensitive } private func createAttachmentView(index: Int) -> AttachmentView { diff --git a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift index 33483d06..cedde5f6 100644 --- a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift @@ -13,6 +13,7 @@ import SwiftSoup class ActionNotificationGroupTableViewCell: UITableViewCell { var delegate: TuskerNavigationDelegate? + var mastodonController: MastodonController! { delegate?.apiController } @IBOutlet weak var actionImageView: UIImageView! @IBOutlet weak var actionAvatarStackView: UIStackView! @@ -33,7 +34,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { } @objc func updateUIForPreferences() { - let people = group.notificationIDs.compactMap(MastodonCache.notification(for:)).map { $0.account } + let people = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account } updateActionLabel(people: people) for case let imageView as UIImageView in actionAvatarStackView.arrangedSubviews { @@ -47,7 +48,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { } self.group = group - guard let firstNotification = MastodonCache.notification(for: group.notificationIDs.first!) else { fatalError() } + guard let firstNotification = mastodonController.cache.notification(for: group.notificationIDs.first!) else { fatalError() } let status = firstNotification.status! self.statusID = status.id @@ -62,7 +63,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { fatalError() } - let people = group.notificationIDs.compactMap(MastodonCache.notification(for:)).map { $0.account } + let people = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account } actionAvatarStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } for account in people { @@ -93,7 +94,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { func updateTimestamp() { guard let id = group.notificationIDs.first, - let notification = MastodonCache.notification(for: id) else { + let notification = mastodonController.cache.notification(for: id) else { fatalError("Missing cached notification") } @@ -155,7 +156,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { extension ActionNotificationGroupTableViewCell: SelectableTableViewCell { func didSelectCell() { guard let delegate = delegate else { return } - let notifications = group.notificationIDs.compactMap(MastodonCache.notification(for:)) + let notifications = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)) let accountIDs = notifications.map { $0.account.id } let action: StatusActionAccountListTableViewController.ActionType switch notifications.first!.kind { @@ -176,7 +177,7 @@ extension ActionNotificationGroupTableViewCell: MenuPreviewProvider { func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { return (content: { - let notifications = self.group.notificationIDs.compactMap(MastodonCache.notification(for:)) + let notifications = self.group.notificationIDs.compactMap(self.mastodonController.cache.notification(for:)) let accountIDs = notifications.map { $0.account.id } let action: StatusActionAccountListTableViewController.ActionType switch notifications.first!.kind { diff --git a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift index b77cb152..0c2e62cc 100644 --- a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift @@ -29,7 +29,7 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { } @objc func updateUIForPreferences() { - let people = group.notificationIDs.compactMap(MastodonCache.notification(for:)).map { $0.account } + let people = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account } updateActionLabel(people: people) for case let imageView as UIImageView in avatarStackView.arrangedSubviews { @@ -40,7 +40,7 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { func updateUI(group: NotificationGroup) { self.group = group - let people = group.notificationIDs.compactMap(MastodonCache.notification(for:)).map { $0.account } + let people = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account } updateActionLabel(people: people) updateTimestamp() @@ -82,7 +82,7 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { func updateTimestamp() { guard let id = group.notificationIDs.first, - let notification = MastodonCache.notification(for: id) else { + let notification = mastodonController.cache.notification(for: id) else { fatalError("Missing cached notification") } @@ -118,7 +118,7 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { extension FollowNotificationGroupTableViewCell: SelectableTableViewCell { func didSelectCell() { - let people = group.notificationIDs.compactMap(MastodonCache.notification(for:)).map { $0.account.id } + let people = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account.id } switch people.count { case 0: return @@ -136,7 +136,7 @@ extension FollowNotificationGroupTableViewCell: MenuPreviewProvider { func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { guard let mastodonController = mastodonController else { return nil } return (content: { - let accountIDs = self.group.notificationIDs.compactMap(MastodonCache.notification(for:)).map { $0.account.id } + let accountIDs = self.group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account.id } if accountIDs.count == 1 { return ProfileTableViewController(accountID: accountIDs.first!, mastodonController: mastodonController) } else { diff --git a/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift b/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift index c83524ff..1674c639 100644 --- a/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift @@ -92,7 +92,7 @@ class FollowRequestNotificationTableViewCell: UITableViewCell { let request = Account.rejectFollowRequest(account) mastodonController.run(request) { (response) in guard case let .success(relationship, _) = response else { fatalError() } - MastodonCache.add(relationship: relationship) + self.mastodonController.cache.add(relationship: relationship) DispatchQueue.main.async { UINotificationFeedbackGenerator().notificationOccurred(.success) self.actionButtonsStackView.isHidden = true @@ -109,7 +109,7 @@ class FollowRequestNotificationTableViewCell: UITableViewCell { let request = Account.authorizeFollowRequest(account) mastodonController.run(request) { (response) in guard case let .success(relationship, _) = response else { fatalError() } - MastodonCache.add(relationship: relationship) + self.mastodonController.cache.add(relationship: relationship) DispatchQueue.main.async { UINotificationFeedbackGenerator().notificationOccurred(.success) self.actionButtonsStackView.isHidden = true diff --git a/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift b/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift index c5dce34e..2b246c2f 100644 --- a/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift +++ b/Tusker/Views/Profile Header/ProfileHeaderTableViewCell.swift @@ -56,7 +56,7 @@ class ProfileHeaderTableViewCell: UITableViewCell { guard accountID != self.accountID else { return } self.accountID = accountID - guard let account = MastodonCache.account(for: accountID) else { fatalError("Missing cached account \(accountID)") } + guard let account = mastodonController.cache.account(for: accountID) else { fatalError("Missing cached account \(accountID)") } updateUIForPreferences() @@ -85,10 +85,10 @@ class ProfileHeaderTableViewCell: UITableViewCell { if accountID != mastodonController.account.id { // don't show relationship label for the user's own account - if let relationship = MastodonCache.relationship(for: accountID) { + if let relationship = mastodonController.cache.relationship(for: accountID) { followsYouLabel.isHidden = !relationship.followedBy } else { - MastodonCache.relationship(for: accountID) { relationship in + mastodonController.cache.relationship(for: accountID) { relationship in DispatchQueue.main.async { self.followsYouLabel.isHidden = !(relationship?.followedBy ?? false) } @@ -121,7 +121,7 @@ class ProfileHeaderTableViewCell: UITableViewCell { } @objc func updateUIForPreferences() { - guard let account = MastodonCache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") } + guard let account = mastodonController.cache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") } avatarContainerView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarContainerView) avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView) diff --git a/Tusker/Views/Status/BaseStatusTableViewCell.swift b/Tusker/Views/Status/BaseStatusTableViewCell.swift index 6d1071e3..be586211 100644 --- a/Tusker/Views/Status/BaseStatusTableViewCell.swift +++ b/Tusker/Views/Status/BaseStatusTableViewCell.swift @@ -95,20 +95,28 @@ class BaseStatusTableViewCell: UITableViewCell { attachmentsView.isAccessibilityElement = true NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil) + } + + open func createObserversIfNecessary() { + if statusUpdater == nil { + statusUpdater = mastodonController.cache.statusSubject + .filter { $0.id == self.statusID } + .receive(on: DispatchQueue.main) + .sink(receiveValue: updateStatusState(status:)) + } - statusUpdater = MastodonCache.statusSubject - .filter { $0.id == self.statusID } - .receive(on: DispatchQueue.main) - .sink(receiveValue: updateStatusState(status:)) - - accountUpdater = MastodonCache.accountSubject - .filter { $0.id == self.accountID } - .receive(on: DispatchQueue.main) - .sink(receiveValue: updateUI(account:)) + if accountUpdater == nil { + accountUpdater = mastodonController.cache.accountSubject + .filter { $0.id == self.accountID } + .receive(on: DispatchQueue.main) + .sink(receiveValue: updateUI(account:)) + } } func updateUI(statusID: String, state: StatusState) { - guard let status = MastodonCache.status(for: statusID) else { + createObserversIfNecessary() + + guard let status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status") } self.statusID = statusID @@ -183,9 +191,10 @@ class BaseStatusTableViewCell: UITableViewCell { } @objc func updateUIForPreferences() { - guard let account = MastodonCache.account(for: accountID) else { return } + guard let account = mastodonController.cache.account(for: accountID) else { return } avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: avatarImageView) displayNameLabel.text = account.realDisplayName + attachmentsView.contentHidden = Preferences.shared.blurAllMedia || (mastodonController.cache.status(for: statusID)?.sensitive ?? false) } override func prepareForReuse() { @@ -243,7 +252,7 @@ class BaseStatusTableViewCell: UITableViewCell { } @IBAction func favoritePressed() { - guard let status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } + guard let status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } let oldValue = favorited favorited = !favorited @@ -254,7 +263,7 @@ class BaseStatusTableViewCell: UITableViewCell { DispatchQueue.main.async { if case let .success(newStatus, _) = response { self.favorited = newStatus.favourited ?? false - MastodonCache.add(status: newStatus) + self.mastodonController.cache.add(status: newStatus) UIImpactFeedbackGenerator(style: .light).impactOccurred() } else { self.favorited = oldValue @@ -268,7 +277,7 @@ class BaseStatusTableViewCell: UITableViewCell { } @IBAction func reblogPressed() { - guard let status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } + guard let status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } let oldValue = reblogged reblogged = !reblogged @@ -279,7 +288,7 @@ class BaseStatusTableViewCell: UITableViewCell { DispatchQueue.main.async { if case let .success(newStatus, _) = response { self.reblogged = newStatus.reblogged ?? false - MastodonCache.add(status: newStatus) + self.mastodonController.cache.add(status: newStatus) UIImpactFeedbackGenerator(style: .light).impactOccurred() } else { self.reblogged = oldValue @@ -306,7 +315,7 @@ class BaseStatusTableViewCell: UITableViewCell { extension BaseStatusTableViewCell: AttachmentViewDelegate { func showAttachmentsGallery(startingAt index: Int) { - guard let status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } + guard let status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } let sourceViews = status.attachments.map(attachmentsView.getAttachmentView(for:)) delegate?.showGallery(attachments: status.attachments, sourceViews: sourceViews, startIndex: index) } diff --git a/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift b/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift index 184fdb5a..6052ee95 100644 --- a/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift +++ b/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift @@ -38,7 +38,7 @@ class ConversationMainStatusTableViewCell: BaseStatusTableViewCell { override func updateUI(statusID: String, state: StatusState) { super.updateUI(statusID: statusID, state: state) - guard let status = MastodonCache.status(for: statusID) else { fatalError() } + guard let status = mastodonController.cache.status(for: statusID) else { fatalError() } var timestampAndClientText = ConversationMainStatusTableViewCell.dateFormatter.string(from: status.createdAt) if let application = status.application { diff --git a/Tusker/Views/Status/TimelineStatusTableViewCell.swift b/Tusker/Views/Status/TimelineStatusTableViewCell.swift index a42ddeb2..b2f926dd 100644 --- a/Tusker/Views/Status/TimelineStatusTableViewCell.swift +++ b/Tusker/Views/Status/TimelineStatusTableViewCell.swift @@ -41,19 +41,25 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell { reblogLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(reblogLabelPressed))) accessibilityElements!.insert(reblogLabel!, at: 0) - - rebloggerAccountUpdater = MastodonCache.accountSubject - .filter { $0.id == self.rebloggerID } - .receive(on: DispatchQueue.main) - .sink(receiveValue: updateRebloggerLabel(reblogger:)) } - + + override func createObserversIfNecessary() { + super.createObserversIfNecessary() + + if rebloggerAccountUpdater == nil { + rebloggerAccountUpdater = mastodonController.cache.accountSubject + .filter { $0.id == self.rebloggerID } + .receive(on: DispatchQueue.main) + .sink(receiveValue: updateRebloggerLabel(reblogger:)) + } + } + override func updateUI(statusID: String, state: StatusState) { - guard var status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") } + guard var status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID)") } let realStatusID: String if let rebloggedStatusID = status.reblog?.id, - let rebloggedStatus = MastodonCache.status(for: rebloggedStatusID) { + let rebloggedStatus = mastodonController.cache.status(for: rebloggedStatusID) { reblogStatusID = statusID rebloggerID = status.account.id status = rebloggedStatus @@ -78,7 +84,7 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell { @objc override func updateUIForPreferences() { super.updateUIForPreferences() if let rebloggerID = rebloggerID, - let reblogger = MastodonCache.account(for: rebloggerID) { + let reblogger = mastodonController.cache.account(for: rebloggerID) { updateRebloggerLabel(reblogger: reblogger) } } @@ -88,7 +94,7 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell { } func updateTimestamp() { - guard let status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } + guard let status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } timestampLabel.text = status.createdAt.timeAgoString() timestampLabel.accessibilityLabel = TimelineStatusTableViewCell.relativeDateFormatter.localizedString(for: status.createdAt, relativeTo: Date()) @@ -144,7 +150,7 @@ extension TimelineStatusTableViewCell: TableViewSwipeActionProvider { func leadingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? { guard let mastodonController = mastodonController else { return nil } - guard let status = MastodonCache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } + guard let status = mastodonController.cache.status(for: statusID) else { fatalError("Missing cached status \(statusID!)") } let favoriteTitle: String let favoriteRequest: Request @@ -167,7 +173,7 @@ extension TimelineStatusTableViewCell: TableViewSwipeActionProvider { return } completion(true) - MastodonCache.add(status: status) + mastodonController.cache.add(status: status) } }) } @@ -194,7 +200,7 @@ extension TimelineStatusTableViewCell: TableViewSwipeActionProvider { return } completion(true) - MastodonCache.add(status: status) + mastodonController.cache.add(status: status) } }) } diff --git a/Tusker/Views/StatusContentLabel.swift b/Tusker/Views/StatusContentLabel.swift index 5c113e74..17bb3c69 100644 --- a/Tusker/Views/StatusContentLabel.swift +++ b/Tusker/Views/StatusContentLabel.swift @@ -11,10 +11,12 @@ import Pachyderm class StatusContentLabel: ContentLabel { + var mastodonController: MastodonController? { navigationDelegate?.apiController } + var statusID: String? { didSet { - guard let statusID = statusID else { return } - guard let status = MastodonCache.status(for: statusID) else { fatalError("Can't set StatusContentLabel text without cached status \(statusID)") } + guard let statusID = statusID, let mastodonController = mastodonController else { return } + guard let status = mastodonController.cache.status(for: statusID) else { fatalError("Can't set StatusContentLabel text without cached status \(statusID)") } setTextFromHtml(status.content) setEmojis(status.emojis) } @@ -23,7 +25,8 @@ class StatusContentLabel: ContentLabel { override func getMention(for url: URL, text: String) -> Mention? { let mention: Mention? if let statusID = statusID, - let status = MastodonCache.status(for: statusID) { + let mastodonController = mastodonController, + let status = mastodonController.cache.status(for: statusID) { mention = status.mentions.first { (mention) in // Mastodon and Pleroma include the @ in the text, GNU Social does not (text.dropFirst() == mention.username || text == mention.username) && url.host == mention.url.host @@ -37,7 +40,8 @@ class StatusContentLabel: ContentLabel { override func getHashtag(for url: URL, text: String) -> Hashtag? { let hashtag: Hashtag? if let statusID = statusID, - let status = MastodonCache.status(for: statusID) { + let mastodonController = mastodonController, + let status = mastodonController.cache.status(for: statusID) { hashtag = status.hashtags.first { (hashtag) in hashtag.url == url } diff --git a/Tusker/XCallbackURL/XCBActions.swift b/Tusker/XCallbackURL/XCBActions.swift index ead66b93..426c4f55 100644 --- a/Tusker/XCallbackURL/XCBActions.swift +++ b/Tusker/XCallbackURL/XCBActions.swift @@ -33,7 +33,7 @@ struct XCBActions { private static func getStatus(from request: XCBRequest, session: XCBSession, completion: @escaping (Status) -> Void) { if let id = request.arguments["statusID"] { - MastodonCache.status(for: id) { (status) in + mastodonController.cache.status(for: id) { (status) in if let status = status { completion(status) } else { @@ -47,7 +47,7 @@ struct XCBActions { mastodonController.run(request) { (response) in if case let .success(results, _) = response, let status = results.statuses.first { - MastodonCache.add(status: status) + mastodonController.cache.add(status: status) completion(status) } else { session.complete(with: .error, additionalData: [ @@ -64,7 +64,7 @@ struct XCBActions { private static func getAccount(from request: XCBRequest, session: XCBSession, completion: @escaping (Account) -> Void) { if let id = request.arguments["accountID"] { - MastodonCache.account(for: id) { (account) in + mastodonController.cache.account(for: id) { (account) in if let account = account { completion(account) } else { @@ -78,7 +78,7 @@ struct XCBActions { mastodonController.run(request) { (response) in if case let .success(results, _) = response { if let account = results.accounts.first { - MastodonCache.add(account: account) + mastodonController.cache.add(account: account) completion(account) } else { session.complete(with: .error, additionalData: [ @@ -96,7 +96,7 @@ struct XCBActions { mastodonController.run(request) { (response) in if case let .success(accounts, _) = response { if let account = accounts.first { - MastodonCache.add(account: account) + mastodonController.cache.add(account: account) completion(account) } else { session.complete(with: .error, additionalData: [ @@ -203,7 +203,7 @@ struct XCBActions { func performAction(status: Status, completion: ((Status) -> Void)?) { mastodonController.run(request(status)) { (response) in if case let .success(status, _) = response { - MastodonCache.add(status: status) + mastodonController.cache.add(status: status) completion?(status) session.complete(with: .success, additionalData: [ "statusURL": status.url?.absoluteString, @@ -289,7 +289,7 @@ struct XCBActions { let request = Account.follow(account.id) mastodonController.run(request) { (response) in if case let .success(relationship, _) = response { - MastodonCache.add(relationship: relationship) + mastodonController.cache.add(relationship: relationship) session.complete(with: .success, additionalData: [ "url": account.url.absoluteString ])