Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamically adjusting the visibleRoomsView's timeline limit based on … #507

Merged
merged 1 commit into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}