From f53474ac905775adcd701342f4f91bb11833cd9d Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Mon, 27 Apr 2020 19:20:09 -0400 Subject: [PATCH] Use CoreData for notifications screen --- Pachyderm/Model/Status.swift | 8 +++---- Pachyderm/Utilities/NotificationGroup.swift | 6 ++--- .../xcshareddata/xcschemes/Tusker.xcscheme | 6 +++++ Tusker/Controllers/MastodonController.swift | 2 +- .../MastodonCachePersistentStore.swift | 4 ++-- .../NotificationsTableViewController.swift | 20 ++++++++-------- ...ActionAccountListTableViewController.swift | 4 ++-- ...ActionNotificationGroupTableViewCell.swift | 16 ++++++------- ...FollowNotificationGroupTableViewCell.swift | 23 +++++++++---------- 9 files changed, 46 insertions(+), 43 deletions(-) diff --git a/Pachyderm/Model/Status.swift b/Pachyderm/Model/Status.swift index 7b89739d..fe5892e5 100644 --- a/Pachyderm/Model/Status.swift +++ b/Pachyderm/Model/Status.swift @@ -46,14 +46,14 @@ public class Status: Decodable { return Request(method: .get, path: "/api/v1/statuses/\(status.id)/card") } - public static func getFavourites(_ status: Status, range: RequestRange = .default) -> Request<[Account]> { - var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(status.id)/favourited_by") + public static func getFavourites(_ statusID: String, range: RequestRange = .default) -> Request<[Account]> { + var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(statusID)/favourited_by") request.range = range return request } - public static func getReblogs(_ status: Status, range: RequestRange = .default) -> Request<[Account]> { - var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(status.id)/reblogged_by") + public static func getReblogs(_ statusID: String, range: RequestRange = .default) -> Request<[Account]> { + var request = Request<[Account]>(method: .get, path: "/api/v1/statuses/\(statusID)/reblogged_by") request.range = range return request } diff --git a/Pachyderm/Utilities/NotificationGroup.swift b/Pachyderm/Utilities/NotificationGroup.swift index bb484556..ef46acc6 100644 --- a/Pachyderm/Utilities/NotificationGroup.swift +++ b/Pachyderm/Utilities/NotificationGroup.swift @@ -9,14 +9,14 @@ import Foundation public class NotificationGroup { - public let notificationIDs: [String] + public let notifications: [Notification] public let id: String public let kind: Notification.Kind public let statusState: StatusState? - + init?(notifications: [Notification]) { guard !notifications.isEmpty else { return nil } - self.notificationIDs = notifications.map { $0.id } + self.notifications = notifications self.id = notifications.first!.id self.kind = notifications.first!.kind if kind == .mention { diff --git a/Tusker.xcodeproj/xcshareddata/xcschemes/Tusker.xcscheme b/Tusker.xcodeproj/xcshareddata/xcschemes/Tusker.xcscheme index 73646bda..68917e5e 100644 --- a/Tusker.xcodeproj/xcshareddata/xcschemes/Tusker.xcscheme +++ b/Tusker.xcodeproj/xcshareddata/xcschemes/Tusker.xcscheme @@ -92,6 +92,12 @@ ReferencedContainer = "container:Tusker.xcodeproj"> + + + + Void)?) { + func addOrUpdate(status: Status, incrementReferenceCount: Bool, completion: (() -> Void)? = nil) { backgroundContext.perform { self.upsert(status: status, incrementReferenceCount: incrementReferenceCount) if self.backgroundContext.hasChanges { @@ -91,7 +91,7 @@ class MastodonCachePersistentStore: NSPersistentContainer { } } - func addOrUpdate(account: Account, completion: (() -> Void)?) { + func addOrUpdate(account: Account, completion: (() -> Void)? = nil) { backgroundContext.perform { self.upsert(account: account) if self.backgroundContext.hasChanges { diff --git a/Tusker/Screens/Notifications/NotificationsTableViewController.swift b/Tusker/Screens/Notifications/NotificationsTableViewController.swift index c8a1a9a6..f0366927 100644 --- a/Tusker/Screens/Notifications/NotificationsTableViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsTableViewController.swift @@ -63,9 +63,8 @@ class NotificationsTableViewController: EnhancedTableViewController { self.groups.append(contentsOf: groups) - 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.mastodonController.persistentContainer.addAll(statuses: notifications.compactMap { $0.status }) + self.mastodonController.persistentContainer.addAll(accounts: notifications.map { $0.account }) self.newer = pagination?.newer self.older = pagination?.older @@ -92,7 +91,7 @@ class NotificationsTableViewController: EnhancedTableViewController { switch group.kind { case .mention: - guard let notification = mastodonController.cache.notification(for: group.notificationIDs.first!), + guard let notification = group.notifications.first, let cell = tableView.dequeueReusableCell(withIdentifier: statusCell, for: indexPath) as? TimelineStatusTableViewCell else { fatalError() } @@ -113,7 +112,7 @@ class NotificationsTableViewController: EnhancedTableViewController { return cell case .followRequest: - guard let notification = mastodonController.cache.notification(for: group.notificationIDs.first!), + guard let notification = group.notifications.first, let cell = tableView.dequeueReusableCell(withIdentifier: followRequestCell, for: indexPath) as? FollowRequestNotificationTableViewCell else { fatalError() } cell.delegate = self cell.updateUI(notification: notification) @@ -195,8 +194,8 @@ class NotificationsTableViewController: EnhancedTableViewController { func dismissNotificationsInGroup(at indexPath: IndexPath, completion: (() -> Void)? = nil) { let group = DispatchGroup() - groups[indexPath.row].notificationIDs - .map(Pachyderm.Notification.dismiss(id:)) + groups[indexPath.row].notifications + .map { Pachyderm.Notification.dismiss(id: $0.id) } .forEach { (request) in group.enter() mastodonController.run(request) { (response) in @@ -259,8 +258,8 @@ extension NotificationsTableViewController: StatusTableViewCellDelegate { extension NotificationsTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { for indexPath in indexPaths { - for notificationID in groups[indexPath.row].notificationIDs { - guard let notification = mastodonController.cache.notification(for: notificationID) else { continue } + for notification in groups[indexPath.row].notifications { + // todo: this account object could be stale _ = ImageCache.avatars.get(notification.account.avatar, completion: nil) } } @@ -268,8 +267,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 = mastodonController.cache.notification(for: notificationID) else { continue } + for notification in groups[indexPath.row].notifications { ImageCache.avatars.cancelWithoutCallback(notification.account.avatar) } } diff --git a/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift index dd60518c..7e367d6c 100644 --- a/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift +++ b/Tusker/Screens/Status Action Account List/StatusActionAccountListTableViewController.swift @@ -73,13 +73,13 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController { if accountIDs == nil { // account IDs haven't been set, so perform a request to load them - guard let status = mastodonController.cache.status(for: statusID) else { + guard let status = mastodonController.persistentContainer.status(for: statusID) else { fatalError("Missing cached status \(statusID)") } tableView.tableFooterView = UIActivityIndicatorView(style: .large) - let request = actionType == .favorite ? Status.getFavourites(status) : Status.getReblogs(status) + let request = actionType == .favorite ? Status.getFavourites(status.id) : Status.getReblogs(status.id) mastodonController.run(request) { (response) in guard case let .success(accounts, _) = response else { fatalError() } self.mastodonController.cache.addAll(accounts: accounts) diff --git a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift index 94bfa4dc..24c297cc 100644 --- a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift @@ -38,7 +38,8 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { } @objc func updateUIForPreferences() { - let people = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account } + // todo: is this compactMap necessary? + let people = group.notifications.compactMap { mastodonController.persistentContainer.account(for: $0.account.id) } updateActionLabel(people: people) for case let imageView as UIImageView in actionAvatarStackView.arrangedSubviews { @@ -52,7 +53,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { } self.group = group - guard let firstNotification = mastodonController.cache.notification(for: group.notificationIDs.first!) else { fatalError() } + guard let firstNotification = group.notifications.first else { fatalError() } let status = firstNotification.status! self.statusID = status.id @@ -67,7 +68,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { fatalError() } - let people = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account } + let people = group.notifications.compactMap { mastodonController.persistentContainer.account(for: $0.account.id) } actionAvatarStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } for account in people { @@ -98,8 +99,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { } func updateTimestamp() { - guard let id = group.notificationIDs.first, - let notification = mastodonController.cache.notification(for: id) else { + guard let notification = group.notifications.first else { fatalError("Missing cached notification") } @@ -126,7 +126,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { } } - func updateActionLabel(people: [Account]) { + func updateActionLabel(people: [AccountMO]) { let verb: String switch group.kind { case .favourite: @@ -163,7 +163,7 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { extension ActionNotificationGroupTableViewCell: SelectableTableViewCell { func didSelectCell() { guard let delegate = delegate else { return } - let notifications = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)) + let notifications = group.notifications let accountIDs = notifications.map { $0.account.id } let action: StatusActionAccountListTableViewController.ActionType switch notifications.first!.kind { @@ -184,7 +184,7 @@ extension ActionNotificationGroupTableViewCell: MenuPreviewProvider { func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { return (content: { - let notifications = self.group.notificationIDs.compactMap(self.mastodonController.cache.notification(for:)) + let notifications = self.group.notifications 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 6660711c..8d211a0f 100644 --- a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift @@ -34,7 +34,7 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { } @objc func updateUIForPreferences() { - let people = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account } + let people = group.notifications.compactMap { mastodonController.persistentContainer.account(for: $0.account.id) } updateActionLabel(people: people) for case let imageView as UIImageView in avatarStackView.arrangedSubviews { @@ -45,8 +45,8 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { func updateUI(group: NotificationGroup) { self.group = group - let people = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account } - + let people = group.notifications.compactMap { mastodonController.persistentContainer.account(for: $0.account.id) } + updateActionLabel(people: people) updateTimestamp() @@ -71,8 +71,8 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { } } - func updateActionLabel(people: [Account]) { - // todo: update to use managed objects + func updateActionLabel(people: [AccountMO]) { + // todo: custom emoji in people display names // todo: figure out how to localize this let peopleStr: String switch people.count { @@ -88,8 +88,7 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { } func updateTimestamp() { - guard let id = group.notificationIDs.first, - let notification = mastodonController.cache.notification(for: id) else { + guard let notification = group.notifications.first else { fatalError("Missing cached notification") } @@ -128,14 +127,14 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { extension FollowNotificationGroupTableViewCell: SelectableTableViewCell { func didSelectCell() { - let people = group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account.id } - switch people.count { + let accountIDs = group.notifications.map { $0.account.id } + switch accountIDs.count { case 0: return case 1: - delegate?.selected(account: people.first!) + delegate?.selected(account: accountIDs.first!) default: - delegate?.showFollowedByList(accountIDs: people) + delegate?.showFollowedByList(accountIDs: accountIDs) } } } @@ -145,7 +144,7 @@ extension FollowNotificationGroupTableViewCell: MenuPreviewProvider { func getPreviewProviders(for location: CGPoint, sourceViewController: UIViewController) -> PreviewProviders? { guard let mastodonController = mastodonController else { return nil } - let accountIDs = self.group.notificationIDs.compactMap(mastodonController.cache.notification(for:)).map { $0.account.id } + let accountIDs = self.group.notifications.map { $0.account.id } return (content: { if accountIDs.count == 1 { return ProfileTableViewController(accountID: accountIDs.first!, mastodonController: mastodonController)