diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 75e676435..4ff08cd64 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -116,6 +116,9 @@ wearToolingPreview = "1.0.0" webkit = "1.15.0" wfp = "1.0.0-rc01" androidx-core-telecom = "1.1.0-alpha04" +wearCompose = "1.6.0" + + [libraries] accompanist-adaptive = "com.google.accompanist:accompanist-adaptive:0.37.3" @@ -293,6 +296,9 @@ validator-push = { module = "com.google.android.wearable.watchface.validator:val wear-compose-material = { module = "androidx.wear.compose:compose-material", version.ref = "wearComposeMaterial" } wear-compose-material3 = { module = "androidx.wear.compose:compose-material3", version.ref = "wearComposeMaterial3" } androidx-core-telecom = { group = "androidx.core", name = "core-telecom", version.ref = "androidx-core-telecom" } +wear-compose-navigation3 = { module = "androidx.wear.compose:compose-navigation3", version.ref = "wearCompose" } + + [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } diff --git a/wear/build.gradle.kts b/wear/build.gradle.kts index a382d6023..9dbff4452 100644 --- a/wear/build.gradle.kts +++ b/wear/build.gradle.kts @@ -4,6 +4,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.compose.compiler) alias(libs.plugins.roborazzi) + alias(libs.plugins.kotlin.serialization) } android { @@ -59,6 +60,12 @@ android { } dependencies { + implementation(libs.androidx.navigation3.runtime) + implementation(libs.androidx.navigation3.ui) + implementation(libs.wear.compose.navigation3) + implementation(libs.kotlinx.serialization.json) + implementation(libs.androidx.lifecycle.viewmodel.navigation3) + implementation(libs.androidx.core.ktx) implementation(libs.androidx.credentials) implementation((libs.androidx.credentials.play.services.auth)) diff --git a/wear/src/main/java/com/example/wear/snippets/m3/navigation/Navigation3.kt b/wear/src/main/java/com/example/wear/snippets/m3/navigation/Navigation3.kt new file mode 100644 index 000000000..97b0b88e6 --- /dev/null +++ b/wear/src/main/java/com/example/wear/snippets/m3/navigation/Navigation3.kt @@ -0,0 +1,110 @@ +/* + * Copyright 2026 The Android Open Source Project + * + * 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 + * + * https://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. + */ + +package com.example.wear.snippets.m3.navigation + +import androidx.compose.runtime.Composable +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator +import androidx.navigation3.runtime.NavKey +import androidx.navigation3.runtime.entryProvider +import androidx.navigation3.runtime.rememberNavBackStack +import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator +import androidx.navigation3.ui.NavDisplay +import androidx.wear.compose.navigation3.rememberSwipeDismissableSceneStrategy +import kotlinx.serialization.Serializable + +// [START android_wear_nav3_destinations] +@Serializable +sealed interface Screen : NavKey { + @Serializable + data object Home : Screen + + @Serializable + data class Details(val itemId: String) : Screen +} +// [END android_wear_nav3_destinations] + +// [START android_wear_nav3_setup] +@Composable +fun WearApp() { + // 1. Create the persistent back stack starting at the Home screen + val backStack = rememberNavBackStack(Screen.Home) + + // 2. Initialize the Wear OS swipe-to-dismiss strategy + val strategy = rememberSwipeDismissableSceneStrategy() + + // 3. Render the NavDisplay + NavDisplay( + backStack = backStack, + sceneStrategies = listOf(strategy), + entryProvider = entryProvider { + // 4. Map keys to Composables + entry { + HomeScreen( + onNavigateToDetails = { id -> backStack.add(Screen.Details(id)) } + ) + } + entry { key -> + DetailsScreen( + itemId = key.itemId, + onBack = { backStack.removeLast() } + ) + } + } + ) +} +// [END android_wear_nav3_setup] + +@Composable +fun WearAppWithViewModel() { + val backStack = rememberNavBackStack(Screen.Home) + val strategy = rememberSwipeDismissableSceneStrategy() + + // [START android_wear_nav3_viewmodel] + NavDisplay( + backStack = backStack, + sceneStrategies = listOf(strategy), + entryDecorators = listOf( + rememberSaveableStateHolderNavEntryDecorator(), + rememberViewModelStoreNavEntryDecorator() + ), + entryProvider = entryProvider { + entry { + // Any viewModel() requested here will be scoped to this NavEntry + val viewModel: HomeViewModel = viewModel() + HomeScreen(onNavigateToDetails = {}) + } + } + ) + // [END android_wear_nav3_viewmodel] +} + +// Mock implementations to make it compile +@Composable +fun HomeScreen(onNavigateToDetails: (String) -> Unit) { + // Mock +} + +@Composable +fun DetailsScreen(itemId: String, onBack: () -> Unit) { + // Mock +} + +class HomeViewModel : ViewModel() { + // Mock +}