// // Coordinator.swift // Coordination // // Created by Javier Cicchelli on 11/04/2023. // Copyright © 2023 Röck+Cöde. All rights reserved. // /// This protocol organize the flow logic between view controllers in the app. public protocol Coordinator: AnyObject { // MARK: Properties /// The child coordinators that are being currently presented. var children: [Coordinator] { get set } /// The router that handles how the view controllers in the coordinators will be shown or dismissed. var router: Router { get } // MARK: Functions /// Present the coordinator animatedly or not, depending on the given `animated` parameter, and also pass a closure that should be called on dismissal. /// - Parameters: /// - animated: A boolean that represents whether the coordinator should be dismissed animatedly or not. /// - onDismiss: A closure to be called or executed when the presented coordinator is dismissed. func present(animated: Bool, onDismiss: Router.OnDismissedClosure?) } // MARK: - Coordinator+Implementations public extension Coordinator { /// Present a child coordinator animatedly or not, depending on the given `animated` parameter, and also pass a closure that should be called on dismissal. /// - Parameters: /// - child: A child coordinator to be presented. /// - animated: A boolean that represents whether the coordinator should be dismissed animatedly or not. /// - onDismiss: A closure to be called or executed when the presented coordinator is dismissed. func present( child: Coordinator, animated: Bool, onDismiss: Router.OnDismissedClosure? = nil ) { store(child) child.present(animated: animated) { [weak self, weak child] in guard let self, let child else { return } self.free(child) onDismiss?() } } /// Dismiss the coordinator animatedly or not, depending on the given `animated` parameter. /// - Parameter animated: A boolean that represents whether the coordinator should be dismissed animatedly or not. func dismiss(animated: Bool) { router.dismiss(animated: animated) } } // MARK: - Helpers private extension Coordinator { // MARK: Functions func store(_ coordinator: Coordinator) { children.append(coordinator) } func free(_ coordinator: Coordinator) { children = children.filter { $0 !== coordinator } } }