Timeline: Cleanup

This commit is contained in:
Thomas Ricouard 2023-02-25 19:47:15 +01:00
parent 151154b335
commit 93ee83c65d
2 changed files with 27 additions and 43 deletions

View File

@ -60,7 +60,7 @@ public struct TimelineView: View {
collectionView.isPrefetchingEnabled = true collectionView.isPrefetchingEnabled = true
collectionView.prefetchDataSource = self.prefetcher collectionView.prefetchDataSource = self.prefetcher
} }
if viewModel.pendingStatusesEnabled { if viewModel.timeline.supportNewestPagination {
PendingStatusesObserverView(observer: viewModel.pendingStatusesObserver) PendingStatusesObserverView(observer: viewModel.pendingStatusesObserver)
} }
} }

View File

@ -17,7 +17,7 @@ class TimelineViewModel: ObservableObject {
timeline = oldValue timeline = oldValue
} }
if oldValue != timeline { if oldValue != timeline {
await datasource.reset() await reset()
pendingStatusesObserver.pendingStatuses = [] pendingStatusesObserver.pendingStatuses = []
tag = nil tag = nil
} }
@ -53,7 +53,7 @@ class TimelineViewModel: ObservableObject {
didSet { didSet {
if oldValue != client { if oldValue != client {
Task { Task {
await datasource.reset() await reset()
} }
} }
} }
@ -67,10 +67,6 @@ class TimelineViewModel: ObservableObject {
} }
} }
var pendingStatusesEnabled: Bool {
timeline.supportNewestPagination
}
var serverName: String { var serverName: String {
client?.server ?? "Error" client?.server ?? "Error"
} }
@ -103,7 +99,6 @@ class TimelineViewModel: ObservableObject {
timeline == .home, timeline == .home,
canStreamEvents, canStreamEvents,
isTimelineVisible, isTimelineVisible,
pendingStatusesEnabled,
await !datasource.contains(statusId: event.status.id) await !datasource.contains(statusId: event.status.id)
{ {
pendingStatusesObserver.pendingStatuses.insert(event.status.id, at: 0) pendingStatusesObserver.pendingStatuses.insert(event.status.id, at: 0)
@ -167,7 +162,7 @@ extension TimelineViewModel: StatusesFetcher {
guard let client else { return } guard let client else { return }
do { do {
if await datasource.isEmpty || !timeline.supportNewestPagination { if await datasource.isEmpty || !timeline.supportNewestPagination {
await datasource.reset() await reset()
try await fetchFirstPage(client: client) try await fetchFirstPage(client: client)
} else if let latest = await datasource.get().first { } else if let latest = await datasource.get().first {
try await fetchNewPagesFrom(latestStatus: latest, client: client) try await fetchNewPagesFrom(latestStatus: latest, client: client)
@ -276,47 +271,36 @@ extension TimelineViewModel: StatusesFetcher {
// Cache statuses for home timeline. // Cache statuses for home timeline.
await cacheHome() await cacheHome()
// If pending statuses are not enabled, we simply load status on the top regardless of the current position. // Append new statuses in the timeline indicator.
if !pendingStatusesEnabled { pendingStatusesObserver.pendingStatuses.insert(contentsOf: newStatuses.map { $0.id }, at: 0)
pendingStatusesObserver.pendingStatuses = []
// High chance the user is scrolled to the top.
// We need to update the statuses state, and then scroll to the previous top most status.
if let topStatusId, visibileStatusesIds.contains(topStatusId), scrollToTopVisible {
pendingStatusesObserver.disableUpdate = true
let statuses = await datasource.get()
statusesState = .display(statuses: statuses,
nextPageState: statuses.count < 20 ? .none : .hasNextPage)
scrollToIndexAnimated = false
scrollToIndex = newStatuses.count + 1
DispatchQueue.main.async {
self.pendingStatusesObserver.disableUpdate = false
self.canStreamEvents = true
}
} else {
// This will keep the scroll position (if the list is scrolled) and prepend statuses on the top.
let statuses = await datasource.get() let statuses = await datasource.get()
withAnimation { withAnimation {
statusesState = .display(statuses: statuses, statusesState = .display(statuses: statuses,
nextPageState: statuses.count < 20 ? .none : .hasNextPage) nextPageState: statuses.count < 20 ? .none : .hasNextPage)
canStreamEvents = true canStreamEvents = true
} }
} else { }
// Append new statuses in the timeline indicator.
pendingStatusesObserver.pendingStatuses.insert(contentsOf: newStatuses.map { $0.id }, at: 0)
// High chance the user is scrolled to the top. // We trigger a new fetch so we can get the next new statuses if any.
// We need to update the statuses state, and then scroll to the previous top most status. // If none, it'll stop there.
if let topStatusId, visibileStatusesIds.contains(topStatusId), scrollToTopVisible { if !Task.isCancelled, let latest = await datasource.get().first, let client {
pendingStatusesObserver.disableUpdate = true try await fetchNewPagesFrom(latestStatus: latest, client: client)
let statuses = await datasource.get()
statusesState = .display(statuses: statuses,
nextPageState: statuses.count < 20 ? .none : .hasNextPage)
scrollToIndexAnimated = false
scrollToIndex = newStatuses.count + 1
DispatchQueue.main.async {
self.pendingStatusesObserver.disableUpdate = false
self.canStreamEvents = true
}
} else {
// This will keep the scroll position (if the list is scrolled) and prepend statuses on the top.
let statuses = await datasource.get()
withAnimation {
statusesState = .display(statuses: statuses,
nextPageState: statuses.count < 20 ? .none : .hasNextPage)
canStreamEvents = true
}
}
// We trigger a new fetch so we can get the next new statuses if any.
// If none, it'll stop there.
if !Task.isCancelled, let latest = await datasource.get().first, let client {
try await fetchNewPagesFrom(latestStatus: latest, client: client)
}
} }
} }