// // Copyright 2022 New Vector Ltd // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // import SwiftUI class NavigationRootCoordinator: ObservableObject, CoordinatorProtocol, CustomStringConvertible { @Published fileprivate var rootModule: NavigationModule? { didSet { if let oldValue { oldValue.coordinator.stop() oldValue.dismissalCallback?() } if let rootModule { logPresentationChange("Set root", rootModule) rootModule.coordinator.start() } } } /// The currently displayed coordinator var rootCoordinator: (any CoordinatorProtocol)? { rootModule?.coordinator } /// Sets or replaces the presented coordinator /// - Parameter coordinator: the coordinator to display func setRootCoordinator(_ coordinator: (any CoordinatorProtocol)?, dismissalCallback: (() -> Void)? = nil) { guard let coordinator else { rootModule = nil return } rootModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback) } // MARK: - CoordinatorProtocol func toPresentable() -> AnyView { AnyView(NavigationRootCoordinatorView(rootCoordinator: self)) } // MARK: - CustomStringConvertible var description: String { if let rootCoordinator = rootModule?.coordinator { return "SingleScreenCoordinator(\(rootCoordinator)" } else { return "SingleScreenCoordinator(Empty)" } } // MARK: - Private private func logPresentationChange(_ change: String, _ module: NavigationModule) { MXLog.info("\(self) \(change): \(module.coordinator)") } } private struct NavigationRootCoordinatorView: View { @ObservedObject var rootCoordinator: NavigationRootCoordinator var body: some View { ZStack { rootCoordinator.rootModule?.coordinator.toPresentable() } .animation(.elementDefault, value: rootCoordinator.rootModule) } }