ekazaev/route-composer

Is it compatible with swiftUI?

vBoykoGit opened this issue · 6 comments

Could you provide some examples of routing and building view with swiftUI?

@vBoykoGit It is compatible, as SwiftUI still sits within UIViewControllers. And RootComposer operates with them. Just default Finders and Factoriyies need to be tweaked though. I did couple experiments. But as imho SwiftUI is still in a Proof of concept state I haven't gone any further yet, so I do not have anything production ready. Sorry about that. But, with this lockdown Ill probably will have a better look.

I will try to add something here. I had it stashed somewhere. Basically they need to support UIHostingController

@vBoykoGit I found something for you

Factory/Finder will look like this:
I wrote with context to be equatable. But I am sure you can adapt it to be used with any type of context by the example with the finders that are present already

#if os(iOS)

import Foundation
import UIKit

import SwiftUI

public protocol ContextInstantiatable {

    associatedtype Context

    var context: Context { get }

    init(context: Context)

}

@available(iOS 13.0.0, *)
public struct UIHostingControllerFactory<ContentView: View & ContextInstantiatable>: Factory {

    public typealias ViewController = UIHostingController<ContentView>

    public typealias Context = ContentView.Context

    public init() {
    }

    public func build(with context: Context) throws -> UIHostingController<ContentView> {
        let viewController = UIHostingController(rootView: ContentView(context: context))
        return viewController
    }

}

@available(iOS 13.0.0, *)
public struct UIHostingControllerFinder<ContentView: View & ContextInstantiatable>: StackIteratingFinder where ContentView.Context: Equatable {

    public typealias ViewController = UIHostingController<ContentView>

    public typealias Context = ContentView.Context

    public let iterator: StackIterator

    public init(iterator: StackIterator = DefaultStackIterator()) {
        self.iterator = iterator
    }

    public func isTarget(_ viewController: ViewController, with context: Context) -> Bool {
        return viewController.rootView.context == context
    }

}

#endif

Lets assume that your SwiftUIView looks like this:

import Foundation
import SwiftUI
import RouteComposer

@available(iOS 13.0.0, *)
struct ContentView: View, ContextInstantiatable {

    let context: String

    init(context: String) {
        self.context = context
    }

    var body: some View {
        Text("Hello SwiftUI. Context is \(context)")
    }

}

So configuration to present it within tab bar will look like this:

let step = StepAssembly(
            finder: UIHostingControllerFinder<ContentView>(),
            factory: UIHostingControllerFactory()
        )
        .using(UITabBarController.add())
        .from(homeScreen.adaptingContext())
        .assemble()

try? router.navigate(to: step, with: "Test Context")

Which will bring you here:

Screenshot 2020-03-24 at 20 45 04

You can check out the example project here:
https://github.com/ekazaev/route-composer/tree/chore/swift-ui-support

Please keep in mind that I just applied the stash I had. But similar factories/finders will be available in the library later. So you will be able to replace your implementations with the library ones.

@vBoykoGit Please let me know if you'll need any further help

@vBoykoGit
Closed due to inactivity.