First you must create a NavigationRoute
sealed class that will represent all the possible routes
of your application.
enum class YourNavigationRouteName {
ROUTE1,
ROUTE2
}
sealed class YourNavigationRoute(routeName: YourNavigationRouteName) :
EnumPilotNavigationRoute(routeName) {
data object Route1 : YourNavigationRoute(ROUTE1)
data class Route2(val someNavigationData: SomeNavigationData) : YourNavigationRoute(ROUTE2)
}
You must also create a NavigationAction
sealed class that will represent all the possible actions
of your application.
sealed interface YourNavigationAction {
data object Action1 : YourNavigationAction
data class Action2(val someActionArgument: SomeActionArgument) : YourNavigationAction
}
Then you must create a NavigationManager
class which will allow you to navigate between routes.
Navigation managers support a parent navigation manager which allows you to create a hierarchy of
navigation managers.
class YourNavigationManager(
coroutineScope: CoroutineScope,
parentNavigationManager: YourNavigationManager? = null,
) : DefaultPilotNavigationManager<YourNavigationRoute, YourNavigationAction>(
coroutineScope,
parentNavigationManager,
)
You must create a YourActionNavigationListener
which will implement your external navigation
actions.
class YourActionNavigationListener : PilotActionNavigationListener<YourNavigationAction> {
override fun handleAction(action: NewsNavigationAction) {
when (action) {
YourNavigationAction.Action1 -> {
// Your code here
}
is YourNavigationAction.Action2 -> {
// Your code here
}
}
}
}
You must create a NavigationHost
composable that will be the entry point of your application.
@Composable
fun YourNavigationHost(
navigationManager: YourNavigationManager,
modifier: Modifier = Modifier,
rootContent: @Composable () -> Unit,
) {
val navController = rememberNavController()
LaunchedEffect(navigationManager, navController) {
navigationManager.listener = PilotNavControllerNavigationListener(navController)
navigationManager.actionListener = YourActionNavigationListener()
}
NavHost(
navController = navController,
startDestination = ROOT_ROUTE,
) {
composable(ROOT_ROUTE) {
rootContent()
}
composable(YourNavigationRoute.ROUTE1.name) {
YourRoute1Screen(navigationManager)
}
composable(YourNavigationRoute.ROUTE2.name) {
YourRoute2Screen(navigationManager)
}
}
PilotBackHandler(
navController = navController,
navigationManager = navigationManager,
rootName = ROOT_ROUTE,
)
}
SwiftUI navigation works through the help of a View Modifier.
extension View {
func yourNavigation(navigationManager: YourNavigationManager) -> some View {
modifier(YourNavigationModifier(navigationManager: navigationManager))
}
}
private struct YourNavigationModifier: ViewModifier {
let navigationManager: YourNavigationManager
func body(content: Content) -> some View {
content
.pilotNavigation(
navigationManager: navigationManager,
buildView: buildView,
buildNavigation: buildNavigation,
handleAction: handleAction
)
}
@ViewBuilder
private func buildView(viewModelHolder: ViewModelHolder) -> some View {
switch viewModelHolder {
case .route1(let viewModel):
Route1View(viewModel: viewModel)
case .route2(let viewModel):
Route2View(viewModel: viewModel)
}
private func buildNavigation(routes: [YourNavigationRoute], route: YourNavigationRoute) -> PilotNavigationType<ViewModelHolder, EmptyViewModifier>? {
let onDismissClosure: () -> Void = {
navigationManager.poppedFrom(route: route)
}
return switch onEnum(of: route) {
case .route1(let route):
.sheet(
screen: ViewModelHolder.route1(
// Create your view model here with the route
),
data: NavigationTypeData(embedInNavigationView: false, onDismiss: onDismissClosure)
)
case .route2(let route):
.fullScreenCover(
screen: ViewModelHolder.route2(
// Create your view model here with the route
),
data: NavigationTypeData(embedInNavigationView: false, onDismiss: onDismissClosure)
)
}
private func handleAction(action: YourNavigationAction) {
switch onEnum(of: action) {
case .action1:
// Your code here
case .action2(let action):
// Your code here
}
}
enum ViewModelHolder {
case route1(Route1ViewModel)
case route2(Route2ViewModel)
}
build.gradle.kts
repositories {
maven(url = "https://s3.amazonaws.com/mirego-maven/public")
}
dependencies {
implementation("com.mirego.pilot:navigation:<version>")
}
!!! warning This library does not support restoring the state of the navigation stack when the application is killed and restarted on android. This is a known limitation and is not planned to be implemented in the future.
Podfile
pod 'Pilot/Navigation', :git => '[email protected]:mirego/viewmodel-pilot.git', :tag => '<version>', :inhibit_warnings => true