implemented the basics of the flow coordinator, the logic and the navigation flow to get to the space settings view

This commit is contained in:
Mauro Romito
2025-10-28 18:40:52 +01:00
committed by Mauro
parent 9cd181ef74
commit dfd757f2b6
19 changed files with 460 additions and 7 deletions
@@ -42,6 +42,7 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
private var childSpaceFlowCoordinator: SpaceFlowCoordinator?
private var roomFlowCoordinator: RoomFlowCoordinator?
private var membersFlowCoordinator: RoomMembersFlowCoordinator?
private var settingsFlowCoordinator: SpaceSettingsFlowCoordinator?
indirect enum State: StateType {
/// The state machine hasn't started.
@@ -56,6 +57,8 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
case roomFlow(previousState: State)
/// A members flow is in progress
case membersFlow
/// A space settings flow is in progress
case settingsFlow
case leftSpace
}
@@ -83,6 +86,9 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
case startMembersFlow
case stopMembersFlow
case startSettingsFlow
case stopSettingsFlow
}
private let stateMachine: StateMachine<State, Event>
@@ -142,6 +148,9 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
case .membersFlow:
membersFlowCoordinator?.clearRoute(animated: animated)
clearRoute(animated: animated) // Re-run with the state machine back in the .space state.
case .settingsFlow:
settingsFlowCoordinator?.clearRoute(animated: animated)
clearRoute(animated: animated) // Re-run with the state machine back in the .space state.
}
}
@@ -212,7 +221,7 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
guard let self, let roomProxy = context.userInfo as? JoinedRoomProxyProtocol else {
fatalError("The room proxy must always be provided")
}
Task { await self.startMembersFlow(roomProxy: roomProxy) }
startMembersFlow(roomProxy: roomProxy)
}
stateMachine.addRouteMapping { event, fromState, _ in
@@ -223,6 +232,22 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
membersFlowCoordinator = nil
}
stateMachine.addRouteMapping { event, fromState, _ in
guard event == .startSettingsFlow, case .space = fromState else { return nil }
return .settingsFlow
} handler: { [weak self] context in
guard let self, let roomProxy = context.userInfo as? JoinedRoomProxyProtocol else { return }
startSettingsFlow(roomProxy: roomProxy)
}
stateMachine.addRouteMapping { event, fromState, _ in
guard event == .stopSettingsFlow, case .settingsFlow = fromState else { return nil }
return .space
} handler: { [weak self] _ in
guard let self else { return }
settingsFlowCoordinator = nil
}
stateMachine.addErrorHandler { context in
fatalError("Unexpected transition: \(context)")
}
@@ -235,6 +260,7 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
spaceServiceProxy: spaceServiceProxy,
selectedSpaceRoomPublisher: selectedSpaceRoomSubject.asCurrentValuePublisher(),
userSession: flowParameters.userSession,
appSettings: flowParameters.appSettings,
userIndicatorController: flowParameters.userIndicatorController)
let coordinator = SpaceScreenCoordinator(parameters: parameters)
coordinator.actionsPublisher
@@ -251,6 +277,8 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
stateMachine.tryEvent(.leftSpace)
case .displayMembers(let roomProxy):
stateMachine.tryEvent(.startMembersFlow, userInfo: roomProxy)
case .displaySpaceSettings(roomProxy: let roomProxy):
stateMachine.tryEvent(.startSettingsFlow, userInfo: roomProxy)
}
}
.store(in: &cancellables)
@@ -372,7 +400,7 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
selectedSpaceRoomSubject.send(roomID)
}
private func startMembersFlow(roomProxy: JoinedRoomProxyProtocol) async {
private func startMembersFlow(roomProxy: JoinedRoomProxyProtocol) {
let flowCoordinator = RoomMembersFlowCoordinator(entryPoint: .roomMembersList,
roomProxy: roomProxy,
navigationStackCoordinator: navigationStackCoordinator,
@@ -393,4 +421,22 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
membersFlowCoordinator = flowCoordinator
flowCoordinator.start()
}
private func startSettingsFlow(roomProxy: JoinedRoomProxyProtocol) {
let flowCoordinator = SpaceSettingsFlowCoordinator(roomProxy: roomProxy,
navigationStackCoordinator: navigationStackCoordinator,
flowParameters: flowParameters)
flowCoordinator.actions.sink { [weak self] actions in
guard let self else { return }
switch actions {
case .finished:
stateMachine.tryEvent(.stopSettingsFlow)
}
}
.store(in: &cancellables)
settingsFlowCoordinator = flowCoordinator
flowCoordinator.start()
}
}
@@ -0,0 +1,101 @@
//
// Copyright 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Combine
import Foundation
import SwiftState
enum SpaceSettingsFlowCoordinatorAction {
case finished
}
final class SpaceSettingsFlowCoordinator: FlowCoordinatorProtocol {
indirect enum State: StateType {
/// The state machine hasn't started.
case initial
/// The space settings screen
case spaceSettings
}
enum Event: EventType {
case start
case presentSpaceSettings
}
private let roomProxy: JoinedRoomProxyProtocol
private let navigationStackCoordinator: NavigationStackCoordinator
private let flowParameters: CommonFlowParameters
private let stateMachine: StateMachine<State, Event>
private var cancellables = Set<AnyCancellable>()
private let actionsSubject: PassthroughSubject<SpaceSettingsFlowCoordinatorAction, Never> = .init()
var actions: AnyPublisher<SpaceSettingsFlowCoordinatorAction, Never> {
actionsSubject.eraseToAnyPublisher()
}
init(roomProxy: JoinedRoomProxyProtocol,
navigationStackCoordinator: NavigationStackCoordinator,
flowParameters: CommonFlowParameters) {
self.roomProxy = roomProxy
self.flowParameters = flowParameters
self.navigationStackCoordinator = navigationStackCoordinator
stateMachine = .init(state: .initial)
configureStateMachine()
}
func start(animated: Bool) {
stateMachine.tryEvent(.presentSpaceSettings, userInfo: animated)
}
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
fatalError("Not implemented yet")
}
func clearRoute(animated: Bool) {
// Not implemented yet
}
private func configureStateMachine() {
stateMachine.addRouteMapping { event, fromState, _ in
switch (fromState, event) {
case (.initial, .presentSpaceSettings):
return .spaceSettings
default:
return nil
}
}
stateMachine.addAnyHandler(.any => .any) { [weak self] context in
guard let self else { return }
let animated = context.userInfo as? Bool ?? true
switch (context.fromState, context.event, context.toState) {
case (.initial, .presentSpaceSettings, .spaceSettings):
presentSpaceSettings(animated: animated)
default:
fatalError("Unhandled transition")
}
}
}
private func presentSpaceSettings(animated: Bool) {
let coordinator = SpaceSettingsScreenCoordinator(parameters: .init())
coordinator.actionsPublisher.sink { [weak self] action in
switch action { }
}
.store(in: &cancellables)
navigationStackCoordinator.push(coordinator, animated: animated) { [weak self] in
self?.actionsSubject.send(.finished)
}
}
}