2
2
3
3
package br.com.mob1st.core.androidx.navigation
4
4
5
- import androidx.activity. compose.BackHandler
5
+ import androidx.compose.foundation.layout.ColumnScope
6
6
import androidx.compose.material3.ExperimentalMaterial3Api
7
7
import androidx.compose.material3.SheetState
8
8
import androidx.compose.runtime.Composable
@@ -11,7 +11,6 @@ import androidx.compose.runtime.collectAsState
11
11
import androidx.compose.runtime.getValue
12
12
import androidx.compose.runtime.mutableStateOf
13
13
import androidx.compose.runtime.produceState
14
- import androidx.compose.runtime.rememberCoroutineScope
15
14
import androidx.compose.runtime.rememberUpdatedState
16
15
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
17
16
import androidx.compose.runtime.setValue
@@ -29,7 +28,6 @@ import kotlinx.coroutines.flow.StateFlow
29
28
import kotlinx.coroutines.flow.distinctUntilChanged
30
29
import kotlinx.coroutines.flow.drop
31
30
import kotlinx.coroutines.flow.transform
32
- import kotlinx.coroutines.launch
33
31
import kotlin.coroutines.cancellation.CancellationException
34
32
35
33
@Navigator.Name (" bottomSheet" )
@@ -70,7 +68,7 @@ class BottomSheetNavigator(
70
68
* sheetContent of your [ModalBottomSheetLayout].
71
69
*/
72
70
73
- internal var sheetContent: @Composable () -> Unit = {}
71
+ internal var sheetContent: @Composable ColumnScope . () -> Unit = {}
74
72
internal var onDismissRequest: () -> Unit = {}
75
73
76
74
internal val sheetInitializer: @Composable () -> Unit = {
@@ -90,7 +88,7 @@ class BottomSheetNavigator(
90
88
// Regardless of whether we're popping or pushing, we always want to hide
91
89
// the sheet first before deciding whether to re-show it or keep it hidden
92
90
try {
93
- sheetEnabled = false
91
+ sheetState.hide()
94
92
} catch (_: CancellationException ) {
95
93
// We catch but ignore possible cancellation exceptions as we don't want
96
94
// them to bubble up and cancel the whole produceState coroutine
@@ -102,11 +100,26 @@ class BottomSheetNavigator(
102
100
value = it
103
101
}
104
102
}
105
-
106
- if (retainedEntry != null ) {
107
- val currentOnSheetShown by rememberUpdatedState {
108
- transitionsInProgressEntries.forEach(state::markTransitionComplete)
103
+ val show = {
104
+ transitionsInProgressEntries.forEach(state::markTransitionComplete)
105
+ }
106
+ val dismiss = {
107
+ sheetEnabled = false
108
+ if (transitionsInProgressEntries.contains(retainedEntry)) {
109
+ state.markTransitionComplete(retainedEntry!! )
110
+ } else {
111
+ // If there is no transition in progress, the sheet has been dimissed by the
112
+ // user (for example by tapping on the scrim or through an accessibility action)
113
+ // In this case, we will immediately pop without a transition as the sheet has
114
+ // already been hidden
115
+ retainedEntry?.let {
116
+ state.pop(popUpTo = it, saveState = false )
117
+ }
109
118
}
119
+ }
120
+ if (retainedEntry != null ) {
121
+ val currentOnSheetShown by rememberUpdatedState(show)
122
+ val currentOnSheetDismissed by rememberUpdatedState(dismiss)
110
123
LaunchedEffect (sheetState, retainedEntry) {
111
124
snapshotFlow { sheetState.isVisible }
112
125
// We are only interested in changes in the sheet's visibility
@@ -116,47 +129,28 @@ class BottomSheetNavigator(
116
129
.collect { visible ->
117
130
if (visible) {
118
131
currentOnSheetShown()
132
+ } else {
133
+ currentOnSheetDismissed()
119
134
}
120
135
}
121
136
}
122
137
123
138
LaunchedEffect (key1 = retainedEntry) {
124
139
sheetEnabled = true
125
-
126
140
sheetContent = {
127
- retainedEntry!! .LocalOwnersProvider (saveableStateHolder) {
128
- val content =
129
- (retainedEntry!! .destination as Destination ).content
130
- content(retainedEntry!! )
141
+ retainedEntry?.let { entry ->
142
+ entry.LocalOwnersProvider (saveableStateHolder) {
143
+ val content =
144
+ (entry.destination as Destination ).content
145
+
146
+ content(entry)
147
+ }
131
148
}
132
149
}
133
150
onDismissRequest = {
134
- sheetEnabled = false
135
-
136
- if (transitionsInProgressEntries.contains(retainedEntry)) {
137
- // Sheet dismissal can be started through popBackStack in which case we have a
138
- // transition that we'll want to complete
139
- state.markTransitionComplete(retainedEntry!! )
140
- } else {
141
- // If there is no transition in progress, the sheet has been dimissed by the
142
- // user (for example by tapping on the scrim or through an accessibility action)
143
- // In this case, we will immediately pop without a transition as the sheet has
144
- // already been hidden
145
- state.pop(popUpTo = retainedEntry!! , saveState = false )
146
- }
151
+ currentOnSheetDismissed()
147
152
}
148
153
}
149
-
150
- val scope = rememberCoroutineScope()
151
- BackHandler {
152
- scope
153
- .launch { sheetState.hide() }
154
- .invokeOnCompletion {
155
- if (! sheetState.isVisible) {
156
- onDismissRequest()
157
- }
158
- }
159
- }
160
154
} else {
161
155
LaunchedEffect (key1 = Unit ) {
162
156
sheetContent = {}
@@ -181,12 +175,12 @@ class BottomSheetNavigator(
181
175
navigatorExtras : Extras ? ,
182
176
) {
183
177
entries.fastForEach { entry ->
184
- state.push (entry)
178
+ state.pushWithTransition (entry)
185
179
}
186
180
}
187
181
188
182
override fun popBackStack (popUpTo : NavBackStackEntry , savedState : Boolean ) {
189
- state.pop (popUpTo, savedState)
183
+ state.popWithTransition (popUpTo, savedState)
190
184
}
191
185
192
186
/* *
@@ -195,6 +189,6 @@ class BottomSheetNavigator(
195
189
@NavDestination.ClassType (Composable ::class )
196
190
class Destination (
197
191
navigator : BottomSheetNavigator ,
198
- internal val content : @Composable (NavBackStackEntry ) -> Unit ,
192
+ internal val content : @Composable ColumnScope . (NavBackStackEntry ) -> Unit ,
199
193
) : NavDestination(navigator), FloatingWindow
200
194
}
0 commit comments