Code Monkey home page Code Monkey logo

serbelga / navigation-compose-extended Goto Github PK

View Code? Open in Web Editor NEW
6.0 1.0 0.0 452 KB

Navigation Compose Extended is a complementary multiplatform library for Jetpack Navigation Compose to improve creation of navigation elements in a more idiomatic way

Home Page: http://sergiobelda.dev/navigation-compose-extended/

License: Apache License 2.0

Kotlin 98.60% Swift 1.40%
compose jetpack navigation annotation-processor ksp safe-nav-args annotations kotlinpoet multiplatform

navigation-compose-extended's Introduction

Navigation Compose Extended

Maven Central

Navigation Compose Extended is a complementary multiplatform library for Jetpack Navigation Compose to improve creation of navigation elements, as destination routes, arguments, deep links, … in a more idiomatic way than using literals. It also provides Safe navigation routes and Safe navigation arguments.

Take a look at the sample-app-annotations and sample-app for working examples.

Visit the project website for documentation and API Reference.

Download

Android only
// Optional: Use Annotations to generate NavDestinations.
plugins {
    id("com.google.devtools.ksp")
}

dependencies {
    // Add AndroidX Navigation Compose dependency.
    implementation("androidx.navigation:navigation-compose:$nav_version")

    implementation("dev.sergiobelda.navigation.compose.extended:navigation-compose-extended:$version") 
    
    // Optional: Use Annotations to generate NavDestinations.
    implementation("dev.sergiobelda.navigation.compose.extended:navigation-compose-extended-annotation:$version")
    ksp("dev.sergiobelda.navigation.compose.extended:navigation-compose-extended-compiler:$version")
}
Multiplatform
// Optional: Use Annotations to generate NavDestinations.
plugins {
    id("com.google.devtools.ksp")
}

kotlin {

    sourceSets {
        val commonMain by getting {
            dependencies {
                // Add Jetbrains Navigation Compose Multiplatform dependency.
                implementation("org.jetbrains.androidx.navigation:navigation-compose:$jetbrains_nav_version")

                implementation("dev.sergiobelda.navigation.compose.extended:navigation-compose-extended:$version")
                // Optional: Use Annotations to generate NavDestinations.
                implementation("dev.sergiobelda.navigation.compose.extended:navigation-compose-extended-annotation:$version")
            }
        }
    }
}

// If use Annotations, add compiler dependency.
dependencies {
    add("kspCommonMainMetadata", "dev.sergiobelda.navigation.compose.extended:navigation-compose-extended-compiler:$version")
}

// Workaround for KSP only in Common Main.
// https://github.com/google/ksp/issues/567
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>>().all {
    if (name != "kspCommonMainKotlinMetadata") {
        dependsOn("kspCommonMainKotlinMetadata")
    }
}

kotlin.sourceSets.commonMain {
    kotlin.srcDir("build/generated/ksp/metadata/commonMain/kotlin")
}

Usage

Important

In the next documentation, annotations are used to create navigation elements, but we can also create them programmatically.

The NavDestination represents some Destination in the Navigation graph.

Create a NavDestination

@NavDestination(
    destinationId = "home",
    name = "Home", // Optional: NavDestination name.
    isTopLevelNavDestination = true, // Optional: Mark NavDestination as a top-level destination.
)
@Composable
fun HomeScreen() {}

The compiler will generate a NavDestination object associated with this destination.

public object HomeNavDestination : NavDestination<HomeNavArgumentKeys>() {
  override val destinationId: String = "home"
}

Using the NavDestination into the NavHost

NavHost(navController = navController, startNavDestination = HomeNavDestination) {
    composable(navDestination = HomeNavDestination) {
        HomeScreen()
    }
    composable(navDestination = SettingsNavDestination) {
        SettingsScreen()
    }
}

Note

Here we are using wrappers (NavHost, composable) that receive the NavDestination type to create the navigation graph. Visit the API Reference for more information.

NavDestination base class also offers route, arguments and deepLinks getters that can be used as follows if we don't want to use these wrappers:

