Use a static room summary provider to resolve room summaries through id and aliases (#3863)

* trying to debug why sometimes the value

is missing even if it appears in the room list

* static room provider implementation

* set the page size through the init

* removed reset filters on .cancel

since using the sop function is safer
This commit is contained in:
Mauro 2025-03-04 14:08:15 +01:00 committed by GitHub
parent 56d8af1d2e
commit 319441d527
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 179 additions and 60 deletions

View File

@ -35,6 +35,7 @@ extension ClientProxyMock {
roomSummaryProvider = configuration.roomSummaryProvider
alternateRoomSummaryProvider = RoomSummaryProviderMock(.init())
staticRoomSummaryProvider = RoomSummaryProviderMock(.init())
roomDirectorySearchProxyReturnValue = configuration.roomDirectorySearchProxy

View File

@ -2268,12 +2268,13 @@ class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
var underlyingIgnoredUsersPublisher: CurrentValuePublisher<[String]?, Never>!
var pusherNotificationClientIdentifier: String?
var roomSummaryProvider: RoomSummaryProviderProtocol?
var alternateRoomSummaryProvider: RoomSummaryProviderProtocol?
var staticRoomSummaryProvider: StaticRoomSummaryProviderProtocol?
var roomsToAwait: Set<String> {
get { return underlyingRoomsToAwait }
set(value) { underlyingRoomsToAwait = value }
}
var underlyingRoomsToAwait: Set<String>!
var alternateRoomSummaryProvider: RoomSummaryProviderProtocol?
var notificationSettings: NotificationSettingsProxyProtocol {
get { return underlyingNotificationSettings }
set(value) { underlyingNotificationSettings = value }
@ -13589,58 +13590,17 @@ class RoomProxyMock: RoomProxyProtocol, @unchecked Sendable {
}
class RoomSummaryProviderMock: RoomSummaryProviderProtocol, @unchecked Sendable {
var roomListPublisher: CurrentValuePublisher<[RoomSummary], Never> {
get { return underlyingRoomListPublisher }
set(value) { underlyingRoomListPublisher = value }
}
var underlyingRoomListPublisher: CurrentValuePublisher<[RoomSummary], Never>!
var statePublisher: CurrentValuePublisher<RoomSummaryProviderState, Never> {
get { return underlyingStatePublisher }
set(value) { underlyingStatePublisher = value }
}
var underlyingStatePublisher: CurrentValuePublisher<RoomSummaryProviderState, Never>!
//MARK: - setRoomList
var setRoomListUnderlyingCallsCount = 0
var setRoomListCallsCount: Int {
get {
if Thread.isMainThread {
return setRoomListUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = setRoomListUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
setRoomListUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
setRoomListUnderlyingCallsCount = newValue
}
}
}
var roomListPublisher: CurrentValuePublisher<[RoomSummary], Never> {
get { return underlyingRoomListPublisher }
set(value) { underlyingRoomListPublisher = value }
}
var setRoomListCalled: Bool {
return setRoomListCallsCount > 0
}
var setRoomListReceivedRoomList: RoomList?
var setRoomListReceivedInvocations: [RoomList] = []
var setRoomListClosure: ((RoomList) -> Void)?
var underlyingRoomListPublisher: CurrentValuePublisher<[RoomSummary], Never>!
func setRoomList(_ roomList: RoomList) {
setRoomListCallsCount += 1
setRoomListReceivedRoomList = roomList
DispatchQueue.main.async {
self.setRoomListReceivedInvocations.append(roomList)
}
setRoomListClosure?(roomList)
}
//MARK: - updateVisibleRange
var updateVisibleRangeUnderlyingCallsCount = 0
@ -13723,6 +13683,47 @@ class RoomSummaryProviderMock: RoomSummaryProviderProtocol, @unchecked Sendable
}
setFilterClosure?(filter)
}
//MARK: - setRoomList
var setRoomListUnderlyingCallsCount = 0
var setRoomListCallsCount: Int {
get {
if Thread.isMainThread {
return setRoomListUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = setRoomListUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
setRoomListUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
setRoomListUnderlyingCallsCount = newValue
}
}
}
}
var setRoomListCalled: Bool {
return setRoomListCallsCount > 0
}
var setRoomListReceivedRoomList: RoomList?
var setRoomListReceivedInvocations: [RoomList] = []
var setRoomListClosure: ((RoomList) -> Void)?
func setRoomList(_ roomList: RoomList) {
setRoomListCallsCount += 1
setRoomListReceivedRoomList = roomList
DispatchQueue.main.async {
self.setRoomListReceivedInvocations.append(roomList)
}
setRoomListClosure?(roomList)
}
}
class SecureBackupControllerMock: SecureBackupControllerProtocol, @unchecked Sendable {
var recoveryState: CurrentValuePublisher<SecureBackupRecoveryState, Never> {
@ -14595,6 +14596,55 @@ class SessionVerificationControllerProxyMock: SessionVerificationControllerProxy
}
}
}
class StaticRoomSummaryProviderMock: StaticRoomSummaryProviderProtocol, @unchecked Sendable {
var roomListPublisher: CurrentValuePublisher<[RoomSummary], Never> {
get { return underlyingRoomListPublisher }
set(value) { underlyingRoomListPublisher = value }
}
var underlyingRoomListPublisher: CurrentValuePublisher<[RoomSummary], Never>!
//MARK: - setRoomList
var setRoomListUnderlyingCallsCount = 0
var setRoomListCallsCount: Int {
get {
if Thread.isMainThread {
return setRoomListUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = setRoomListUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
setRoomListUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
setRoomListUnderlyingCallsCount = newValue
}
}
}
}
var setRoomListCalled: Bool {
return setRoomListCallsCount > 0
}
var setRoomListReceivedRoomList: RoomList?
var setRoomListReceivedInvocations: [RoomList] = []
var setRoomListClosure: ((RoomList) -> Void)?
func setRoomList(_ roomList: RoomList) {
setRoomListCallsCount += 1
setRoomListReceivedRoomList = roomList
DispatchQueue.main.async {
self.setRoomListReceivedInvocations.append(roomList)
}
setRoomListClosure?(roomList)
}
}
class TimelineControllerFactoryMock: TimelineControllerFactoryProtocol, @unchecked Sendable {
//MARK: - buildTimelineController

View File

@ -51,4 +51,8 @@ class GlobalSearchScreenCoordinator: CoordinatorProtocol {
func toPresentable() -> AnyView {
AnyView(GlobalSearchScreen(context: viewModel.context))
}
func stop() {
viewModel.stop()
}
}

View File

@ -47,6 +47,11 @@ class GlobalSearchScreenViewModel: GlobalSearchScreenViewModelType, GlobalSearch
updateRooms(with: roomSummaryProvider.roomListPublisher.value)
}
func stop() {
// This is a shared provider so we should reset the filtering when we are done with the view
roomSummaryProvider.setFilter(.all(filters: []))
}
// MARK: - Public
override func process(viewAction: GlobalSearchScreenViewAction) {
@ -55,7 +60,6 @@ class GlobalSearchScreenViewModel: GlobalSearchScreenViewModelType, GlobalSearch
switch viewAction {
case .dismiss:
actionsSubject.send(.dismiss)
roomSummaryProvider.setFilter(.all(filters: [])) // This is a shared provider
case .select(let roomID):
actionsSubject.send(.select(roomID: roomID))
case .reachedTop:

View File

@ -11,4 +11,6 @@ import Combine
protocol GlobalSearchScreenViewModelProtocol {
var actions: AnyPublisher<GlobalSearchScreenViewModelAction, Never> { get }
var context: GlobalSearchScreenViewModelType.Context { get }
func stop()
}

View File

@ -140,7 +140,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
roomInfo = invitedRoomProxy.info
case .knocked(let knockedRoomProxy):
roomInfo = knockedRoomProxy.info
if let roomSummaryProvider = clientProxy.alternateRoomSummaryProvider {
if let roomSummaryProvider = clientProxy.staticRoomSummaryProvider {
membershipStateChangeCancellable = roomSummaryProvider.roomListPublisher
.compactMap { summaries -> Void? in
guard let roomSummary = summaries.first(where: { $0.id == roomInfo?.id }),

View File

@ -53,4 +53,8 @@ final class MessageForwardingScreenCoordinator: CoordinatorProtocol {
func toPresentable() -> AnyView {
AnyView(MessageForwardingScreen(context: viewModel.context))
}
func stop() {
viewModel.stop()
}
}

View File

@ -60,7 +60,6 @@ class MessageForwardingScreenViewModel: MessageForwardingScreenViewModelType, Me
switch viewAction {
case .cancel:
actionsSubject.send(.dismiss)
roomSummaryProvider.setFilter(.all(filters: []))
case .send:
Task { await forward() }
case .selectRoom(let roomID):
@ -72,6 +71,11 @@ class MessageForwardingScreenViewModel: MessageForwardingScreenViewModelType, Me
}
}
func stop() {
// This is a shared provider so we should reset the filtering when we are done with the view
roomSummaryProvider.setFilter(.all(filters: []))
}
// MARK: - Private
private func updateRooms() {

View File

@ -11,4 +11,6 @@ import Combine
protocol MessageForwardingScreenViewModelProtocol {
var actions: AnyPublisher<MessageForwardingScreenViewModelAction, Never> { get }
var context: MessageForwardingScreenViewModelType.Context { get }
func stop()
}

View File

@ -46,6 +46,10 @@ final class RoomSelectionScreenCoordinator: CoordinatorProtocol {
.store(in: &cancellables)
}
func stop() {
viewModel.stop()
}
func toPresentable() -> AnyView {
AnyView(RoomSelectionScreen(context: viewModel.context))
}

View File

@ -54,7 +54,6 @@ class RoomSelectionScreenViewModel: RoomSelectionScreenViewModelType, RoomSelect
switch viewAction {
case .cancel:
actionsSubject.send(.dismiss)
roomSummaryProvider.setFilter(.all(filters: []))
case .confirm:
guard let selectedRoomID = state.selectedRoomID else {
return
@ -70,6 +69,11 @@ class RoomSelectionScreenViewModel: RoomSelectionScreenViewModelType, RoomSelect
}
}
func stop() {
// This is a shared provider so we should reset the filtering when we are done with the view
roomSummaryProvider.setFilter(.all(filters: []))
}
// MARK: - Private
private func updateRooms() {

View File

@ -11,4 +11,6 @@ import Combine
protocol RoomSelectionScreenViewModelProtocol {
var actionsPublisher: AnyPublisher<RoomSelectionScreenViewModelAction, Never> { get }
var context: RoomSelectionScreenViewModelType.Context { get }
func stop()
}

View File

@ -46,6 +46,8 @@ class ClientProxy: ClientProxyProtocol {
private(set) var roomSummaryProvider: RoomSummaryProviderProtocol?
private(set) var alternateRoomSummaryProvider: RoomSummaryProviderProtocol?
private(set) var staticRoomSummaryProvider: StaticRoomSummaryProviderProtocol?
let notificationSettings: NotificationSettingsProxyProtocol
let secureBackupController: SecureBackupControllerProtocol
@ -523,14 +525,32 @@ class ClientProxy: ClientProxyProtocol {
func roomSummaryForIdentifier(_ identifier: String) -> RoomSummary? {
// the alternate room summary provider is not impacted by filtering
alternateRoomSummaryProvider?.roomListPublisher.value.first { $0.id == identifier }
guard let provider = staticRoomSummaryProvider else {
MXLog.verbose("Missing room summary provider")
return nil
}
guard let roomSummary = provider.roomListPublisher.value.first(where: { $0.id == identifier }) else {
MXLog.verbose("Missing room summary, count: \(provider.roomListPublisher.value.count)")
return nil
}
return roomSummary
}
func roomSummaryForAlias(_ alias: String) -> RoomSummary? {
// the alternate room summary provider is not impacted by filtering
alternateRoomSummaryProvider?.roomListPublisher.value.first { roomSummary in
roomSummary.canonicalAlias == alias || roomSummary.alternativeAliases.contains(alias)
guard let provider = staticRoomSummaryProvider else {
MXLog.verbose("Missing room summary provider")
return nil
}
guard let roomSummary = provider.roomListPublisher.value.first(where: { $0.canonicalAlias == alias || $0.alternativeAliases.contains(alias) }) else {
MXLog.verbose("Missing room summary, count: \(provider.roomListPublisher.value.count)")
return nil
}
return roomSummary
}
func loadUserDisplayName() async -> Result<Void, ClientProxyError> {
@ -847,6 +867,14 @@ class ClientProxy: ClientProxyProtocol {
appSettings: appSettings)
try await alternateRoomSummaryProvider?.setRoomList(roomListService.allRooms())
staticRoomSummaryProvider = RoomSummaryProvider(roomListService: roomListService,
eventStringBuilder: eventStringBuilder,
name: "StaticAllRooms",
roomListPageSize: .max,
notificationSettings: notificationSettings,
appSettings: appSettings)
try await staticRoomSummaryProvider?.setRoomList(roomListService.allRooms())
self.syncService = syncService
self.roomListService = roomListService

View File

@ -96,11 +96,16 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
var roomSummaryProvider: RoomSummaryProviderProtocol? { get }
var roomsToAwait: Set<String> { get set }
/// Used for listing rooms that shouldn't be affected by the main `roomSummaryProvider` filtering
/// But can still be filtered by queries, since this may be shared across multiple views, remember to reset
/// The filtering state when you are done with it
var alternateRoomSummaryProvider: RoomSummaryProviderProtocol? { get }
/// Used for listing rooms, can't be filtered nor its state observed
var staticRoomSummaryProvider: StaticRoomSummaryProviderProtocol? { get }
var roomsToAwait: Set<String> { get set }
var notificationSettings: NotificationSettingsProxyProtocol { get }
var secureBackupController: SecureBackupControllerProtocol { get }

View File

@ -17,7 +17,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
private let notificationSettings: NotificationSettingsProxyProtocol
private let appSettings: AppSettings
private let roomListPageSize = 200
private let roomListPageSize: UInt32
private let serialDispatchQueue: DispatchQueue
@ -59,6 +59,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
eventStringBuilder: RoomEventStringBuilder,
name: String,
shouldUpdateVisibleRange: Bool = false,
roomListPageSize: UInt32 = 200,
notificationSettings: NotificationSettingsProxyProtocol,
appSettings: AppSettings) {
self.roomListService = roomListService
@ -68,6 +69,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
self.shouldUpdateVisibleRange = shouldUpdateVisibleRange
self.notificationSettings = notificationSettings
self.appSettings = appSettings
self.roomListPageSize = roomListPageSize
diffsPublisher
.receive(on: serialDispatchQueue)

View File

@ -42,15 +42,18 @@ enum RoomSummaryProviderFilter: Equatable {
}
// sourcery: AutoMockable
protocol RoomSummaryProviderProtocol {
protocol StaticRoomSummaryProviderProtocol {
/// Publishes the currently available room summaries
var roomListPublisher: CurrentValuePublisher<[RoomSummary], Never> { get }
func setRoomList(_ roomList: RoomList)
}
// sourcery: AutoMockable
protocol RoomSummaryProviderProtocol: StaticRoomSummaryProviderProtocol {
/// Publishes the current state the summary provider is finding itself in
var statePublisher: CurrentValuePublisher<RoomSummaryProviderState, Never> { get }
func setRoomList(_ roomList: RoomList)
func updateVisibleRange(_ range: Range<Int>)
func setFilter(_ filter: RoomSummaryProviderFilter)