Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Short circuiting Coordinators Routing Logic #60

Open
shahzadmajeed opened this issue Dec 23, 2023 · 0 comments
Open

Short circuiting Coordinators Routing Logic #60

shahzadmajeed opened this issue Dec 23, 2023 · 0 comments

Comments

@shahzadmajeed
Copy link

Hello, I am facing a unique navigation problem so I will try to describe it as simply as I can but I am hoping that I can get some help from this forum as TCACoordinators user:

We are migrating our Xamarin (C#) based application to native features while binding new features back into the existing Xamarin app at the same time. So, we have a native SwiftUI app that is being built in parallel to the existing C# app. All new native features use TCA.

We want to setup the navigation system so that:

  1. Our native app uses SwiftUI navigation via. TCACoordinators to take advantage of how the library provides flexibility to model complex navigations by decoupling it from UI/Presentation layer
  2. Our Xamarin app is in control of navigation when native features are placed inside the Xamarin app so we send native views to C# via. bindings and C# renderes those views. This is because our business use cases require us to push native features on xamarin features and xamarin on top of native features. So. native navigation cannot help here.

Now, my TCACoordinator seems to be working fine (with some issues that are a separate topic) in the native app but they don't work when I short-circuit the coordinator reducer by scoping it, instantiating view with scoped store and render that view in Xamarin. The problem is that the scoped reducer loses the context of its parent (the coordinator) and the actions of scoped reducers don't go through the coordinator anymore.

I am wondering if I can create a scoped store such that the actions of the scoped store still go through the coordinator just like the normal TCA feature hierarchy.

Here is how I do that:

public struct NativeDemoFeatureCoordinator: Reducer {

    public let xamarinNavigationOverride: XamarinNavigationOverride?

    public init(xamarinNavigationOverride: XamarinNavigationOverride? = nil) {
        self.xamarinNavigationOverride = xamarinNavigationOverride
    }

    public struct State: Equatable, IdentifiedRouterState {
        public var routes: IdentifiedArrayOf<Route<Screen.State>>
    }

    public enum Action: IdentifiedRouterAction {
        case routeAction(Screen.State.ID, action: Screen.Action)
        case updateRoutes(IdentifiedArrayOf<Route<Screen.State>>)
    }

    public var body: some ReducerOf<Self> {

        Reduce<State, Action> { state, action in

            let canRouteToXamarin: (Screen.State, NavType) -> Bool = { childState, navType in
                guard let xamarinNavigationOverride else { return false }

                let coordinator = Store(initialState: .init(routes: [])) { self }
                let feature = coordinator.scope(
                    state: { _ in childState },
                    action: { (_: Screen.Action) in action }
                )

                xamarinNavigationOverride(screen(for: feature), navType)

                return true
            }

            switch action {

            /// MyFeatureActions
            case .routeAction(_, .myFeatureAction(.navigateOnStack)):
                if canRouteToXamarin(.myFeatureState(.init(nav: .push)), .push) {
                    return .none
                }

                state.routes.push(.myFeatureState(.init(nav: .push)))
                return .none

            default:
                return .none
            }
        }.forEachRoute {
            Screen()
        }
    }


    func screen(for store: Store<Screen.State, Screen.Action>) -> some View {
        SwitchStore(store) { screen in
            switch screen {
            case .myFeatureState:
                CaseLet(
                    /Screen.State.myFeatureState,
                     action: Screen.Action.myFeatureAction,
                     then: MyFeatureView.init
                )
            }
        }
    }
}

Any idea how can I achieve this goal where the scoped child feature can continue to go through the coordinator in the case when the feature is being rendered in Xamarin?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant