mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 20:39:24 +00:00
Introduce a StartChatFlowCoordinator instead of handing a navigation stack to the Screen Coordinator. (#4674)
* Introduce a basic StartChatFlowCoordinator. * Move the rest of the start chat flow from the screen coordinator into the flow coordinator. * Add a UI test for the entire start chat flow. * Refactor CreateRoom… to CreateRoomScreen…
This commit is contained in:
@@ -11,8 +11,8 @@ import SwiftUI
|
||||
|
||||
struct InviteUsersScreenCoordinatorParameters {
|
||||
let userSession: UserSessionProtocol
|
||||
let selectedUsers: CurrentValuePublisher<[UserProfileProxy], Never>?
|
||||
let roomType: InviteUsersScreenRoomType
|
||||
let roomProxy: JoinedRoomProxyProtocol
|
||||
let isSkippable: Bool
|
||||
let userDiscoveryService: UserDiscoveryServiceProtocol
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
let appSettings: AppSettings
|
||||
@@ -20,7 +20,6 @@ struct InviteUsersScreenCoordinatorParameters {
|
||||
|
||||
enum InviteUsersScreenCoordinatorAction {
|
||||
case dismiss
|
||||
case proceed(selectedUsers: [UserProfileProxy])
|
||||
}
|
||||
|
||||
final class InviteUsersScreenCoordinator: CoordinatorProtocol {
|
||||
@@ -34,8 +33,8 @@ final class InviteUsersScreenCoordinator: CoordinatorProtocol {
|
||||
|
||||
init(parameters: InviteUsersScreenCoordinatorParameters) {
|
||||
viewModel = InviteUsersScreenViewModel(userSession: parameters.userSession,
|
||||
selectedUsers: parameters.selectedUsers,
|
||||
roomType: parameters.roomType,
|
||||
roomProxy: parameters.roomProxy,
|
||||
isSkippable: parameters.isSkippable,
|
||||
userDiscoveryService: parameters.userDiscoveryService,
|
||||
userIndicatorController: parameters.userIndicatorController,
|
||||
appSettings: parameters.appSettings)
|
||||
@@ -47,8 +46,6 @@ final class InviteUsersScreenCoordinator: CoordinatorProtocol {
|
||||
switch action {
|
||||
case .dismiss:
|
||||
actionsSubject.send(.dismiss)
|
||||
case .proceed(let selectedUsers):
|
||||
actionsSubject.send(.proceed(selectedUsers: selectedUsers))
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
@@ -16,7 +16,6 @@ enum InviteUsersScreenErrorType: Error {
|
||||
|
||||
enum InviteUsersScreenViewModelAction {
|
||||
case dismiss
|
||||
case proceed(selectedUsers: [UserProfileProxy])
|
||||
}
|
||||
|
||||
enum InviteUsersScreenRoomType {
|
||||
@@ -53,18 +52,18 @@ struct InviteUsersScreenViewState: BindableState {
|
||||
membershipState[user.userID]
|
||||
}
|
||||
|
||||
let isCreatingRoom: Bool
|
||||
let isSkippable: Bool
|
||||
|
||||
var actionText: String {
|
||||
if isCreatingRoom {
|
||||
return selectedUsers.isEmpty ? L10n.actionSkip : L10n.actionNext
|
||||
if isSkippable, selectedUsers.isEmpty {
|
||||
L10n.actionSkip
|
||||
} else {
|
||||
return L10n.actionInvite
|
||||
L10n.actionInvite
|
||||
}
|
||||
}
|
||||
|
||||
var isActionDisabled: Bool {
|
||||
isCreatingRoom ? false : selectedUsers.isEmpty
|
||||
isSkippable ? false : selectedUsers.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import SwiftUI
|
||||
typealias InviteUsersScreenViewModelType = StateStoreViewModel<InviteUsersScreenViewState, InviteUsersScreenViewAction>
|
||||
|
||||
class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScreenViewModelProtocol {
|
||||
private let roomType: InviteUsersScreenRoomType
|
||||
private let roomProxy: JoinedRoomProxyProtocol
|
||||
private let userDiscoveryService: UserDiscoveryServiceProtocol
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private let appSettings: AppSettings
|
||||
@@ -25,22 +25,19 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
private let selectedUsers: CurrentValuePublisher<[UserProfileProxy], Never>?
|
||||
|
||||
init(userSession: UserSessionProtocol,
|
||||
selectedUsers: CurrentValuePublisher<[UserProfileProxy], Never>?,
|
||||
roomType: InviteUsersScreenRoomType,
|
||||
roomProxy: JoinedRoomProxyProtocol,
|
||||
isSkippable: Bool,
|
||||
userDiscoveryService: UserDiscoveryServiceProtocol,
|
||||
userIndicatorController: UserIndicatorControllerProtocol,
|
||||
appSettings: AppSettings) {
|
||||
self.roomType = roomType
|
||||
self.roomProxy = roomProxy
|
||||
self.userDiscoveryService = userDiscoveryService
|
||||
self.userIndicatorController = userIndicatorController
|
||||
self.appSettings = appSettings
|
||||
self.selectedUsers = selectedUsers
|
||||
|
||||
super.init(initialViewState: InviteUsersScreenViewState(selectedUsers: selectedUsers?.value ?? [],
|
||||
isCreatingRoom: roomType.isCreatingRoom),
|
||||
super.init(initialViewState: InviteUsersScreenViewState(selectedUsers: [],
|
||||
isSkippable: isSkippable),
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
setupSubscriptions()
|
||||
@@ -62,12 +59,7 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
case .cancel:
|
||||
actionsSubject.send(.dismiss)
|
||||
case .proceed:
|
||||
switch roomType {
|
||||
case .draft:
|
||||
actionsSubject.send(.proceed(selectedUsers: state.selectedUsers))
|
||||
case .room(let roomProxy):
|
||||
inviteUsers(state.selectedUsers.map(\.userID), roomProxy: roomProxy)
|
||||
}
|
||||
inviteUsers(state.selectedUsers.map(\.userID), roomProxy: roomProxy)
|
||||
case .toggleUser(let user):
|
||||
toggleUser(user)
|
||||
}
|
||||
@@ -78,7 +70,7 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
private func toggleUser(_ user: UserProfileProxy) {
|
||||
if state.selectedUsers.contains(user) {
|
||||
state.scrollToLastID = nil
|
||||
state.selectedUsers.removeAll(where: { $0.userID == user.userID })
|
||||
state.selectedUsers.removeAll { $0.userID == user.userID }
|
||||
} else {
|
||||
state.scrollToLastID = user.userID
|
||||
state.selectedUsers.append(user)
|
||||
@@ -87,15 +79,14 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
|
||||
private func inviteUsers(_ users: [String], roomProxy: JoinedRoomProxyProtocol) {
|
||||
if appSettings.enableKeyShareOnInvite {
|
||||
showLoader(title: L10n.screenRoomDetailsInvitePeoplePreparing,
|
||||
message: L10n.screenRoomDetailsInvitePeopleDontClose)
|
||||
showLoadingIndicator(title: L10n.screenRoomDetailsInvitePeoplePreparing, message: L10n.screenRoomDetailsInvitePeopleDontClose)
|
||||
} else {
|
||||
showLoader()
|
||||
showLoadingIndicator()
|
||||
}
|
||||
|
||||
Task {
|
||||
defer {
|
||||
hideLoader()
|
||||
hideLoadingIndicator()
|
||||
actionsSubject.send(.dismiss)
|
||||
}
|
||||
|
||||
@@ -122,7 +113,7 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
}
|
||||
|
||||
private func buildMembershipStateIfNeeded(members: [RoomMemberProxyProtocol]) {
|
||||
showLoader()
|
||||
showLoadingIndicator()
|
||||
|
||||
Task.detached { [members] in
|
||||
// accessing RoomMember's properties is very slow. We need to do it in a background thread.
|
||||
@@ -133,7 +124,7 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
|
||||
Task { @MainActor in
|
||||
self.state.membershipState = membershipState
|
||||
self.hideLoader()
|
||||
self.hideLoadingIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,25 +141,13 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
self?.fetchUsers()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
if let selectedUsers {
|
||||
selectedUsers
|
||||
.sink { [weak self] users in
|
||||
self?.state.selectedUsers = users
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchMembersIfNeeded() {
|
||||
guard case let .room(roomProxy) = roomType else {
|
||||
return
|
||||
}
|
||||
|
||||
Task {
|
||||
showLoader()
|
||||
showLoadingIndicator()
|
||||
await roomProxy.updateMembers()
|
||||
hideLoader()
|
||||
hideLoadingIndicator()
|
||||
}
|
||||
|
||||
roomProxy.membersPublisher
|
||||
@@ -211,8 +190,8 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
|
||||
private let userIndicatorID = UUID().uuidString
|
||||
|
||||
private func showLoader(title: String = L10n.commonLoading,
|
||||
message: String? = nil) {
|
||||
private func showLoadingIndicator(title: String = L10n.commonLoading,
|
||||
message: String? = nil) {
|
||||
userIndicatorController.submitIndicator(UserIndicator(id: userIndicatorID,
|
||||
type: .modal,
|
||||
title: title,
|
||||
@@ -221,18 +200,7 @@ class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScr
|
||||
delay: .milliseconds(200))
|
||||
}
|
||||
|
||||
private func hideLoader() {
|
||||
private func hideLoadingIndicator() {
|
||||
userIndicatorController.retractIndicatorWithId(userIndicatorID)
|
||||
}
|
||||
}
|
||||
|
||||
private extension InviteUsersScreenRoomType {
|
||||
var isCreatingRoom: Bool {
|
||||
switch self {
|
||||
case .draft:
|
||||
return true
|
||||
case .room:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ struct InviteUsersScreen: View {
|
||||
accessibilityFocusOnStart: true)
|
||||
.compoundSearchField()
|
||||
.alert(item: $context.alertInfo)
|
||||
.navigationBarBackButtonHidden(context.viewState.isSkippable)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -126,7 +127,7 @@ struct InviteUsersScreen: View {
|
||||
|
||||
@ToolbarContentBuilder
|
||||
private var toolbar: some ToolbarContent {
|
||||
if !context.viewState.isCreatingRoom {
|
||||
if !context.viewState.isSkippable {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button(L10n.actionCancel) {
|
||||
context.send(viewAction: .cancel)
|
||||
@@ -155,8 +156,8 @@ struct InviteUsersScreen_Previews: PreviewProvider, TestablePreview {
|
||||
let userDiscoveryService = UserDiscoveryServiceMock()
|
||||
userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice])
|
||||
return InviteUsersScreenViewModel(userSession: UserSessionMock(.init()),
|
||||
selectedUsers: .init([]),
|
||||
roomType: .draft,
|
||||
roomProxy: JoinedRoomProxyMock(.init()),
|
||||
isSkippable: true,
|
||||
userDiscoveryService: userDiscoveryService,
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
appSettings: ServiceLocator.shared.settings)
|
||||
|
||||
Reference in New Issue
Block a user