New SlidingSync flow (#373)

* Switch back to using slidingSync rooms for timeline listeners

* Expose 2 types of slidingSync views from the clientProxy and combine their results for the roomList

* Fix breaking api changes

* Remove sender mxids from the room list (until rust provides resolved display names)

* Bump RustSDK to v1.0.22-alpha

* Rename originServerTs to timestamp throughout

* Simplified sliding sync view list merging

* Rollback some SS changes as things still don't work properly

* Revert "Switch back to using slidingSync rooms for timeline listeners"

This reverts commit 1d6a6c09d8ddf386edefbe0ac6beaf52cc333fba.
This commit is contained in:
Stefan Ceriu
2022-12-16 14:05:08 +02:00
committed by GitHub
parent 6f974a4422
commit ab10278ff5
13 changed files with 119 additions and 76 deletions
@@ -21,7 +21,8 @@ typealias HomeScreenViewModelType = StateStoreViewModel<HomeScreenViewState, Hom
class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol {
private let userSession: UserSessionProtocol
private let roomSummaryProvider: RoomSummaryProviderProtocol?
private let visibleRoomsSummaryProvider: RoomSummaryProviderProtocol?
private let allRoomsSummaryProvider: RoomSummaryProviderProtocol?
private let attributedStringBuilder: AttributedStringBuilderProtocol
private var roomsForIdentifiers = [String: HomeScreenRoom]()
@@ -32,9 +33,11 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
// swiftlint:disable:next function_body_length
init(userSession: UserSessionProtocol, attributedStringBuilder: AttributedStringBuilderProtocol) {
self.userSession = userSession
roomSummaryProvider = userSession.clientProxy.roomSummaryProvider
self.attributedStringBuilder = attributedStringBuilder
visibleRoomsSummaryProvider = userSession.clientProxy.visibleRoomsSummaryProvider
allRoomsSummaryProvider = userSession.clientProxy.allRoomsSummaryProvider
super.init(initialViewState: HomeScreenViewState(userID: userSession.userID))
userSession.callbacks
@@ -65,14 +68,15 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
}
}
guard let roomSummaryProvider else {
guard let visibleRoomsSummaryProvider, let allRoomsSummaryProvider else {
MXLog.error("Room summary provider unavailable")
return
}
Publishers.CombineLatest3(roomSummaryProvider.statePublisher,
roomSummaryProvider.countPublisher,
roomSummaryProvider.roomListPublisher)
// Combine all 3 publishers to correctly compute the screen state
Publishers.CombineLatest3(visibleRoomsSummaryProvider.statePublisher,
visibleRoomsSummaryProvider.countPublisher,
visibleRoomsSummaryProvider.roomListPublisher)
.receive(on: DispatchQueue.main)
.sink { [weak self] state, totalCount, rooms in
if state != .live {
@@ -89,7 +93,16 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
}
.store(in: &cancellables)
roomSummaryProvider.roomListPublisher
// Listen to changes from both roomSummaryProviders and update state accordingly
visibleRoomsSummaryProvider.roomListPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
self?.updateRooms()
}
.store(in: &cancellables)
allRoomsSummaryProvider.roomListPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
self?.updateRooms()
@@ -127,12 +140,12 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
// MARK: - Private
private func loadDataForRoomIdentifier(_ identifier: String) {
guard let roomSummaryProvider else {
guard let visibleRoomsSummaryProvider else {
MXLog.error("Room summary provider unavailable")
return
}
guard let roomSummary = roomSummaryProvider.roomListPublisher.value.first(where: { $0.asFilled?.id == identifier })?.asFilled,
guard let roomSummary = visibleRoomsSummaryProvider.roomListPublisher.value.first(where: { $0.asFilled?.id == identifier })?.asFilled,
let roomIndex = state.rooms.firstIndex(where: { $0.id == identifier }) else {
return
}
@@ -153,8 +166,11 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
}
}
/// This method will update all view state rooms by merging the data from both summary providers
/// If a room is empty in the visible room summary provider it will try to get it from the allRooms one
/// This ensures that we show as many room details as possible without loading up timelines
private func updateRooms() {
guard let roomSummaryProvider else {
guard let visibleRoomsSummaryProvider else {
MXLog.error("Room summary provider unavailable")
return
}
@@ -162,27 +178,19 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
var rooms = [HomeScreenRoom]()
var newRoomsForIdentifiers = [String: HomeScreenRoom]()
for summary in roomSummaryProvider.roomListPublisher.value {
for (index, summary) in visibleRoomsSummaryProvider.roomListPublisher.value.enumerated() {
switch summary {
case .empty(let id):
rooms.append(HomeScreenRoom.placeholder(id: id))
case .filled(let summary):
let oldRoom = roomsForIdentifiers[summary.id]
let avatarImage = userSession.mediaProvider.imageFromURLString(summary.avatarURLString, avatarSize: .room(on: .home))
var timestamp: String?
if let lastMessageTimestamp = summary.lastMessageTimestamp {
timestamp = lastMessageTimestamp.formatted(date: .omitted, time: .shortened)
guard case let .filled(summary) = allRoomsSummaryProvider?.roomListPublisher.value[safe: index] else {
rooms.append(HomeScreenRoom.placeholder(id: id))
continue
}
let room = HomeScreenRoom(id: summary.id,
name: summary.name,
hasUnreads: summary.unreadNotificationCount > 0,
timestamp: timestamp ?? oldRoom?.timestamp,
lastMessage: summary.lastMessage ?? oldRoom?.lastMessage,
avatar: avatarImage ?? oldRoom?.avatar)
let room = buildRoomForSummary(summary)
rooms.append(room)
newRoomsForIdentifiers[summary.id] = room
case .filled(let summary):
let room = buildRoomForSummary(summary)
rooms.append(room)
newRoomsForIdentifiers[summary.id] = room
}
@@ -192,6 +200,24 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
roomsForIdentifiers = newRoomsForIdentifiers
}
private func buildRoomForSummary(_ summary: RoomSummaryDetails) -> HomeScreenRoom {
let oldRoom = roomsForIdentifiers[summary.id]
let avatarImage = userSession.mediaProvider.imageFromURLString(summary.avatarURLString, avatarSize: .room(on: .home))
var timestamp: String?
if let lastMessageTimestamp = summary.lastMessageTimestamp {
timestamp = lastMessageTimestamp.formatted(date: .omitted, time: .shortened)
}
return HomeScreenRoom(id: summary.id,
name: summary.name,
hasUnreads: summary.unreadNotificationCount > 0,
timestamp: timestamp ?? oldRoom?.timestamp,
lastMessage: summary.lastMessage ?? oldRoom?.lastMessage,
avatar: avatarImage ?? oldRoom?.avatar)
}
private func updateVisibleRange(visibleItemIdentifiers items: Set<String>) {
let result = items.compactMap { itemIdentifier in
state.rooms.firstIndex { $0.id == itemIdentifier }
@@ -205,6 +231,6 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
return
}
userSession.clientProxy.roomSummaryProvider?.updateVisibleRange(lowerBound...upperBound)
visibleRoomsSummaryProvider?.updateVisibleRange(lowerBound...upperBound)
}
}