@momo-kits/native-kits 0.152.4-beta.3 → 0.152.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -6
- package/shared/build.gradle.kts +74 -0
- package/CODE_OF_CONDUCT.md +0 -133
- package/CONTRIBUTING.md +0 -114
- package/LICENSE +0 -20
- package/README.md +0 -7
- package/build.gradle.kts +0 -32
- package/compose/MoMoComposeKits.podspec +0 -54
- package/compose/build.gradle.kts +0 -149
- package/compose/src/androidMain/AndroidManifest.xml +0 -2
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -105
- package/compose/src/commonMain/composeResources/files/lottie_circle_loader.json +0 -1
- package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
- package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -57
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -201
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -222
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -48
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -306
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -715
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -214
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -236
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -77
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -27
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -334
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -345
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -90
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -131
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -543
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -23
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -69
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -143
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -179
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -111
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -384
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -160
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -234
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -223
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -232
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -236
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -228
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -364
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -50
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -34
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -85
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -33
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -338
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -95
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -64
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -89
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -84
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -208
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -172
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -199
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -237
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -191
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -306
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -13
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -191
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -258
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -35
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -59
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -68
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -49
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -232
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -111
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -94
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -159
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -232
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScaleSizeScope.kt +0 -17
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -459
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -169
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -216
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -180
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -251
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -80
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -306
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -31
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -385
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -38
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -62
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -88
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -144
- package/gradle.properties +0 -19
- package/gradlew +0 -240
- package/gradlew.bat +0 -91
- package/ios/Application/ApplicationEnvironment.swift +0 -50
- package/ios/Application/Components.swift +0 -263
- package/ios/Application/ComposeApi.swift +0 -22
- package/ios/Application/FloatingButton.swift +0 -172
- package/ios/Application/HeaderRight.swift +0 -271
- package/ios/Application/Screen.swift +0 -249
- package/ios/Badge/BadgeDot.swift +0 -31
- package/ios/Button/Button.swift +0 -211
- package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +0 -126
- package/ios/Checkbox/Checkbox.swift +0 -81
- package/ios/Chip/Chip.swift +0 -96
- package/ios/Colors+Radius+Spacing/Colors.swift +0 -172
- package/ios/Colors+Radius+Spacing/Radius.swift +0 -22
- package/ios/Colors+Radius+Spacing/Spacing.swift +0 -12
- package/ios/Extensions/Color++.swift +0 -25
- package/ios/Icon/Icon.swift +0 -51
- package/ios/Image/Image.swift +0 -70
- package/ios/Input/Input.swift +0 -207
- package/ios/Input/InputPhoneNumber.swift +0 -176
- package/ios/Input/InputSearch.swift +0 -238
- package/ios/Input/InputTextArea.swift +0 -242
- package/ios/Lottie/LottieView.swift +0 -86
- package/ios/OTPKeyboard/KeyboardButton.swift +0 -41
- package/ios/OTPKeyboard/OTPKeyboard.swift +0 -145
- package/ios/Popup/PopupDisplay.swift +0 -284
- package/ios/Popup/PopupInput.swift +0 -96
- package/ios/Popup/PopupPromotion.swift +0 -73
- package/ios/PopupView/FullscreenPopup.swift +0 -251
- package/ios/PopupView/Modifiers.swift +0 -158
- package/ios/PopupView/PopupView.swift +0 -289
- package/ios/PopupView/Utils++.swift +0 -281
- package/ios/ScrollIndicator/ScrollIndicator.swift +0 -110
- package/ios/Swipeable/SwipeCell.swift +0 -278
- package/ios/Swipeable/SwipeCellModel.swift +0 -86
- package/ios/Switch/Switch.swift +0 -44
- package/ios/Template/Logo/Logo.swift +0 -75
- package/ios/Template/TrustBanner/TrustBanner.swift +0 -120
- package/ios/Theme.md +0 -18
- package/ios/Typography/Text.swift +0 -140
- package/ios/Typography/Typography.swift +0 -95
- package/ios/native-kits.podspec +0 -18
- package/settings.gradle.kts +0 -25
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
package vn.momo.kits.navigation
|
|
2
|
-
|
|
3
|
-
import androidx.compose.runtime.Composable
|
|
4
|
-
import androidx.compose.runtime.MutableState
|
|
5
|
-
import androidx.compose.runtime.mutableStateOf
|
|
6
|
-
import androidx.compose.runtime.staticCompositionLocalOf
|
|
7
|
-
import androidx.navigation.NavController
|
|
8
|
-
import kotlinx.coroutines.CoroutineScope
|
|
9
|
-
import kotlinx.coroutines.Dispatchers
|
|
10
|
-
import kotlinx.coroutines.SupervisorJob
|
|
11
|
-
import kotlinx.coroutines.cancel
|
|
12
|
-
import kotlinx.coroutines.delay
|
|
13
|
-
import kotlinx.coroutines.launch
|
|
14
|
-
import kotlinx.serialization.Serializable
|
|
15
|
-
import vn.momo.maxapi.IMaxApi
|
|
16
|
-
|
|
17
|
-
class Navigator(
|
|
18
|
-
private val navController: NavController,
|
|
19
|
-
private val maxApi: IMaxApi?
|
|
20
|
-
) {
|
|
21
|
-
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
|
22
|
-
|
|
23
|
-
fun push(content: @Composable () -> Unit, options: NavigationOptions? = null) {
|
|
24
|
-
val route = DynamicScreenRegistry.register(content, options)
|
|
25
|
-
navController.navigate(DynamicScreenRoute(route.id))
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
fun replace(content: @Composable () -> Unit, options: NavigationOptions? = null) {
|
|
29
|
-
if (navController.previousBackStackEntry != null){
|
|
30
|
-
val latestScreen = DynamicScreenRegistry.getLatestScreen()
|
|
31
|
-
latestScreen?.let { DynamicScreenRegistry.unregisterScreen(it.id) }
|
|
32
|
-
navController.popBackStack()
|
|
33
|
-
push(content, options)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
fun pop(count: Int = 1, callBack: (() -> Unit)? = null) {
|
|
38
|
-
scope.launch {
|
|
39
|
-
repeat(count) {
|
|
40
|
-
if (OverplayComponentRegistry.isOverplayShowing()){
|
|
41
|
-
OverplayComponentRegistry.clear()
|
|
42
|
-
delay(300L)
|
|
43
|
-
OverplayComponentRegistry.hardClearAfterDismiss()
|
|
44
|
-
} else {
|
|
45
|
-
if (navController.previousBackStackEntry != null){
|
|
46
|
-
navController.popBackStack()
|
|
47
|
-
delay(300L)
|
|
48
|
-
DynamicScreenRegistry.getLatestScreen()?.let { it1 ->
|
|
49
|
-
DynamicScreenRegistry.unregisterScreen(it1.id)
|
|
50
|
-
}
|
|
51
|
-
} else {
|
|
52
|
-
maxApi?.dismiss { }
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
callBack?.invoke()
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
fun present(content: @Composable () -> Unit, options: NavigationOptions? = null) {
|
|
61
|
-
val route = DynamicScreenRegistry.register(content, options)
|
|
62
|
-
navController.navigate(DynamicDialogRoute(route.id))
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
fun reset(content: @Composable () -> Unit, options: NavigationOptions? = null) {
|
|
66
|
-
DynamicScreenRegistry.unregisterAll()
|
|
67
|
-
|
|
68
|
-
val route = DynamicScreenRegistry.register(content, options)
|
|
69
|
-
navController.navigate(DynamicScreenRoute(route.id)) {
|
|
70
|
-
popUpTo(0) { inclusive = true }
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
fun showModal(
|
|
75
|
-
content: @Composable () -> Unit,
|
|
76
|
-
barrierDismissible: Boolean = true,
|
|
77
|
-
onDismiss: (() -> Unit)? = null
|
|
78
|
-
){
|
|
79
|
-
OverplayComponentRegistry.registerModal(content, false, barrierDismissible, onDismiss, false)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
fun showBottomSheet(
|
|
83
|
-
content: @Composable () -> Unit,
|
|
84
|
-
isSurface: Boolean = false,
|
|
85
|
-
barrierDismissible: Boolean = true,
|
|
86
|
-
onDismiss: (() -> Unit)? = null,
|
|
87
|
-
bottomSheetHeader: BottomHeader? = null
|
|
88
|
-
){
|
|
89
|
-
OverplayComponentRegistry.registerModal(content, isSurface, barrierDismissible, onDismiss, true, bottomSheetHeader)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
fun dispose(){
|
|
93
|
-
scope.cancel()
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
val LocalNavigator = staticCompositionLocalOf<Navigator> {
|
|
98
|
-
error("No NavigationStack provided")
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
@Serializable
|
|
102
|
-
data class DynamicScreenRoute(val id: Int)
|
|
103
|
-
|
|
104
|
-
@Serializable
|
|
105
|
-
data class DynamicDialogRoute(val id: Int)
|
|
106
|
-
|
|
107
|
-
data class DynamicScreen(
|
|
108
|
-
val id: Int,
|
|
109
|
-
val content: @Composable () -> Unit,
|
|
110
|
-
var options: NavigationOptions? = null
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
object DynamicScreenRegistry {
|
|
114
|
-
private val screens = mutableMapOf<Int, DynamicScreen>()
|
|
115
|
-
private var idCounter = 1
|
|
116
|
-
|
|
117
|
-
fun register(content: @Composable () -> Unit, options: NavigationOptions?): DynamicScreenRoute {
|
|
118
|
-
val id = idCounter++
|
|
119
|
-
screens[id] = DynamicScreen(
|
|
120
|
-
id = id,
|
|
121
|
-
content = content,
|
|
122
|
-
options = options
|
|
123
|
-
)
|
|
124
|
-
return DynamicScreenRoute(id)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
fun unregisterScreen(id: Int) {
|
|
128
|
-
screens.remove(id)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
fun getLatestScreen(): DynamicScreen?{
|
|
132
|
-
return screens.entries.lastOrNull()?.value
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
fun unregisterAll(){
|
|
136
|
-
val ids = screens.keys.toList()
|
|
137
|
-
for (id in ids) {
|
|
138
|
-
unregisterScreen(id)
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
fun getScreen(id: Int): DynamicScreen? = screens[id]
|
|
143
|
-
|
|
144
|
-
fun setOptions(id: Int, options: NavigationOptions){
|
|
145
|
-
screens[id]?.options = options
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
sealed class OverplayComponentParams {
|
|
151
|
-
class Modal(
|
|
152
|
-
val onDismiss: (() -> Unit)? = null,
|
|
153
|
-
val barrierDismissible: Boolean = true
|
|
154
|
-
) : OverplayComponentParams()
|
|
155
|
-
|
|
156
|
-
class BottomSheet(
|
|
157
|
-
val isSurface: Boolean = false,
|
|
158
|
-
val onDismiss: (() -> Unit)? = null,
|
|
159
|
-
val barrierDismissible: Boolean = true,
|
|
160
|
-
val bottomSheetHeader: BottomHeader? = null,
|
|
161
|
-
) : OverplayComponentParams()
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
data class OverplayComponent(
|
|
165
|
-
val content: @Composable () -> Unit,
|
|
166
|
-
val params: OverplayComponentParams? = null
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
object OverplayComponentRegistry {
|
|
170
|
-
private var currentOverlayComponent : MutableState<OverplayComponent?> = mutableStateOf(null)
|
|
171
|
-
private var requestClose: (() -> Unit)? = null
|
|
172
|
-
internal fun bindClose(handler: (() -> Unit)?) {
|
|
173
|
-
requestClose = handler
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
fun registerModal(
|
|
177
|
-
content: @Composable () -> Unit,
|
|
178
|
-
isSurface: Boolean = false,
|
|
179
|
-
barrierDismissible: Boolean = true,
|
|
180
|
-
onDismiss: (() -> Unit)?,
|
|
181
|
-
isBottomSheet: Boolean = false,
|
|
182
|
-
bottomSheetHeader: BottomHeader? = null,
|
|
183
|
-
){
|
|
184
|
-
val params = if (isBottomSheet) {
|
|
185
|
-
OverplayComponentParams.BottomSheet(isSurface, onDismiss, barrierDismissible, bottomSheetHeader)
|
|
186
|
-
} else {
|
|
187
|
-
OverplayComponentParams.Modal(onDismiss, barrierDismissible)
|
|
188
|
-
}
|
|
189
|
-
currentOverlayComponent.value = OverplayComponent(
|
|
190
|
-
content = content,
|
|
191
|
-
params = params
|
|
192
|
-
)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
fun isOverplayShowing(): Boolean = currentOverlayComponent.value != null
|
|
196
|
-
|
|
197
|
-
fun clear(){
|
|
198
|
-
if (requestClose != null) {
|
|
199
|
-
requestClose?.invoke()
|
|
200
|
-
} else {
|
|
201
|
-
currentOverlayComponent.value = null
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
internal fun hardClearAfterDismiss() {
|
|
206
|
-
currentOverlayComponent.value = null
|
|
207
|
-
requestClose = null
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
@Composable
|
|
211
|
-
fun OverlayComponent(){
|
|
212
|
-
val overplay = currentOverlayComponent.value ?: return
|
|
213
|
-
|
|
214
|
-
if (overplay.params is OverplayComponentParams.BottomSheet) {
|
|
215
|
-
val param = overplay.params
|
|
216
|
-
BottomSheet(
|
|
217
|
-
content = overplay.content,
|
|
218
|
-
header = param.bottomSheetHeader ?: BottomHeader.Title(),
|
|
219
|
-
isSurface = param.isSurface,
|
|
220
|
-
barrierDismissible = param.barrierDismissible,
|
|
221
|
-
onDismiss = param.onDismiss
|
|
222
|
-
)
|
|
223
|
-
} else if (overplay.params is OverplayComponentParams.Modal) {
|
|
224
|
-
val param = overplay.params
|
|
225
|
-
ModalScreen(
|
|
226
|
-
content = overplay.content,
|
|
227
|
-
barrierDismissible = param.barrierDismissible,
|
|
228
|
-
onDismiss = param.onDismiss
|
|
229
|
-
)
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
package vn.momo.kits.navigation
|
|
2
|
-
|
|
3
|
-
import androidx.compose.runtime.Composable
|
|
4
|
-
import androidx.compose.runtime.CompositionLocalProvider
|
|
5
|
-
import vn.momo.kits.const.ScaleSizeMaxRate
|
|
6
|
-
|
|
7
|
-
@Composable
|
|
8
|
-
fun ScaleSizeScope(
|
|
9
|
-
scaleSizeMaxRate: Float? = null,
|
|
10
|
-
content: @Composable () -> Unit
|
|
11
|
-
) {
|
|
12
|
-
CompositionLocalProvider(
|
|
13
|
-
ScaleSizeMaxRate provides scaleSizeMaxRate
|
|
14
|
-
) {
|
|
15
|
-
content()
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,459 +0,0 @@
|
|
|
1
|
-
package vn.momo.kits.navigation
|
|
2
|
-
|
|
3
|
-
import androidx.compose.animation.animateColorAsState
|
|
4
|
-
import androidx.compose.animation.core.animateDpAsState
|
|
5
|
-
import androidx.compose.foundation.ScrollState
|
|
6
|
-
import androidx.compose.foundation.background
|
|
7
|
-
import androidx.compose.foundation.gestures.ScrollableState
|
|
8
|
-
import androidx.compose.foundation.layout.Box
|
|
9
|
-
import androidx.compose.foundation.layout.Column
|
|
10
|
-
import androidx.compose.foundation.layout.ColumnScope
|
|
11
|
-
import androidx.compose.foundation.layout.Spacer
|
|
12
|
-
import androidx.compose.foundation.layout.WindowInsets
|
|
13
|
-
import androidx.compose.foundation.layout.aspectRatio
|
|
14
|
-
import androidx.compose.foundation.layout.fillMaxSize
|
|
15
|
-
import androidx.compose.foundation.layout.fillMaxWidth
|
|
16
|
-
import androidx.compose.foundation.layout.height
|
|
17
|
-
import androidx.compose.foundation.layout.ime
|
|
18
|
-
import androidx.compose.foundation.layout.imePadding
|
|
19
|
-
import androidx.compose.foundation.layout.offset
|
|
20
|
-
import androidx.compose.foundation.layout.padding
|
|
21
|
-
import androidx.compose.foundation.lazy.LazyListState
|
|
22
|
-
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
23
|
-
import androidx.compose.foundation.rememberScrollState
|
|
24
|
-
import androidx.compose.foundation.verticalScroll
|
|
25
|
-
import androidx.compose.material.ExperimentalMaterialApi
|
|
26
|
-
import androidx.compose.runtime.Composable
|
|
27
|
-
import androidx.compose.runtime.CompositionLocalProvider
|
|
28
|
-
import androidx.compose.runtime.LaunchedEffect
|
|
29
|
-
import androidx.compose.runtime.getValue
|
|
30
|
-
import androidx.compose.runtime.mutableIntStateOf
|
|
31
|
-
import androidx.compose.runtime.mutableStateOf
|
|
32
|
-
import androidx.compose.runtime.remember
|
|
33
|
-
import androidx.compose.runtime.snapshotFlow
|
|
34
|
-
import androidx.compose.runtime.staticCompositionLocalOf
|
|
35
|
-
import androidx.compose.ui.Alignment
|
|
36
|
-
import androidx.compose.ui.Modifier
|
|
37
|
-
import androidx.compose.ui.graphics.Brush
|
|
38
|
-
import androidx.compose.ui.graphics.Color
|
|
39
|
-
import androidx.compose.ui.graphics.lerp
|
|
40
|
-
import androidx.compose.ui.layout.onGloballyPositioned
|
|
41
|
-
import androidx.compose.ui.platform.LocalDensity
|
|
42
|
-
import androidx.compose.ui.unit.Dp
|
|
43
|
-
import androidx.compose.ui.unit.dp
|
|
44
|
-
import androidx.compose.ui.unit.min
|
|
45
|
-
import androidx.compose.ui.zIndex
|
|
46
|
-
import vn.momo.kits.components.InputSearch
|
|
47
|
-
import vn.momo.kits.const.AppNavigationBar
|
|
48
|
-
import vn.momo.kits.const.AppStatusBar
|
|
49
|
-
import vn.momo.kits.const.AppTheme
|
|
50
|
-
import vn.momo.kits.const.Spacing
|
|
51
|
-
import vn.momo.kits.modifier.conditional
|
|
52
|
-
import vn.momo.kits.modifier.hideKeyboardOnTap
|
|
53
|
-
import vn.momo.kits.navigation.component.FABPosition
|
|
54
|
-
import vn.momo.kits.navigation.component.FloatingButton
|
|
55
|
-
import vn.momo.kits.navigation.component.HEADER_HEIGHT
|
|
56
|
-
import vn.momo.kits.navigation.component.Header
|
|
57
|
-
import vn.momo.kits.navigation.component.HeaderBackground
|
|
58
|
-
import vn.momo.kits.navigation.component.HeaderRight
|
|
59
|
-
import vn.momo.kits.navigation.component.HeaderType
|
|
60
|
-
import vn.momo.kits.navigation.component.InputSearchType
|
|
61
|
-
import vn.momo.kits.platform.BackHandler
|
|
62
|
-
import vn.momo.kits.platform.getAndroidBuildVersion
|
|
63
|
-
|
|
64
|
-
internal val LocalFooterHeightPx = staticCompositionLocalOf { mutableIntStateOf(0) }
|
|
65
|
-
internal val LocalHeaderRightWidthPx = staticCompositionLocalOf { mutableIntStateOf(0) }
|
|
66
|
-
|
|
67
|
-
@OptIn(ExperimentalMaterialApi::class)
|
|
68
|
-
@Composable
|
|
69
|
-
internal fun StackScreen(
|
|
70
|
-
content: @Composable () -> Unit,
|
|
71
|
-
navigationOptions: NavigationOptions? = null,
|
|
72
|
-
id: Int = -1,
|
|
73
|
-
bottomTabIndex: Int = -1,
|
|
74
|
-
) {
|
|
75
|
-
val navigator = LocalNavigator.current
|
|
76
|
-
val statusBar = AppStatusBar.current
|
|
77
|
-
val density = LocalDensity.current
|
|
78
|
-
val navigation = remember { Navigation(id = id, bottomTabIndex = bottomTabIndex, initOptions = navigationOptions) }
|
|
79
|
-
|
|
80
|
-
val options by navigation.currentOptions
|
|
81
|
-
|
|
82
|
-
val limit = with(density) {
|
|
83
|
-
(statusBar).toPx() + HEADER_HEIGHT
|
|
84
|
-
}.toInt()
|
|
85
|
-
|
|
86
|
-
val (scrollState, scrollInProcess) = if (options.scrollData.scrollState is LazyListState)
|
|
87
|
-
(options.scrollData.scrollState as? LazyListState ?: rememberLazyListState()).proxyScrollState(limit, 15)
|
|
88
|
-
else
|
|
89
|
-
(options.scrollData.scrollState as? ScrollState ?: rememberScrollState()).proxyLimitedScrollState(limit, 15)
|
|
90
|
-
|
|
91
|
-
val footerHeightPx = remember { mutableIntStateOf(0) }
|
|
92
|
-
val headerRightWidthPx = remember { mutableIntStateOf(0) }
|
|
93
|
-
|
|
94
|
-
BackHandler(true) { navigator.pop() }
|
|
95
|
-
|
|
96
|
-
CompositionLocalProvider(
|
|
97
|
-
StackScreenScrollableState provides options.scrollData.scrollState,
|
|
98
|
-
LocalNavigation provides navigation,
|
|
99
|
-
LocalScrollState provides scrollState,
|
|
100
|
-
LocalOptions provides options,
|
|
101
|
-
LocalFooterHeightPx provides footerHeightPx,
|
|
102
|
-
LocalHeaderRightWidthPx provides headerRightWidthPx
|
|
103
|
-
) {
|
|
104
|
-
Box(Modifier
|
|
105
|
-
.fillMaxSize()
|
|
106
|
-
.background(options.backgroundColor ?: AppTheme.current.colors.background.default)
|
|
107
|
-
.conditional(options.keyboardOptions.keyboardShouldPersistTaps) {
|
|
108
|
-
hideKeyboardOnTap()
|
|
109
|
-
}
|
|
110
|
-
.conditional(options.keyboardOptions.useAvoidKeyboard && getAndroidBuildVersion() > 29) {
|
|
111
|
-
imePadding()
|
|
112
|
-
}
|
|
113
|
-
) {
|
|
114
|
-
Box(Modifier.zIndex(1f)) {
|
|
115
|
-
HeaderBackground()
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
Box(Modifier.zIndex(4f)) {
|
|
119
|
-
Header()
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
Column (Modifier.zIndex(5f)) {
|
|
123
|
-
SearchAnimated(isScrollInProgress = scrollInProcess)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
Column(Modifier.zIndex(2f).fillMaxSize()) {
|
|
127
|
-
MainContent(content = content)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
Box(Modifier.zIndex(5f)){
|
|
131
|
-
FloatingContent()
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
Box(Modifier.zIndex(6f).fillMaxSize()){
|
|
135
|
-
if (bottomTabIndex != -1) return@Box
|
|
136
|
-
OverplayComponentRegistry.OverlayComponent()
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
@Composable
|
|
143
|
-
fun FloatingContent(){
|
|
144
|
-
val options = LocalOptions.current
|
|
145
|
-
val density = LocalDensity.current
|
|
146
|
-
val footerHeightPx = LocalFooterHeightPx.current
|
|
147
|
-
val scrollState = LocalScrollState.current
|
|
148
|
-
|
|
149
|
-
val fabProps = options.floatingButtonProps ?: return
|
|
150
|
-
val bottomPadding = fabProps.bottom ?:
|
|
151
|
-
(Spacing.M + if (options.footerComponent != null) with(density){ footerHeightPx.intValue.toDp() } else 0.dp)
|
|
152
|
-
|
|
153
|
-
FloatingButton(
|
|
154
|
-
scrollPosition = fabProps.scrollState?.value ?: scrollState.value,
|
|
155
|
-
onClick = fabProps.onClick,
|
|
156
|
-
containerColor = AppTheme.current.colors.primary,
|
|
157
|
-
bottom = bottomPadding,
|
|
158
|
-
icon = fabProps.icon,
|
|
159
|
-
iconColor = fabProps.iconColor,
|
|
160
|
-
text = fabProps.label,
|
|
161
|
-
size = fabProps.size,
|
|
162
|
-
position = fabProps.position ?: FABPosition.END,
|
|
163
|
-
)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
@Composable
|
|
167
|
-
fun ColumnScope.MainContent(content: @Composable ()-> Unit){
|
|
168
|
-
val options = LocalOptions.current
|
|
169
|
-
val inputSearchType = getInputSearchType(options)
|
|
170
|
-
val density = LocalDensity.current
|
|
171
|
-
val scrollState = LocalScrollState.current
|
|
172
|
-
|
|
173
|
-
Spacer(Modifier.height(if (options.headerType is HeaderType.DefaultOrExtended) AppStatusBar.current + HEADER_HEIGHT.dp else 0.dp))
|
|
174
|
-
if (inputSearchType == InputSearchType.Animated){
|
|
175
|
-
val scrollDp = with(density) { scrollState.value.toDp() }
|
|
176
|
-
|
|
177
|
-
val animatedTopPadding by animateDpAsState(
|
|
178
|
-
targetValue = (HEADER_HEIGHT.dp - scrollDp).coerceIn(0.dp, HEADER_HEIGHT.dp),
|
|
179
|
-
label = "AnimatedTopPadding"
|
|
180
|
-
)
|
|
181
|
-
Spacer(Modifier.height(animatedTopPadding))
|
|
182
|
-
}
|
|
183
|
-
Column (Modifier
|
|
184
|
-
.fillMaxWidth()
|
|
185
|
-
.weight(1f)
|
|
186
|
-
.conditional(options.scrollData.scrollable && options.scrollData.scrollState is ScrollState) {
|
|
187
|
-
verticalScroll(scrollState)
|
|
188
|
-
}
|
|
189
|
-
) {
|
|
190
|
-
ScreenContent(content = content)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (options.footerComponent != null){
|
|
194
|
-
val isKeyboardVisible = isKeyboardVisible()
|
|
195
|
-
val bottomPadding = min(AppNavigationBar.current, if (isKeyboardVisible) 0.dp else 21.dp)
|
|
196
|
-
Footer(footerComponent = options.footerComponent, bottomPadding = bottomPadding)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
@Composable
|
|
201
|
-
fun ScreenContent(content: @Composable () -> Unit){
|
|
202
|
-
val scrollState = LocalScrollState.current
|
|
203
|
-
val options = LocalOptions.current
|
|
204
|
-
|
|
205
|
-
if (options.headerType is HeaderType.Animated){
|
|
206
|
-
val animatedHeader = options.headerType
|
|
207
|
-
Box {
|
|
208
|
-
Box(Modifier.fillMaxWidth().aspectRatio(animatedHeader.aspectRatio.value)){
|
|
209
|
-
animatedHeader.composable.invoke(scrollState.value)
|
|
210
|
-
}
|
|
211
|
-
Box(Modifier.offset(x = 0.dp, y = AppStatusBar.current + HEADER_HEIGHT.dp + animatedHeader.layoutOffSet)){
|
|
212
|
-
content()
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
} else {
|
|
216
|
-
content()
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
@Composable
|
|
221
|
-
fun Footer(footerComponent: @Composable (() -> Unit)?, bottomPadding: Dp) {
|
|
222
|
-
if (footerComponent == null) return
|
|
223
|
-
|
|
224
|
-
val footerHeightPx = LocalFooterHeightPx.current
|
|
225
|
-
|
|
226
|
-
val shadowBrush = remember {
|
|
227
|
-
Brush.verticalGradient(
|
|
228
|
-
colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.05f))
|
|
229
|
-
)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
Box(Modifier.onGloballyPositioned {
|
|
233
|
-
if (footerHeightPx.intValue != it.size.height) footerHeightPx.intValue = it.size.height
|
|
234
|
-
}) {
|
|
235
|
-
Box(Modifier
|
|
236
|
-
.fillMaxWidth()
|
|
237
|
-
.background(AppTheme.current.colors.background.surface)
|
|
238
|
-
.padding(top = Spacing.S, start = Spacing.M, end = Spacing.M, bottom = bottomPadding + Spacing.S)
|
|
239
|
-
){
|
|
240
|
-
footerComponent.invoke()
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
Box(modifier = Modifier
|
|
244
|
-
.fillMaxWidth()
|
|
245
|
-
.height(6.dp)
|
|
246
|
-
.offset(x = 0.dp, y = (-6).dp)
|
|
247
|
-
.background(shadowBrush)
|
|
248
|
-
)
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
data class InputSearchLayoutParams(
|
|
253
|
-
val topPadding: Dp,
|
|
254
|
-
val startPadding: Dp,
|
|
255
|
-
val endPadding: Dp
|
|
256
|
-
)
|
|
257
|
-
@Composable
|
|
258
|
-
fun SearchAnimated(
|
|
259
|
-
isScrollInProgress: Boolean
|
|
260
|
-
) {
|
|
261
|
-
val scrollState = LocalScrollState.current
|
|
262
|
-
val options = LocalOptions.current
|
|
263
|
-
val navigator = LocalNavigator.current
|
|
264
|
-
val density = LocalDensity.current
|
|
265
|
-
|
|
266
|
-
val scrollDp = with(density) { scrollState.value.toDp() }
|
|
267
|
-
|
|
268
|
-
val inputSearchType = getInputSearchType(options)
|
|
269
|
-
val headerRightWidthPx = LocalHeaderRightWidthPx.current
|
|
270
|
-
val headerRightWidthDp = with(density) { headerRightWidthPx.intValue.toDp() }
|
|
271
|
-
|
|
272
|
-
if (inputSearchType == InputSearchType.None) return
|
|
273
|
-
val inputSearchProps = (options.headerType as? HeaderType.DefaultOrExtended)?.inputSearchProps ?: return
|
|
274
|
-
|
|
275
|
-
val minTopPadding = AppStatusBar.current
|
|
276
|
-
val maxTopPadding = AppStatusBar.current + HEADER_HEIGHT.dp
|
|
277
|
-
val minStartPadding = Spacing.M
|
|
278
|
-
val maxStartPadding = if (options.hiddenBack) Spacing.M else 52.dp
|
|
279
|
-
val minEndPadding = Spacing.M
|
|
280
|
-
val maxEndPadding = headerRightWidthDp + if (options.headerRight is HeaderRight.None) Spacing.M else Spacing.M * 2
|
|
281
|
-
|
|
282
|
-
val targetColor = lerp(
|
|
283
|
-
AppTheme.current.colors.background.surface,
|
|
284
|
-
AppTheme.current.colors.background.default,
|
|
285
|
-
(scrollDp / minTopPadding).coerceIn(0f, 1f)
|
|
286
|
-
)
|
|
287
|
-
val animatedColor by animateColorAsState(targetValue = targetColor, label = "BackgroundColor")
|
|
288
|
-
|
|
289
|
-
val layoutParams = when (inputSearchType) {
|
|
290
|
-
InputSearchType.Header -> {
|
|
291
|
-
InputSearchLayoutParams(
|
|
292
|
-
topPadding = minTopPadding,
|
|
293
|
-
startPadding = maxStartPadding,
|
|
294
|
-
endPadding = maxEndPadding
|
|
295
|
-
)
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
InputSearchType.Animated -> {
|
|
299
|
-
val animatedTopPadding by animateDpAsState(
|
|
300
|
-
targetValue = (maxTopPadding - scrollDp).coerceIn(minTopPadding, maxTopPadding),
|
|
301
|
-
label = "AnimatedTopPadding"
|
|
302
|
-
)
|
|
303
|
-
|
|
304
|
-
val animatedStartPadding by animateDpAsState(
|
|
305
|
-
targetValue = (minStartPadding + scrollDp).coerceIn(minStartPadding, maxStartPadding),
|
|
306
|
-
label = "AnimatedStartPadding"
|
|
307
|
-
)
|
|
308
|
-
|
|
309
|
-
val animatedEndPadding by animateDpAsState(
|
|
310
|
-
targetValue = (minEndPadding + scrollDp).coerceIn(minEndPadding, maxEndPadding),
|
|
311
|
-
label = "AnimatedEndPadding"
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
val maxPadding = remember(maxTopPadding, maxStartPadding, maxEndPadding) {
|
|
315
|
-
maxOf(maxEndPadding, maxStartPadding, maxTopPadding)
|
|
316
|
-
}
|
|
317
|
-
val snapScrollValue = with(density) { maxPadding.toPx().toInt() }
|
|
318
|
-
|
|
319
|
-
LaunchedEffect(isScrollInProgress && scrollState.value != 0 && scrollState.value != snapScrollValue) {
|
|
320
|
-
if (scrollDp < maxPadding) {
|
|
321
|
-
if (!isScrollInProgress) {
|
|
322
|
-
val midpoint = (maxTopPadding - minTopPadding) / 2
|
|
323
|
-
|
|
324
|
-
if (scrollDp < midpoint) {
|
|
325
|
-
scrollState.animateScrollTo(0)
|
|
326
|
-
} else {
|
|
327
|
-
scrollState.animateScrollTo(snapScrollValue)
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
InputSearchLayoutParams(
|
|
334
|
-
topPadding = animatedTopPadding,
|
|
335
|
-
startPadding = animatedStartPadding,
|
|
336
|
-
endPadding = animatedEndPadding
|
|
337
|
-
)
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
InputSearchType.None -> return
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
Spacer(Modifier.height(layoutParams.topPadding))
|
|
344
|
-
Box(
|
|
345
|
-
modifier = Modifier
|
|
346
|
-
.height(HEADER_HEIGHT.dp)
|
|
347
|
-
.fillMaxWidth()
|
|
348
|
-
.padding(
|
|
349
|
-
start = layoutParams.startPadding,
|
|
350
|
-
end = layoutParams.endPadding
|
|
351
|
-
),
|
|
352
|
-
contentAlignment = Alignment.Center
|
|
353
|
-
) {
|
|
354
|
-
InputSearch(
|
|
355
|
-
inputSearchProps = inputSearchProps.copy(
|
|
356
|
-
backgroundColor = animatedColor,
|
|
357
|
-
onPressButtonText = {
|
|
358
|
-
navigator.pop()
|
|
359
|
-
}
|
|
360
|
-
)
|
|
361
|
-
)
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
@Composable
|
|
366
|
-
internal fun isKeyboardVisible(): Boolean {
|
|
367
|
-
val ime = WindowInsets.ime
|
|
368
|
-
val density = LocalDensity.current
|
|
369
|
-
return ime.getBottom(density) > 0
|
|
370
|
-
}
|
|
371
|
-
private fun quantize(value: Int, stepPx: Int): Int {
|
|
372
|
-
if (stepPx <= 1) return value
|
|
373
|
-
return (value / stepPx) * stepPx
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
@Composable
|
|
377
|
-
fun LazyListState.proxyScrollState(
|
|
378
|
-
thresholdPx: Int = 200,
|
|
379
|
-
stepPx: Int = 10
|
|
380
|
-
): Pair<ScrollState, Boolean> {
|
|
381
|
-
val scrollState = rememberScrollState()
|
|
382
|
-
val locked = remember { mutableStateOf(false) }
|
|
383
|
-
|
|
384
|
-
LaunchedEffect(this, scrollState, thresholdPx, stepPx) {
|
|
385
|
-
snapshotFlow { firstVisibleItemIndex to firstVisibleItemScrollOffset }
|
|
386
|
-
.collect { (index, offset) ->
|
|
387
|
-
val rawTarget = if (index == 0) offset else SCROLLED_PAST_FIRST_ITEM_THRESHOLD
|
|
388
|
-
val shouldLock = rawTarget > thresholdPx
|
|
389
|
-
if (locked.value != shouldLock) locked.value = shouldLock
|
|
390
|
-
|
|
391
|
-
val desired = if (shouldLock) thresholdPx else quantize(rawTarget, stepPx)
|
|
392
|
-
|
|
393
|
-
if (scrollState.value != desired) {
|
|
394
|
-
scrollState.scrollTo(desired.coerceAtLeast(0))
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
val inProgress = remember { mutableStateOf(false) }
|
|
400
|
-
LaunchedEffect(this, thresholdPx) {
|
|
401
|
-
snapshotFlow { isScrollInProgress }
|
|
402
|
-
.collect { progressing ->
|
|
403
|
-
inProgress.value = if (locked.value) false else progressing
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return scrollState to inProgress.value
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
@Composable
|
|
411
|
-
fun ScrollState.proxyLimitedScrollState(
|
|
412
|
-
thresholdPx: Int = 200,
|
|
413
|
-
stepPx: Int = 10
|
|
414
|
-
): Pair<ScrollState, Boolean> {
|
|
415
|
-
val proxy = rememberScrollState()
|
|
416
|
-
val locked = remember { mutableStateOf(false) }
|
|
417
|
-
|
|
418
|
-
LaunchedEffect(this, proxy, thresholdPx, stepPx) {
|
|
419
|
-
snapshotFlow { value }
|
|
420
|
-
.collect { rawTarget ->
|
|
421
|
-
val shouldLock = rawTarget > thresholdPx
|
|
422
|
-
if (locked.value != shouldLock) locked.value = shouldLock
|
|
423
|
-
|
|
424
|
-
val desired = if (shouldLock) thresholdPx else quantize(rawTarget, stepPx)
|
|
425
|
-
|
|
426
|
-
if (proxy.value != desired) {
|
|
427
|
-
proxy.scrollTo(desired.coerceAtLeast(0))
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
val inProgress = remember { mutableStateOf(false) }
|
|
433
|
-
LaunchedEffect(this, thresholdPx) {
|
|
434
|
-
snapshotFlow { isScrollInProgress }
|
|
435
|
-
.collect { progressing ->
|
|
436
|
-
inProgress.value = if (locked.value) false else progressing
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
return proxy to inProgress.value
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
private const val SCROLLED_PAST_FIRST_ITEM_THRESHOLD = 10_000
|
|
444
|
-
|
|
445
|
-
internal val LocalScrollState = staticCompositionLocalOf<ScrollState> { error("No Scroll State provided") }
|
|
446
|
-
internal val LocalOptions = staticCompositionLocalOf<NavigationOptions> { error("No NavigationOptions provided") }
|
|
447
|
-
|
|
448
|
-
val StackScreenScrollableState = staticCompositionLocalOf<ScrollableState?> { null }
|
|
449
|
-
|
|
450
|
-
internal fun getInputSearchType(options: NavigationOptions): InputSearchType{
|
|
451
|
-
return when (val headerType = options.headerType) {
|
|
452
|
-
is HeaderType.DefaultOrExtended -> when {
|
|
453
|
-
headerType.inputSearchProps == null -> InputSearchType.None
|
|
454
|
-
headerType.useAnimated -> InputSearchType.Animated
|
|
455
|
-
else -> InputSearchType.Header
|
|
456
|
-
}
|
|
457
|
-
else -> InputSearchType.None
|
|
458
|
-
}
|
|
459
|
-
}
|