@@ -21,19 +21,14 @@ import androidx.compose.runtime.LaunchedEffect
2121import androidx.compose.runtime.collectAsState
2222import androidx.compose.runtime.getValue
2323import androidx.compose.runtime.mutableFloatStateOf
24- import androidx.compose.runtime.mutableStateListOf
2524import androidx.compose.runtime.mutableStateOf
2625import androidx.compose.runtime.remember
2726import androidx.compose.runtime.saveable.rememberSaveableStateHolder
2827import androidx.compose.runtime.setValue
29- import androidx.compose.runtime.snapshots.SnapshotStateList
3028import androidx.compose.ui.Alignment
3129import androidx.compose.ui.Modifier
3230import androidx.compose.ui.graphics.Color
33- import androidx.compose.ui.platform.LocalInspectionMode
3431import androidx.compose.ui.window.SecureFlagPolicy
35- import androidx.lifecycle.Lifecycle
36- import androidx.lifecycle.LifecycleEventObserver
3732import androidx.navigation.NavBackStackEntry
3833import androidx.navigation.NavDestination.Companion.hierarchy
3934import androidx.navigation.compose.LocalOwnersProvider
@@ -57,24 +52,14 @@ public fun ModalSheetHost(
5752 sizeTransform : (AnimatedContentTransitionScope <NavBackStackEntry >.() -> @JvmSuppressWildcards SizeTransform ? )? =
5853 null,
5954) {
60- val modalBackStack by modalSheetNavigator.backStack.collectAsState(listOf ())
61-
6255 var progress by remember { mutableFloatStateOf(0f ) }
6356 var inPredictiveBack by remember { mutableStateOf(false ) }
64-
6557 val zIndices = remember { mutableMapOf<String , Float >() }
6658
6759 val saveableStateHolder = rememberSaveableStateHolder()
6860
69- val visibleEntries = rememberVisibleList(modalBackStack)
70- visibleEntries.PopulateVisibleList (modalBackStack)
71-
72- val currentBackStack = if (LocalInspectionMode .current) {
73- modalSheetNavigator.backStack.collectAsState(emptyList()).value
74- } else {
75- visibleEntries
76- }
77- val backStackEntry: NavBackStackEntry ? = currentBackStack.lastOrNull()
61+ val modalBackStack by modalSheetNavigator.backStack.collectAsState(listOf ())
62+ val backStackEntry: NavBackStackEntry ? = modalBackStack.lastOrNull()
7863
7964 val finalEnter: AnimatedContentTransitionScope <NavBackStackEntry >.() -> EnterTransition = {
8065 val targetDestination = targetState.destination as ModalSheetNavigator .Destination
@@ -90,7 +75,6 @@ public fun ModalSheetHost(
9075 }
9176 val finalExit: AnimatedContentTransitionScope <NavBackStackEntry >.() -> ExitTransition = {
9277 val initialDestination = initialState.destination as ModalSheetNavigator .Destination
93-
9478 if (modalSheetNavigator.isPop.value) {
9579 initialDestination.hierarchy.firstNotNullOfOrNull { destination ->
9680 null // destination.createPopExitTransition(this)
@@ -103,7 +87,6 @@ public fun ModalSheetHost(
10387 }
10488 val finalSizeTransform: AnimatedContentTransitionScope <NavBackStackEntry >.() -> SizeTransform ? = {
10589 val targetDestination = targetState.destination as ModalSheetNavigator .Destination
106-
10790 targetDestination.hierarchy.firstNotNullOfOrNull { destination ->
10891 null // destination.createSizeTransform(this)
10992 } ? : sizeTransform?.invoke(this )
@@ -115,14 +98,16 @@ public fun ModalSheetHost(
11598 // scope exposed by the transitions on the NavHost and composable APIs.
11699 SeekableTransitionState (backStackEntry)
117100 }
101+ val transitionsInProgress = modalSheetNavigator.transitionsInProgress.collectAsState().value
118102 val transition = rememberTransition(transitionState, label = " entry" )
119103 val nothingToShow = transition.currentState == transition.targetState &&
120104 transition.currentState == null &&
121- backStackEntry == null
105+ backStackEntry == null &&
106+ transitionsInProgress.isEmpty()
122107
123108 if (inPredictiveBack) {
124109 LaunchedEffect (progress) {
125- val previousEntry = currentBackStack .getOrNull(currentBackStack .size - 2 )
110+ val previousEntry = modalBackStack .getOrNull(modalBackStack .size - 2 )
126111 transitionState.seekTo(progress, previousEntry)
127112 }
128113 } else {
@@ -163,10 +148,12 @@ public fun ModalSheetHost(
163148 ? : SecureFlagPolicy .Inherit
164149
165150 ModalSheetDialog (
166- onPredictiveBack = { backEvent ->
151+ onPredictiveBack = onPredictBack@ { backEvent ->
167152 progress = 0f
168- val currentBackStackEntry = modalBackStack.lastOrNull()
169- modalSheetNavigator.prepareForTransition(currentBackStackEntry!! )
153+ // early return: already animating backstack out, repeated back handling
154+ // probably reproducible only with slowed animations
155+ val currentBackStackEntry = modalBackStack.lastOrNull() ? : return @onPredictBack
156+ modalSheetNavigator.prepareForTransition(currentBackStackEntry)
170157 val previousEntry = modalBackStack.getOrNull(modalBackStack.size - 2 )
171158 if (previousEntry != null ) {
172159 modalSheetNavigator.prepareForTransition(previousEntry)
@@ -186,7 +173,7 @@ public fun ModalSheetHost(
186173 ) {
187174 transition.AnimatedContent (
188175 modifier = modifier
189- .background(if (transition.targetState == null ) Color .Unspecified else containerColor),
176+ .background(if (transition.targetState == null || transition.currentState == null ) Color .Transparent else containerColor),
190177 contentAlignment = Alignment .TopStart ,
191178 transitionSpec = block@{
192179 val initialState = initialState ? : return @block ContentTransform (
@@ -218,13 +205,7 @@ public fun ModalSheetHost(
218205 sizeTransform = finalSizeTransform(this ),
219206 )
220207 },
221- ) {
222- val currentEntry = if (inPredictiveBack) {
223- it
224- } else {
225- visibleEntries.lastOrNull { entry -> it == entry }
226- }
227-
208+ ) { currentEntry ->
228209 if (currentEntry == null ) {
229210 Box (Modifier .fillMaxSize()) {}
230211 return @AnimatedContent
@@ -251,58 +232,3 @@ public fun ModalSheetHost(
251232 }
252233 }
253234}
254-
255- @Suppress(" ComposeUnstableCollections" )
256- @Composable
257- internal fun MutableList<NavBackStackEntry>.PopulateVisibleList (
258- transitionsInProgress : List <NavBackStackEntry >,
259- ) {
260- val isInspecting = LocalInspectionMode .current
261- transitionsInProgress.forEach { entry ->
262- DisposableEffect (entry.lifecycle) {
263- val observer = LifecycleEventObserver { _, event ->
264- // show dialog in preview
265- if (isInspecting && ! contains(entry)) {
266- add(entry)
267- }
268- // ON_START -> add to visibleBackStack, ON_STOP -> remove from visibleBackStack
269- if (event == Lifecycle .Event .ON_START ) {
270- // We want to treat the visible lists as sets, but we want to keep
271- // the functionality of mutableStateListOf() so that we recompose in response
272- // to adds and removes.
273- if (! contains(entry)) {
274- add(entry)
275- }
276- }
277- if (event == Lifecycle .Event .ON_STOP ) {
278- remove(entry)
279- }
280- }
281- entry.lifecycle.addObserver(observer)
282- onDispose {
283- entry.lifecycle.removeObserver(observer)
284- }
285- }
286- }
287- }
288-
289- @Composable
290- internal fun rememberVisibleList (
291- transitionsInProgress : List <NavBackStackEntry >,
292- ): SnapshotStateList <NavBackStackEntry > {
293- // show dialog in preview
294- val isInspecting = LocalInspectionMode .current
295- return remember(transitionsInProgress) {
296- mutableStateListOf<NavBackStackEntry >().also {
297- it.addAll(
298- transitionsInProgress.filter { entry ->
299- if (isInspecting) {
300- true
301- } else {
302- entry.lifecycle.currentState.isAtLeast(Lifecycle .State .STARTED )
303- }
304- },
305- )
306- }
307- }
308- }
0 commit comments