Skip to content

Commit f3adbbd

Browse files
Make API for showing DialogNavigator destinations public
Previously, the only way to use DialogNavigator via public APIs was directly through usage of NavHost. By making the DialogNavigator->Dialog Composable function public, DialogNavigator can be reused in any custom NavHost without making its internal state public. Test: DialogNavigatorTest suite still passes Relnote: N/A Change-Id: I125838dc978ee014af46a264deb1458596cce691
1 parent 6fd54d3 commit f3adbbd

File tree

7 files changed

+73
-28
lines changed

7 files changed

+73
-28
lines changed

navigation/navigation-compose/api/current.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ package androidx.navigation.compose {
1010
ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
1111
}
1212

13+
public final class DialogHostKt {
14+
method @androidx.compose.runtime.Composable public static void DialogHost(androidx.navigation.compose.DialogNavigator dialogNavigator);
15+
}
16+
1317
@androidx.navigation.Navigator.Name("dialog") public final class DialogNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.DialogNavigator.Destination> {
1418
ctor public DialogNavigator();
1519
method public androidx.navigation.compose.DialogNavigator.Destination createDestination();

navigation/navigation-compose/api/public_plus_experimental_current.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ package androidx.navigation.compose {
1010
ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
1111
}
1212

13+
public final class DialogHostKt {
14+
method @androidx.compose.runtime.Composable public static void DialogHost(androidx.navigation.compose.DialogNavigator dialogNavigator);
15+
}
16+
1317
@androidx.navigation.Navigator.Name("dialog") public final class DialogNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.DialogNavigator.Destination> {
1418
ctor public DialogNavigator();
1519
method public androidx.navigation.compose.DialogNavigator.Destination createDestination();

navigation/navigation-compose/api/restricted_current.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ package androidx.navigation.compose {
1010
ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
1111
}
1212

13+
public final class DialogHostKt {
14+
method @androidx.compose.runtime.Composable public static void DialogHost(androidx.navigation.compose.DialogNavigator dialogNavigator);
15+
}
16+
1317
@androidx.navigation.Navigator.Name("dialog") public final class DialogNavigator extends androidx.navigation.Navigator<androidx.navigation.compose.DialogNavigator.Destination> {
1418
ctor public DialogNavigator();
1519
method public androidx.navigation.compose.DialogNavigator.Destination createDestination();

navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/DialogNavigatorTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class DialogNavigatorTest {
4242
navigator.onAttach(navigatorState)
4343

4444
rule.setContent {
45-
navigator.Dialogs()
45+
DialogHost(navigator)
4646
}
4747

4848
rule.onNodeWithText(defaultText).assertDoesNotExist()
@@ -68,7 +68,7 @@ class DialogNavigatorTest {
6868
navigator.navigate(listOf(entry), null, null)
6969

7070
rule.setContent {
71-
navigator.Dialogs()
71+
DialogHost(navigator)
7272
}
7373

7474
rule.onNodeWithText(defaultText).assertIsDisplayed()
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2021 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package androidx.navigation.compose
18+
19+
import androidx.compose.runtime.Composable
20+
import androidx.compose.runtime.collectAsState
21+
import androidx.compose.runtime.getValue
22+
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
23+
import androidx.compose.ui.window.Dialog
24+
import androidx.lifecycle.Lifecycle
25+
import androidx.navigation.compose.DialogNavigator.Destination
26+
27+
/**
28+
* Show each [Destination] on the [DialogNavigator]'s back stack as a [Dialog].
29+
*
30+
* Note that [NavHost] will call this for you; you do not need to call it manually.
31+
*/
32+
@Composable
33+
public fun DialogHost(dialogNavigator: DialogNavigator) {
34+
val saveableStateHolder = rememberSaveableStateHolder()
35+
val dialogBackStack by dialogNavigator.backStack.collectAsState()
36+
37+
dialogBackStack.filter { backStackEntry ->
38+
backStackEntry.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
39+
}.forEach { backStackEntry ->
40+
val destination = backStackEntry.destination as Destination
41+
Dialog(
42+
onDismissRequest = { dialogNavigator.dismiss(backStackEntry) },
43+
properties = destination.dialogProperties
44+
) {
45+
// while in the scope of the composable, we provide the navBackStackEntry as the
46+
// ViewModelStoreOwner and LifecycleOwner
47+
backStackEntry.LocalOwnersProvider(saveableStateHolder) {
48+
destination.content(backStackEntry)
49+
}
50+
}
51+
}
52+
}

navigation/navigation-compose/src/main/java/androidx/navigation/compose/DialogNavigator.kt

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,11 @@
1717
package androidx.navigation.compose
1818

1919
import androidx.compose.runtime.Composable
20-
import androidx.compose.runtime.collectAsState
2120
import androidx.compose.runtime.getValue
2221
import androidx.compose.runtime.mutableStateOf
23-
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
2422
import androidx.compose.runtime.setValue
2523
import androidx.compose.ui.window.Dialog
2624
import androidx.compose.ui.window.DialogProperties
27-
import androidx.lifecycle.Lifecycle
2825
import androidx.navigation.FloatingWindow
2926
import androidx.navigation.NavBackStackEntry
3027
import androidx.navigation.NavDestination
@@ -50,36 +47,20 @@ public class DialogNavigator : Navigator<Destination>() {
5047
* the Navigator is attached, so we specifically return an empty flow if we
5148
* aren't attached yet.
5249
*/
53-
private val backStack: StateFlow<List<NavBackStackEntry>> get() = if (attached) {
50+
internal val backStack: StateFlow<List<NavBackStackEntry>> get() = if (attached) {
5451
state.backStack
5552
} else {
5653
MutableStateFlow(emptyList())
5754
}
5855

5956
/**
60-
* Show each [Destination] on the back stack as a [Dialog].
61-
*
62-
* Note that [NavHost] will call this for you; you do not need to call it manually.
57+
* Dismiss the dialog destination associated with the given [backStackEntry].
6358
*/
64-
internal val Dialogs: @Composable () -> Unit = @Composable {
65-
val saveableStateHolder = rememberSaveableStateHolder()
66-
val dialogBackStack by backStack.collectAsState()
67-
68-
dialogBackStack.filter { backStackEntry ->
69-
backStackEntry.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
70-
}.forEach { backStackEntry ->
71-
val destination = backStackEntry.destination as Destination
72-
Dialog(
73-
onDismissRequest = { state.pop(backStackEntry, false) },
74-
properties = destination.dialogProperties
75-
) {
76-
// while in the scope of the composable, we provide the navBackStackEntry as the
77-
// ViewModelStoreOwner and LifecycleOwner
78-
backStackEntry.LocalOwnersProvider(saveableStateHolder) {
79-
destination.content(backStackEntry)
80-
}
81-
}
59+
internal fun dismiss(backStackEntry: NavBackStackEntry) {
60+
check(attached) {
61+
"The DialogNavigator must be attached to a NavController to call dismiss"
8262
}
63+
state.pop(backStackEntry, false)
8364
}
8465

8566
override fun onAttach(state: NavigatorState) {

navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,5 +141,5 @@ public fun NavHost(
141141
) as? DialogNavigator ?: return
142142

143143
// Show any dialog destinations
144-
dialogNavigator.Dialogs()
144+
DialogHost(dialogNavigator)
145145
}

0 commit comments

Comments
 (0)