Handle Task Cancelling in the timeline

This commit is contained in:
Thomas Ricouard 2023-02-08 18:46:09 +01:00
parent 970305210b
commit eb5733a90b

View file

@ -10,7 +10,8 @@ class TimelineViewModel: ObservableObject {
@Published var statusesState: StatusesState = .loading @Published var statusesState: StatusesState = .loading
@Published var timeline: TimelineFilter = .federated { @Published var timeline: TimelineFilter = .federated {
didSet { didSet {
Task { timelineTask?.cancel()
timelineTask = Task {
if timeline == .latest, let client { if timeline == .latest, let client {
await cache.clearCache(for: client) await cache.clearCache(for: client)
timeline = .home timeline = .home
@ -20,6 +21,9 @@ class TimelineViewModel: ObservableObject {
pendingStatusesObserver.pendingStatuses = [] pendingStatusesObserver.pendingStatuses = []
tag = nil tag = nil
} }
guard !Task.isCancelled else {
return
}
await fetchStatuses() await fetchStatuses()
switch timeline { switch timeline {
case let .hashtag(tag, _): case let .hashtag(tag, _):
@ -31,6 +35,8 @@ class TimelineViewModel: ObservableObject {
} }
} }
private var timelineTask: Task<Void, Never>?
@Published var tag: Tag? @Published var tag: Tag?
// Internal source of truth for a timeline. // Internal source of truth for a timeline.
@ -164,7 +170,10 @@ extension TimelineViewModel: StatusesFetcher {
// Hydrate statuses in the Timeline when statuses are empty. // Hydrate statuses in the Timeline when statuses are empty.
private func fetchFirstPage(client: Client) async throws { private func fetchFirstPage(client: Client) async throws {
pendingStatusesObserver.pendingStatuses = [] pendingStatusesObserver.pendingStatuses = []
if statuses.isEmpty {
statusesState = .loading statusesState = .loading
}
// If we get statuses from the cache for the home timeline, we displays those. // If we get statuses from the cache for the home timeline, we displays those.
// Else we fetch top most page from the API. // Else we fetch top most page from the API.
@ -230,6 +239,12 @@ extension TimelineViewModel: StatusesFetcher {
return return
} }
// Return if task has been cancelled.
guard !Task.isCancelled else {
canStreamEvents = true
return
}
// Keep track of the top most status, so we can scroll back to it after view update. // Keep track of the top most status, so we can scroll back to it after view update.
let topStatusId = statuses.first?.id let topStatusId = statuses.first?.id
@ -271,7 +286,7 @@ extension TimelineViewModel: StatusesFetcher {
// We trigger a new fetch so we can get the next new statuses if any. // We trigger a new fetch so we can get the next new statuses if any.
// If none, it'll stop there. // If none, it'll stop there.
if let latest = statuses.first, let client { if !Task.isCancelled, let latest = statuses.first, let client {
try await fetchNewPagesFrom(latestStatus: latest, client: client) try await fetchNewPagesFrom(latestStatus: latest, client: client)
} }
} }