mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Accept and decline invites (#806)
* Add accept/decline invite api * Fix isDirect logic * Add logic for accepting/decling invites * Add error handling structure * Add decline alert * Add navigation to joined room * Add generic error * Add changelog.d file * Cleanup * Fix failing UTs * Add UTs * Add UI tests * Cleanup * Update ref screenshots * Refactor invitesScreen state * Improve switch handling in UserSessionFlowCoordinator * Fix build error
This commit is contained in:
@@ -65,6 +65,7 @@ class MockClientProxy: ClientProxyProtocol {
|
||||
return RoomProxyMock(with: .init(displayName: "Empty room"))
|
||||
case .filled(let details), .invalidated(let details):
|
||||
let room = RoomProxyMock(with: .init(displayName: details.name))
|
||||
room.acceptInvitationReturnValue = .success(())
|
||||
room.inviterReturnValue = roomInviter
|
||||
return room
|
||||
}
|
||||
|
||||
@@ -348,6 +348,26 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func rejectInvitation() async -> Result<Void, RoomProxyError> {
|
||||
await Task.dispatch(on: .global()) {
|
||||
do {
|
||||
return try .success(self.room.rejectInvitation())
|
||||
} catch {
|
||||
return .failure(.failedRejectingInvite)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func acceptInvitation() async -> Result<Void, RoomProxyError> {
|
||||
await Task.dispatch(on: .global()) {
|
||||
do {
|
||||
return try .success(self.room.acceptInvitation())
|
||||
} catch {
|
||||
return .failure(.failedAcceptingInvite)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
/// Force the timeline to load member details so it can populate sender profiles whenever we add a timeline listener
|
||||
|
||||
@@ -33,6 +33,8 @@ enum RoomProxyError: Error {
|
||||
case failedAddingTimelineListener
|
||||
case failedRetrievingMembers
|
||||
case failedLeavingRoom
|
||||
case failedAcceptingInvite
|
||||
case failedRejectingInvite
|
||||
}
|
||||
|
||||
@MainActor
|
||||
@@ -90,6 +92,10 @@ protocol RoomProxyProtocol {
|
||||
func updateMembers() async
|
||||
|
||||
func inviter() async -> RoomMemberProxyProtocol?
|
||||
|
||||
func rejectInvitation() async -> Result<Void, RoomProxyError>
|
||||
|
||||
func acceptInvitation() async -> Result<Void, RoomProxyError>
|
||||
}
|
||||
|
||||
extension RoomProxyProtocol {
|
||||
|
||||
@@ -129,7 +129,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
|
||||
|
||||
let details = RoomSummaryDetails(id: room.roomId(),
|
||||
name: room.name() ?? room.roomId(),
|
||||
isDirect: room.isDm() ?? false,
|
||||
isDirect: fullRoom?.isDirect() ?? room.isDm() ?? false,
|
||||
avatarURL: avatarURL,
|
||||
lastMessage: attributedLastMessage,
|
||||
lastMessageFormattedTimestamp: lastMessageFormattedTimestamp,
|
||||
|
||||
@@ -121,6 +121,11 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
|
||||
self.presentInvitesList(animated: animated)
|
||||
case (.invitesScreen, .closedInvitesScreen, .roomList):
|
||||
break
|
||||
case (.invitesScreen, .selectRoom(let roomId), .invitesScreen(let selectedRoomId)) where roomId == selectedRoomId:
|
||||
self.presentRoomWithIdentifier(roomId)
|
||||
case (.invitesScreen, .deselectRoom, .invitesScreen):
|
||||
break
|
||||
|
||||
default:
|
||||
fatalError("Unknown transition: \(context)")
|
||||
}
|
||||
@@ -200,12 +205,18 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
|
||||
detailNavigationStackCoordinator.setRootCoordinator(coordinator, animated: animated) { [weak self, roomIdentifier] in
|
||||
guard let self else { return }
|
||||
|
||||
// Move the state machine to no room selected if the room currently being dimissed
|
||||
// Move the state machine to no room selected if the room currently being dismissed
|
||||
// is the same as the one selected in the state machine.
|
||||
// This generally happens when popping the room screen while in a compact layout
|
||||
if case let .roomList(selectedRoomId) = self.stateMachine.state, selectedRoomId == roomIdentifier {
|
||||
switch self.stateMachine.state {
|
||||
case
|
||||
let .roomList(selectedRoomId) where selectedRoomId == roomIdentifier,
|
||||
let .invitesScreen(selectedRoomId) where selectedRoomId == roomIdentifier:
|
||||
|
||||
self.stateMachine.processEvent(.deselectRoom)
|
||||
self.detailNavigationStackCoordinator.setRootCoordinator(nil)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,10 +341,15 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
|
||||
let coordinator = InvitesCoordinator(parameters: parameters)
|
||||
|
||||
coordinator.actions
|
||||
.sink { _ in }
|
||||
.sink { [weak self] action in
|
||||
switch action {
|
||||
case .openRoom(let roomId):
|
||||
self?.stateMachine.processEvent(.selectRoom(roomId: roomId))
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
navigationSplitCoordinator.setDetailCoordinator(coordinator, animated: animated) { [weak self] in
|
||||
sidebarNavigationStackCoordinator.push(coordinator, animated: animated) { [weak self] in
|
||||
self?.stateMachine.processEvent(.closedInvitesScreen)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class UserSessionFlowCoordinatorStateMachine {
|
||||
/// The initial state, used before the coordinator starts
|
||||
case initial
|
||||
|
||||
/// Showing the home screen
|
||||
/// Showing the home screen. The `selectedRoomId` represents the timeline shown on the detail panel (if any)
|
||||
case roomList(selectedRoomId: String?)
|
||||
|
||||
/// Showing the session verification flows
|
||||
@@ -125,7 +125,11 @@ class UserSessionFlowCoordinatorStateMachine {
|
||||
return .invitesScreen(selectedRoomId: selectedRoomId)
|
||||
case (.closedInvitesScreen, .invitesScreen(let selectedRoomId)):
|
||||
return .roomList(selectedRoomId: selectedRoomId)
|
||||
|
||||
case (.selectRoom(let roomId), .invitesScreen):
|
||||
return .invitesScreen(selectedRoomId: roomId)
|
||||
case (.deselectRoom, .invitesScreen):
|
||||
return .invitesScreen(selectedRoomId: nil)
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user