mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Add a SpaceExplorerFlowCoordinator. (#4383)
* Add a SpaceExplorerFlowCoordinator.
* Project tweaks
- iOS 17.5 so that we can use the simulator.
- Make a Spaces group for common Space related views.
- Fix the tab bar badge colour on iPhone landscape and iPadOS 17 (18 is still wrong 😒)
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// 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 SpaceExplorerFlowCoordinatorAction: Equatable {
|
||||
case showSettings
|
||||
}
|
||||
|
||||
class SpaceExplorerFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let userSession: UserSessionProtocol
|
||||
|
||||
private let navigationSplitCoordinator: NavigationSplitCoordinator
|
||||
private let sidebarNavigationStackCoordinator: NavigationStackCoordinator
|
||||
private let detailNavigationStackCoordinator: NavigationStackCoordinator
|
||||
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
|
||||
enum State: StateType {
|
||||
/// The state machine hasn't started.
|
||||
case initial
|
||||
/// The root screen for this flow.
|
||||
case spaceList
|
||||
}
|
||||
|
||||
enum Event: EventType {
|
||||
/// The flow is being started.
|
||||
case start
|
||||
}
|
||||
|
||||
private let stateMachine: StateMachine<State, Event>
|
||||
private var cancellables: Set<AnyCancellable> = []
|
||||
|
||||
private let actionsSubject: PassthroughSubject<SpaceExplorerFlowCoordinatorAction, Never> = .init()
|
||||
var actionsPublisher: AnyPublisher<SpaceExplorerFlowCoordinatorAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(userSession: UserSessionProtocol,
|
||||
navigationSplitCoordinator: NavigationSplitCoordinator,
|
||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
self.userSession = userSession
|
||||
self.navigationSplitCoordinator = navigationSplitCoordinator
|
||||
self.userIndicatorController = userIndicatorController
|
||||
|
||||
sidebarNavigationStackCoordinator = NavigationStackCoordinator(navigationSplitCoordinator: navigationSplitCoordinator)
|
||||
detailNavigationStackCoordinator = NavigationStackCoordinator(navigationSplitCoordinator: navigationSplitCoordinator)
|
||||
|
||||
navigationSplitCoordinator.setSidebarCoordinator(sidebarNavigationStackCoordinator)
|
||||
|
||||
stateMachine = .init(state: .initial)
|
||||
configureStateMachine()
|
||||
}
|
||||
|
||||
func start() {
|
||||
stateMachine.tryEvent(.start)
|
||||
}
|
||||
|
||||
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) {
|
||||
// There aren't any routes to this screen yet, so clear the stacks.
|
||||
clearRoute(animated: animated)
|
||||
}
|
||||
|
||||
func clearRoute(animated: Bool) {
|
||||
switch stateMachine.state {
|
||||
case .initial, .spaceList:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func configureStateMachine() {
|
||||
stateMachine.addRoutes(event: .start, transitions: [.initial => .spaceList]) { [weak self] _ in
|
||||
self?.presentSpaceList()
|
||||
}
|
||||
|
||||
stateMachine.addErrorHandler { context in
|
||||
fatalError("Unexpected transition: \(context)")
|
||||
}
|
||||
}
|
||||
|
||||
private func presentSpaceList() {
|
||||
let parameters = SpaceListScreenCoordinatorParameters(userSession: userSession)
|
||||
let coordinator = SpaceListScreenCoordinator(parameters: parameters)
|
||||
coordinator.actionsPublisher.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .showSettings:
|
||||
actionsSubject.send(.showSettings)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
sidebarNavigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
private let onboardingStackCoordinator: NavigationStackCoordinator
|
||||
private let chatsFlowCoordinator: ChatsFlowCoordinator
|
||||
private let chatsTabDetails: NavigationTabCoordinator<HomeTab>.TabDetails
|
||||
private let spaceExplorerFlowCoordinator: SpaceExplorerFlowCoordinator
|
||||
private let spacesTabDetails: NavigationTabCoordinator<HomeTab>.TabDetails
|
||||
|
||||
private let actionsSubject: PassthroughSubject<UserSessionFlowCoordinatorAction, Never> = .init()
|
||||
@@ -75,10 +76,10 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
chatsTabDetails = .init(tag: HomeTab.chats, title: L10n.screenHomeTabChats, icon: \.chat, selectedIcon: \.chatSolid)
|
||||
chatsTabDetails.barVisibility = .hidden
|
||||
|
||||
// This is just temporary, it needs a flow coordinator to properly handle (amongst other things) navigation/split views.
|
||||
let spaceListScreenCoordinator = SpaceListScreenCoordinator(parameters: .init(userSession: userSession))
|
||||
let spacesNavigationCoordinator = NavigationStackCoordinator()
|
||||
spacesNavigationCoordinator.setRootCoordinator(spaceListScreenCoordinator)
|
||||
let spacesSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator())
|
||||
spaceExplorerFlowCoordinator = SpaceExplorerFlowCoordinator(userSession: userSession,
|
||||
navigationSplitCoordinator: spacesSplitCoordinator,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
spacesTabDetails = .init(tag: HomeTab.spaces, title: L10n.screenHomeTabSpaces, icon: \.space, selectedIcon: \.spaceSolid)
|
||||
|
||||
onboardingStackCoordinator = NavigationStackCoordinator()
|
||||
@@ -94,7 +95,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
navigationTabCoordinator.setTabs([
|
||||
.init(coordinator: chatsSplitCoordinator, details: chatsTabDetails),
|
||||
.init(coordinator: spacesNavigationCoordinator, details: spacesTabDetails)
|
||||
.init(coordinator: spacesSplitCoordinator, details: spacesTabDetails)
|
||||
])
|
||||
|
||||
setupObservers()
|
||||
@@ -104,6 +105,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
#warning("This flow still needs a state machine.")
|
||||
|
||||
chatsFlowCoordinator.start()
|
||||
spaceExplorerFlowCoordinator.start()
|
||||
|
||||
attemptStartingOnboarding()
|
||||
}
|
||||
@@ -147,6 +149,16 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
spaceExplorerFlowCoordinator.actionsPublisher
|
||||
.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .showSettings:
|
||||
break
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
userSession.sessionSecurityStatePublisher
|
||||
.map(\.verificationState)
|
||||
.filter { $0 != .unknown }
|
||||
|
||||
Reference in New Issue
Block a user