1 /*
<lambda>null2  * 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  *      https://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 com.google.accompanist.navigation.material
18 
19 import androidx.compose.foundation.layout.ColumnScope
20 import androidx.compose.material.ExperimentalMaterialApi
21 import androidx.compose.material.ModalBottomSheetState
22 import androidx.compose.runtime.Composable
23 import androidx.compose.runtime.LaunchedEffect
24 import androidx.compose.runtime.getValue
25 import androidx.compose.runtime.rememberUpdatedState
26 import androidx.compose.runtime.saveable.SaveableStateHolder
27 import androidx.compose.runtime.snapshotFlow
28 import androidx.navigation.NavBackStackEntry
29 import androidx.navigation.compose.LocalOwnersProvider
30 import kotlinx.coroutines.flow.distinctUntilChanged
31 import kotlinx.coroutines.flow.drop
32 
33 /**
34  * Hosts a [BottomSheetNavigator.Destination]'s [NavBackStackEntry] and its
35  * [BottomSheetNavigator.Destination.content] and provides a [onSheetDismissed] callback. It also
36  * shows and hides the [ModalBottomSheetLayout] through the [sheetState] when the sheet content
37  * enters or leaves the composition.
38  *
39  * @param backStackEntry The [NavBackStackEntry] holding the [BottomSheetNavigator.Destination],
40  * or null if there is no [NavBackStackEntry]
41  * @param sheetState The [ModalBottomSheetState] used to observe and control the sheet visibility
42  * @param onSheetDismissed Callback when the sheet has been dismissed. Typically, you'll want to
43  * pop the back stack here.
44  */
45 @ExperimentalMaterialNavigationApi
46 @OptIn(ExperimentalMaterialApi::class)
47 @Composable
48 internal fun ColumnScope.SheetContentHost(
49     backStackEntry: NavBackStackEntry?,
50     sheetState: ModalBottomSheetState,
51     saveableStateHolder: SaveableStateHolder,
52     onSheetShown: (entry: NavBackStackEntry) -> Unit,
53     onSheetDismissed: (entry: NavBackStackEntry) -> Unit,
54 ) {
55     if (backStackEntry != null) {
56         val currentOnSheetShown by rememberUpdatedState(onSheetShown)
57         val currentOnSheetDismissed by rememberUpdatedState(onSheetDismissed)
58         LaunchedEffect(sheetState, backStackEntry) {
59             snapshotFlow { sheetState.isVisible }
60                 // We are only interested in changes in the sheet's visibility
61                 .distinctUntilChanged()
62                 // distinctUntilChanged emits the initial value which we don't need
63                 .drop(1)
64                 .collect { visible ->
65                     if (visible) {
66                         currentOnSheetShown(backStackEntry)
67                     } else {
68                         currentOnSheetDismissed(backStackEntry)
69                     }
70                 }
71         }
72         backStackEntry.LocalOwnersProvider(saveableStateHolder) {
73             val content =
74                 (backStackEntry.destination as BottomSheetNavigator.Destination).content
75             content(backStackEntry)
76         }
77     }
78 }
79