From 468af3f9a6b8dcf5ca4e56c97ac406ec76e1da61 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 14 May 2023 18:55:34 -0400 Subject: [PATCH] Move CollapseState out of NotificationGroup --- .../Utilities/NotificationGroup.swift | 8 --- ...otificationsCollectionViewController.swift | 68 +++++++++++++------ 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/Packages/Pachyderm/Sources/Pachyderm/Utilities/NotificationGroup.swift b/Packages/Pachyderm/Sources/Pachyderm/Utilities/NotificationGroup.swift index 98543a73..ae633c4b 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Utilities/NotificationGroup.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Utilities/NotificationGroup.swift @@ -12,20 +12,12 @@ public struct NotificationGroup: Identifiable, Hashable, Sendable { public private(set) var notifications: [Notification] public let id: String public let kind: Notification.Kind - public let statusState: CollapseState? - @MainActor public init?(notifications: [Notification]) { guard !notifications.isEmpty else { return nil } self.notifications = notifications self.id = notifications.first!.id self.kind = notifications.first!.kind - switch kind { - case .mention, .status: - self.statusState = .unknown - default: - self.statusState = nil - } } public static func ==(lhs: NotificationGroup, rhs: NotificationGroup) -> Bool { diff --git a/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift b/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift index 7f92a01d..f5344716 100644 --- a/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift @@ -109,10 +109,10 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle } private func createDataSource() -> UICollectionViewDiffableDataSource { - let statusCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, itemIdentifier in + let statusCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, itemIdentifier in cell.delegate = self - let statusID = itemIdentifier.notifications.first!.status!.id - let statusState = itemIdentifier.statusState! + let statusID = itemIdentifier.0.notifications.first!.status!.id + let statusState = itemIdentifier.1 cell.updateUI(statusID: statusID, state: statusState, filterResult: .allow, precomputedContent: nil) } let actionGroupCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, itemIdentifier in @@ -142,10 +142,10 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle } return UICollectionViewDiffableDataSource(collectionView: collectionView) { [unowned self] collectionView, indexPath, itemIdentifier in switch itemIdentifier { - case .group(let group): + case .group(let group, let collapseState): switch group.kind { case .status, .mention: - return collectionView.dequeueConfiguredReusableCell(using: statusCell, for: indexPath, item: group) + return collectionView.dequeueConfiguredReusableCell(using: statusCell, for: indexPath, item: (group, collapseState!)) case .favourite, .reblog: return collectionView.dequeueConfiguredReusableCell(using: actionGroupCell, for: indexPath, item: group) case .follow: @@ -193,7 +193,7 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle } private func dismissNotificationsInGroup(at indexPath: IndexPath) async { - guard case .group(let group) = dataSource.itemIdentifier(for: indexPath) else { + guard case .group(let group, let collapseState) = dataSource.itemIdentifier(for: indexPath) else { return } let notifications = group.notifications @@ -216,11 +216,11 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle } var snapshot = dataSource.snapshot() if dismissFailedIndices.isEmpty { - snapshot.deleteItems([.group(group)]) + snapshot.deleteItems([.group(group, collapseState)]) } else if !dismissFailedIndices.isEmpty && dismissFailedIndices.count == notifications.count { let dismissFailed = dismissFailedIndices.sorted().map { notifications[$0] } - snapshot.insertItems([.group(NotificationGroup(notifications: dismissFailed)!)], afterItem: .group(group)) - snapshot.deleteItems([.group(group)]) + snapshot.insertItems([.group(NotificationGroup(notifications: dismissFailed)!, collapseState)], afterItem: .group(group, collapseState)) + snapshot.deleteItems([.group(group, collapseState)]) } await apply(snapshot, animatingDifferences: true) } @@ -235,16 +235,46 @@ extension NotificationsCollectionViewController { static var entries: Self { .notifications } } enum Item: TimelineLikeCollectionViewItem { - case group(NotificationGroup) + case group(NotificationGroup, CollapseState?) case loadingIndicator case confirmLoadMore static func fromTimelineItem(_ item: NotificationGroup) -> Self { - return .group(item) + switch item.kind { + case .mention, .status: + return .group(item, .unknown) + default: + return .group(item, nil) + } + } + + static func ==(lhs: Item, rhs: Item) -> Bool { + switch (lhs, rhs) { + case (.group(let a, _), .group(let b, _)): + return a == b + case (.loadingIndicator, .loadingIndicator): + return true + case (.confirmLoadMore, .confirmLoadMore): + return true + default: + return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .group(let group, _): + hasher.combine(0) + hasher.combine(group) + case .loadingIndicator: + hasher.combine(1) + case .confirmLoadMore: + hasher.combine(1) + } } var group: NotificationGroup? { - if case .group(let group) = self { + if case .group(let group, _) = self { return group } else { return nil @@ -253,7 +283,7 @@ extension NotificationsCollectionViewController { var isSelectable: Bool { switch self { - case .group(_): + case .group(_, _): return true default: return false @@ -369,7 +399,7 @@ extension NotificationsCollectionViewController { $0.id == topID } }! - if let newTopIndexPath = dataSource.indexPath(for: .group(newTopGroup)) { + if let newTopIndexPath = dataSource.indexPath(for: .group(newTopGroup, nil)) { collectionView.scrollToItem(at: newTopIndexPath, at: .top, animated: false) } } @@ -429,13 +459,13 @@ extension NotificationsCollectionViewController: UICollectionViewDelegate { } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard case .group(let group) = dataSource.itemIdentifier(for: indexPath) else { + guard case .group(let group, let collapseState) = dataSource.itemIdentifier(for: indexPath) else { return } switch group.kind { case .mention, .status, .poll, .update: let statusID = group.notifications.first!.status!.id - let state = group.statusState?.copy() ?? .unknown + let state = collapseState?.copy() ?? .unknown selected(status: statusID, state: state) case .favourite, .reblog: let type = group.kind == .favourite ? StatusActionAccountListViewController.ActionType.favorite : .reblog @@ -463,7 +493,7 @@ extension NotificationsCollectionViewController: UICollectionViewDelegate { } func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { - guard case .group(let group) = dataSource.itemIdentifier(for: indexPath), + guard case .group(let group, let collapseState) = dataSource.itemIdentifier(for: indexPath), let cell = collectionView.cellForItem(at: indexPath) else { return nil } @@ -473,7 +503,7 @@ extension NotificationsCollectionViewController: UICollectionViewDelegate { let status = mastodonController.persistentContainer.status(for: statusID) else { return nil } - let state = group.statusState?.copy() ?? .unknown + let state = collapseState?.copy() ?? .unknown return UIContextMenuConfiguration { ConversationViewController(for: statusID, state: state, mastodonController: self.mastodonController) } actionProvider: { _ in @@ -536,7 +566,7 @@ extension NotificationsCollectionViewController: UICollectionViewDelegate { extension NotificationsCollectionViewController: UICollectionViewDragDelegate { func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { - guard case .group(let group) = dataSource.itemIdentifier(for: indexPath) else { + guard case .group(let group, _) = dataSource.itemIdentifier(for: indexPath) else { return [] } switch group.kind {