mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00
Honor requested minID when fetching notifications
Contributes to #399 [BUG] Multiple interactions do not collapse into a single notification
This commit is contained in:
parent
c746507cc4
commit
7502daecd0
@ -206,13 +206,13 @@ final public class GroupedNotificationFeedLoader {
|
||||
switch kind {
|
||||
case .notificationsAll:
|
||||
return try await loadNotifications(
|
||||
withScope: .everything, olderThan: request.olderThan)
|
||||
withScope: .everything, olderThan: request.olderThan, newerThan: request.newerThan)
|
||||
case .notificationsMentionsOnly:
|
||||
return try await loadNotifications(
|
||||
withScope: .mentions, olderThan: request.olderThan)
|
||||
withScope: .mentions, olderThan: request.olderThan, newerThan: request.newerThan)
|
||||
case .notificationsWithAccount(let accountID):
|
||||
return try await loadNotifications(
|
||||
withAccountID: accountID, olderThan: request.olderThan)
|
||||
withAccountID: accountID, olderThan: request.olderThan, newerThan: request.newerThan)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -257,27 +257,28 @@ extension GroupedNotificationFeedLoader {
|
||||
extension GroupedNotificationFeedLoader {
|
||||
private func loadNotifications(
|
||||
withScope scope: APIService.MastodonNotificationScope,
|
||||
olderThan maxID: String? = nil
|
||||
olderThan maxID: String? = nil,
|
||||
newerThan minID: String?
|
||||
) async throws -> NotificationsResultType {
|
||||
if useGroupedNotificationsApi {
|
||||
do {
|
||||
return try await getGroupedNotifications(
|
||||
withScope: scope, olderThan: maxID)
|
||||
withScope: scope, olderThan: maxID, newerThan: minID)
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
return try await getUngroupedNotifications(withScope: scope, olderThan: maxID)
|
||||
return try await getUngroupedNotifications(withScope: scope, olderThan: maxID, newerThan: minID)
|
||||
}
|
||||
|
||||
private func loadNotifications(
|
||||
withAccountID accountID: String, olderThan maxID: String? = nil
|
||||
withAccountID accountID: String, olderThan maxID: String? = nil, newerThan minID: String?
|
||||
) async throws -> [Mastodon.Entity.Notification] {
|
||||
return try await getUngroupedNotifications(
|
||||
accountID: accountID, olderThan: maxID)
|
||||
accountID: accountID, olderThan: maxID, newerThan: minID)
|
||||
}
|
||||
|
||||
private func getGroupedNotifications(
|
||||
withScope scope: APIService.MastodonNotificationScope, olderThan maxID: String? = nil
|
||||
withScope scope: APIService.MastodonNotificationScope, olderThan maxID: String? = nil, newerThan minID: String?
|
||||
) async throws -> Mastodon.Entity.GroupedNotificationsResults {
|
||||
guard
|
||||
let authenticationBox = AuthenticationServiceProvider.shared
|
||||
@ -285,7 +286,7 @@ extension GroupedNotificationFeedLoader {
|
||||
else { throw APIService.APIError.implicit(.authenticationMissing) }
|
||||
|
||||
let results = try await APIService.shared.groupedNotifications(
|
||||
olderThan: maxID, fromAccount: nil, scope: scope,
|
||||
olderThan: maxID, newerThan: minID, fromAccount: nil, scope: scope,
|
||||
authenticationBox: authenticationBox
|
||||
)
|
||||
|
||||
@ -294,7 +295,7 @@ extension GroupedNotificationFeedLoader {
|
||||
|
||||
private func getUngroupedNotifications(
|
||||
withScope scope: APIService.MastodonNotificationScope? = nil,
|
||||
accountID: String? = nil, olderThan maxID: String? = nil
|
||||
accountID: String? = nil, olderThan maxID: String? = nil, newerThan minID: String?
|
||||
) async throws -> [Mastodon.Entity.Notification] {
|
||||
|
||||
assert(scope != nil || accountID != nil, "need a scope or an accountID")
|
||||
|
@ -97,7 +97,7 @@ class UngroupedNotificationCacheManager: NotificationsCacheManager {
|
||||
updatedMostRecentChunk = newlyFetched
|
||||
}
|
||||
if let staleResults {
|
||||
let (dedupedNewer, stale) = dedupeAndCombine(newer: updatedMostRecentChunk, older: staleResults)
|
||||
let (dedupedNewer, stale) = merge(newer: updatedMostRecentChunk, older: staleResults)
|
||||
mostRecentlyFetchedResults = Array(dedupedNewer)
|
||||
if stale == nil {
|
||||
self.staleResults = nil
|
||||
@ -214,7 +214,7 @@ class GroupedNotificationCacheManager: NotificationsCacheManager {
|
||||
let allStatuses: [Mastodon.Entity.Status]
|
||||
|
||||
if let staleResults {
|
||||
let (dedupedNewer, dedupedStale) = dedupeAndCombine(newer: updatedNewerChunk, older: staleResults.notificationGroups)
|
||||
let (dedupedNewer, dedupedStale) = merge(newer: updatedNewerChunk, older: staleResults.notificationGroups)
|
||||
truncatedGroups = truncate(notificationGroups: dedupedNewer)
|
||||
if dedupedStale == nil {
|
||||
// the lists were combined, so we don't have to keep track of the stale one anymore
|
||||
@ -346,14 +346,14 @@ class GroupedNotificationCacheManager: NotificationsCacheManager {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func dedupeAndCombine<T: Overlappable>(newer: [T], older: [T]) -> ([T], [T]?) {
|
||||
fileprivate func merge<T: Overlappable>(newer: [T], older: [T], assumeOverlap: Bool = true) -> ([T], [T]?) {
|
||||
// There can be multiple matches between the older and newer feeds, with no guarantee of order. The newer version of a duplicate is always the one that should be used.
|
||||
// Note that the check here is not fully sufficient to test for a gap between freshly fetched notifications and cached notifications (this check could miss a gap that was skipped over by a group that got promoted far enough up the list).
|
||||
// Note that the check here is not fully sufficient to test for a gap between freshly fetched notifications and cached notifications (this check could miss a gap that was skipped over by a group that got promoted far enough up the list), which is why for now we fetch with a minID to avoid gaps and always assume there is an overlap.
|
||||
|
||||
var dedupedNewer = [T]()
|
||||
var dedupedOlder = [T]()
|
||||
var alreadyAdded = Set<T.ID>()
|
||||
var canCombine = false
|
||||
var hasOverlap = false
|
||||
|
||||
for element in newer {
|
||||
guard !alreadyAdded.contains(element.id) else { continue }
|
||||
@ -362,12 +362,12 @@ fileprivate func dedupeAndCombine<T: Overlappable>(newer: [T], older: [T]) -> ([
|
||||
}
|
||||
|
||||
for element in older {
|
||||
guard !alreadyAdded.contains(element.id) else { canCombine = true; continue }
|
||||
guard !alreadyAdded.contains(element.id) else { hasOverlap = true; continue }
|
||||
dedupedOlder.append(element)
|
||||
alreadyAdded.insert(element.id)
|
||||
}
|
||||
|
||||
if canCombine {
|
||||
if hasOverlap || assumeOverlap {
|
||||
return (dedupedNewer + dedupedOlder, nil)
|
||||
} else {
|
||||
return (dedupedNewer, dedupedOlder)
|
||||
|
@ -290,13 +290,13 @@ private extension MastodonFeedLoader {
|
||||
}
|
||||
}
|
||||
|
||||
private func _getGroupedNotifications(withScope scope: APIService.MastodonNotificationScope? = nil, accountID: String? = nil, olderThan maxID: String? = nil) async throws -> [MastodonFeedItemIdentifier] {
|
||||
private func _getGroupedNotifications(withScope scope: APIService.MastodonNotificationScope? = nil, accountID: String? = nil, olderThan maxID: String? = nil, newerThan minID: String?) async throws -> [MastodonFeedItemIdentifier] {
|
||||
|
||||
assert(scope != nil || accountID != nil, "need a scope or an accountID")
|
||||
|
||||
guard let authenticationBox = AuthenticationServiceProvider.shared.currentActiveUser.value else { throw APIService.APIError.implicit(.authenticationMissing) }
|
||||
|
||||
let results = try await APIService.shared.groupedNotifications(olderThan: maxID, fromAccount: accountID, scope: scope, authenticationBox: authenticationBox)
|
||||
let results = try await APIService.shared.groupedNotifications(olderThan: maxID, newerThan: minID, fromAccount: accountID, scope: scope, authenticationBox: authenticationBox)
|
||||
|
||||
for account in results.accounts {
|
||||
MastodonFeedItemCacheManager.shared.addToCache(account)
|
||||
@ -319,13 +319,13 @@ private extension MastodonFeedLoader {
|
||||
}
|
||||
}
|
||||
|
||||
private func _getGroupedNotificationResults(withScope scope: APIService.MastodonNotificationScope? = nil, accountID: String? = nil, olderThan maxID: String? = nil) async throws -> Mastodon.Entity.GroupedNotificationsResults {
|
||||
private func _getGroupedNotificationResults(withScope scope: APIService.MastodonNotificationScope? = nil, accountID: String? = nil, olderThan maxID: String? = nil, newerThan minID: String?) async throws -> Mastodon.Entity.GroupedNotificationsResults {
|
||||
|
||||
assert(scope != nil || accountID != nil, "need a scope or an accountID")
|
||||
|
||||
guard let authenticationBox = AuthenticationServiceProvider.shared.currentActiveUser.value else { throw APIService.APIError.implicit(.authenticationMissing) }
|
||||
|
||||
let results = try await APIService.shared.groupedNotifications(olderThan: maxID, fromAccount: accountID, scope: scope, authenticationBox: authenticationBox)
|
||||
let results = try await APIService.shared.groupedNotifications(olderThan: maxID, newerThan: minID, fromAccount: accountID, scope: scope, authenticationBox: authenticationBox)
|
||||
|
||||
return results
|
||||
}
|
||||
|
@ -59,7 +59,8 @@ extension APIService {
|
||||
}
|
||||
|
||||
public func groupedNotifications(
|
||||
olderThan maxID: Mastodon.Entity.Status.ID?,
|
||||
olderThan maxID: Mastodon.Entity.Notification.ID?,
|
||||
newerThan minID: Mastodon.Entity.Notification.ID?,
|
||||
fromAccount accountID: String? = nil,
|
||||
scope: MastodonNotificationScope?,
|
||||
authenticationBox: MastodonAuthenticationBox
|
||||
@ -83,6 +84,7 @@ extension APIService {
|
||||
|
||||
let query = Mastodon.API.Notifications.GroupedQuery(
|
||||
maxID: maxID,
|
||||
minID: minID,
|
||||
types: types,
|
||||
excludeTypes: excludedTypes,
|
||||
accountID: accountID
|
||||
|
Loading…
x
Reference in New Issue
Block a user