Prefetch the next room list page before reaching the bottom

Growing the list only once the last row was already visible, on top of the half a
second visible range throttle, meant hitting and bouncing off the end of the list
while the next page loaded. Ask for the next page half a page early instead, so
the growth happens while the user is still scrolling towards the boundary.

The threshold is clamped so that it stays positive for accounts with fewer rooms
than half a page, where it would otherwise always match and leave the list unable
to shrink back to a single page.
This commit is contained in:
Stefan Ceriu
2026-08-18 16:57:42 +03:00
parent e7787f4c3f
commit 9dd9fd9176
2 changed files with 37 additions and 5 deletions
@@ -19,6 +19,8 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
private let appSettings: AppSettings
private let roomListPageSize: UInt32
/// Remember how many rooms we had on the previous requests so we can deduplicate
private var roomCountOnLastPageAddRequest = -1
private let visibleItemRangePublisher = CurrentValueSubject<Range<Int>, Never>(0..<0)
@@ -182,6 +184,24 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
// MARK: - Private
private func setupVisibleRangeObservers() {
// Unthrottled to add another page half way through the last one
visibleItemRangePublisher
.sink { [weak self] range in
guard let self,
!range.isEmpty,
range.upperBound >= rooms.count - Int(roomListPageSize) / 2,
rooms.count != roomCountOnLastPageAddRequest else {
return
}
roomCountOnLastPageAddRequest = rooms.count
MXLog.info("\(self.name): Adding a page at \(rooms.count) rooms, visible range: \(range)")
listUpdatesSubscriptionResult?.controller().addOnePage()
}
.store(in: &cancellables)
visibleItemRangePublisher
.throttle(for: 0.5, scheduler: DispatchQueue.main, latest: true)
.removeDuplicates()
@@ -190,9 +210,8 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
MXLog.info("\(self.name): Updating visible range: \(range)")
if range.upperBound >= rooms.count {
listUpdatesSubscriptionResult?.controller().addOnePage()
} else if range.lowerBound == 0 {
if range.lowerBound == 0, range.upperBound < rooms.count {
roomCountOnLastPageAddRequest = -1
listUpdatesSubscriptionResult?.controller().resetToOnePage()
}
}
@@ -215,6 +234,8 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
range = range.lowerBound..<upperBound
}
MXLog.info("\(self.name): Subscribing to rooms in range: \(range)")
return range
.filter { $0 < self.rooms.count }
.map { self.rooms[$0].id }