Fix: consolidated notifications (#461)

* Fix consolidated notifications pagination

* Only group followers on All notifications screen
This commit is contained in:
Jérôme Danthinne 2023-01-28 09:04:35 +01:00 committed by GitHub
parent 1983ae0f48
commit ffcb0574cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -65,7 +65,7 @@ class NotificationsViewModel: ObservableObject {
maxId: nil, maxId: nil,
types: queryTypes)) types: queryTypes))
self.notifications = notifications self.notifications = notifications
consolidatedNotifications = notifications.consolidated() consolidatedNotifications = notifications.consolidated(selectedType: selectedType)
nextPageState = notifications.count < 15 ? .none : .hasNextPage nextPageState = notifications.count < 15 ? .none : .hasNextPage
} else if let first = consolidatedNotifications.first { } else if let first = consolidatedNotifications.first {
var newNotifications: [Models.Notification] = var newNotifications: [Models.Notification] =
@ -77,7 +77,10 @@ class NotificationsViewModel: ObservableObject {
!consolidatedNotifications.contains(where: { $0.id == notification.id }) !consolidatedNotifications.contains(where: { $0.id == notification.id })
} }
notifications.append(contentsOf: newNotifications) notifications.append(contentsOf: newNotifications)
consolidatedNotifications.insert(contentsOf: newNotifications.consolidated(), at: 0) consolidatedNotifications.insert(
contentsOf: newNotifications.consolidated(selectedType: selectedType),
at: 0
)
} }
withAnimation { withAnimation {
state = .display(notifications: consolidatedNotifications, state = .display(notifications: consolidatedNotifications,
@ -91,13 +94,13 @@ class NotificationsViewModel: ObservableObject {
func fetchNextPage() async { func fetchNextPage() async {
guard let client else { return } guard let client else { return }
do { do {
guard let lastId = consolidatedNotifications.last?.id else { return } guard let lastId = consolidatedNotifications.last?.notificationIds.last else { return }
state = .display(notifications: consolidatedNotifications, nextPageState: .loadingNextPage) state = .display(notifications: consolidatedNotifications, nextPageState: .loadingNextPage)
let newNotifications: [Models.Notification] = let newNotifications: [Models.Notification] =
try await client.get(endpoint: Notifications.notifications(sinceId: nil, try await client.get(endpoint: Notifications.notifications(sinceId: nil,
maxId: lastId, maxId: lastId,
types: queryTypes)) types: queryTypes))
consolidatedNotifications.append(contentsOf: newNotifications.consolidated()) consolidatedNotifications.append(contentsOf: newNotifications.consolidated(selectedType: selectedType))
notifications.append(contentsOf: newNotifications) notifications.append(contentsOf: newNotifications)
state = .display(notifications: consolidatedNotifications, nextPageState: newNotifications.count < 15 ? .none : .hasNextPage) state = .display(notifications: consolidatedNotifications, nextPageState: newNotifications.count < 15 ? .none : .hasNextPage)
} catch { } catch {
@ -118,10 +121,10 @@ class NotificationsViewModel: ObservableObject {
{ {
if let selectedType, event.notification.type == selectedType.rawValue { if let selectedType, event.notification.type == selectedType.rawValue {
notifications.insert(event.notification, at: 0) notifications.insert(event.notification, at: 0)
consolidatedNotifications = notifications.consolidated() consolidatedNotifications = notifications.consolidated(selectedType: selectedType)
} else if selectedType == nil { } else if selectedType == nil {
notifications.insert(event.notification, at: 0) notifications.insert(event.notification, at: 0)
consolidatedNotifications = notifications.consolidated() consolidatedNotifications = notifications.consolidated(selectedType: selectedType)
} }
state = .display(notifications: consolidatedNotifications, nextPageState: .hasNextPage) state = .display(notifications: consolidatedNotifications, nextPageState: .hasNextPage)
} }
@ -129,14 +132,16 @@ class NotificationsViewModel: ObservableObject {
} }
struct ConsolidatedNotification: Identifiable { struct ConsolidatedNotification: Identifiable {
let id: String let notificationIds: [String]
let type: Models.Notification.NotificationType let type: Models.Notification.NotificationType
let createdAt: ServerDate let createdAt: ServerDate
let accounts: [Account] let accounts: [Account]
let status: Status? let status: Status?
var id: String? { notificationIds.first }
static func placeholder() -> ConsolidatedNotification { static func placeholder() -> ConsolidatedNotification {
.init(id: UUID().uuidString, .init(notificationIds: [UUID().uuidString],
type: .favourite, type: .favourite,
createdAt: "2022-12-16T10:20:54.000Z", createdAt: "2022-12-16T10:20:54.000Z",
accounts: [.placeholder()], accounts: [.placeholder()],
@ -149,19 +154,19 @@ struct ConsolidatedNotification: Identifiable {
} }
extension Array where Element == Models.Notification { extension Array where Element == Models.Notification {
func consolidated() -> [ConsolidatedNotification] { func consolidated(selectedType: Models.Notification.NotificationType?) -> [ConsolidatedNotification] {
Dictionary(grouping: self) { notification -> String? in Dictionary(grouping: self) { notification -> String? in
guard let supportedType = notification.supportedType else { return nil } guard let supportedType = notification.supportedType else { return nil }
switch supportedType { switch supportedType {
case .follow: case .follow where selectedType != .follow:
// Always group followers // Always group followers
return supportedType.rawValue return supportedType.rawValue
case .reblog, .favourite: case .reblog, .favourite:
// Group boosts and favourites by status // Group boosts and favourites by status
return "\(supportedType.rawValue)-\(notification.status?.id ?? "")" return "\(supportedType.rawValue)-\(notification.status?.id ?? "")"
case .follow_request, .poll, .status, .update, .mention: default:
// Never group those // Never group remaining ones
return notification.id return notification.id
} }
} }
@ -171,7 +176,7 @@ extension Array where Element == Models.Notification {
let supportedType = notification.supportedType let supportedType = notification.supportedType
else { return nil } else { return nil }
return ConsolidatedNotification(id: notification.id, return ConsolidatedNotification(notificationIds: notifications.map(\.id),
type: supportedType, type: supportedType,
createdAt: notification.createdAt, createdAt: notification.createdAt,
accounts: notifications.map(\.account), accounts: notifications.map(\.account),