Make sure we pass the via parameters with all the routes.

Put the event ID first.

Fix tests.

Bump the SDK.
This commit is contained in:
Doug
2024-05-09 12:25:54 +01:00
committed by Stefan Ceriu
parent 52b6c25bd8
commit 1e0a6d76ae
23 changed files with 293 additions and 199 deletions
@@ -189,11 +189,11 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
} else {
handleAppRoute(.roomMemberDetails(userID: userID))
}
case .room(let roomID):
case .room(let roomID, let via):
if isExternalURL {
handleAppRoute(route)
} else {
handleAppRoute(.childRoom(roomID: roomID))
handleAppRoute(.childRoom(roomID: roomID, via: via))
}
case .roomAlias(let alias):
if isExternalURL {
@@ -201,17 +201,17 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
} else {
handleAppRoute(.childRoomAlias(alias))
}
case .event(let roomID, let eventID):
case .event(let eventID, let roomID, let via):
if isExternalURL {
handleAppRoute(route)
} else {
handleAppRoute(.childEvent(roomID: roomID, eventID: eventID))
handleAppRoute(.childEvent(eventID: eventID, roomID: roomID, via: via))
}
case .eventOnRoomAlias(let alias, let eventID):
case .eventOnRoomAlias(let eventID, let alias):
if isExternalURL {
handleAppRoute(route)
} else {
handleAppRoute(.childEventOnRoomAlias(alias: alias, eventID: eventID))
handleAppRoute(.childEventOnRoomAlias(eventID: eventID, alias: alias))
}
default:
break
@@ -267,7 +267,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
return
}
handleAppRoute(.room(roomID: roomID))
handleAppRoute(.room(roomID: roomID, via: []))
}
func handleInlineReply(_ service: NotificationManagerProtocol, content: UNNotificationContent, replyText: String) async {
@@ -23,11 +23,11 @@ enum AppRoute: Equatable {
/// The app's home screen.
case roomList
/// A room, shown as the root of the stack (popping any child rooms).
case room(roomID: String)
case room(roomID: String, via: [String])
/// The same as ``room`` but using a room alias.
case roomAlias(String)
/// A room, pushed as a child of any existing rooms on the stack.
case childRoom(roomID: String)
case childRoom(roomID: String, via: [String])
/// The same as ``childRoom`` but using a room alias.
case childRoomAlias(String)
/// The information about a particular room.
@@ -35,13 +35,13 @@ enum AppRoute: Equatable {
/// The profile of a member within the current room.
case roomMemberDetails(userID: String)
/// An event within a room, shown as the root of the stack (popping any child rooms).
case event(roomID: String, eventID: String)
case event(eventID: String, roomID: String, via: [String])
/// The same as ``event`` but using a room alias.
case eventOnRoomAlias(alias: String, eventID: String)
case eventOnRoomAlias(eventID: String, alias: String)
/// An event within a room, either within the last child on the stack or pushing a new child if needed.
case childEvent(roomID: String, eventID: String)
case childEvent(eventID: String, roomID: String, via: [String])
/// The same as ``childEvent`` but using a room alias.
case childEventOnRoomAlias(alias: String, eventID: String)
case childEventOnRoomAlias(eventID: String, alias: String)
/// The profile of a matrix user (outside of a room).
case userProfile(userID: String)
/// An Element Call link generated outside of a chat room.
@@ -134,19 +134,19 @@ struct ElementCallURLParser: URLParser {
struct MatrixPermalinkParser: URLParser {
func route(from url: URL) -> AppRoute? {
switch parseMatrixEntityFrom(uri: url.absoluteString)?.id {
guard let entity = parseMatrixEntityFrom(uri: url.absoluteString) else { return nil }
switch entity.id {
case .room(let id):
return .room(roomID: id)
return .room(roomID: id, via: entity.via)
case .roomAlias(let alias):
return .roomAlias(alias)
case .user(let id):
return .userProfile(userID: id)
case .eventOnRoomId(let roomID, let eventID):
return .event(roomID: roomID, eventID: eventID)
return .event(eventID: eventID, roomID: roomID, via: entity.via)
case .eventOnRoomAlias(let alias, let eventID):
return .eventOnRoomAlias(alias: alias, eventID: eventID)
default:
return nil
return .eventOnRoomAlias(eventID: eventID, alias: alias)
}
}
}
@@ -21,14 +21,11 @@ import UserNotifications
// swiftlint:disable file_length
enum RoomFlowCoordinatorAction: Equatable {
case presentRoom(roomID: String)
case presentCallScreen(roomProxy: RoomProxyProtocol)
case finished
static func == (lhs: RoomFlowCoordinatorAction, rhs: RoomFlowCoordinatorAction) -> Bool {
switch (lhs, rhs) {
case (.presentRoom(let lhsRoomID), .presentRoom(let rhsRoomID)):
lhsRoomID == rhsRoomID
case (.presentCallScreen(let lhsRoomProxy), .presentCallScreen(let rhsRoomProxy)):
lhsRoomProxy.id == rhsRoomProxy.id
case (.finished, .finished):
@@ -126,15 +123,15 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
}
switch appRoute {
case .room(let roomID):
case .room(let roomID, let via):
Task {
await handleRoomRoute(roomID: roomID, animated: animated)
await handleRoomRoute(roomID: roomID, via: via, animated: animated)
}
case .childRoom(let roomID):
case .childRoom(let roomID, let via):
if case .presentingChild = stateMachine.state, let childRoomFlowCoordinator {
childRoomFlowCoordinator.handleAppRoute(appRoute, animated: animated)
} else if roomID != roomProxy.id {
stateMachine.tryEvent(.startChildFlow(roomID: roomID, entryPoint: .room), userInfo: EventUserInfo(animated: animated))
stateMachine.tryEvent(.startChildFlow(roomID: roomID, via: via, entryPoint: .room), userInfo: EventUserInfo(animated: animated))
} else {
MXLog.info("Ignoring presentation of the same room as a child of this one.")
}
@@ -159,13 +156,13 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
} else {
stateMachine.tryEvent(.presentRoomMemberDetails(userID: userID), userInfo: EventUserInfo(animated: animated))
}
case .event(let roomID, let eventID):
Task { await handleRoomRoute(roomID: roomID, focussedEventID: eventID, animated: animated) }
case .childEvent(let roomID, let eventID):
case .event(let eventID, let roomID, let via):
Task { await handleRoomRoute(roomID: roomID, via: via, focussedEventID: eventID, animated: animated) }
case .childEvent(let eventID, let roomID, let via):
if case .presentingChild = stateMachine.state, let childRoomFlowCoordinator {
childRoomFlowCoordinator.handleAppRoute(appRoute, animated: animated)
} else if roomID != roomProxy.id {
stateMachine.tryEvent(.startChildFlow(roomID: roomID, entryPoint: .eventID(eventID)), userInfo: EventUserInfo(animated: animated))
stateMachine.tryEvent(.startChildFlow(roomID: roomID, via: via, entryPoint: .eventID(eventID)), userInfo: EventUserInfo(animated: animated))
} else {
roomScreenCoordinator?.focusOnEvent(eventID: eventID)
}
@@ -184,11 +181,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
actionsSubject.send(.presentCallScreen(roomProxy: roomProxy))
}
private func handleRoomRoute(roomID: String, focussedEventID: String? = nil, animated: Bool) async {
private func handleRoomRoute(roomID: String, via: [String], focussedEventID: String? = nil, animated: Bool) async {
guard roomID == self.roomID else { fatalError("Navigation route doesn't belong to this room flow.") }
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else {
stateMachine.tryEvent(.presentJoinRoomScreen, userInfo: EventUserInfo(animated: animated))
stateMachine.tryEvent(.presentJoinRoomScreen(via: via), userInfo: EventUserInfo(animated: animated))
return
}
@@ -197,7 +194,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
await storeAndSubscribeToRoomProxy(roomProxy)
stateMachine.tryEvent(.presentRoom(focussedEventID: focussedEventID), userInfo: EventUserInfo(animated: animated))
default:
stateMachine.tryEvent(.presentJoinRoomScreen, userInfo: EventUserInfo(animated: animated))
stateMachine.tryEvent(.presentJoinRoomScreen(via: via), userInfo: EventUserInfo(animated: animated))
}
}
@@ -343,7 +340,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
// Child flow
case (_, .startChildFlow(let roomID, _)):
case (_, .startChildFlow(let roomID, _, _)):
return .presentingChild(childRoomID: roomID, previousState: fromState)
case (.presentingChild(_, let previousState), .dismissChildFlow):
return previousState
@@ -359,8 +356,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
let animated = (context.userInfo as? EventUserInfo)?.animated ?? true
switch (context.fromState, context.event, context.toState) {
case (_, .presentJoinRoomScreen, .joinRoomScreen):
presentJoinRoomScreen(animated: true)
case (_, .presentJoinRoomScreen(let via), .joinRoomScreen):
presentJoinRoomScreen(via: via, animated: true)
case (_, .dismissJoinRoomScreen, .complete):
dismissFlow(animated: animated)
@@ -474,8 +471,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
rolesAndPermissionsFlowCoordinator = nil
// Child flow
case (_, .startChildFlow(let roomID, let entryPoint), .presentingChild):
Task { await self.startChildFlow(for: roomID, entryPoint: entryPoint) }
case (_, .startChildFlow(let roomID, let via, let entryPoint), .presentingChild):
Task { await self.startChildFlow(for: roomID, via: via, entryPoint: entryPoint) }
case (.presentingChild, .dismissChildFlow, _):
childRoomFlowCoordinator = nil
@@ -612,8 +609,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
}
}
private func presentJoinRoomScreen(animated: Bool) {
private func presentJoinRoomScreen(via: [String], animated: Bool) {
let coordinator = JoinRoomScreenCoordinator(parameters: .init(roomID: roomID,
via: via,
clientProxy: userSession.clientProxy,
mediaProvider: userSession.mediaProvider,
userIndicatorController: userIndicatorController))
@@ -1073,7 +1071,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
case .openUserProfile:
stateMachine.tryEvent(.presentUserProfile(userID: userID))
case .openDirectChat(let roomID):
stateMachine.tryEvent(.startChildFlow(roomID: roomID, entryPoint: .room))
stateMachine.tryEvent(.startChildFlow(roomID: roomID, via: [], entryPoint: .room))
case .startCall(let roomID):
Task { await self.presentCallScreen(roomID: roomID) }
}
@@ -1098,7 +1096,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
switch action {
case .openDirectChat(let roomID):
stateMachine.tryEvent(.startChildFlow(roomID: roomID, entryPoint: .room))
stateMachine.tryEvent(.startChildFlow(roomID: roomID, via: [], entryPoint: .room))
case .startCall(let roomID):
Task { await self.presentCallScreen(roomID: roomID) }
case .dismiss:
@@ -1140,7 +1138,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
case .sent(let roomID):
navigationStackCoordinator.setSheetCoordinator(nil)
// Timelines are cached - the local echo will be visible when fetching the room by its ID.
stateMachine.tryEvent(.startChildFlow(roomID: roomID, entryPoint: .room))
stateMachine.tryEvent(.startChildFlow(roomID: roomID, via: [], entryPoint: .room))
}
}
.store(in: &cancellables)
@@ -1283,7 +1281,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
// MARK: - Child Flow
private func startChildFlow(for roomID: String, entryPoint: RoomFlowCoordinatorEntryPoint) async {
private func startChildFlow(for roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint) async {
let coordinator = await RoomFlowCoordinator(roomID: roomID,
userSession: userSession,
isChildFlow: true,
@@ -1298,8 +1296,6 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
guard let self else { return }
switch action {
case .presentRoom(let roomID):
actionsSubject.send(.presentRoom(roomID: roomID))
case .presentCallScreen(let roomProxy):
actionsSubject.send(.presentCallScreen(roomProxy: roomProxy))
case .finished:
@@ -1311,9 +1307,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
childRoomFlowCoordinator = coordinator
switch entryPoint {
case .room:
coordinator.handleAppRoute(.room(roomID: roomID), animated: true)
coordinator.handleAppRoute(.room(roomID: roomID, via: via), animated: true)
case .eventID(let eventID):
coordinator.handleAppRoute(.event(roomID: roomID, eventID: eventID), animated: true)
coordinator.handleAppRoute(.event(eventID: eventID, roomID: roomID, via: via), animated: true)
case .roomDetails:
coordinator.handleAppRoute(.roomDetails(roomID: roomID), animated: true)
}
@@ -1367,7 +1363,7 @@ private extension RoomFlowCoordinator {
}
enum Event: EventType {
case presentJoinRoomScreen
case presentJoinRoomScreen(via: [String])
case dismissJoinRoomScreen
case presentRoom(focussedEventID: String?)
@@ -1425,7 +1421,7 @@ private extension RoomFlowCoordinator {
case dismissRolesAndPermissionsScreen
// Child room flow events
case startChildFlow(roomID: String, entryPoint: RoomFlowCoordinatorEntryPoint)
case startChildFlow(roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint)
case dismissChildFlow
}
}
@@ -200,40 +200,40 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
await clearPresentedSheets(animated: animated)
switch appRoute {
case .room(let roomID):
stateMachine.processEvent(.selectRoom(roomID: roomID, entryPoint: .room), userInfo: .init(animated: animated))
case .room(let roomID, let via):
stateMachine.processEvent(.selectRoom(roomID: roomID, via: via, entryPoint: .room), userInfo: .init(animated: animated))
case .roomAlias(let alias):
guard let roomID = await userSession.clientProxy.resolveRoomAlias(alias) else { return }
await asyncHandleAppRoute(.room(roomID: roomID), animated: animated)
case .childRoom(let roomID):
guard let resolved = await userSession.clientProxy.resolveRoomAlias(alias) else { return }
await asyncHandleAppRoute(.room(roomID: resolved.roomId, via: resolved.servers), animated: animated)
case .childRoom(let roomID, let via):
if let roomFlowCoordinator {
roomFlowCoordinator.handleAppRoute(appRoute, animated: animated)
} else {
stateMachine.processEvent(.selectRoom(roomID: roomID, entryPoint: .room), userInfo: .init(animated: animated))
stateMachine.processEvent(.selectRoom(roomID: roomID, via: via, entryPoint: .room), userInfo: .init(animated: animated))
}
case .childRoomAlias(let alias):
guard let roomID = await userSession.clientProxy.resolveRoomAlias(alias) else { return }
await asyncHandleAppRoute(.childRoom(roomID: roomID), animated: animated)
guard let resolved = await userSession.clientProxy.resolveRoomAlias(alias) else { return }
await asyncHandleAppRoute(.childRoom(roomID: resolved.roomId, via: resolved.servers), animated: animated)
case .roomDetails(let roomID):
if stateMachine.state.selectedRoomID == roomID {
roomFlowCoordinator?.handleAppRoute(appRoute, animated: animated)
} else {
stateMachine.processEvent(.selectRoom(roomID: roomID, entryPoint: .roomDetails), userInfo: .init(animated: animated))
stateMachine.processEvent(.selectRoom(roomID: roomID, via: [], entryPoint: .roomDetails), userInfo: .init(animated: animated))
}
case .roomList:
roomFlowCoordinator?.clearRoute(animated: animated)
case .roomMemberDetails:
roomFlowCoordinator?.handleAppRoute(appRoute, animated: animated)
case .event(let roomID, let eventID):
stateMachine.processEvent(.selectRoom(roomID: roomID, entryPoint: .eventID(eventID)), userInfo: .init(animated: animated))
case .eventOnRoomAlias(let alias, let eventID):
guard let roomID = await userSession.clientProxy.resolveRoomAlias(alias) else { return }
await asyncHandleAppRoute(.event(roomID: roomID, eventID: eventID), animated: animated)
case .event(let eventID, let roomID, let via):
stateMachine.processEvent(.selectRoom(roomID: roomID, via: via, entryPoint: .eventID(eventID)), userInfo: .init(animated: animated))
case .eventOnRoomAlias(let eventID, let alias):
guard let resolved = await userSession.clientProxy.resolveRoomAlias(alias) else { return }
await asyncHandleAppRoute(.event(eventID: eventID, roomID: resolved.roomId, via: resolved.servers), animated: animated)
case .childEvent:
roomFlowCoordinator?.handleAppRoute(appRoute, animated: animated)
case .childEventOnRoomAlias(let alias, let eventID):
guard let roomID = await userSession.clientProxy.resolveRoomAlias(alias) else { return }
await asyncHandleAppRoute(.childEvent(roomID: roomID, eventID: eventID), animated: animated)
case .childEventOnRoomAlias(let eventID, let alias):
guard let resolved = await userSession.clientProxy.resolveRoomAlias(alias) else { return }
await asyncHandleAppRoute(.childEvent(eventID: eventID, roomID: resolved.roomId, via: resolved.servers), animated: animated)
case .userProfile(let userID):
stateMachine.processEvent(.showUserProfileScreen(userID: userID), userInfo: .init(animated: animated))
case .genericCallLink(let url):
@@ -271,18 +271,18 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
case (.initial, .start, .roomList):
presentHomeScreen()
attemptStartingOnboarding()
case(.roomList(let selectedRoomID), .selectRoom(let roomID, let entryPoint), .roomList):
case(.roomList(let selectedRoomID), .selectRoom(let roomID, let via, let entryPoint), .roomList):
if selectedRoomID == roomID,
!entryPoint.isEventID, // Don't reuse the existing room so the live timeline is hidden while the detached timeline is loading.
let roomFlowCoordinator {
let route: AppRoute = switch entryPoint {
case .room: .room(roomID: roomID)
case .room: .room(roomID: roomID, via: via)
case .roomDetails: .roomDetails(roomID: roomID)
case .eventID(let eventID): .event(roomID: roomID, eventID: eventID) // ignored.
case .eventID(let eventID): .event(eventID: eventID, roomID: roomID, via: via) // ignored.
}
roomFlowCoordinator.handleAppRoute(route, animated: animated)
} else {
Task { await self.startRoomFlow(roomID: roomID, entryPoint: entryPoint, animated: animated) }
Task { await self.startRoomFlow(roomID: roomID, via: via, entryPoint: entryPoint, animated: animated) }
}
case(.roomList, .deselectRoom, .roomList):
dismissRoomFlow(animated: animated)
@@ -359,7 +359,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
switch action {
case .presentRoom(let roomID):
handleAppRoute(.room(roomID: roomID), animated: true)
handleAppRoute(.room(roomID: roomID, via: []), animated: true)
case .presentRoomDetails(let roomID):
handleAppRoute(.roomDetails(roomID: roomID), animated: true)
case .roomLeft(let roomID):
@@ -438,6 +438,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
// MARK: Room Flow
private func startRoomFlow(roomID: String,
via: [String],
entryPoint: RoomFlowCoordinatorEntryPoint,
animated: Bool) async {
let coordinator = await RoomFlowCoordinator(roomID: roomID,
@@ -455,12 +456,10 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
guard let self else { return }
switch action {
case .finished:
stateMachine.processEvent(.deselectRoom)
case .presentRoom(let roomID):
stateMachine.processEvent(.selectRoom(roomID: roomID, entryPoint: .room))
case .presentCallScreen(let roomProxy):
presentCallScreen(roomProxy: roomProxy)
case .finished:
stateMachine.processEvent(.deselectRoom)
}
}
.store(in: &cancellables)
@@ -473,9 +472,9 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
switch entryPoint {
case .room:
coordinator.handleAppRoute(.room(roomID: roomID), animated: animated)
coordinator.handleAppRoute(.room(roomID: roomID, via: via), animated: animated)
case .eventID(let eventID):
coordinator.handleAppRoute(.event(roomID: roomID, eventID: eventID), animated: animated)
coordinator.handleAppRoute(.event(eventID: eventID, roomID: roomID, via: via), animated: animated)
case .roomDetails:
coordinator.handleAppRoute(.roomDetails(roomID: roomID), animated: animated)
}
@@ -513,7 +512,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
self.navigationSplitCoordinator.setSheetCoordinator(nil)
case .openRoom(let roomID):
self.navigationSplitCoordinator.setSheetCoordinator(nil)
self.stateMachine.processEvent(.selectRoom(roomID: roomID, entryPoint: .room))
self.stateMachine.processEvent(.selectRoom(roomID: roomID, via: [], entryPoint: .room))
}
}
.store(in: &cancellables)
@@ -597,7 +596,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
dismissGlobalSearch()
case .select(let roomID):
dismissGlobalSearch()
handleAppRoute(.room(roomID: roomID), animated: true)
handleAppRoute(.room(roomID: roomID, via: []), animated: true)
}
}
.store(in: &cancellables)
@@ -627,9 +626,12 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
guard let self else { return }
switch action {
case .select(let roomID):
case .selectAlias(let alias):
stateMachine.processEvent(.dismissedRoomDirectorySearchScreen)
handleAppRoute(.room(roomID: roomID), animated: true)
handleAppRoute(.roomAlias(alias), animated: true)
case .selectRoomID(let roomID):
stateMachine.processEvent(.dismissedRoomDirectorySearchScreen)
handleAppRoute(.room(roomID: roomID, via: []), animated: true)
case .dismiss:
stateMachine.processEvent(.dismissedRoomDirectorySearchScreen)
}
@@ -662,7 +664,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
switch action {
case .openDirectChat(let roomID):
navigationSplitCoordinator.setSheetCoordinator(nil)
stateMachine.processEvent(.selectRoom(roomID: roomID, entryPoint: .room))
stateMachine.processEvent(.selectRoom(roomID: roomID, via: [], entryPoint: .room))
case .startCall(let roomID):
Task { await self.presentCallScreen(roomID: roomID) }
case .dismiss:
@@ -70,10 +70,11 @@ class UserSessionFlowCoordinatorStateMachine {
/// Start the user session flows.
case start
/// Request presentation for a particular room
/// - Parameter roomID: The room identifier
/// Request presentation for a particular room.
/// - Parameter roomID: The room identifier.
/// - Parameter via: Any servers necessary to discover the room.
/// - Parameter entryPoint: The starting point for the presented room.
case selectRoom(roomID: String, entryPoint: RoomFlowCoordinatorEntryPoint)
case selectRoom(roomID: String, via: [String], entryPoint: RoomFlowCoordinatorEntryPoint)
/// The room screen has been dismissed
case deselectRoom
@@ -129,7 +130,7 @@ class UserSessionFlowCoordinatorStateMachine {
stateMachine.addRouteMapping { event, fromState, _ in
switch (fromState, event) {
case (.roomList, .selectRoom(let roomID, _)):
case (.roomList, .selectRoom(let roomID, _, _)):
return .roomList(selectedRoomID: roomID)
case (.roomList, .deselectRoom):
return .roomList(selectedRoomID: nil)
@@ -2428,15 +2428,15 @@ class ClientProxyMock: ClientProxyProtocol {
}
//MARK: - joinRoom
var joinRoomUnderlyingCallsCount = 0
var joinRoomCallsCount: Int {
var joinRoomViaUnderlyingCallsCount = 0
var joinRoomViaCallsCount: Int {
get {
if Thread.isMainThread {
return joinRoomUnderlyingCallsCount
return joinRoomViaUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = joinRoomUnderlyingCallsCount
returnValue = joinRoomViaUnderlyingCallsCount
}
return returnValue!
@@ -2444,29 +2444,29 @@ class ClientProxyMock: ClientProxyProtocol {
}
set {
if Thread.isMainThread {
joinRoomUnderlyingCallsCount = newValue
joinRoomViaUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
joinRoomUnderlyingCallsCount = newValue
joinRoomViaUnderlyingCallsCount = newValue
}
}
}
}
var joinRoomCalled: Bool {
return joinRoomCallsCount > 0
var joinRoomViaCalled: Bool {
return joinRoomViaCallsCount > 0
}
var joinRoomReceivedRoomID: String?
var joinRoomReceivedInvocations: [String] = []
var joinRoomViaReceivedArguments: (roomID: String, via: [String])?
var joinRoomViaReceivedInvocations: [(roomID: String, via: [String])] = []
var joinRoomUnderlyingReturnValue: Result<Void, ClientProxyError>!
var joinRoomReturnValue: Result<Void, ClientProxyError>! {
var joinRoomViaUnderlyingReturnValue: Result<Void, ClientProxyError>!
var joinRoomViaReturnValue: Result<Void, ClientProxyError>! {
get {
if Thread.isMainThread {
return joinRoomUnderlyingReturnValue
return joinRoomViaUnderlyingReturnValue
} else {
var returnValue: Result<Void, ClientProxyError>? = nil
DispatchQueue.main.sync {
returnValue = joinRoomUnderlyingReturnValue
returnValue = joinRoomViaUnderlyingReturnValue
}
return returnValue!
@@ -2474,24 +2474,24 @@ class ClientProxyMock: ClientProxyProtocol {
}
set {
if Thread.isMainThread {
joinRoomUnderlyingReturnValue = newValue
joinRoomViaUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
joinRoomUnderlyingReturnValue = newValue
joinRoomViaUnderlyingReturnValue = newValue
}
}
}
}
var joinRoomClosure: ((String) async -> Result<Void, ClientProxyError>)?
var joinRoomViaClosure: ((String, [String]) async -> Result<Void, ClientProxyError>)?
func joinRoom(_ roomID: String) async -> Result<Void, ClientProxyError> {
joinRoomCallsCount += 1
joinRoomReceivedRoomID = roomID
joinRoomReceivedInvocations.append(roomID)
if let joinRoomClosure = joinRoomClosure {
return await joinRoomClosure(roomID)
func joinRoom(_ roomID: String, via: [String]) async -> Result<Void, ClientProxyError> {
joinRoomViaCallsCount += 1
joinRoomViaReceivedArguments = (roomID: roomID, via: via)
joinRoomViaReceivedInvocations.append((roomID: roomID, via: via))
if let joinRoomViaClosure = joinRoomViaClosure {
return await joinRoomViaClosure(roomID, via)
} else {
return joinRoomReturnValue
return joinRoomViaReturnValue
}
}
//MARK: - uploadMedia
@@ -3431,13 +3431,13 @@ class ClientProxyMock: ClientProxyProtocol {
var resolveRoomAliasReceivedAlias: String?
var resolveRoomAliasReceivedInvocations: [String] = []
var resolveRoomAliasUnderlyingReturnValue: String?
var resolveRoomAliasReturnValue: String? {
var resolveRoomAliasUnderlyingReturnValue: ResolvedRoomAlias?
var resolveRoomAliasReturnValue: ResolvedRoomAlias? {
get {
if Thread.isMainThread {
return resolveRoomAliasUnderlyingReturnValue
} else {
var returnValue: String?? = nil
var returnValue: ResolvedRoomAlias?? = nil
DispatchQueue.main.sync {
returnValue = resolveRoomAliasUnderlyingReturnValue
}
@@ -3455,9 +3455,9 @@ class ClientProxyMock: ClientProxyProtocol {
}
}
}
var resolveRoomAliasClosure: ((String) async -> String?)?
var resolveRoomAliasClosure: ((String) async -> ResolvedRoomAlias?)?
func resolveRoomAlias(_ alias: String) async -> String? {
func resolveRoomAlias(_ alias: String) async -> ResolvedRoomAlias? {
resolveRoomAliasCallsCount += 1
resolveRoomAliasReceivedAlias = alias
resolveRoomAliasReceivedInvocations.append(alias)
@@ -1480,6 +1480,78 @@ class SDKClientMock: SDKClientProtocol {
return joinRoomByIdRoomIdReturnValue
}
}
//MARK: - joinRoomByIdOrAlias
public var joinRoomByIdOrAliasRoomIdOrAliasServerNamesThrowableError: Error?
var joinRoomByIdOrAliasRoomIdOrAliasServerNamesUnderlyingCallsCount = 0
public var joinRoomByIdOrAliasRoomIdOrAliasServerNamesCallsCount: Int {
get {
if Thread.isMainThread {
return joinRoomByIdOrAliasRoomIdOrAliasServerNamesUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = joinRoomByIdOrAliasRoomIdOrAliasServerNamesUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
joinRoomByIdOrAliasRoomIdOrAliasServerNamesUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
joinRoomByIdOrAliasRoomIdOrAliasServerNamesUnderlyingCallsCount = newValue
}
}
}
}
public var joinRoomByIdOrAliasRoomIdOrAliasServerNamesCalled: Bool {
return joinRoomByIdOrAliasRoomIdOrAliasServerNamesCallsCount > 0
}
public var joinRoomByIdOrAliasRoomIdOrAliasServerNamesReceivedArguments: (roomIdOrAlias: String, serverNames: [String])?
public var joinRoomByIdOrAliasRoomIdOrAliasServerNamesReceivedInvocations: [(roomIdOrAlias: String, serverNames: [String])] = []
var joinRoomByIdOrAliasRoomIdOrAliasServerNamesUnderlyingReturnValue: Room!
public var joinRoomByIdOrAliasRoomIdOrAliasServerNamesReturnValue: Room! {
get {
if Thread.isMainThread {
return joinRoomByIdOrAliasRoomIdOrAliasServerNamesUnderlyingReturnValue
} else {
var returnValue: Room? = nil
DispatchQueue.main.sync {
returnValue = joinRoomByIdOrAliasRoomIdOrAliasServerNamesUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
joinRoomByIdOrAliasRoomIdOrAliasServerNamesUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
joinRoomByIdOrAliasRoomIdOrAliasServerNamesUnderlyingReturnValue = newValue
}
}
}
}
public var joinRoomByIdOrAliasRoomIdOrAliasServerNamesClosure: ((String, [String]) async throws -> Room)?
public func joinRoomByIdOrAlias(roomIdOrAlias: String, serverNames: [String]) async throws -> Room {
if let error = joinRoomByIdOrAliasRoomIdOrAliasServerNamesThrowableError {
throw error
}
joinRoomByIdOrAliasRoomIdOrAliasServerNamesCallsCount += 1
joinRoomByIdOrAliasRoomIdOrAliasServerNamesReceivedArguments = (roomIdOrAlias: roomIdOrAlias, serverNames: serverNames)
joinRoomByIdOrAliasRoomIdOrAliasServerNamesReceivedInvocations.append((roomIdOrAlias: roomIdOrAlias, serverNames: serverNames))
if let joinRoomByIdOrAliasRoomIdOrAliasServerNamesClosure = joinRoomByIdOrAliasRoomIdOrAliasServerNamesClosure {
return try await joinRoomByIdOrAliasRoomIdOrAliasServerNamesClosure(roomIdOrAlias, serverNames)
} else {
return joinRoomByIdOrAliasRoomIdOrAliasServerNamesReturnValue
}
}
//MARK: - login
public var loginUsernamePasswordInitialDeviceNameDeviceIdThrowableError: Error?
@@ -1735,13 +1807,13 @@ class SDKClientMock: SDKClientProtocol {
public var resolveRoomAliasRoomAliasReceivedRoomAlias: String?
public var resolveRoomAliasRoomAliasReceivedInvocations: [String] = []
var resolveRoomAliasRoomAliasUnderlyingReturnValue: String!
public var resolveRoomAliasRoomAliasReturnValue: String! {
var resolveRoomAliasRoomAliasUnderlyingReturnValue: ResolvedRoomAlias!
public var resolveRoomAliasRoomAliasReturnValue: ResolvedRoomAlias! {
get {
if Thread.isMainThread {
return resolveRoomAliasRoomAliasUnderlyingReturnValue
} else {
var returnValue: String? = nil
var returnValue: ResolvedRoomAlias? = nil
DispatchQueue.main.sync {
returnValue = resolveRoomAliasRoomAliasUnderlyingReturnValue
}
@@ -1759,9 +1831,9 @@ class SDKClientMock: SDKClientProtocol {
}
}
}
public var resolveRoomAliasRoomAliasClosure: ((String) async throws -> String)?
public var resolveRoomAliasRoomAliasClosure: ((String) async throws -> ResolvedRoomAlias)?
public func resolveRoomAlias(roomAlias: String) async throws -> String {
public func resolveRoomAlias(roomAlias: String) async throws -> ResolvedRoomAlias {
if let error = resolveRoomAliasRoomAliasThrowableError {
throw error
}
@@ -19,6 +19,7 @@ import SwiftUI
struct JoinRoomScreenCoordinatorParameters {
let roomID: String
let via: [String]
let clientProxy: ClientProxyProtocol
let mediaProvider: MediaProviderProtocol
let userIndicatorController: UserIndicatorControllerProtocol
@@ -44,6 +45,7 @@ final class JoinRoomScreenCoordinator: CoordinatorProtocol {
self.parameters = parameters
viewModel = JoinRoomScreenViewModel(roomID: parameters.roomID,
via: parameters.via,
clientProxy: parameters.clientProxy,
mediaProvider: parameters.mediaProvider,
userIndicatorController: parameters.userIndicatorController)
@@ -21,6 +21,7 @@ typealias JoinRoomScreenViewModelType = StateStoreViewModel<JoinRoomScreenViewSt
class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewModelProtocol {
private let roomID: String
private let via: [String]
private let clientProxy: ClientProxyProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
@@ -30,10 +31,12 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
}
init(roomID: String,
via: [String],
clientProxy: ClientProxyProtocol,
mediaProvider: MediaProviderProtocol,
userIndicatorController: UserIndicatorControllerProtocol) {
self.roomID = roomID
self.via = via
self.clientProxy = clientProxy
self.userIndicatorController = userIndicatorController
@@ -74,6 +77,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
hideLoadingIndicator()
}
// We need an SDK update to pass the via into this preview.
switch await clientProxy.roomPreviewForIdentifier(roomID) {
case .success(let roomDetails):
state.roomDetails = roomDetails
@@ -89,7 +93,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
hideLoadingIndicator()
}
switch await clientProxy.joinRoom(roomID) {
switch await clientProxy.joinRoom(roomID, via: via) {
case .success:
actionsSubject.send(.joined)
case .failure(let error):
@@ -165,6 +165,7 @@ struct JoinRoomScreen_Previews: PreviewProvider, TestablePreview {
}
return JoinRoomScreenViewModel(roomID: "1",
via: [],
clientProxy: clientProxy,
mediaProvider: MockMediaProvider(),
userIndicatorController: ServiceLocator.shared.userIndicatorController)
@@ -24,7 +24,8 @@ struct RoomDirectorySearchScreenCoordinatorParameters {
}
enum RoomDirectorySearchScreenCoordinatorAction {
case select(roomID: String)
case selectAlias(String)
case selectRoomID(String)
case dismiss
}
@@ -48,8 +49,10 @@ final class RoomDirectorySearchScreenCoordinator: CoordinatorProtocol {
viewModel.actionsPublisher.sink { [weak self] action in
guard let self else { return }
switch action {
case .select(let roomID):
actionsSubject.send(.select(roomID: roomID))
case .selectAlias(let alias):
actionsSubject.send(.selectAlias(alias))
case .selectRoomID(let roomID):
actionsSubject.send(.selectRoomID(roomID))
case .dismiss:
actionsSubject.send(.dismiss)
}
@@ -17,7 +17,8 @@
import Foundation
enum RoomDirectorySearchScreenViewModelAction {
case select(roomID: String)
case selectAlias(String)
case selectRoomID(String)
case dismiss
}
@@ -35,6 +36,6 @@ struct RoomDirectorySearchScreenViewStateBindings {
enum RoomDirectorySearchScreenViewAction {
case dismiss
case select(roomID: String)
case select(room: RoomDirectorySearchResult)
case reachedBottom
}
@@ -65,8 +65,12 @@ class RoomDirectorySearchScreenViewModel: RoomDirectorySearchScreenViewModelType
switch viewAction {
case .dismiss:
actionsSubject.send(.dismiss)
case .select(roomID: let roomID):
actionsSubject.send(.select(roomID: roomID))
case .select(let room):
if let alias = room.alias {
actionsSubject.send(.selectAlias(alias))
} else {
actionsSubject.send(.selectRoomID(room.id))
}
case .reachedBottom:
loadNextPage()
}
@@ -26,7 +26,7 @@ struct RoomDirectorySearchScreen: View {
Section {
ForEach(context.viewState.rooms) { room in
RoomDirectorySearchCell(result: room, imageProvider: context.imageProvider) {
context.send(viewAction: .select(roomID: room.id))
context.send(viewAction: .select(room: room))
}
}
} footer: {
@@ -350,9 +350,9 @@ class ClientProxy: ClientProxyProtocol {
}
}
func joinRoom(_ roomID: String) async -> Result<Void, ClientProxyError> {
func joinRoom(_ roomID: String, via: [String]) async -> Result<Void, ClientProxyError> {
do {
let _ = try await client.joinRoomById(roomId: roomID)
let _ = try await client.joinRoomByIdOrAlias(roomIdOrAlias: roomID, serverNames: via)
// Wait for the room to appear in the room lists to avoid issues downstream
let _ = await waitForRoomSummary(with: .success(roomID), name: nil, timeout: 30)
@@ -569,7 +569,7 @@ class ClientProxy: ClientProxyProtocol {
RoomDirectorySearchProxy(roomDirectorySearch: client.roomDirectorySearch())
}
func resolveRoomAlias(_ alias: String) async -> String? {
func resolveRoomAlias(_ alias: String) async -> ResolvedRoomAlias? {
do {
return try await client.resolveRoomAlias(roomAlias: alias)
} catch {
@@ -678,7 +678,6 @@ class ClientProxy: ClientProxyProtocol {
.syncService()
.withCrossProcessLock(appIdentifier: "MainApp")
.withUtdHook(delegate: ClientDecryptionErrorDelegate(actionsSubject: actionsSubject))
.withUnifiedInvitesInRoomList(withUnifiedInvites: true)
.finish()
let roomListService = syncService.roomListService()
@@ -129,7 +129,7 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
func createRoom(name: String, topic: String?, isRoomPrivate: Bool, userIDs: [String], avatarURL: URL?) async -> Result<String, ClientProxyError>
func joinRoom(_ roomID: String) async -> Result<Void, ClientProxyError>
func joinRoom(_ roomID: String, via: [String]) async -> Result<Void, ClientProxyError>
func uploadMedia(_ media: MediaInfo) async -> Result<String, ClientProxyError>
@@ -159,7 +159,7 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
func roomDirectorySearchProxy() -> RoomDirectorySearchProxyProtocol
func resolveRoomAlias(_ alias: String) async -> String?
func resolveRoomAlias(_ alias: String) async -> ResolvedRoomAlias?
// MARK: - Ignored users