Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
917a444
Adding tests for Navigator
dturner Jul 21, 2025
e88d470
First draft of Navigator for nested and shared destinations
dturner Jul 30, 2025
1b9681c
Address AI feedback
dturner Jul 31, 2025
8a36488
Add Nav2 activity and dependencies
dturner Jul 16, 2025
2104f89
Add starting point for migration
dturner Jul 31, 2025
6a56eca
Step 1 of migration complete
dturner Jul 31, 2025
24d2fb9
Lots of refactoring
dturner Jul 31, 2025
caed027
Add Step 4 of the migration
dturner Aug 1, 2025
40482df
Add Step 5 of the migration
dturner Aug 12, 2025
0110faa
Part way through step 6 of migration
dturner Aug 13, 2025
309f912
Updating all steps
dturner Aug 14, 2025
5019ac2
Add final step 7.
dturner Aug 14, 2025
3e9bc63
Tidy up imports
dturner Aug 15, 2025
26f754d
Merge branch 'main' into dt/2to3migration
dturner Aug 15, 2025
0d9b38e
Merge branch 'main' into dt/2to3migration
dturner Aug 15, 2025
17b4015
Navigator uses SavedState APIs and KotlinX Serialization to persist s…
dturner Aug 18, 2025
de6bdf4
Remove remaining Nav2 references from step 7
dturner Aug 18, 2025
466b3a1
Handle shared routes
dturner Aug 18, 2025
201f488
Switch to using Saver
dturner Aug 18, 2025
9caf04f
Add bottom sheet recipe
jbw0033 Aug 19, 2025
bd08782
Remove parenthesis from BottomSheetSceneStrategy
jbw0033 Aug 19, 2025
bde7f74
Minor edits
dturner Aug 21, 2025
6bb1fe4
Update headings in README for better structure
dturner Sep 2, 2025
ba8221f
Update to latest library versions and disable snapshot artifact repo
dturner Sep 11, 2025
4141b46
Replace SnapshotStateList with NavBackStack
dturner Sep 11, 2025
fd7be63
Address Gemini feedback
dturner Sep 11, 2025
d23149d
Add link to bug
dturner Sep 11, 2025
5928c4d
Merge pull request #79 from android/dt/update-versions
dturner Sep 11, 2025
93f9730
Create Supporting Pane Recipe
tiwiz Sep 11, 2025
efee1c1
Create Supporting Pane Recipe
tiwiz Sep 11, 2025
17a045d
Update dependencies to sync with Supporting Pane PR
tiwiz Sep 12, 2025
fb49912
Merge branch 'dependencies-update' into supporting-pane
tiwiz Sep 12, 2025
28146a5
Merge pull request #81 from android/dependencies-update
ianhanniballake Sep 14, 2025
c324bab
Fix comments
tiwiz Sep 18, 2025
f178728
Merge remote-tracking branch 'origin/main' into supporting-pane
tiwiz Sep 18, 2025
2f164b9
Fix comments
tiwiz Sep 18, 2025
f496dbc
Update README file
tiwiz Sep 18, 2025
d4db6e1
Fix naming
tiwiz Sep 18, 2025
975d88e
Merge pull request #80 from android/supporting-pane
ianhanniballake Sep 24, 2025
c054009
Add koin injected ViewModel recipe
dturner Sep 25, 2025
3f5fe09
Slight formatting change
dturner Sep 25, 2025
a8e577e
Addressing AI code review
dturner Sep 25, 2025
dccb089
Merge pull request #83 from android/dt/koin
ianhanniballake Sep 27, 2025
bce2b1b
Move Material recipes to their specific package
tiwiz Sep 29, 2025
47b4df3
Update README.md
tiwiz Sep 29, 2025
1f0c2ee
Update README.md
dturner Sep 29, 2025
496be6a
Update README.md
dturner Sep 29, 2025
8def1d6
Update README.md
dturner Sep 29, 2025
804f572
Update README.md
dturner Sep 29, 2025
a0841fe
Merge pull request #85 from android/material
tiwiz Sep 29, 2025
0e5efe3
Add bottom sheet recipe
jbw0033 Aug 19, 2025
2bb993e
Remove parenthesis from BottomSheetSceneStrategy
jbw0033 Aug 19, 2025
8d0e30d
Minor edits
dturner Aug 21, 2025
f512dfe
Merge remote-tracking branch 'origin/bottomsheet' into bottomsheet
jbw0033 Oct 2, 2025
df2d43e
Add bottom sheet recipe
jbw0033 Aug 19, 2025
c303cd0
Remove parenthesis from BottomSheetSceneStrategy
jbw0033 Aug 19, 2025
49cff71
Minor edits
dturner Aug 21, 2025
2115ada
Merge remote-tracking branch 'origin/bottomsheet' into bottomsheet
jbw0033 Oct 2, 2025
a857897
Update to alpha10
dturner Oct 2, 2025
2648ce8
Update gradle/libs.versions.toml
dturner Oct 2, 2025
72108df
Add migration guide
dturner Oct 3, 2025
0c9eb4b
Update guide
dturner Oct 3, 2025
7510ef3
Update guide
dturner Oct 3, 2025
a8da9c4
Update guide
dturner Oct 3, 2025
90f66ab
Update guide
dturner Oct 3, 2025
52032b2
Update guide
dturner Oct 3, 2025
f31ea9e
Update guide
dturner Oct 3, 2025
f46b3fc
Update guide
dturner Oct 3, 2025
5c94195
Merge branch 'main' into dt/2to3migration
dturner Oct 3, 2025
26133a4
Remove navigator package
dturner Oct 3, 2025
aaab38f
Merge pull request #89 from android/dt/alpha10
jbw0033 Oct 3, 2025
4ea983d
Merge remote-tracking branch 'origin/bottomsheet' into bottomsheet
jbw0033 Oct 3, 2025
495c65b
Fix errors in Bottomsheet Recipe
jbw0033 Oct 3, 2025
4beb9c0
Refactor to render NavDisplay on top of NavHost, rather than wrapping it
dturner Oct 3, 2025
598c263
Merge branch 'main' into dt/2to3migration
dturner Oct 3, 2025
beeeddc
Update to use alpha10 API
dturner Oct 3, 2025
00e4e2a
Merge pull request #46 from android/dt/2to3migration
dturner Oct 3, 2025
78dd22b
Update links in migration guide
dturner Oct 3, 2025
08b63ff
Fix link to migration package
dturner Oct 3, 2025
28947aa
Fix version
dturner Oct 3, 2025
13642c3
Merge remote-tracking branch 'origin/bottomsheet' into bottomsheet
jbw0033 Oct 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
android:name=".dialog.DialogActivity"
android:exported="true"
android:theme="@style/Theme.Nav3Recipes"/>
<activity
android:name=".bottomsheet.BottomSheetActivity"
android:exported="true"
android:theme="@style/Theme.Nav3Recipes"/>
<activity
android:name=".scenes.materiallistdetail.MaterialListDetailActivity"
android:exported="true"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2025 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
*
* 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.
*/

