Dynamically adjusting the visibleRoomsView's timeline limit based on the app state
This commit is contained in:
committed by
Stefan Ceriu
parent
0063b9ef11
commit
a6f255d203
@@ -14,6 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
@@ -90,6 +91,8 @@ struct HomeScreenViewState: BindableState {
|
||||
struct HomeScreenViewStateBindings {
|
||||
var searchQuery = ""
|
||||
|
||||
var isScrolling = false
|
||||
|
||||
var alertInfo: AlertInfo<UUID>?
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
|
||||
var callback: ((HomeScreenViewModelAction) -> Void)?
|
||||
|
||||
// swiftlint:disable:next function_body_length
|
||||
// swiftlint:disable:next function_body_length cyclomatic_complexity
|
||||
init(userSession: UserSessionProtocol, attributedStringBuilder: AttributedStringBuilderProtocol) {
|
||||
self.userSession = userSession
|
||||
self.attributedStringBuilder = attributedStringBuilder
|
||||
@@ -64,7 +64,17 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
.debounce(for: 0.1, scheduler: DispatchQueue.main)
|
||||
.removeDuplicates()
|
||||
.sink { [weak self] range in
|
||||
self?.updateVisibleRange(range)
|
||||
guard let self else { return }
|
||||
|
||||
guard self.state.bindings.searchQuery.isEmpty else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.state.bindings.isScrolling {
|
||||
self.updateVisibleRange(range, timelineLimit: SlidingSyncConstants.lastMessageTimelineLimit)
|
||||
} else {
|
||||
self.updateVisibleRange(range, timelineLimit: SlidingSyncConstants.timelinePrecachingTimelineLimit)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
@@ -234,7 +244,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
return room
|
||||
}
|
||||
|
||||
private func updateVisibleRange(_ range: Range<Int>) {
|
||||
private func updateVisibleRange(_ range: Range<Int>, timelineLimit: UInt) {
|
||||
guard visibleRoomsSummaryProvider?.statePublisher.value == .live,
|
||||
!range.isEmpty else { return }
|
||||
|
||||
@@ -246,6 +256,6 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
let lowerBound = max(0, range.lowerBound - Constants.slidingWindowBoundsPadding)
|
||||
let upperBound = min(Int(visibleRoomsSummaryProvider.countPublisher.value), range.upperBound + Constants.slidingWindowBoundsPadding)
|
||||
|
||||
visibleRoomsSummaryProvider.updateVisibleRange(lowerBound..<upperBound)
|
||||
visibleRoomsSummaryProvider.updateVisibleRange(lowerBound..<upperBound, timelineLimit: timelineLimit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,10 @@ import SwiftUI
|
||||
struct HomeScreen: View {
|
||||
@ObservedObject var context: HomeScreenViewModel.Context
|
||||
|
||||
@State private var scrollViewAdapter = ScrollViewAdapter()
|
||||
@State private var showingLogoutConfirmation = false
|
||||
@State private var visibleItemIdentifiers = Set<String>() {
|
||||
didSet {
|
||||
if visibleItemIdentifiers != oldValue {
|
||||
updateVisibleRange()
|
||||
}
|
||||
}
|
||||
}
|
||||
@State private var visibleItemIdentifiers = Set<String>()
|
||||
@State private var hasTriggeredInitialVisibleItemUpdate = false
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
@@ -65,6 +61,10 @@ struct HomeScreen: View {
|
||||
.disableAutocorrection(true)
|
||||
}
|
||||
}
|
||||
.introspectScrollView { scrollView in
|
||||
guard scrollView != scrollViewAdapter.scrollView else { return }
|
||||
scrollViewAdapter.scrollView = scrollView
|
||||
}
|
||||
.scrollDismissesKeyboard(.immediately)
|
||||
.disabled(context.viewState.roomListMode == .skeletons)
|
||||
.animation(.elementDefault, value: context.viewState.showSessionVerificationBanner)
|
||||
@@ -76,6 +76,17 @@ struct HomeScreen: View {
|
||||
userMenuButton
|
||||
}
|
||||
}
|
||||
.onChange(of: visibleItemIdentifiers) { _ in
|
||||
if !hasTriggeredInitialVisibleItemUpdate {
|
||||
updateVisibleRange()
|
||||
hasTriggeredInitialVisibleItemUpdate = true
|
||||
}
|
||||
}
|
||||
.onReceive(scrollViewAdapter.isScrolling) { isScrolling in
|
||||
context.isScrolling = isScrolling
|
||||
|
||||
updateVisibleRange()
|
||||
}
|
||||
.background(Color.element.background)
|
||||
}
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ class ClientProxy: ClientProxyProtocol {
|
||||
// Build the visibleRoomsSlidingSyncView here so that it can take advantage of the SS builder cold cache
|
||||
// We will still register the allRoomsSlidingSyncView later, and than will have no cache
|
||||
let visibleRoomsView = try SlidingSyncViewBuilder()
|
||||
.timelineLimit(limit: 1)
|
||||
.timelineLimit(limit: UInt32(SlidingSyncConstants.initialTimelineLimit)) // Starts off with zero to quickly load rooms, then goes to 1 while scrolling to quickly load last messages and 20 when the scrolling stops to load room history
|
||||
.requiredState(requiredState: slidingSyncRequiredState)
|
||||
.filters(filters: slidingSyncFilters)
|
||||
.name(name: "CurrentlyVisibleRooms")
|
||||
@@ -301,8 +301,8 @@ class ClientProxy: ClientProxyProtocol {
|
||||
|
||||
// The allRoomsSlidingSyncView will be registered as soon as the visibleRoomsSlidingSyncView receives its first update
|
||||
visibleRoomsViewProxyStateObservationToken = visibleRoomsViewProxy.diffPublisher.sink { [weak self] _ in
|
||||
MXLog.info("Visible rooms view received first update, registering all rooms view")
|
||||
self?.registerAllRoomSlidingSyncView()
|
||||
MXLog.info("Visible rooms view received first update, configuring views post initial sync")
|
||||
self?.configureViewsPostInitialSync()
|
||||
self?.visibleRoomsViewProxyStateObservationToken = nil
|
||||
}
|
||||
}
|
||||
@@ -349,13 +349,21 @@ class ClientProxy: ClientProxyProtocol {
|
||||
tags: [],
|
||||
notTags: [])
|
||||
|
||||
private func registerAllRoomSlidingSyncView() {
|
||||
guard let allRoomsSlidingSyncView else {
|
||||
MXLog.error("All rooms sliding sync view unavailable")
|
||||
return
|
||||
private func configureViewsPostInitialSync() {
|
||||
if let visibleRoomsSlidingSyncView {
|
||||
MXLog.info("Setting visible rooms view timeline limit to \(SlidingSyncConstants.lastMessageTimelineLimit)")
|
||||
visibleRoomsSlidingSyncView.setTimelineLimit(value: UInt32(SlidingSyncConstants.lastMessageTimelineLimit))
|
||||
} else {
|
||||
MXLog.error("Visible rooms sliding sync view unavailable")
|
||||
}
|
||||
|
||||
if let allRoomsSlidingSyncView {
|
||||
MXLog.info("Registering all rooms view")
|
||||
_ = slidingSync?.addView(view: allRoomsSlidingSyncView)
|
||||
} else {
|
||||
MXLog.error("All rooms sliding sync view unavailable")
|
||||
}
|
||||
|
||||
_ = slidingSync?.addView(view: allRoomsSlidingSyncView)
|
||||
restartSync()
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,12 @@ enum PushFormat {
|
||||
// }
|
||||
}
|
||||
|
||||
enum SlidingSyncConstants {
|
||||
static let initialTimelineLimit: UInt = 0
|
||||
static let lastMessageTimelineLimit: UInt = 1
|
||||
static let timelinePrecachingTimelineLimit: UInt = 20
|
||||
}
|
||||
|
||||
protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
|
||||
var callbacks: PassthroughSubject<ClientProxyCallback, Never> { get }
|
||||
|
||||
|
||||
@@ -102,10 +102,11 @@ class SlidingSyncViewProxy {
|
||||
try slidingSync.getRoom(roomId: identifier)
|
||||
}
|
||||
|
||||
func updateVisibleRange(_ range: Range<Int>) {
|
||||
MXLog.info("Setting sliding sync view range to \(range)")
|
||||
func updateVisibleRange(_ range: Range<Int>, timelineLimit: UInt) {
|
||||
MXLog.info("Setting sliding sync view range to \(range), timelineLimit: \(timelineLimit)")
|
||||
|
||||
slidingSyncView.setRange(start: UInt32(range.lowerBound), end: UInt32(range.upperBound))
|
||||
slidingSyncView.setTimelineLimit(value: UInt32(timelineLimit))
|
||||
|
||||
visibleRangeUpdatePublisher.send(())
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class MockRoomSummaryProvider: RoomSummaryProviderProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func updateVisibleRange(_ range: Range<Int>) { }
|
||||
func updateVisibleRange(_ range: Range<Int>, timelineLimit: UInt) { }
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
|
||||
@@ -61,8 +61,8 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func updateVisibleRange(_ range: Range<Int>) {
|
||||
slidingSyncViewProxy.updateVisibleRange(range)
|
||||
func updateVisibleRange(_ range: Range<Int>, timelineLimit: UInt) {
|
||||
slidingSyncViewProxy.updateVisibleRange(range, timelineLimit: timelineLimit)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@@ -50,5 +50,5 @@ protocol RoomSummaryProviderProtocol {
|
||||
/// Publishes the total number of rooms
|
||||
var countPublisher: CurrentValueSubject<UInt, Never> { get }
|
||||
|
||||
func updateVisibleRange(_ range: Range<Int>)
|
||||
func updateVisibleRange(_ range: Range<Int>, timelineLimit: UInt)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user