Fixes #2840 - Use both the room list room and the room preview details to populate the join room screen

- the room summary API is indeed enabled on matrix.org and working fine for most rooms
- it is not however capable of giving us data about non-joined + private rooms
- the SDK addresses that by first trying to use known rooms before resorting to the preview endpoint
- that fails if it's a brand new room that the client doesn't know about yet i.e. a sync hasn't ran, which is exactly what's happening here
- the ClientProxy instead does wait for the room list to go into the first loaded before returning the room
This commit is contained in:
Stefan Ceriu 2024-07-18 16:49:04 +03:00 committed by Stefan Ceriu
parent 86ce3def13
commit f1de42a1f3
4 changed files with 49 additions and 13 deletions

View File

@ -29,11 +29,19 @@ enum JoinRoomScreenInteractionMode {
case knock case knock
} }
struct JoinRoomScreenRoomDetails {
let name: String?
let topic: String?
let canonicalAlias: String?
let avatar: RoomAvatar
let memberCount: UInt
}
struct JoinRoomScreenViewState: BindableState { struct JoinRoomScreenViewState: BindableState {
// Maybe use room summary details or similar here?? // Maybe use room summary details or similar here??
let roomID: String let roomID: String
var roomDetails: RoomPreviewDetails? var roomDetails: JoinRoomScreenRoomDetails?
var mode: JoinRoomScreenInteractionMode = .loading var mode: JoinRoomScreenInteractionMode = .loading
@ -52,7 +60,7 @@ struct JoinRoomScreenViewState: BindableState {
} }
var avatar: RoomAvatar { var avatar: RoomAvatar {
.room(id: roomID, name: title, avatarURL: roomDetails?.avatarURL) roomDetails?.avatar ?? .room(id: roomID, name: title, avatarURL: nil)
} }
} }

View File

@ -26,6 +26,9 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
private let clientProxy: ClientProxyProtocol private let clientProxy: ClientProxyProtocol
private let userIndicatorController: UserIndicatorControllerProtocol private let userIndicatorController: UserIndicatorControllerProtocol
private var roomPreviewDetails: RoomPreviewDetails?
private var roomProxy: RoomProxyProtocol?
private let actionsSubject: PassthroughSubject<JoinRoomScreenViewModelAction, Never> = .init() private let actionsSubject: PassthroughSubject<JoinRoomScreenViewModelAction, Never> = .init()
var actionsPublisher: AnyPublisher<JoinRoomScreenViewModelAction, Never> { var actionsPublisher: AnyPublisher<JoinRoomScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
@ -77,13 +80,23 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
showLoadingIndicator() showLoadingIndicator()
defer { defer {
updateMode()
hideLoadingIndicator() hideLoadingIndicator()
} }
// Using only the preview API isn't enough as it's not capable
// of giving us information for non-joined rooms (at least not on synapse)
// See if we known about the room locally and, if so, have that
// take priority over the preview one.
if let roomProxy = await clientProxy.roomForIdentifier(roomID) {
self.roomProxy = roomProxy
updateRoomDetails()
}
switch await clientProxy.roomPreviewForIdentifier(roomID, via: via) { switch await clientProxy.roomPreviewForIdentifier(roomID, via: via) {
case .success(let roomDetails): case .success(let roomPreviewDetails):
state.roomDetails = roomDetails self.roomPreviewDetails = roomPreviewDetails
updateRoomDetails()
case .failure(.roomPreviewIsPrivate): case .failure(.roomPreviewIsPrivate):
break // Handled by the mode, we don't need an error indicator. break // Handled by the mode, we don't need an error indicator.
case .failure: case .failure:
@ -91,17 +104,32 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
} }
} }
private func updateRoomDetails() {
if roomProxy == nil, roomPreviewDetails == nil {
return
}
let name = roomProxy?.name ?? roomPreviewDetails?.name
state.roomDetails = JoinRoomScreenRoomDetails(name: name,
topic: roomProxy?.topic ?? roomPreviewDetails?.topic,
canonicalAlias: roomProxy?.canonicalAlias ?? roomPreviewDetails?.canonicalAlias,
avatar: roomProxy?.avatar ?? .room(id: roomID, name: name ?? "", avatarURL: roomPreviewDetails?.avatarURL),
memberCount: UInt(roomProxy?.activeMembersCount ?? Int(roomPreviewDetails?.memberCount ?? 0)))
updateMode()
}
private func updateMode() { private func updateMode() {
guard let roomDetails = state.roomDetails else { if roomProxy == nil, roomPreviewDetails == nil {
state.mode = .unknown state.mode = .unknown
return return
} }
if roomDetails.isPublic { if roomProxy?.isPublic ?? false || roomPreviewDetails?.isPublic ?? false {
state.mode = .join state.mode = .join
} else if roomDetails.isInvited { } else if roomProxy?.membership == .invited || roomPreviewDetails?.isInvited ?? false {
state.mode = .invited state.mode = .invited
} else if roomDetails.canKnock, allowKnocking { // Knocking is not supported yet, the flag is purely for preview tests. } else if roomPreviewDetails?.canKnock ?? false, allowKnocking { // Knocking is not supported yet, the flag is purely for preview tests.
state.mode = .knock state.mode = .knock
} else { } else {
state.mode = .unknown state.mode = .unknown