ekazaev / route-composer

Protocol oriented, Cocoa UI abstractions based library that helps to handle view controllers composition, navigation and deep linking tasks in the iOS application. Can be used as the universal replacement for the Coordinator pattern.
MIT License
896 stars 63 forks source link

How to push 2 view controllers, both which can accept context #91

Closed vykut closed 1 year ago

vykut commented 1 year ago

Hello,

In my usecase I have 2 view controllers - View Controller A and View Controller B - which I want to push both on the same navigation stack. Both of the view controllers conform to the ContextAccepting protocol, but I only care of applying a new context for the View Controller B.

Schematically it would look like this: NavController -> View Controller A -> View Controller B

the routes are defined as follows:

View Controller A

static func viewControllerA() -> DestinationStep<ViewControllerA, ViewControllerA.Context> {
        StepAssembly(
            finder: ClassFinder(),
            factory: ViewControllerAFactory()
        )
        .adding(ContextSettingTask())
        .using(UINavigationController.pushAsRoot())
        .from(NavigationControllerStep<UINavigationController, ViewControllerA.Context>())
        .using(UITabBarController.add())
        .from(tabBar().unsafelyRewrapped())
        .assemble()
    }

View Controller B

static func viewControllerB() -> DestinationStep<ViewControllerB, ViewControllerB.Context> {
        StepAssembly(
            finder: NilFinder(),
            factory: ViewControllerBFactory()
        )
        .using(BPNavigationController.push())
        .from(
            viewControllerA()
                .adaptingContext(
                    using: InlineContextTransformer { (ctx: ViewControllerB.Context) in
                        return ViewControllerA.Context(...)
                    }
                )
                .expectingContainer()
        )
        .assemble()
    }

The "problem" I'm facing is that I don't actually need (or want) to pass any kind of context to View Controller A, but I'm required to by the library. In my case, the ViewControllerA.Context is not used for building the ViewController, but rather for "injecting" a different state based on the source of the navigation. In this case, though, I would like View Controller A to not change its state if View Controller B is pushed on top of it.

A potential solution might be to make ViewControllerA.Context optional, and in case it is missing, View Controller A could just ignore it, but I was wondering whether the authors of this library envisioned a different approach for solving this.

How should one approach the aforementioned behavior?

ekazaev commented 1 year ago

@vykut Sorry for the late reply.

Here everything depends what you want to do. If you want always to push into any navigation controller that is curently visible you can do something like

    let screen = StepAssembly(
            finder: NilFinder(),
            factory: ViewControllerBFactory())
            .using(UINavigationController.push())
            .from(GeneralStep.custom(using: ClassFinder<UINavigationController, Any?>()))
            .assemble()

If you always want to push from the view controller A but you do not expect to create it - so it doesnt miss the pice of information that is stored in it context

    let screen = StepAssembly(
            finder: NilFinder(),
            factory: ViewControllerBFactory())
            .using(UINavigationController.push())
                .from(
                    GeneralStep.custom(
                        using: ClassFinder<ViewControllerAFactory.ViewController, Any?>()
                    ).expectingContainer()
                )
                .assemble()

Please check also some suggestions from here

Please let me know if there is anything I can help with

ekazaev commented 1 year ago

Ill close the issue for now. Feel free to reopen it if needed