Skip to content

Commit

Permalink
Dynamically adjusting the visibleRoomsView's timeline limit based on …
Browse files Browse the repository at this point in the history
…the app state
  • Loading branch information
stefanceriu committed Jan 31, 2023
1 parent a8f1547 commit 8f3842f
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 24 deletions.
3 changes: 3 additions & 0 deletions ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// limitations under the License.
//

import Combine
import Foundation
import UIKit

Expand Down Expand Up @@ -90,6 +91,8 @@ struct HomeScreenViewState: BindableState {
struct HomeScreenViewStateBindings {
var searchQuery = ""

var isScrolling = false

var alertInfo: AlertInfo<UUID>?
}

Expand Down
18 changes: 14 additions & 4 deletions ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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 }

Expand All @@ -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)
}
}
25 changes: 18 additions & 7 deletions ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand All @@ -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)
}

Expand Down
22 changes: 15 additions & 7 deletions ElementX/Sources/Services/Client/ClientProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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
}
}
Expand Down Expand Up @@ -349,13 +349,21 @@ class ClientProxy: ClientProxyProtocol {
tags: [],
notTags: [])

private func registerAllRoomSlidingSyncView() {
guard let allRoomsSlidingSyncView else {
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")
return
}

_ = slidingSync?.addView(view: allRoomsSlidingSyncView)
restartSync()
}

Expand Down
6 changes: 6 additions & 0 deletions ElementX/Sources/Services/Client/ClientProxyProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
5 changes: 3 additions & 2 deletions ElementX/Sources/Services/Client/SlidingSyncViewProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class MockRoomSummaryProvider: RoomSummaryProviderProtocol {
}
}

func updateVisibleRange(_ range: Range<Int>) { }
func updateVisibleRange(_ range: Range<Int>, timelineLimit: UInt) { }

// MARK: - Private

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

0 comments on commit 8f3842f

Please sign in to comment.