Skip to content

Commit

Permalink
Use a static room summary provider to resolve room summaries through …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Velin92 authored Mar 4, 2025
1 parent 56d8af1 commit 319441d
Show file tree
Hide file tree
Showing 16 changed files with 179 additions and 60 deletions.
1 change: 1 addition & 0 deletions ElementX/Sources/Mocks/ClientProxyMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ extension ClientProxyMock {

roomSummaryProvider = configuration.roomSummaryProvider
alternateRoomSummaryProvider = RoomSummaryProviderMock(.init())
staticRoomSummaryProvider = RoomSummaryProviderMock(.init())

roomDirectorySearchProxyReturnValue = configuration.roomDirectorySearchProxy

Expand Down
142 changes: 96 additions & 46 deletions ElementX/Sources/Mocks/Generated/GeneratedMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -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 setRoomListCalled: Bool {
return setRoomListCallsCount > 0
var roomListPublisher: CurrentValuePublisher<[RoomSummary], Never> {
get { return underlyingRoomListPublisher }
set(value) { underlyingRoomListPublisher = value }
}
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
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ class GlobalSearchScreenCoordinator: CoordinatorProtocol {
func toPresentable() -> AnyView {
AnyView(GlobalSearchScreen(context: viewModel.context))
}

func stop() {
viewModel.stop()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ import Combine
protocol GlobalSearchScreenViewModelProtocol {
var actions: AnyPublisher<GlobalSearchScreenViewModelAction, Never> { get }
var context: GlobalSearchScreenViewModelType.Context { get }

func stop()
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,8 @@ final class MessageForwardingScreenCoordinator: CoordinatorProtocol {
func toPresentable() -> AnyView {
AnyView(MessageForwardingScreen(context: viewModel.context))
}

func stop() {
viewModel.stop()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ import Combine
protocol MessageForwardingScreenViewModelProtocol {
var actions: AnyPublisher<MessageForwardingScreenViewModelAction, Never> { get }
var context: MessageForwardingScreenViewModelType.Context { get }

func stop()
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ final class RoomSelectionScreenCoordinator: CoordinatorProtocol {
}
.store(in: &cancellables)
}

func stop() {
viewModel.stop()
}

func toPresentable() -> AnyView {
AnyView(RoomSelectionScreen(context: viewModel.context))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ import Combine
protocol RoomSelectionScreenViewModelProtocol {
var actionsPublisher: AnyPublisher<RoomSelectionScreenViewModelAction, Never> { get }
var context: RoomSelectionScreenViewModelType.Context { get }

func stop()
}
34 changes: 31 additions & 3 deletions ElementX/Sources/Services/Client/ClientProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -846,6 +866,14 @@ class ClientProxy: ClientProxyProtocol {
notificationSettings: notificationSettings,
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
Expand Down
9 changes: 7 additions & 2 deletions ElementX/Sources/Services/Client/ClientProxyProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
Loading

0 comments on commit 319441d

Please sign in to comment.