SkillAgentSearch skills...

Solivagant

πŸ”† Compose Multiplatform Navigation library - 🌸 Pragmatic, type safety navigation for Compose Multiplatform. Based on Freeletics Khonshu Navigation. β™₯️ ViewModel, SavedStateHandle, Lifecycle, Multi-Backstacks, Transitions, Back-press handling, and more...

Install / Use

/learn @hoc081098/Solivagant

README

solivagant πŸ”†

[🟒 ACTIVE] πŸ”† Compose Multiplatform Navigation library - 🌸 Pragmatic, type safety navigation for Compose Multiplatform. Based on Freeletics Khonshu Navigation. β™₯️ ViewModel, SavedStateHandle, Lifecycle, Multi-Backstacks, Transitions, Back-press handling, and more...

maven-central <img src="https://img.shields.io/nexus/snapshots/https/s01.oss.sonatype.org/io.github.hoc081098/solivagant-navigation.svg?label=latest%20snapshot"/> codecov Build and publish snapshot Build sample Publish Release GitHub license Kotlin version KotlinX Coroutines version Compose Multiplatform version Hits

![badge][badge-android] ![badge][badge-jvm] ![badge][badge-js] ![badge][badge-js-ir] ![badge][badge-wasm] ![badge][badge-nodejs] ![badge][badge-linux] ![badge][badge-windows] ![badge][badge-ios] ![badge][badge-mac] ![badge][badge-watchos] ![badge][badge-tvos] ![badge][badge-apple-silicon]

  • Integrates with Jetbrains Compose Multiplatform seamlessly and easily.

  • Integrates with kmp-viewmodel library seamlessly and smoothly

    • Stack entry scoped ViewModel, exists as long as the stack entry is on the navigation stack, including the configuration changes on Android.

    • Supports SavedStateHandle, used to save and restore data over configuration changes or process death on Android.

  • The navigation stack state is saved and restored automatically over configuration changes and process death on Android. On other platforms, you can use a support class provided by this library to store the navigation stack state as long as you want.

  • Type safety navigation, easy to pass data between destinations. No more String route and dynamic query parameters. The Solivagant library uses NavRoutes and NavRoots to define routes that can be navigated to. Arguments can be defined as part of the route (a.ka. properties of the route class) and are type safe. Each NavRoute and NavRoot has a corresponding NavDestination that describes the UI (a.k.a @Composable) of the route.

  • Supports Multi-Backstacks, this is most commonly used in apps that use bottom navigation to separate the back stack of each tab. See Freeletics Khonshu Navigation - Multiple back stacks for more details.

  • Supports LifecycleOwner, Lifecycle events and states, similar to AndroidX Lifecycle library.

<p align="center"> <img src="https://github.com/hoc081098/solivagant/raw/master/logo.png" width="400"> </p>

[!NOTE] This library is still in alpha, so the API may change in the future.

Credits

Author: Petrus Nguyα»…n ThΓ‘i Học

Liked some of my work? Buy me a coffee (or more likely a beer)

<a href="https://www.buymeacoffee.com/hoc081098" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-blue.png" alt="Buy Me A Coffee" height=64></a>

Docs & Installation

0.x release docs: https://hoc081098.github.io/solivagant/docs/0.x

Snapshot docs: https://hoc081098.github.io/solivagant/docs/latest

Installation

allprojects {
  repositories {
    [...]
    mavenCentral()
  }
}
implementation("io.github.hoc081098:solivagant-navigation:0.5.0")

Snapshot

<details> <summary>Snapshots of the development version are available in Sonatype's snapshots repository.</summary>
allprojects {
  repositories {
    ...
    maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/")
  }
}

dependencies {
  implementation("io.github.hoc081098:solivagant-navigation:0.5.1-SNAPSHOT")
}
</details>

Getting started

The library is ported from Freeletics Khonshu Navigation library, so the concepts is similar. You can read the Freeletics Khonshu Navigation to understand the concepts.

