From 288a0eac9fb76d466a79bda02651672eaf9ba5ef Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Sat, 4 Feb 2023 14:42:10 +0100 Subject: [PATCH] Save / Restore latest seen statuses --- .../Sources/Timeline/TimelineCache.swift | 8 ++++++++ .../Sources/Timeline/TimelineViewModel.swift | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Packages/Timeline/Sources/Timeline/TimelineCache.swift b/Packages/Timeline/Sources/Timeline/TimelineCache.swift index 7eeb7a4b..39a1a272 100644 --- a/Packages/Timeline/Sources/Timeline/TimelineCache.swift +++ b/Packages/Timeline/Sources/Timeline/TimelineCache.swift @@ -41,4 +41,12 @@ actor TimelineCache { return nil } } + + func setLatestSeenStatuses(ids: [String], for client: Client) { + UserDefaults.standard.set(ids, forKey: client.id) + } + + func getLatestSeenStatus(for client: Client) -> [String]? { + UserDefaults.standard.array(forKey: client.id) as? [String] + } } diff --git a/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift b/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift index 0119ac61..7cb53c74 100644 --- a/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift +++ b/Packages/Timeline/Sources/Timeline/TimelineViewModel.swift @@ -17,6 +17,7 @@ class TimelineViewModel: ObservableObject { // Internal source of truth for a timeline. private var statuses: [Status] = [] private var visibileStatusesIds = Set() + var scrollToTopVisible: Bool = false { didSet { if scrollToTopVisible { @@ -168,8 +169,18 @@ extension TimelineViewModel: StatusesFetcher { !cachedStatuses.isEmpty, timeline == .home { statuses = cachedStatuses - withAnimation { + if let latestSeenId = await cache.getLatestSeenStatus(for: client)?.last, + let index = statuses.firstIndex(where: { $0.id == latestSeenId }), + index > 0 { + // Restore cache and scroll to latest seen status. statusesState = .display(statuses: statuses, nextPageState: statuses.count < 20 ? .none : .hasNextPage) + scrollToIndexAnimated = false + scrollToIndex = index + 1 + } else { + // Restore cache and scroll to top. + withAnimation { + statusesState = .display(statuses: statuses, nextPageState: statuses.count < 20 ? .none : .hasNextPage) + } } // And then we fetch statuses again toget newest statuses from there. await fetchStatuses() @@ -311,6 +322,12 @@ extension TimelineViewModel: StatusesFetcher { func statusDidAppear(status: Status) { pendingStatusesObserver.removeStatus(status: status) visibileStatusesIds.insert(status.id) + + if let client, timeline == .home { + Task { + await cache.setLatestSeenStatuses(ids: visibileStatusesIds.map{ $0 }, for: client) + } + } } func statusDidDisappear(status: Status) {