From 9026f487ec21f6fea83441a141de6efbac5d15de Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 15 Aug 2021 19:25:29 -0400 Subject: [PATCH] Convert notifications to use DiffableTimelineLikeTableViewController --- Pachyderm/Utilities/NotificationGroup.swift | 12 +- .../NotificationsTableViewController.swift | 203 ++++++++++-------- .../TimelineTableViewController.swift | 17 +- ...fableTimelineLikeTableViewController.swift | 10 + 4 files changed, 143 insertions(+), 99 deletions(-) diff --git a/Pachyderm/Utilities/NotificationGroup.swift b/Pachyderm/Utilities/NotificationGroup.swift index ef46acc6..84efc16e 100644 --- a/Pachyderm/Utilities/NotificationGroup.swift +++ b/Pachyderm/Utilities/NotificationGroup.swift @@ -8,7 +8,7 @@ import Foundation -public class NotificationGroup { +public class NotificationGroup: Identifiable, Hashable { public let notifications: [Notification] public let id: String public let kind: Notification.Kind @@ -25,6 +25,14 @@ public class NotificationGroup { self.statusState = nil } } + + public static func ==(lhs: NotificationGroup, rhs: NotificationGroup) -> Bool { + return lhs.id == rhs.id + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(id) + } public static func createGroups(notifications: [Notification], only allowedTypes: [Notification.Kind]) -> [NotificationGroup] { var groups = [[Notification]]() @@ -50,5 +58,3 @@ public class NotificationGroup { } } - -extension NotificationGroup: Identifiable {} diff --git a/Tusker/Screens/Notifications/NotificationsTableViewController.swift b/Tusker/Screens/Notifications/NotificationsTableViewController.swift index ab5b59c2..bfc5e4a3 100644 --- a/Tusker/Screens/Notifications/NotificationsTableViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsTableViewController.swift @@ -9,7 +9,7 @@ import UIKit import Pachyderm -class NotificationsTableViewController: TimelineLikeTableViewController { +class NotificationsTableViewController: DiffableTimelineLikeTableViewController { private let statusCell = "statusCell" private let actionGroupCell = "actionGroupCell" @@ -54,88 +54,9 @@ class NotificationsTableViewController: TimelineLikeTableViewController Void) { - let request = Client.getNotifications(excludeTypes: excludedTypes) - mastodonController.run(request) { (response) in - guard case let .success(notifications, pagination) = response else { - completion([]) - return - } - - let groups = NotificationGroup.createGroups(notifications: notifications, only: self.groupTypes) - - self.newer = pagination?.newer - self.older = pagination?.older - - self.mastodonController.persistentContainer.addAll(notifications: notifications) { - completion(groups) - } - } - } + // MARK: - DiffableTimelineLikeTableViewController - override func loadOlder(completion: @escaping ([NotificationGroup]) -> Void) { - guard let older = older else { - completion([]) - return - } - - let request = Client.getNotifications(excludeTypes: excludedTypes, range: older) - mastodonController.run(request) { (response) in - guard case let .success(newNotifications, pagination) = response else { fatalError() } - - self.older = pagination?.older - - let groups = NotificationGroup.createGroups(notifications: newNotifications, only: self.groupTypes) - - self.mastodonController.persistentContainer.addAll(notifications: newNotifications) { - completion(groups) - } - } - } - - override func loadNewer(completion: @escaping ([NotificationGroup]) -> Void) { - guard let newer = newer else { - completion([]) - return - } - - let request = Client.getNotifications(excludeTypes: excludedTypes, range: newer) - mastodonController.run(request) { (response) in - guard case let .success(newNotifications, pagination) = response else { fatalError() } - - if let newer = pagination?.newer { - self.newer = newer - } - - let groups = NotificationGroup.createGroups(notifications: newNotifications, only: self.groupTypes) - - self.mastodonController.persistentContainer.addAll(notifications: newNotifications) { - completion(groups) - } - } - } - - private func dismissNotificationsInGroup(at indexPath: IndexPath, completion: (() -> Void)? = nil) { - let group = DispatchGroup() - item(for: indexPath).notifications - .map { Pachyderm.Notification.dismiss(id: $0.id) } - .forEach { (request) in - group.enter() - mastodonController.run(request) { (_) in - group.leave() - } - } - group.notify(queue: .main) { - self.sections[indexPath.section].remove(at: indexPath.row) - self.tableView.deleteRows(at: [indexPath], with: .automatic) - completion?() - } - } - - // MARK: - UITableViewDataSource - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let group = item(for: indexPath) - + override func cellProvider(_ tableView: UITableView, _ indexPath: IndexPath, _ group: NotificationGroup) -> UITableViewCell? { switch group.kind { case .mention: guard let notification = group.notifications.first, @@ -179,6 +100,112 @@ class NotificationsTableViewController: TimelineLikeTableViewController Void) { + let request = Client.getNotifications(excludeTypes: excludedTypes) + mastodonController.run(request) { (response) in + switch response { + case let .failure(error): + completion(.failure(.client(error))) + + case let .success(notifications, pagination): + let groups = NotificationGroup.createGroups(notifications: notifications, only: self.groupTypes) + + self.newer = pagination?.newer + self.older = pagination?.older + + self.mastodonController.persistentContainer.addAll(notifications: notifications) { + var snapshot = Snapshot() + snapshot.appendSections([.notifications]) + snapshot.appendItems(groups, toSection: .notifications) + completion(.success(snapshot)) + } + } + } + } + + override func loadOlderItems(currentSnapshot: @escaping () -> Snapshot, completion: @escaping (LoadResult) -> Void) { + guard let older = older else { + completion(.failure(.noOlder)) + return + } + + let request = Client.getNotifications(excludeTypes: excludedTypes, range: older) + mastodonController.run(request) { (response) in + switch response { + case let .failure(error): + completion(.failure(.client(error))) + + case let .success(newNotifications, pagination): + if let older = pagination?.older { + self.older = older + } + + let groups = NotificationGroup.createGroups(notifications: newNotifications, only: self.groupTypes) + + self.mastodonController.persistentContainer.addAll(notifications: newNotifications) { + var snapshot = currentSnapshot() + snapshot.appendItems(groups, toSection: .notifications) + completion(.success(snapshot)) + } + } + } + } + + override func loadNewerItems(currentSnapshot: @escaping () -> Snapshot, completion: @escaping (LoadResult) -> Void) { + guard let newer = newer else { + completion(.failure(.noNewer)) + return + } + + let request = Client.getNotifications(excludeTypes: excludedTypes, range: newer) + mastodonController.run(request) { (response) in + switch response { + case let .failure(error): + completion(.failure(.client(error))) + + case let .success(newNotifications, pagination): + guard !newNotifications.isEmpty else { + completion(.failure(.allCaughtUp)) + return + } + + if let newer = pagination?.newer { + self.newer = newer + } + + let groups = NotificationGroup.createGroups(notifications: newNotifications, only: self.groupTypes) + + self.mastodonController.persistentContainer.addAll(notifications: newNotifications) { + var snapshot = currentSnapshot() + if let first = snapshot.itemIdentifiers(inSection: .notifications).first { + snapshot.insertItems(groups, beforeItem: first) + } else { + snapshot.appendItems(groups, toSection: .notifications) + } + completion(.success(snapshot)) + } + } + } + } + + private func dismissNotificationsInGroup(at indexPath: IndexPath, completion: (() -> Void)? = nil) { + guard let item = dataSource.itemIdentifier(for: indexPath) else { return } + let group = DispatchGroup() + item.notifications + .map { Pachyderm.Notification.dismiss(id: $0.id) } + .forEach { (request) in + group.enter() + mastodonController.run(request) { (_) in + group.leave() + } + } + group.notify(queue: .main) { + var snapshot = self.dataSource.snapshot() + snapshot.deleteItems([item]) + self.dataSource.apply(snapshot, completion: completion) + } + } + // MARK: - UITableViewDelegate override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { @@ -211,6 +238,12 @@ class NotificationsTableViewController: TimelineLikeTableViewController