NavHost(navController = navController, startDestination = HomeNavDestination.route) {
    composable(
        route = HomeNavDestination.route,
        deepLinks = HomeNavDestination.deepLinks
    ) {
        HomeScreen()
    }
    composable(
        route = HomeNavDestination.route,
        arguments = HomeNavDestination.arguments
    ) {
        SettingsScreen()
    }
}

Navigate

We can navigate to some destination using the actions functions provided by the NavAction class. The NavAction.navigate() function receive a NavRoute instance to navigate to some destination. This NavRoute associated with a destination can be obtained using the navRoute() function in the NavDestination class or the safeNavRoute() function if we are using annotations. In the following code, we navigate to the SettingsNavDestination:

val navAction = rememberNavAction(navController)
NavHost(navController = navController, startNavDestination = HomeNavDestination) {
    composable(navDestination = HomeNavDestination) {
        HomeScreen(
            navigateToSettings = {
                navAction.navigate(
                    SettingsNavDestination.navRoute()
                )
            },
        )
    }

Navigate with arguments

If we are using annotations, we can use the arguments parameter in @NavDestination annotation:

@NavDestination(
    name = "Settings",
    destinationId = "settings",
    arguments = [
        NavArgument(name = "userId", type = NavArgumentType.Int),
        NavArgument(name = "text", type = NavArgumentType.String, defaultValue = "Default"),
        NavArgument(name = "result", type = NavArgumentType.Boolean, defaultValue = "true"),
    ],
)
@Composable
fun SettingsScreen(
    viewModel: SettingsViewModel
) {}

The compiler will generate an enum class containing the navigation arguments keys for this navigation destination. The NavArgumentKey represents the navigation argument's key.

public enum class SettingsNavArgumentKeys(
  override val argumentKey: String,
) : NavArgumentKey {
  UserIdNavArgumentKey("userId"),
  TextNavArgumentKey("text"),
  ResultNavArgumentKey("result"),
  ;
}

The compiler also set the argumentsMap property in the NavDestination that associate each NavArgumentKey with its properties.

public object SettingsNavDestination : NavDestination<SettingsNavArgumentKeys>() {
  override val destinationId: String = "settings"

  override val argumentsMap: Map<SettingsNavArgumentKeys, NavArgumentBuilder.() -> Unit> = mapOf(
    SettingsNavArgumentKeys.UserIdNavArgumentKey to {
      type = NavType.IntType
    },
    SettingsNavArgumentKeys.TextNavArgumentKey to {
      type = NavType.StringType
      nullable = true
      defaultValue = "Default"
    },
    SettingsNavArgumentKeys.ResultNavArgumentKey to {
      type = NavType.BoolType
      defaultValue = true
    },
  )

Note

If we don't use annotations, we should create this enum class and set the argumentsMap programmatically.

If we use annotations, we can use the generated safeNavRoute() function with the navigation arguments as parameters:

composable(navDestination = HomeNavDestination) {
    HomeScreen(
        navigateToSettings = {
            navAction.navigate(
                SettingsNavDestination.safeNavRoute(
                    userId = 1,
                    text = "Text",
                    result = true
                )
            )
        },
    )
}

otherwise, we must use navRoute() function associating the NavArgumentKey to its value.

composable(navDestination = HomeNavDestination) {
    HomeScreen(
        navigateToSettings = {
            navAction.navigate(
                SettingsNavDestination.navRoute(
                    SettingsNavArgumentKeys.UserIdNavArgumentKey to 1,
                    SettingsNavArgumentKeys.TextNavArgumentKey to "Text",
                    SettingsNavArgumentKeys.ResultNavArgumentKey to true
                )
            )
        },
    )
}

Retrieving the navigation arguments values

The value of navigation arguments can be obtained using the NavArgs class. The NavDestination.navArgs() provides an instance of this class. There are multiple getters to retrieve values:

composable(navDestination = SettingsNavDestination) { navBackStackEntry ->
    val navArgs = SettingsNavDestination.navArgs(navBackStackEntry)
    val userId = navArgs.getInt(SettingsNavArgumentKeys.UserIdNavArgumentKey) ?: 0
    SettingsScreen(
        userId = userId,

If we use annotations, a SafeNavArgs class is generated with getters for each navigation argument:

composable(navDestination = SettingsNavDestination) { navBackStackEntry ->
    val navArgs = SettingsSafeNavArgs(navBackStackEntry)
    SettingsScreen(
        userId =  navArgs.userId ?: 0,

Navigate with Deep Links

In the AndroidManifest.xml:

<activity
    ...>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="sample" android:host="home" />
    </intent-filter>
</activity>

If we are defining the navigation destinations using the @NavDestination annotation, we can use the property deepLinkUris as follows:

@NavDestination(
    destinationId = "home",
    deepLinkUris = [
        "sample://home",
    ]
)
@Composable
fun HomeScreen(navigateToSettings: () -> Unit) {}

otherwise, we should set the list of deepLink uris in the NavDestination object:

object HomeNavDestination : NavDestination<HomeNavArgumentKeys>() {
  override val deepLinkUris: List<String> = listOf(
    "sample://home",
    "sample://home_secondary"
  )

Trigger the deep link using adb:

adb shell am start -a android.intent.action.VIEW -d "sample://home"

License

   Copyright 2024 Sergio Belda

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

navigation-compose-extended's People

Contributors

serbelga avatar renovate[bot] avatar

Stargazers

 avatar Bharath K Malviya avatar Krzysztof Bohdanowicz avatar Diego Beraldin avatar 吴上阿吉 avatar Andi Hasan A avatar

Watchers

 avatar

navigation-compose-extended's Issues

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/build.yml
  • actions/checkout v4
  • actions/setup-java v4
  • macos 14
.github/workflows/deploy-docs.yml
  • actions/checkout v4
  • actions/setup-java v4
  • actions/setup-python v5
  • actions/configure-pages v5
  • gradle/gradle-build-action v3
  • actions/upload-pages-artifact v3
  • actions/deploy-pages v4
  • macos 14
gradle
gradle.properties
settings.gradle.kts
build.gradle.kts
gradle/libs.versions.toml
  • com.android.tools.build:gradle 8.3.2
  • androidx.activity:activity-compose 1.9.0
  • androidx.compose:compose-bom 2024.04.01
  • androidx.compose.material3:material3 1.3.0-alpha05
  • androidx.core:core-ktx 1.13.0
  • androidx.lifecycle:lifecycle-runtime-ktx 2.7.0
  • androidx.navigation:navigation-compose 2.8.0-alpha07
  • androidx.wear.compose:compose-navigation 1.3.1
  • org.jetbrains.androidx.navigation:navigation-compose 2.8.0-dev1590
  • org.jetbrains.kotlin:kotlin-gradle-plugin 1.9.23
  • com.google.devtools.ksp:symbol-processing-api 1.9.23-1.0.20
  • com.diffplug.spotless:spotless-plugin-gradle 6.25.0
  • com.squareup:kotlinpoet 1.16.0
  • com.squareup:kotlinpoet-ksp 1.16.0
  • com.android.application 8.3.2
  • com.android.library 8.3.2
  • org.jetbrains.compose 1.6.10-dev1590
  • org.jetbrains.dokka 1.9.20
  • org.jetbrains.kotlin.android 1.9.23
  • com.google.devtools.ksp 1.9.23-1.0.20
  • com.vanniktech.maven.publish 0.28.0
gradle/build-logic/settings.gradle.kts
gradle/build-logic/convention/build.gradle.kts
navigation-compose-extended/build.gradle.kts
navigation-compose-extended-annotation/build.gradle.kts
navigation-compose-extended-compiler/build.gradle.kts
navigation-compose-extended-wear/build.gradle.kts
sample-app/build.gradle.kts
sample-app-annotations/build.gradle.kts
gradle-wrapper
gradle/build-logic/gradle/wrapper/gradle-wrapper.properties
  • gradle 8.7
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.7

  • Check this box to trigger a request for Renovate to run again on this repository

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.