mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-12-01 04:31:00 +00:00
New pending statuses behavior
This commit is contained in:
parent
7c5f2aea81
commit
491090e373
3 changed files with 29 additions and 21 deletions
|
@ -10,7 +10,6 @@ import SwiftUI
|
||||||
var pendingStatusesCount: Int = 0
|
var pendingStatusesCount: Int = 0
|
||||||
|
|
||||||
var disableUpdate: Bool = false
|
var disableUpdate: Bool = false
|
||||||
var scrollToIndex: ((Int) -> Void)?
|
|
||||||
|
|
||||||
var isLoadingNewStatuses: Bool = false
|
var isLoadingNewStatuses: Bool = false
|
||||||
|
|
||||||
|
@ -39,9 +38,7 @@ struct TimelineUnreadStatusesView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if observer.pendingStatusesCount > 0 || observer.isLoadingNewStatuses {
|
if observer.pendingStatusesCount > 0 || observer.isLoadingNewStatuses {
|
||||||
Button {
|
Button { } label: {
|
||||||
observer.scrollToIndex?(observer.pendingStatusesCount)
|
|
||||||
} label: {
|
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
if observer.isLoadingNewStatuses {
|
if observer.isLoadingNewStatuses {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
|
|
|
@ -99,8 +99,7 @@ public struct TimelineView: View {
|
||||||
{
|
{
|
||||||
collectionView.scrollToItem(at: .init(row: newValue, section: 0),
|
collectionView.scrollToItem(at: .init(row: newValue, section: 0),
|
||||||
at: .top,
|
at: .top,
|
||||||
animated: viewModel.scrollToIndexAnimated)
|
animated: false)
|
||||||
viewModel.scrollToIndexAnimated = false
|
|
||||||
viewModel.scrollToIndex = nil
|
viewModel.scrollToIndex = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,13 +80,7 @@ import SwiftUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var scrollToTopVisible: Bool = false {
|
var scrollToTopVisible: Bool = false
|
||||||
didSet {
|
|
||||||
if scrollToTopVisible {
|
|
||||||
pendingStatusesObserver.pendingStatuses = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var serverName: String {
|
var serverName: String {
|
||||||
client?.server ?? "Error"
|
client?.server ?? "Error"
|
||||||
|
@ -94,15 +88,10 @@ import SwiftUI
|
||||||
|
|
||||||
var isTimelineVisible: Bool = false
|
var isTimelineVisible: Bool = false
|
||||||
let pendingStatusesObserver: TimelineUnreadStatusesObserver = .init()
|
let pendingStatusesObserver: TimelineUnreadStatusesObserver = .init()
|
||||||
var scrollToIndexAnimated: Bool = false
|
|
||||||
var marker: Marker.Content?
|
var marker: Marker.Content?
|
||||||
|
|
||||||
init(statusFetcher: TimelineStatusFetching = TimelineStatusFetcher()) {
|
init(statusFetcher: TimelineStatusFetching = TimelineStatusFetcher()) {
|
||||||
self.statusFetcher = statusFetcher
|
self.statusFetcher = statusFetcher
|
||||||
pendingStatusesObserver.scrollToIndex = { [weak self] index in
|
|
||||||
self?.scrollToIndexAnimated = true
|
|
||||||
self?.scrollToIndex = index
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func fetchTag(id: String) async {
|
private func fetchTag(id: String) async {
|
||||||
|
@ -159,6 +148,12 @@ extension TimelineViewModel {
|
||||||
extension TimelineViewModel: StatusesFetcher {
|
extension TimelineViewModel: StatusesFetcher {
|
||||||
func pullToRefresh() async {
|
func pullToRefresh() async {
|
||||||
timelineTask?.cancel()
|
timelineTask?.cancel()
|
||||||
|
|
||||||
|
if !pendingStatusesObserver.pendingStatuses.isEmpty {
|
||||||
|
await dequeuePendingStatuses()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !timeline.supportNewestPagination || UserPreferences.shared.fastRefreshEnabled {
|
if !timeline.supportNewestPagination || UserPreferences.shared.fastRefreshEnabled {
|
||||||
await reset()
|
await reset()
|
||||||
}
|
}
|
||||||
|
@ -245,7 +240,6 @@ extension TimelineViewModel: StatusesFetcher {
|
||||||
{
|
{
|
||||||
// Restore cache and scroll to latest seen status.
|
// Restore cache and scroll to latest seen status.
|
||||||
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
|
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
|
||||||
scrollToIndexAnimated = false
|
|
||||||
scrollToIndex = index + 1
|
scrollToIndex = index + 1
|
||||||
} else {
|
} else {
|
||||||
// Restore cache and scroll to top.
|
// Restore cache and scroll to top.
|
||||||
|
@ -309,6 +303,23 @@ extension TimelineViewModel: StatusesFetcher {
|
||||||
return newStatuses
|
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 {
|
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)
|
||||||
|
@ -332,7 +343,6 @@ extension TimelineViewModel: StatusesFetcher {
|
||||||
private func updateTimelineWithScrollToTop(newStatuses: [Status], statuses: [Status], nextPageState: StatusesState.PagingState) {
|
private func updateTimelineWithScrollToTop(newStatuses: [Status], statuses: [Status], nextPageState: StatusesState.PagingState) {
|
||||||
pendingStatusesObserver.disableUpdate = true
|
pendingStatusesObserver.disableUpdate = true
|
||||||
statusesState = .display(statuses: statuses, nextPageState: nextPageState)
|
statusesState = .display(statuses: statuses, nextPageState: nextPageState)
|
||||||
scrollToIndexAnimated = false
|
|
||||||
scrollToIndex = newStatuses.count + 1
|
scrollToIndex = newStatuses.count + 1
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
@ -437,8 +447,10 @@ extension TimelineViewModel {
|
||||||
await datasource.insert(event.status, at: 0)
|
await datasource.insert(event.status, at: 0)
|
||||||
await cache()
|
await cache()
|
||||||
StatusDataControllerProvider.shared.updateDataControllers(for: [event.status], client: client)
|
StatusDataControllerProvider.shared.updateDataControllers(for: [event.status], client: client)
|
||||||
|
if scrollToTopVisible, pendingStatusesObserver.pendingStatuses.isEmpty {
|
||||||
await updateStatusesState()
|
await updateStatusesState()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func handleDeleteEvent(_ event: StreamEventDelete) async {
|
private func handleDeleteEvent(_ event: StreamEventDelete) async {
|
||||||
await datasource.remove(event.status)
|
await datasource.remove(event.status)
|
||||||
|
|
Loading…
Reference in a new issue