Various sliding sync tweaks (#446)

* Refactor SS configuration and add (unfinished) support for adding views dynamically.

* Implement pop and clear support on the room summary provider

* Register views against sliding sync

* Read invalidated vislbeRoomsSummaryProvider from the allRoomSummaryProvider

* Switch SS window range setting from the ScrollViewAdapter to a publisher debounce

* Tweak allRoomsView addition: switch from listening the visibleRoomsView's state to when it publishes the first diff update

* Cleanup client delegate and sliding sync observers and lifecycle

* Bump the RustSDK to 1.0.30-alpha

* Reuse startSync within restartSync
This commit is contained in:
Stefan Ceriu
2023-01-13 17:09:37 +02:00
committed by GitHub
parent c383029203
commit 83e6ba8f6b
13 changed files with 215 additions and 137 deletions
@@ -39,7 +39,7 @@ enum HomeScreenViewAction {
case userMenu(action: HomeScreenViewUserMenuAction)
case verifySession
case skipSessionVerification
case updatedVisibleItemIdentifiers(Set<String>)
case updatedVisibleItemRange(Range<Int>)
}
enum HomeScreenRoomListMode {
@@ -20,11 +20,17 @@ import SwiftUI
typealias HomeScreenViewModelType = StateStoreViewModel<HomeScreenViewState, HomeScreenViewAction>
class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol {
enum Constants {
static let slidingWindowBoundsPadding = 5
}
private let userSession: UserSessionProtocol
private let visibleRoomsSummaryProvider: RoomSummaryProviderProtocol?
private let allRoomsSummaryProvider: RoomSummaryProviderProtocol?
private let attributedStringBuilder: AttributedStringBuilderProtocol
private let visibleItemRangePublisher = CurrentValueSubject<Range<Int>, Never>(0..<0)
var callback: ((HomeScreenViewModelAction) -> Void)?
// MARK: - Setup
@@ -53,6 +59,14 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
}
.store(in: &cancellables)
visibleItemRangePublisher
.debounce(for: 0.1, scheduler: RunLoop.main)
.removeDuplicates()
.sink { range in
self.updateVisibleRange(range)
}
.store(in: &cancellables)
Task {
if case let .success(userAvatarURLString) = await userSession.clientProxy.loadUserAvatarURLString() {
if case let .success(avatar) = await userSession.mediaProvider.loadImageFromURLString(userAvatarURLString, avatarSize: .user(on: .home)) {
@@ -136,8 +150,8 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
callback?(.presentSessionVerificationScreen)
case .skipSessionVerification:
state.showSessionVerificationBanner = false
case .updatedVisibleItemIdentifiers(let identifiers):
updateVisibleRange(visibleItemIdentifiers: identifiers)
case .updatedVisibleItemRange(let range):
visibleItemRangePublisher.send(range)
}
}
@@ -185,7 +199,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
for (index, summary) in visibleRoomsSummaryProvider.roomListPublisher.value.enumerated() {
switch summary {
case .empty:
case .empty, .invalidated:
guard let allRoomsRoomSummary = allRoomsSummaryProvider?.roomListPublisher.value[safe: index] else {
rooms.append(HomeScreenRoom.placeholder())
continue
@@ -201,9 +215,6 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
case .filled(let details):
let room = buildRoom(with: details, invalidated: false)
rooms.append(room)
case .invalidated(let details):
let room = buildRoom(with: details, invalidated: true)
rooms.append(room)
}
}
@@ -229,19 +240,17 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
avatar: avatarImage)
}
private func updateVisibleRange(visibleItemIdentifiers items: Set<String>) {
let result = items.compactMap { itemIdentifier in
state.rooms.firstIndex { $0.id == itemIdentifier }
}.sorted()
private func updateVisibleRange(_ range: Range<Int>) {
guard !range.isEmpty else { return }
guard !result.isEmpty else {
guard let visibleRoomsSummaryProvider else {
MXLog.error("Visible rooms summary provider unavailable")
return
}
guard let lowerBound = result.first, let upperBound = result.last else {
return
}
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)
}
}
@@ -17,12 +17,17 @@
import SwiftUI
struct HomeScreen: View {
@State private var showingLogoutConfirmation = false
@State private var visibleItemIdentifiers = Set<String>()
@State private var scrollViewAdapter = ScrollViewAdapter()
@ObservedObject var context: HomeScreenViewModel.Context
@State private var showingLogoutConfirmation = false
@State private var visibleItemIdentifiers = Set<String>() {
didSet {
if visibleItemIdentifiers != oldValue {
updateVisibleRange()
}
}
}
var body: some View {
ScrollView {
if context.viewState.showSessionVerificationBanner {
@@ -62,10 +67,6 @@ struct HomeScreen: View {
.disableAutocorrection(true)
}
}
.introspectScrollView { scrollView in
guard scrollView != scrollViewAdapter.scrollView else { return }
scrollViewAdapter.scrollView = scrollView
}
.disabled(context.viewState.roomListMode == .skeletons)
.animation(.elementDefault, value: context.viewState.showSessionVerificationBanner)
.animation(.elementDefault, value: context.viewState.roomListMode)
@@ -76,14 +77,6 @@ struct HomeScreen: View {
userMenuButton
}
}
.onReceive(scrollViewAdapter.isScrolling) { isScrolling in
guard context.viewState.bindings.searchQuery.isEmpty,
!isScrolling else {
return
}
context.send(viewAction: .updatedVisibleItemIdentifiers(visibleItemIdentifiers))
}
}
@ViewBuilder
@@ -191,6 +184,22 @@ struct HomeScreen: View {
private func signOut() {
context.send(viewAction: .userMenu(action: .signOut))
}
private func updateVisibleRange() {
let result = visibleItemIdentifiers.compactMap { itemIdentifier in
context.viewState.rooms.firstIndex { $0.id == itemIdentifier }
}.sorted()
guard !result.isEmpty else {
return
}
guard let firstIndex = result.first, let lastIndex = result.last else {
return
}
context.send(viewAction: .updatedVisibleItemRange(firstIndex..<lastIndex))
}
}
// MARK: - Previews