New pending statuses behavior

This commit is contained in:
Thomas Ricouard 2024-09-13 11:27:01 +02:00
parent 7c5f2aea81
commit 491090e373
3 changed files with 29 additions and 21 deletions

View file

@ -10,7 +10,6 @@ import SwiftUI
var pendingStatusesCount: Int = 0
var disableUpdate: Bool = false
var scrollToIndex: ((Int) -> Void)?
var isLoadingNewStatuses: Bool = false
@ -39,9 +38,7 @@ struct TimelineUnreadStatusesView: View {
var body: some View {
if observer.pendingStatusesCount > 0 || observer.isLoadingNewStatuses {
Button {
observer.scrollToIndex?(observer.pendingStatusesCount)
} label: {
Button { } label: {
HStack(spacing: 8) {
if observer.isLoadingNewStatuses {
ProgressView()

View file

@ -99,8 +99,7 @@ public struct TimelineView: View {
{
collectionView.scrollToItem(at: .init(row: newValue, section: 0),
at: .top,
animated: viewModel.scrollToIndexAnimated)
viewModel.scrollToIndexAnimated = false
animated: false)
viewModel.scrollToIndex = nil
}
}

View file

@ -80,13 +80,7 @@ import SwiftUI
}
}
var scrollToTopVisible: Bool = false {
didSet {
if scrollToTopVisible {
pendingStatusesObserver.pendingStatuses = []
}
}
}
var scrollToTopVisible: Bool = false
var serverName: String {
client?.server ?? "Error"
@ -94,15 +88,10 @@ import SwiftUI
var isTimelineVisible: Bool = false
let pendingStatusesObserver: TimelineUnreadStatusesObserver = .init()
var scrollToIndexAnimated: Bool = false
var marker: Marker.Content?
init(statusFetcher: TimelineStatusFetching = TimelineStatusFetcher()) {
self.statusFetcher = statusFetcher
pendingStatusesObserver.scrollToIndex = { [weak self] index in
self?.scrollToIndexAnimated = true
self?.scrollToIndex = index
}
}
private func fetchTag(id: String) async {
@ -159,6 +148,12 @@ extension TimelineViewModel {
extension TimelineViewModel: StatusesFetcher {
func pullToRefresh() async {
timelineTask?.cancel()
if !pendingStatusesObserver.pendingStatuses.isEmpty {
await dequeuePendingStatuses()
return
}
if !timeline.supportNewestPagination || UserPreferences.shared.fastRefreshEnabled {
await reset()
}
@ -245,7 +240,6 @@ extension TimelineViewModel: StatusesFetcher {
{
// Restore cache and scroll to latest seen status.
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
scrollToIndexAnimated = false
scrollToIndex = index + 1
} else {
// Restore cache and scroll to top.
@ -309,6 +303,23 @@ extension TimelineViewModel: StatusesFetcher {
return newStatuses
}
private func dequeuePendingStatuses() async {
canStreamEvents = false
pendingStatusesObserver.disableUpdate = true
let statuses = await datasource.getFiltered()
let newStatuses = pendingStatusesObserver.pendingStatuses.count + 1
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
try? await Task.sleep(for: .milliseconds(0.005))
scrollToIndex = newStatuses
DispatchQueue.main.async { [weak self] in
self?.pendingStatusesObserver.disableUpdate = false
self?.canStreamEvents = true
}
if pendingStatusesObserver.pendingStatuses.count <= 2 {
pendingStatusesObserver.pendingStatuses = []
}
}
private func updateTimelineWithNewStatuses(_ newStatuses: [Status]) async {
let topStatus = await datasource.getFiltered().first
await datasource.insert(contentOf: newStatuses, at: 0)
@ -332,7 +343,6 @@ extension TimelineViewModel: StatusesFetcher {
private func updateTimelineWithScrollToTop(newStatuses: [Status], statuses: [Status], nextPageState: StatusesState.PagingState) {
pendingStatusesObserver.disableUpdate = true
statusesState = .display(statuses: statuses, nextPageState: nextPageState)
scrollToIndexAnimated = false
scrollToIndex = newStatuses.count + 1
DispatchQueue.main.async { [weak self] in
@ -437,8 +447,10 @@ extension TimelineViewModel {
await datasource.insert(event.status, at: 0)
await cache()
StatusDataControllerProvider.shared.updateDataControllers(for: [event.status], client: client)
if scrollToTopVisible, pendingStatusesObserver.pendingStatuses.isEmpty {
await updateStatusesState()
}
}
private func handleDeleteEvent(_ event: StreamEventDelete) async {
await datasource.remove(event.status)