Move CollapseState out of NotificationGroup

This commit is contained in:
Shadowfacts 2023-05-14 18:55:34 -04:00
parent 038e4b2e4e
commit 468af3f9a6
2 changed files with 49 additions and 27 deletions

View File

@ -12,20 +12,12 @@ public struct NotificationGroup: Identifiable, Hashable, Sendable {
public private(set) var notifications: [Notification] public private(set) var notifications: [Notification]
public let id: String public let id: String
public let kind: Notification.Kind public let kind: Notification.Kind
public let statusState: CollapseState?
@MainActor
public init?(notifications: [Notification]) { public init?(notifications: [Notification]) {
guard !notifications.isEmpty else { return nil } guard !notifications.isEmpty else { return nil }
self.notifications = notifications self.notifications = notifications
self.id = notifications.first!.id self.id = notifications.first!.id
self.kind = notifications.first!.kind 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 { public static func ==(lhs: NotificationGroup, rhs: NotificationGroup) -> Bool {

View File

@ -109,10 +109,10 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle
} }
private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> { private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> {
let statusCell = UICollectionView.CellRegistration<TimelineStatusCollectionViewCell, NotificationGroup> { [unowned self] cell, indexPath, itemIdentifier in let statusCell = UICollectionView.CellRegistration<TimelineStatusCollectionViewCell, (NotificationGroup, CollapseState)> { [unowned self] cell, indexPath, itemIdentifier in
cell.delegate = self cell.delegate = self
let statusID = itemIdentifier.notifications.first!.status!.id let statusID = itemIdentifier.0.notifications.first!.status!.id
let statusState = itemIdentifier.statusState! let statusState = itemIdentifier.1
cell.updateUI(statusID: statusID, state: statusState, filterResult: .allow, precomputedContent: nil) cell.updateUI(statusID: statusID, state: statusState, filterResult: .allow, precomputedContent: nil)
} }
let actionGroupCell = UICollectionView.CellRegistration<ActionNotificationGroupCollectionViewCell, NotificationGroup> { [unowned self] cell, indexPath, itemIdentifier in let actionGroupCell = UICollectionView.CellRegistration<ActionNotificationGroupCollectionViewCell, NotificationGroup> { [unowned self] cell, indexPath, itemIdentifier in
@ -142,10 +142,10 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle
} }
return UICollectionViewDiffableDataSource(collectionView: collectionView) { [unowned self] collectionView, indexPath, itemIdentifier in return UICollectionViewDiffableDataSource(collectionView: collectionView) { [unowned self] collectionView, indexPath, itemIdentifier in
switch itemIdentifier { switch itemIdentifier {
case .group(let group): case .group(let group, let collapseState):
switch group.kind { switch group.kind {
case .status, .mention: 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: case .favourite, .reblog:
return collectionView.dequeueConfiguredReusableCell(using: actionGroupCell, for: indexPath, item: group) return collectionView.dequeueConfiguredReusableCell(using: actionGroupCell, for: indexPath, item: group)
case .follow: case .follow:
@ -193,7 +193,7 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle
} }
private func dismissNotificationsInGroup(at indexPath: IndexPath) async { 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 return
} }
let notifications = group.notifications let notifications = group.notifications
@ -216,11 +216,11 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle
} }
var snapshot = dataSource.snapshot() var snapshot = dataSource.snapshot()
if dismissFailedIndices.isEmpty { if dismissFailedIndices.isEmpty {
snapshot.deleteItems([.group(group)]) snapshot.deleteItems([.group(group, collapseState)])
} else if !dismissFailedIndices.isEmpty && dismissFailedIndices.count == notifications.count { } else if !dismissFailedIndices.isEmpty && dismissFailedIndices.count == notifications.count {
let dismissFailed = dismissFailedIndices.sorted().map { notifications[$0] } let dismissFailed = dismissFailedIndices.sorted().map { notifications[$0] }
snapshot.insertItems([.group(NotificationGroup(notifications: dismissFailed)!)], afterItem: .group(group)) snapshot.insertItems([.group(NotificationGroup(notifications: dismissFailed)!, collapseState)], afterItem: .group(group, collapseState))
snapshot.deleteItems([.group(group)]) snapshot.deleteItems([.group(group, collapseState)])
} }
await apply(snapshot, animatingDifferences: true) await apply(snapshot, animatingDifferences: true)
} }
@ -235,16 +235,46 @@ extension NotificationsCollectionViewController {
static var entries: Self { .notifications } static var entries: Self { .notifications }
} }
enum Item: TimelineLikeCollectionViewItem { enum Item: TimelineLikeCollectionViewItem {
case group(NotificationGroup) case group(NotificationGroup, CollapseState?)
case loadingIndicator case loadingIndicator
case confirmLoadMore case confirmLoadMore
static func fromTimelineItem(_ item: NotificationGroup) -> Self { 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? { var group: NotificationGroup? {
if case .group(let group) = self { if case .group(let group, _) = self {
return group return group
} else { } else {
return nil return nil
@ -253,7 +283,7 @@ extension NotificationsCollectionViewController {
var isSelectable: Bool { var isSelectable: Bool {
switch self { switch self {
case .group(_): case .group(_, _):
return true return true
default: default:
return false return false
@ -369,7 +399,7 @@ extension NotificationsCollectionViewController {
$0.id == topID $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) collectionView.scrollToItem(at: newTopIndexPath, at: .top, animated: false)
} }
} }
@ -429,13 +459,13 @@ extension NotificationsCollectionViewController: UICollectionViewDelegate {
} }
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 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 return
} }
switch group.kind { switch group.kind {
case .mention, .status, .poll, .update: case .mention, .status, .poll, .update:
let statusID = group.notifications.first!.status!.id let statusID = group.notifications.first!.status!.id
let state = group.statusState?.copy() ?? .unknown let state = collapseState?.copy() ?? .unknown
selected(status: statusID, state: state) selected(status: statusID, state: state)
case .favourite, .reblog: case .favourite, .reblog:
let type = group.kind == .favourite ? StatusActionAccountListViewController.ActionType.favorite : .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? { 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 { let cell = collectionView.cellForItem(at: indexPath) else {
return nil return nil
} }
@ -473,7 +503,7 @@ extension NotificationsCollectionViewController: UICollectionViewDelegate {
let status = mastodonController.persistentContainer.status(for: statusID) else { let status = mastodonController.persistentContainer.status(for: statusID) else {
return nil return nil
} }
let state = group.statusState?.copy() ?? .unknown let state = collapseState?.copy() ?? .unknown
return UIContextMenuConfiguration { return UIContextMenuConfiguration {
ConversationViewController(for: statusID, state: state, mastodonController: self.mastodonController) ConversationViewController(for: statusID, state: state, mastodonController: self.mastodonController)
} actionProvider: { _ in } actionProvider: { _ in
@ -536,7 +566,7 @@ extension NotificationsCollectionViewController: UICollectionViewDelegate {
extension NotificationsCollectionViewController: UICollectionViewDragDelegate { extension NotificationsCollectionViewController: UICollectionViewDragDelegate {
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { 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 [] return []
} }
switch group.kind { switch group.kind {