pr suggestions and implemented a simpler way to clear the route, that always brings back to the initial coordinator

This commit is contained in:
Mauro Romito
2025-11-05 16:05:09 +01:00
committed by Mauro
parent e597dd8722
commit 6dee4176f2
7 changed files with 136 additions and 50 deletions
@@ -574,6 +574,21 @@ private struct NavigationSplitCoordinatorView: View {
}
}
func pop(to coordinator: CoordinatorProtocol, animated: Bool = true) {
if rootCoordinator === coordinator {
popToRoot(animated: animated)
} else if stackCoordinators.contains(where: { $0 === coordinator }) {
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
while stackCoordinators.last !== coordinator, !stackCoordinators.isEmpty {
_ = stackModules.popLast()
}
}
}
}
/// Present a sheet on top of the stack. If this NavigationStackCoordinator is embedded within a NavigationSplitCoordinator
/// then the presentation will be proxied to the split
/// - Parameters:
@@ -59,6 +59,8 @@ final class RoomMembersFlowCoordinator: FlowCoordinatorProtocol {
private let entryPoint: RoomMembersFlowCoordinatorEntryPoint
private let roomProxy: JoinedRoomProxyProtocol
private let navigationStackCoordinator: NavigationStackCoordinator
/// The last coordinator in the `navigationStackCoordinator` stack at the initial state
private let initialCoordinator: CoordinatorProtocol?
private let flowParameters: CommonFlowParameters
private let stateMachine: StateMachine<State, Event>
@@ -79,8 +81,9 @@ final class RoomMembersFlowCoordinator: FlowCoordinatorProtocol {
self.roomProxy = roomProxy
self.flowParameters = flowParameters
self.navigationStackCoordinator = navigationStackCoordinator
initialCoordinator = navigationStackCoordinator.stackCoordinators.last ?? navigationStackCoordinator.rootCoordinator
stateMachine = .init(state: .initial)
stateMachine = flowParameters.stateMachineFactory.makeMembersFlowStateMachine(state: .initial)
configureStateMachine()
}
@@ -123,14 +126,21 @@ final class RoomMembersFlowCoordinator: FlowCoordinatorProtocol {
}
func clearRoute(animated: Bool) {
if stateMachine.state == .inviteUsersScreen {
switch stateMachine.state {
case .inviteUsersScreen:
navigationStackCoordinator.setSheetCoordinator(nil, animated: animated)
} else if let roomFlowCoordinator {
roomFlowCoordinator.clearRoute(animated: animated)
clearRoute(animated: animated)
case .roomFlow:
roomFlowCoordinator?.clearRoute(animated: animated)
clearRoute(animated: animated)
case .initial:
break
case .roomMemberDetails, .roomMembersList, .userProfile:
guard let initialCoordinator else {
return
}
navigationStackCoordinator.pop(to: initialCoordinator, animated: animated)
}
// We don't support dismissing a sub flow by itself, only the entire chain.
// The presenter flow will take care of dismissing it
actionsSubject.send(.finished)
}
private func configureStateMachine() {
@@ -59,14 +59,11 @@ final class SpaceSettingsFlowCoordinator: FlowCoordinatorProtocol {
private let roomProxy: JoinedRoomProxyProtocol
private let navigationStackCoordinator: NavigationStackCoordinator
private let initialCoordinator: CoordinatorProtocol?
private let flowParameters: CommonFlowParameters
private let stateMachine: StateMachine<State, Event>
private var cancellables = Set<AnyCancellable>()
private var modalNavigationStackCoordinator: NavigationStackCoordinator?
private var membersFlowCoordinator: RoomMembersFlowCoordinator?
private var rolesAndPermissionsFlowCoordinator: RoomRolesAndPermissionsFlowCoordinator?
private var membersFlowCoordinator: RoomMembersFlowCoordinator?
private var rolesAndPermissionsFlowCoordinator: RoomRolesAndPermissionsFlowCoordinator?
@@ -82,6 +79,7 @@ final class SpaceSettingsFlowCoordinator: FlowCoordinatorProtocol {
self.roomProxy = roomProxy
self.flowParameters = flowParameters
self.navigationStackCoordinator = navigationStackCoordinator
initialCoordinator = navigationStackCoordinator.stackCoordinators.last ?? navigationStackCoordinator.rootCoordinator
stateMachine = .init(state: .initial)
configureStateMachine()
@@ -99,11 +97,9 @@ final class SpaceSettingsFlowCoordinator: FlowCoordinatorProtocol {
switch stateMachine.state {
case .initial:
break
case .spaceSettings:
navigationStackCoordinator.pop(animated: animated)
case .securityAndPrivacy:
navigationStackCoordinator.pop(animated: animated)
clearRoute(animated: animated)
case .spaceSettings, .securityAndPrivacy:
guard let initialCoordinator else { return }
navigationStackCoordinator.pop(to: initialCoordinator, animated: animated)
case .editDetailsScreen, .editAddress:
navigationStackCoordinator.setSheetCoordinator(nil, animated: animated)
clearRoute(animated: animated)
@@ -39,37 +39,3 @@ struct OverridableAvatarImage: View {
}
}
}
extension View {
func clipAvatar(isSpace: Bool, size: CGFloat) -> some View {
modifier(ClipAvatarModifier(isSpace: isSpace, size: size))
}
func clipAvatar(isSpace: Bool, scaledSize: ScaledMetric<CGFloat>) -> some View {
modifier(ClipAvatarModifier(isSpace: isSpace, scaledSize: scaledSize))
}
}
struct ClipAvatarModifier: ViewModifier {
private let isSpace: Bool
@ScaledMetric private var scaledSize: CGFloat
init(isSpace: Bool, size: CGFloat) {
self.isSpace = isSpace
_scaledSize = ScaledMetric(wrappedValue: size)
}
init(isSpace: Bool, scaledSize: ScaledMetric<CGFloat>) {
self.isSpace = isSpace
_scaledSize = scaledSize
}
func body(content: Content) -> some View {
content
.clipShape(avatarShape)
}
private var avatarShape: some Shape {
isSpace ? AnyShape(RoundedRectangle(cornerRadius: scaledSize / 4)) : AnyShape(Circle())
}
}
@@ -13,6 +13,7 @@ import SwiftState
protocol StateMachineFactoryProtocol {
func makeUserSessionFlowStateMachine(state: UserSessionFlowCoordinator.State) -> StateMachine<UserSessionFlowCoordinator.State, UserSessionFlowCoordinator.Event>
func makeChatsFlowStateMachine() -> ChatsFlowCoordinatorStateMachine
func makeMembersFlowStateMachine(state: RoomMembersFlowCoordinator.State) -> StateMachine<RoomMembersFlowCoordinator.State, RoomMembersFlowCoordinator.Event>
}
struct StateMachineFactory: StateMachineFactoryProtocol {
@@ -23,6 +24,10 @@ struct StateMachineFactory: StateMachineFactoryProtocol {
func makeChatsFlowStateMachine() -> ChatsFlowCoordinatorStateMachine {
.init()
}
func makeMembersFlowStateMachine(state: RoomMembersFlowCoordinator.State) -> StateMachine<RoomMembersFlowCoordinator.State, RoomMembersFlowCoordinator.Event> {
.init(state: state)
}
}
// MARK: For testing
@@ -49,4 +54,14 @@ class PublishedStateMachineFactory: StateMachineFactoryProtocol {
stateMachine.addTransitionHandler { [weak self] in self?.chatsFlowStatePublisher.send($0.toState) }
return stateMachine
}
// MARK: MembersFlowCoordinator
let membersFlowStatePublisher = PassthroughSubject<RoomMembersFlowCoordinator.State, Never>()
func makeMembersFlowStateMachine(state: RoomMembersFlowCoordinator.State) -> StateMachine<RoomMembersFlowCoordinator.State, RoomMembersFlowCoordinator.Event> {
let stateMachine = baseFactory.makeMembersFlowStateMachine(state: state)
stateMachine.addAnyHandler(.any => .any) { [weak self] in self?.membersFlowStatePublisher.send($0.toState) }
return stateMachine
}
}