package com.example.nav3recipes.bottomsheet

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import androidx.navigation3.runtime.NavKey
import androidx.navigation3.runtime.entry
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay
import com.example.nav3recipes.content.ContentBlue
import com.example.nav3recipes.content.ContentGreen
import com.example.nav3recipes.ui.setEdgeToEdgeConfig
import kotlinx.serialization.Serializable

/**
* This recipe demonstrates how to create a bottom sheet. It does this by:
*
* - Adding the `BottomSheetSceneStrategy` to the list of strategies used by `NavDisplay`.
* - Adding `BottomSheetSceneStrategy.bottomsheet` to a `NavEntry`'s metadata to indicate that it
* is a bottom sheet. In this case it is applied to the `NavEntry` for `RouteB`.
*
* See also https://developer.android.com/guide/navigation/navigation-3/custom-layouts
*/

@Serializable
private data object RouteA : NavKey

@Serializable
private data class RouteB(val id: String) : NavKey

class BottomSheetActivity : ComponentActivity() {

@OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
setEdgeToEdgeConfig()
super.onCreate(savedInstanceState)
setContent {
val backStack = rememberNavBackStack(RouteA)
val bottomSheetStrategy = remember { BottomSheetSceneStrategy<NavKey>() }

NavDisplay(
backStack = backStack,
onBack = { backStack.removeLastOrNull() },
sceneStrategy = bottomSheetStrategy,
entryProvider = entryProvider {
entry<RouteA> {
ContentGreen("Welcome to Nav3") {
Button(onClick = {
backStack.add(RouteB("123"))
}) {
Text("Click to open bottom sheet")
}
}
}
entry<RouteB>(
metadata = BottomSheetSceneStrategy.bottomSheet()
) { key ->
ContentBlue(
title = "Route id: ${key.id}",
modifier = Modifier.clip(
shape = RoundedCornerShape(16.dp)
)
)
}
}
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.example.nav3recipes.bottomsheet

import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.ModalBottomSheetProperties
import androidx.compose.runtime.Composable
import androidx.navigation3.runtime.NavEntry
import androidx.navigation3.ui.OverlayScene
import androidx.navigation3.ui.Scene
import androidx.navigation3.ui.SceneStrategy

/** An [OverlayScene] that renders an [entry] within a [ModalBottomSheet]. */
@OptIn(ExperimentalMaterial3Api::class)
internal class BottomSheetScene<T : Any>(
override val key: T,
override val previousEntries: List<NavEntry<T>>,
override val overlaidEntries: List<NavEntry<T>>,
private val entry: NavEntry<T>,
private val modalBottomSheetProperties: ModalBottomSheetProperties,
private val onBack: (count: Int) -> Unit,
) : OverlayScene<T> {

override val entries: List<NavEntry<T>> = listOf(entry)

override val content: @Composable (() -> Unit) = {
ModalBottomSheet(
onDismissRequest = { onBack(1) },
properties = modalBottomSheetProperties,
) {
entry.Content()
}
}
}

/**
* A [SceneStrategy] that displays entries that have added [bottomSheet] to their [NavEntry.metadata]
* within a [ModalBottomSheet] instance.
*
* This strategy should always be added before any non-overlay scene strategies.
*/
@OptIn(ExperimentalMaterial3Api::class)
class BottomSheetSceneStrategy<T : Any>() : SceneStrategy<T> {

@Composable
override fun calculateScene(
entries: List<NavEntry<T>>,
onBack: (Int) -> Unit
): Scene<T>? {
val lastEntry = entries.lastOrNull()
val bottomSheetProperties = lastEntry?.metadata?.get(BOTTOM_SHEET_KEY) as? ModalBottomSheetProperties
return bottomSheetProperties?.let { properties ->
@Suppress("UNCHECKED_CAST")
BottomSheetScene(
key = lastEntry.contentKey as T,
previousEntries = entries.dropLast(1),
overlaidEntries = entries.dropLast(1),
entry = lastEntry,
modalBottomSheetProperties = properties,
onBack = onBack
)
}
}

companion object {
/**
* Function to be called on the [NavEntry.metadata] to mark this entry as something that
* should be displayed within a [ModalBottomSheet].
*
* @param modalBottomSheetProperties properties that should be passed to the containing
* [ModalBottomSheet].
*/
@OptIn(ExperimentalMaterial3Api::class)
fun bottomSheet(
modalBottomSheetProperties: ModalBottomSheetProperties = ModalBottomSheetProperties()
): Map<String, Any> = mapOf(BOTTOM_SHEET_KEY to modalBottomSheetProperties)

internal const val BOTTOM_SHEET_KEY = "bottomsheet"
}
}