From b0b4271202f93ac189b32d79c7968d1d8531372a Mon Sep 17 00:00:00 2001 From: shannon Date: Tue, 4 Mar 2025 09:21:21 -0500 Subject: [PATCH] Wait for cache to load before reporting results Contributes to #399 [BUG] Multiple interactions do not collapse into a single notification --- .../GroupedNotificationFeedLoader.swift | 6 +- .../NotificationsCacheManager.swift | 98 ++++++++++++------- 2 files changed, 64 insertions(+), 40 deletions(-) diff --git a/Mastodon/In Progress New Layout and Datamodel/GroupedNotificationFeedLoader.swift b/Mastodon/In Progress New Layout and Datamodel/GroupedNotificationFeedLoader.swift index ee790adc1..5bd81eb1d 100644 --- a/Mastodon/In Progress New Layout and Datamodel/GroupedNotificationFeedLoader.swift +++ b/Mastodon/In Progress New Layout and Datamodel/GroupedNotificationFeedLoader.swift @@ -198,7 +198,8 @@ final public class GroupedNotificationFeedLoader { defer { isFetching = false } - try await replaceRecordsAfterFiltering(rowViewModels(from: cacheManager.currentResults), canLoadOlder: true) + let currentResults = await cacheManager.currentResults() + try await replaceRecordsAfterFiltering(rowViewModels(from: currentResults), canLoadOlder: true) } private func load(_ request: FeedLoadRequest) async throws @@ -225,7 +226,8 @@ extension GroupedNotificationFeedLoader { guard let cacheManager else { assertionFailure(); return } do { cacheManager.updateByInserting(newlyFetched: newlyFetchedResults, at: insertionPoint) - let unfiltered = try rowViewModels(from: cacheManager.currentResults) + let currentResults = await cacheManager.currentResults() + let unfiltered = try rowViewModels(from: currentResults) let canLoadOlder: Bool? = { switch insertionPoint { diff --git a/Mastodon/In Progress New Layout and Datamodel/NotificationsCacheManager.swift b/Mastodon/In Progress New Layout and Datamodel/NotificationsCacheManager.swift index 3b7cee59b..29c26b3ab 100644 --- a/Mastodon/In Progress New Layout and Datamodel/NotificationsCacheManager.swift +++ b/Mastodon/In Progress New Layout and Datamodel/NotificationsCacheManager.swift @@ -8,7 +8,7 @@ import MastodonCore protocol NotificationsCacheManager { associatedtype T: NotificationsResultType - var currentResults: T? { get } + func currentResults() async -> T? var currentLastReadMarker: LastReadMarkers.MarkerPosition? { get } var mostRecentlyFetchedResults: T? { get } func updateByInserting(newlyFetched: NotificationsResultType, at insertionPoint: GroupedNotificationFeedLoader.FeedLoadRequest.InsertLocation) @@ -40,19 +40,31 @@ class UngroupedNotificationCacheManager: NotificationsCacheManager { self.userIdentifier = userIdentifier lastReadMarkerStore = Store.lastReadMarkersStore() self.cachedNotifications = Store.ungroupedNotificationStore(forKind: feedKind, forUser: userIdentifier) - self.staleResults = cachedNotifications.items - switch feedKind { - case .notificationsAll, .notificationsMentionsOnly: - self.staleMarkers = lastReadMarkerStore.items.first(where: { $0.userGUID == userIdentifier.globallyUniqueUserIdentifier }) - case .notificationsWithAccount: - self.staleMarkers = nil - } + staleResults = nil + staleMarkers = nil self.mostRecentlyFetchedResults = nil self.mostRecentMarkers = nil } - var currentResults: T? { - return mostRecentlyFetchedResults ?? staleResults + func currentResults() async -> T? { + if let mostRecentlyFetchedResults { + return mostRecentlyFetchedResults + } else { + do { + switch feedKind { + case .notificationsAll, .notificationsMentionsOnly: + try await lastReadMarkerStore.itemsHaveLoaded() + self.staleMarkers = lastReadMarkerStore.items.first(where: { $0.userGUID == userIdentifier.globallyUniqueUserIdentifier }) + case .notificationsWithAccount: + self.staleMarkers = nil + } + try await cachedNotifications.itemsHaveLoaded() + staleResults = cachedNotifications.items + } catch { + debugPrint("error reading notifications cache: \(error)") + } + return mostRecentlyFetchedResults ?? staleResults + } } var currentLastReadMarker: LastReadMarkers.MarkerPosition? { @@ -148,15 +160,8 @@ class GroupedNotificationCacheManager: NotificationsCacheManager { fullAccountStore = Store.notificationRelevantFullAccountStore(forKind: feedKind, forUser: userIdentifier) partialAccountStore = Store.notificationRelevantPartialAccountStore(forKind: feedKind, forUser: userIdentifier) statusStore = Store.notificationRelevantStatusStore(forKind: feedKind, forUser: userIdentifier) - - staleResults = Mastodon.Entity.GroupedNotificationsResults(notificationGroups: notificationGroupStore.items, fullAccounts: fullAccountStore.items, partialAccounts: partialAccountStore.items, statuses: statusStore.items) - - switch feedKind { - case .notificationsAll, .notificationsMentionsOnly: - staleMarkers = lastReadMarkerStore.items.first(where: { $0.userGUID == userIdentifier.globallyUniqueUserIdentifier }) - case .notificationsWithAccount: - staleMarkers = nil - } + staleMarkers = nil + staleResults = nil } func updateByInserting(newlyFetched: NotificationsResultType, at insertionPoint: GroupedNotificationFeedLoader.FeedLoadRequest.InsertLocation) { @@ -265,15 +270,28 @@ class GroupedNotificationCacheManager: NotificationsCacheManager { mostRecentMarkers = updatable } - var currentResults: T? { + func currentResults() async -> T? { + do { + try await lastReadMarkerStore.itemsHaveLoaded() + try await notificationGroupStore.itemsHaveLoaded() + try await fullAccountStore.itemsHaveLoaded() + try await partialAccountStore.itemsHaveLoaded() + try await statusStore.itemsHaveLoaded() + staleMarkers = lastReadMarkerStore.items.first(where: { $0.userGUID == userIdentifier.globallyUniqueUserIdentifier }) + staleResults = Mastodon.Entity.GroupedNotificationsResults(notificationGroups: notificationGroupStore.items, fullAccounts: fullAccountStore.items, partialAccounts: partialAccountStore.items, statuses: statusStore.items) + } catch { + debugPrint("error loading notifications caches: \(error)") + } return mostRecentlyFetchedResults ?? staleResults } var currentLastReadMarker: LastReadMarkers.MarkerPosition? { - guard let markers = mostRecentMarkers ?? staleMarkers else { + switch feedKind { + case .notificationsAll, .notificationsMentionsOnly: + return (mostRecentMarkers ?? staleMarkers)?.lastRead(forKind: feedKind) + case .notificationsWithAccount: return nil } - return markers.lastRead(forKind: feedKind) } func commitToCache() async { @@ -284,22 +302,26 @@ class GroupedNotificationCacheManager: NotificationsCacheManager { } } if let mostRecentlyFetchedResults { - try? await notificationGroupStore - .removeAll() - .insert(mostRecentlyFetchedResults.notificationGroups) - .run() - try? await fullAccountStore - .removeAll() - .insert(mostRecentlyFetchedResults.accounts) - .run() - try? await partialAccountStore - .removeAll() - .insert(mostRecentlyFetchedResults.partialAccounts ?? []) - .run() - try? await statusStore - .removeAll() - .insert(mostRecentlyFetchedResults.statuses) - .run() + do { + try await notificationGroupStore + .removeAll() + .insert(mostRecentlyFetchedResults.notificationGroups) + .run() + try await fullAccountStore + .removeAll() + .insert(mostRecentlyFetchedResults.accounts) + .run() + try await partialAccountStore + .removeAll() + .insert(mostRecentlyFetchedResults.partialAccounts ?? []) + .run() + try await statusStore + .removeAll() + .insert(mostRecentlyFetchedResults.statuses) + .run() + } catch { + debugPrint("error comitting to store \(error)") + } } } }