πŸ‘‰ Full samples are available here.

1. Create NavRoots, NavRoutes

@Immutable
@Parcelize
data object StartScreenRoute : NavRoot

@Immutable
@Parcelize
data object SearchProductScreenRoute : NavRoute

[!NOTE] @Parcelize is provided by kmp-viewmodel-savedstate library. See kmp-viewmodel-savedstate for more details.

2. Create NavDestinations along with Composables and ViewModels

StartScreen.kt

@JvmField
val StartScreenDestination: NavDestination =
  ScreenDestination<StartScreenRoute> { StartScreen() }

@Composable
internal fun StartScreen(
  modifier: Modifier = Modifier,
  // kmpViewModel or kojectKmpViewModel can be used instead.
  viewModel: StartViewModel = koinKmpViewModel(),
) {
  // UI Composable
}

internal class StartViewModel(
  // used to trigger navigation actions from outside the view layer (e.g. from a ViewModel).
  // Usually, it is singleton object, or the host Activity retained scope.
  private val navigator: NavEventNavigator,
) : ViewModel() {
  internal fun navigateToProductsScreen() = navigator.navigateTo(ProductsScreenRoute)
  internal fun navigateToSearchProductScreen() = navigator.navigateTo(SearchProductScreenRoute)
}
SearchProductScreen.kt
@JvmField
val SearchProductScreenDestination: NavDestination =
  ScreenDestination<SearchProductScreenRoute> { SearchProductsScreen() }

@Composable
internal fun SearchProductsScreen(
  modifier: Modifier = Modifier,
  // kmpViewModel or kojectKmpViewModel can be used instead.
  viewModel: SearchProductsViewModel = koinKmpViewModel<SearchProductsViewModel>(),
) {
  // UI Composable
}

internal class SearchProductsViewModel(
  private val searchProducts: SearchProducts,
  private val savedStateHandle: SavedStateHandle,
  // used to trigger navigation actions from outside the view layer (e.g. from a ViewModel).
  // Usually, it is singleton object, or the host Activity retained scope.
  private val navigator: NavEventNavigator,
) : ViewModel() {
  fun navigateToProductDetail(id: Int) {
    navigator.navigateTo(ProductDetailScreenRoute(id))
  }
}

3. Setup

3.1. NavHost

Gather all NavDestinations in a set and use NavEventNavigator to trigger navigation actions.

MyAwesomeApp.kt
@Stable
private val AllDestinations: ImmutableSet<NavDestination> = persistentSetOf(
  StartScreenDestination,
  SearchProductScreenDestination,
  // and more ...
)

@Composable
fun MyAwesomeApp(
  // used to trigger navigation actions from outside the view layer (e.g. from a ViewModel).
  // Usually, it is singleton object, or the host Activity retained scope.
  navigator: NavEventNavigator = koinInject(),
  modifier: Modifier = Modifier,
) {
  // BaseRoute is the parent interface of NavRoute and NavRoot.
  // It implements Parcelable so that it can be used with rememberSavable.
  var currentRoute: BaseRoute? by rememberSavable { mutableStateOf(null) }

  NavHost(
    modifier = modifier,
    // route to the screen that should be shown initially
    startRoute = StartScreenRoute,
    // should contain all destinations that can be navigated to
    destinations = AllDestinations,
    // when passing a NavEventNavigator to NavHost, NavHost will take care of setting up the navigator by calling `NavigationSetup(navigator)`
    navEventNavigator = navigator,
    destinationChangedCallback = { currentRoute = it },
  )
}

[!IMPORTANT] When passing a NavEventNavigator to NavHost composable, the NavHost will take care of setting up the navigator by calling `Navigatio

View on GitHub
GitHub Stars124
CategoryDevelopment
Updated8d ago
Forks4

Languages

Kotlin

Security Score

100/100

Audited on Mar 18, 2026

No findings