Timeline: cleanup datasource near bottom

This commit is contained in:
Thomas Ricouard 2024-09-15 13:25:51 +02:00
parent 0b7c6a799f
commit 93421c56d9
3 changed files with 29 additions and 11 deletions

View file

@ -65,7 +65,7 @@ public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
} }
.padding(.horizontal, .layoutPadding) .padding(.horizontal, .layoutPadding)
#if !os(visionOS) #if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
#endif #endif
case .none: case .none:

View file

@ -57,7 +57,7 @@ import SwiftUI
} }
@ObservationIgnored @ObservationIgnored
private var visibileStatuses: [Status] = [] private var visibleStatuses: [Status] = []
private var canStreamEvents: Bool = true { private var canStreamEvents: Bool = true {
didSet { didSet {
@ -301,6 +301,9 @@ extension TimelineViewModel: StatusesFetcher {
private func updateTimelineWithNewStatuses(_ newStatuses: [Status]) async { private func updateTimelineWithNewStatuses(_ newStatuses: [Status]) async {
let topStatus = await datasource.getFiltered().first let topStatus = await datasource.getFiltered().first
await datasource.insert(contentOf: newStatuses, at: 0) await datasource.insert(contentOf: newStatuses, at: 0)
if let lastVisible = visibleStatuses.last {
await datasource.remove(after: lastVisible, safeOffset: 15)
}
await cache() await cache()
pendingStatusesObserver.pendingStatuses.insert(contentsOf: newStatuses.map(\.id), at: 0) pendingStatusesObserver.pendingStatuses.insert(contentsOf: newStatuses.map(\.id), at: 0)
@ -308,7 +311,7 @@ extension TimelineViewModel: StatusesFetcher {
let nextPageState: StatusesState.PagingState = statuses.count < 20 ? .none : .hasNextPage let nextPageState: StatusesState.PagingState = statuses.count < 20 ? .none : .hasNextPage
if let topStatus = topStatus, if let topStatus = topStatus,
visibileStatuses.contains(where: { $0.id == topStatus.id }), visibleStatuses.contains(where: { $0.id == topStatus.id }),
scrollToTopVisible scrollToTopVisible
{ {
updateTimelineWithScrollToTop(newStatuses: newStatuses, statuses: statuses, nextPageState: nextPageState) updateTimelineWithScrollToTop(newStatuses: newStatuses, statuses: statuses, nextPageState: nextPageState)
@ -359,17 +362,17 @@ extension TimelineViewModel: StatusesFetcher {
func statusDidAppear(status: Status) { func statusDidAppear(status: Status) {
pendingStatusesObserver.removeStatus(status: status) pendingStatusesObserver.removeStatus(status: status)
visibileStatuses.insert(status, at: 0) visibleStatuses.insert(status, at: 0)
if let client, timeline.supportNewestPagination { if let client, timeline.supportNewestPagination {
Task { Task {
await cache.setLatestSeenStatuses(visibileStatuses, for: client, filter: timeline.id) await cache.setLatestSeenStatuses(visibleStatuses, for: client, filter: timeline.id)
} }
} }
} }
func statusDidDisappear(status: Status) { func statusDidDisappear(status: Status) {
visibileStatuses.removeAll(where: { $0.id == status.id }) visibleStatuses.removeAll(where: { $0.id == status.id })
} }
} }
@ -419,9 +422,10 @@ extension TimelineViewModel {
} }
private func handleDeleteEvent(_ event: StreamEventDelete) async { private func handleDeleteEvent(_ event: StreamEventDelete) async {
await datasource.remove(event.status) if let _ = await datasource.remove(event.status) {
await cache() await cache()
await updateStatusesState() await updateStatusesState()
}
} }
private func handleStatusUpdateEvent(_ event: StreamEventStatusUpdate, client: Client) async { private func handleStatusUpdateEvent(_ event: StreamEventStatusUpdate, client: Client) async {

View file

@ -67,12 +67,26 @@ actor TimelineDatasource {
func insert(contentOf: [Status], at: Int) { func insert(contentOf: [Status], at: Int) {
statuses.insert(contentsOf: contentOf, at: at) statuses.insert(contentsOf: contentOf, at: at)
} }
func remove(after: Status, safeOffset: Int) {
if let index = statuses.firstIndex(of: after) {
let safeIndex = index + safeOffset
if statuses.count > safeIndex {
statuses.removeSubrange(safeIndex..<statuses.endIndex)
}
}
}
func replace(_ status: Status, at: Int) { func replace(_ status: Status, at: Int) {
statuses[at] = status statuses[at] = status
} }
func remove(_ statusId: String) { func remove(_ statusId: String) -> Status? {
statuses.removeAll(where: { $0.id == statusId }) if let index = statuses.firstIndex(where: { status in
status.id == statusId
}) {
return statuses.remove(at: index)
}
return nil
} }
} }