@momo-kits/native-kits 0.157.2-debug → 0.157.2

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.
Files changed (117) hide show
  1. package/package.json +1 -1
  2. package/build.gradle.kts +0 -11
  3. package/compose/build.gradle.kts +0 -180
  4. package/compose/build.gradle.kts.backup +0 -180
  5. package/compose/compose.podspec +0 -54
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -110
  7. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  8. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  9. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  10. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  11. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  12. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -57
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -107
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -201
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -222
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -48
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -305
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -720
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -121
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -405
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -85
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -340
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -198
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -357
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -94
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -136
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -543
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -23
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -148
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -188
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -116
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -448
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -172
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -255
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -231
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -233
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -254
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -241
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -364
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -92
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -352
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -103
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -70
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -17
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -96
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -96
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -92
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -130
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -214
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -576
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -177
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -205
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -239
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -191
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -306
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -13
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -185
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -285
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -2
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -35
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -2
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -59
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -68
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -14
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -50
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -239
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -119
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -98
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -161
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -331
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -497
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -162
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -243
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -187
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -279
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -80
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -306
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -32
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -370
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -42
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -62
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -88
  110. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -149
  111. package/gradle/libs.versions.toml +0 -57
  112. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  113. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  114. package/gradle.properties +0 -26
  115. package/gradlew +0 -252
  116. package/gradlew.bat +0 -94
  117. package/settings.gradle.kts +0 -52
@@ -1,497 +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.border
8
- import androidx.compose.foundation.gestures.ScrollableState
9
- import androidx.compose.foundation.layout.Box
10
- import androidx.compose.foundation.layout.Column
11
- import androidx.compose.foundation.layout.ColumnScope
12
- import androidx.compose.foundation.layout.Spacer
13
- import androidx.compose.foundation.layout.WindowInsets
14
- import androidx.compose.foundation.layout.aspectRatio
15
- import androidx.compose.foundation.layout.fillMaxSize
16
- import androidx.compose.foundation.layout.fillMaxWidth
17
- import androidx.compose.foundation.layout.height
18
- import androidx.compose.foundation.layout.ime
19
- import androidx.compose.foundation.layout.imePadding
20
- import androidx.compose.foundation.layout.offset
21
- import androidx.compose.foundation.layout.padding
22
- import androidx.compose.foundation.lazy.LazyListState
23
- import androidx.compose.foundation.lazy.rememberLazyListState
24
- import androidx.compose.foundation.rememberScrollState
25
- import androidx.compose.foundation.verticalScroll
26
- import androidx.compose.material.ExperimentalMaterialApi
27
- import androidx.compose.runtime.Composable
28
- import androidx.compose.runtime.CompositionLocalProvider
29
- import androidx.compose.runtime.LaunchedEffect
30
- import androidx.compose.runtime.getValue
31
- import androidx.compose.runtime.mutableIntStateOf
32
- import androidx.compose.runtime.mutableStateOf
33
- import androidx.compose.runtime.remember
34
- import androidx.compose.runtime.snapshotFlow
35
- import androidx.compose.runtime.staticCompositionLocalOf
36
- import androidx.compose.ui.Alignment
37
- import androidx.compose.ui.Modifier
38
- import androidx.compose.ui.graphics.Brush
39
- import androidx.compose.ui.graphics.Color
40
- import androidx.compose.ui.graphics.lerp
41
- import androidx.compose.ui.layout.onGloballyPositioned
42
- import androidx.compose.ui.platform.LocalDensity
43
- import androidx.compose.ui.unit.Dp
44
- import androidx.compose.ui.unit.dp
45
- import androidx.compose.ui.unit.min
46
- import androidx.compose.ui.zIndex
47
- import vn.momo.kits.components.InputSearch
48
- import vn.momo.kits.const.AppNavigationBar
49
- import vn.momo.kits.const.AppStatusBar
50
- import vn.momo.kits.const.AppTheme
51
- import vn.momo.kits.application.IsShowBaseLineDebug
52
- import vn.momo.kits.const.Colors
53
- import vn.momo.kits.const.Spacing
54
- import vn.momo.kits.modifier.conditional
55
- import vn.momo.kits.modifier.hideKeyboardOnTap
56
- import vn.momo.kits.navigation.component.FABPosition
57
- import vn.momo.kits.navigation.component.FloatingButton
58
- import vn.momo.kits.navigation.component.HEADER_HEIGHT
59
- import vn.momo.kits.navigation.component.Header
60
- import vn.momo.kits.navigation.component.HeaderBackground
61
- import vn.momo.kits.navigation.component.HeaderRight
62
- import vn.momo.kits.navigation.component.HeaderType
63
- import vn.momo.kits.navigation.component.InputSearchType
64
- import vn.momo.kits.platform.BackHandler
65
- import vn.momo.kits.platform.getAndroidBuildVersion
66
-
67
- internal val LocalFooterHeightPx = staticCompositionLocalOf { mutableIntStateOf(0) }
68
- internal val LocalHeaderRightWidthPx = staticCompositionLocalOf { mutableIntStateOf(0) }
69
-
70
- @OptIn(ExperimentalMaterialApi::class)
71
- @Composable
72
- internal fun StackScreen(
73
- content: @Composable () -> Unit,
74
- navigationOptions: NavigationOptions? = null,
75
- id: Int = -1,
76
- bottomTabIndex: Int = -1,
77
- onBackHandler: (() -> Unit)? = null,
78
- ) {
79
- val navigator = LocalNavigator.current
80
- val statusBar = AppStatusBar.current
81
- val density = LocalDensity.current
82
- val navigation = remember { Navigation(id = id, bottomTabIndex = bottomTabIndex, initOptions = navigationOptions) }
83
-
84
- val options by navigation.currentOptions
85
-
86
- val limit = with(density) {
87
- (statusBar).toPx() + HEADER_HEIGHT
88
- }.toInt()
89
-
90
- val (scrollState, scrollInProcess) = if (options.scrollData.scrollState is LazyListState)
91
- (options.scrollData.scrollState as? LazyListState ?: rememberLazyListState()).proxyScrollState(limit, 15)
92
- else
93
- (options.scrollData.scrollState as? ScrollState ?: rememberScrollState()).proxyLimitedScrollState(limit, 15)
94
-
95
- val footerHeightPx = remember { mutableIntStateOf(0) }
96
- val headerRightWidthPx = remember { mutableIntStateOf(0) }
97
-
98
- BackHandler(true) { navigator.onBackSafe() }
99
-
100
- CompositionLocalProvider(
101
- StackScreenScrollableState provides options.scrollData.scrollState,
102
- LocalNavigation provides navigation,
103
- LocalScrollState provides scrollState,
104
- LocalOptions provides options,
105
- LocalFooterHeightPx provides footerHeightPx,
106
- LocalHeaderRightWidthPx provides headerRightWidthPx
107
- ) {
108
- Box(Modifier
109
- .fillMaxSize()
110
- .background(options.backgroundColor ?: AppTheme.current.colors.background.default)
111
- .conditional(options.keyboardOptions.keyboardShouldPersistTaps) {
112
- hideKeyboardOnTap()
113
- }
114
- .conditional(options.keyboardOptions.useAvoidKeyboard && getAndroidBuildVersion() > 29) {
115
- imePadding()
116
- }
117
- ) {
118
- Box(Modifier.zIndex(1f)) {
119
- HeaderBackground()
120
- }
121
-
122
- Box(Modifier.zIndex(5f)) {
123
- Header(onBackHandler)
124
- }
125
-
126
- Column (Modifier.zIndex(6f)) {
127
- SearchAnimated(isScrollInProgress = scrollInProcess)
128
- }
129
-
130
- Column(Modifier.zIndex(2f).fillMaxSize()) {
131
- MainContent(content = content)
132
- }
133
-
134
- Box(Modifier.zIndex(4f).align(Alignment.BottomCenter)) {
135
- FooterContent()
136
- }
137
-
138
- Box(Modifier.zIndex(7f)){
139
- FloatingContent()
140
- }
141
-
142
- OverplayView(bottomTabIndex = bottomTabIndex, id = id)
143
- }
144
- }
145
- }
146
-
147
- @Composable
148
- fun FloatingContent(){
149
- val options = LocalOptions.current
150
- val density = LocalDensity.current
151
- val footerHeightPx = LocalFooterHeightPx.current
152
- val scrollState = LocalScrollState.current
153
-
154
- val fabProps = options.floatingButtonProps ?: return
155
- val bottomPadding = fabProps.bottom ?:
156
- (Spacing.M + if (options.footerComponent != null) with(density){ footerHeightPx.intValue.toDp() } else 0.dp)
157
-
158
- FloatingButton(
159
- scrollPosition = fabProps.scrollState?.value ?: scrollState.value,
160
- onClick = fabProps.onClick,
161
- containerColor = AppTheme.current.colors.primary,
162
- bottom = bottomPadding,
163
- icon = fabProps.icon,
164
- iconColor = fabProps.iconColor,
165
- text = fabProps.label,
166
- size = fabProps.size,
167
- position = fabProps.position ?: FABPosition.END,
168
- )
169
- }
170
-
171
- @Composable
172
- fun ColumnScope.MainContent(content: @Composable ()-> Unit){
173
- val options = LocalOptions.current
174
- val inputSearchType = getInputSearchType(options)
175
- val density = LocalDensity.current
176
- val scrollState = LocalScrollState.current
177
-
178
- Spacer(Modifier.height(
179
- if (options.headerType is HeaderType.DefaultOrExtended || (options.headerType is HeaderType.Transparent && !options.headerType.isFullScreenContent))
180
- AppStatusBar.current + HEADER_HEIGHT.dp else 0.dp)
181
- )
182
- if (inputSearchType == InputSearchType.Animated){
183
- val scrollDp = with(density) { scrollState.value.toDp() }
184
-
185
- val animatedTopPadding by animateDpAsState(
186
- targetValue = (HEADER_HEIGHT.dp - scrollDp).coerceIn(0.dp, HEADER_HEIGHT.dp),
187
- label = "AnimatedTopPadding"
188
- )
189
- Spacer(Modifier.height(animatedTopPadding))
190
- }
191
- Column (Modifier
192
- .fillMaxWidth()
193
- .weight(1f)
194
- .conditional(options.scrollData.scrollable && options.scrollData.scrollState is ScrollState) {
195
- verticalScroll(scrollState)
196
- }
197
- ) {
198
- ScreenContent(content = content)
199
- }
200
-
201
- if (options.footerComponent != null){
202
- val footerHeight = LocalFooterHeightPx.current
203
- val footerHeightDp = with(density) { footerHeight.value.toDp() }
204
- Spacer(Modifier.height(footerHeightDp))
205
- }
206
- }
207
-
208
- @Composable
209
- fun ScreenContent(content: @Composable () -> Unit){
210
- val scrollState = LocalScrollState.current
211
- val options = LocalOptions.current
212
-
213
- if (options.headerType is HeaderType.Animated){
214
- val animatedHeader = options.headerType
215
- Box {
216
- Box(Modifier.fillMaxWidth().aspectRatio(animatedHeader.aspectRatio.value)){
217
- animatedHeader.composable.invoke(scrollState.value)
218
- }
219
- Box(Modifier.offset(x = 0.dp, y = AppStatusBar.current + HEADER_HEIGHT.dp + animatedHeader.layoutOffSet)){
220
- content()
221
- }
222
- }
223
- } else {
224
- content()
225
- }
226
- }
227
-
228
- @Composable
229
- fun FooterContent(){
230
- val options = LocalOptions.current
231
- if (options.footerComponent != null){
232
- val ime = WindowInsets.ime
233
- val density = LocalDensity.current
234
- val imeBottom = ime.getBottom(density)
235
- val thresholdPx = with(density) { 50.dp.toPx() }
236
- val isKeyboardVisible = imeBottom > thresholdPx
237
- val bottomPadding = min(AppNavigationBar.current, if (isKeyboardVisible) 0.dp else 21.dp)
238
- Footer(footerComponent = options.footerComponent, bottomPadding = bottomPadding)
239
- }
240
- }
241
-
242
- @Composable
243
- fun OverplayView(bottomTabIndex: Int, id: Int){
244
- val overplayType = OverplayComponentRegistry.getOverplayType()
245
-
246
- if (overplayType != null) {
247
- Box(Modifier.zIndex(if (overplayType == OverplayComponentType.SNACK_BAR) 3f else 8f).fillMaxSize()){
248
- if (bottomTabIndex != -1) return@Box
249
- if (OverplayComponentRegistry.currentRootId() != id) return@Box
250
- OverplayComponentRegistry.OverlayComponent()
251
- }
252
- }
253
- }
254
-
255
- @Composable
256
- fun Footer(footerComponent: @Composable (() -> Unit)?, bottomPadding: Dp) {
257
- if (footerComponent == null) return
258
-
259
- val footerHeightPx = LocalFooterHeightPx.current
260
-
261
- val shadowBrush = remember {
262
- Brush.verticalGradient(
263
- colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.05f))
264
- )
265
- }
266
-
267
- Box(Modifier.onGloballyPositioned {
268
- if (footerHeightPx.intValue != it.size.height) footerHeightPx.intValue = it.size.height
269
- }) {
270
- Box(Modifier
271
- .fillMaxWidth()
272
- .background(AppTheme.current.colors.background.surface)
273
- .conditional(IsShowBaseLineDebug) {
274
- border(1.dp, Colors.blue_03)
275
- }
276
- .padding(top = Spacing.S, start = Spacing.M, end = Spacing.M, bottom = bottomPadding + Spacing.S)
277
- ){
278
- footerComponent.invoke()
279
- }
280
-
281
- Box(modifier = Modifier
282
- .fillMaxWidth()
283
- .height(6.dp)
284
- .offset(x = 0.dp, y = (-6).dp)
285
- .background(shadowBrush)
286
- )
287
- }
288
- }
289
-
290
- data class InputSearchLayoutParams(
291
- val topPadding: Dp,
292
- val startPadding: Dp,
293
- val endPadding: Dp
294
- )
295
- @Composable
296
- fun SearchAnimated(
297
- isScrollInProgress: Boolean
298
- ) {
299
- val scrollState = LocalScrollState.current
300
- val options = LocalOptions.current
301
- val navigator = LocalNavigator.current
302
- val density = LocalDensity.current
303
-
304
- val scrollDp = with(density) { scrollState.value.toDp() }
305
-
306
- val inputSearchType = getInputSearchType(options)
307
- val headerRightWidthPx = LocalHeaderRightWidthPx.current
308
- val headerRightWidthDp = with(density) { headerRightWidthPx.intValue.toDp() }
309
-
310
- if (inputSearchType == InputSearchType.None) return
311
- val inputSearchProps = (options.headerType as? HeaderType.DefaultOrExtended)?.inputSearchProps ?: return
312
-
313
- val minTopPadding = AppStatusBar.current
314
- val maxTopPadding = AppStatusBar.current + HEADER_HEIGHT.dp
315
- val minStartPadding = Spacing.M
316
- val maxStartPadding = if (options.hiddenBack) Spacing.M else 52.dp
317
- val minEndPadding = Spacing.M
318
- val maxEndPadding = headerRightWidthDp + if (options.headerRight is HeaderRight.None) Spacing.M else Spacing.M * 2
319
-
320
- val targetColor = lerp(
321
- AppTheme.current.colors.background.surface,
322
- AppTheme.current.colors.background.default,
323
- (scrollDp / minTopPadding).coerceIn(0f, 1f)
324
- )
325
- val animatedColor by animateColorAsState(targetValue = targetColor, label = "BackgroundColor")
326
-
327
- val layoutParams = when (inputSearchType) {
328
- InputSearchType.Header -> {
329
- InputSearchLayoutParams(
330
- topPadding = minTopPadding,
331
- startPadding = maxStartPadding,
332
- endPadding = maxEndPadding
333
- )
334
- }
335
-
336
- InputSearchType.Animated -> {
337
- val animatedTopPadding by animateDpAsState(
338
- targetValue = (maxTopPadding - scrollDp).coerceIn(minTopPadding, maxTopPadding),
339
- label = "AnimatedTopPadding"
340
- )
341
-
342
- val animatedStartPadding by animateDpAsState(
343
- targetValue = (minStartPadding + scrollDp).coerceIn(minStartPadding, maxStartPadding),
344
- label = "AnimatedStartPadding"
345
- )
346
-
347
- val animatedEndPadding by animateDpAsState(
348
- targetValue = (minEndPadding + scrollDp).coerceIn(minEndPadding, maxEndPadding),
349
- label = "AnimatedEndPadding"
350
- )
351
-
352
- val maxPadding = remember(maxTopPadding, maxStartPadding, maxEndPadding) {
353
- maxOf(maxEndPadding, maxStartPadding, maxTopPadding)
354
- }
355
- val snapScrollValue = with(density) { maxPadding.toPx().toInt() }
356
-
357
- LaunchedEffect(isScrollInProgress && scrollState.value != 0 && scrollState.value != snapScrollValue) {
358
- if (scrollDp < maxPadding) {
359
- if (!isScrollInProgress) {
360
- val midpoint = (maxTopPadding - minTopPadding) / 2
361
-
362
- if (scrollDp < midpoint) {
363
- scrollState.animateScrollTo(0)
364
- } else {
365
- scrollState.animateScrollTo(snapScrollValue)
366
- }
367
- }
368
- }
369
- }
370
-
371
- InputSearchLayoutParams(
372
- topPadding = animatedTopPadding,
373
- startPadding = animatedStartPadding,
374
- endPadding = animatedEndPadding
375
- )
376
- }
377
-
378
- InputSearchType.None -> return
379
- }
380
-
381
- Spacer(Modifier.height(layoutParams.topPadding))
382
- Box(
383
- modifier = Modifier
384
- .height(HEADER_HEIGHT.dp)
385
- .fillMaxWidth()
386
- .padding(
387
- start = layoutParams.startPadding,
388
- end = layoutParams.endPadding
389
- ),
390
- contentAlignment = Alignment.Center
391
- ) {
392
- InputSearch(
393
- inputSearchProps = inputSearchProps.copy(
394
- backgroundColor = animatedColor,
395
- onPressButtonText = {
396
- navigator.pop()
397
- }
398
- )
399
- )
400
- }
401
- }
402
-
403
- @Composable
404
- internal fun isKeyboardVisible(): Boolean {
405
- val ime = WindowInsets.ime
406
- val density = LocalDensity.current
407
- return ime.getBottom(density) > 0
408
- }
409
- private fun quantize(value: Int, stepPx: Int): Int {
410
- if (stepPx <= 1) return value
411
- return (value / stepPx) * stepPx
412
- }
413
-
414
- @Composable
415
- fun LazyListState.proxyScrollState(
416
- thresholdPx: Int = 200,
417
- stepPx: Int = 4
418
- ): Pair<ScrollState, Boolean> {
419
- val scrollState = rememberScrollState()
420
- val locked = remember { mutableStateOf(false) }
421
-
422
- LaunchedEffect(this, scrollState, thresholdPx, stepPx) {
423
- snapshotFlow { firstVisibleItemIndex to firstVisibleItemScrollOffset }
424
- .collect { (index, offset) ->
425
- val rawTarget = if (index == 0) offset else SCROLLED_PAST_FIRST_ITEM_THRESHOLD
426
- val shouldLock = rawTarget > thresholdPx
427
- if (locked.value != shouldLock) locked.value = shouldLock
428
-
429
- val desired = if (shouldLock) thresholdPx else quantize(rawTarget, stepPx)
430
-
431
- if (scrollState.value != desired) {
432
- scrollState.scrollTo(desired.coerceAtLeast(0))
433
- }
434
- }
435
- }
436
-
437
- val inProgress = remember { mutableStateOf(false) }
438
- LaunchedEffect(this, thresholdPx) {
439
- snapshotFlow { isScrollInProgress }
440
- .collect { progressing ->
441
- inProgress.value = if (locked.value) false else progressing
442
- }
443
- }
444
-
445
- return scrollState to inProgress.value
446
- }
447
-
448
- @Composable
449
- fun ScrollState.proxyLimitedScrollState(
450
- thresholdPx: Int = 200,
451
- stepPx: Int = 4
452
- ): Pair<ScrollState, Boolean> {
453
- val proxy = rememberScrollState()
454
- val locked = remember { mutableStateOf(false) }
455
-
456
- LaunchedEffect(this, proxy, thresholdPx, stepPx) {
457
- snapshotFlow { value }
458
- .collect { rawTarget ->
459
- val shouldLock = rawTarget > thresholdPx
460
- if (locked.value != shouldLock) locked.value = shouldLock
461
-
462
- val desired = if (shouldLock) thresholdPx else quantize(rawTarget, stepPx)
463
-
464
- if (proxy.value != desired) {
465
- proxy.scrollTo(desired.coerceAtLeast(0))
466
- }
467
- }
468
- }
469
-
470
- val inProgress = remember { mutableStateOf(false) }
471
- LaunchedEffect(this, thresholdPx) {
472
- snapshotFlow { isScrollInProgress }
473
- .collect { progressing ->
474
- inProgress.value = if (locked.value) false else progressing
475
- }
476
- }
477
-
478
- return proxy to inProgress.value
479
- }
480
-
481
- private const val SCROLLED_PAST_FIRST_ITEM_THRESHOLD = 10_000
482
-
483
- internal val LocalScrollState = staticCompositionLocalOf<ScrollState> { error("No Scroll State provided") }
484
- internal val LocalOptions = staticCompositionLocalOf<NavigationOptions> { error("No NavigationOptions provided") }
485
-
486
- val StackScreenScrollableState = staticCompositionLocalOf<ScrollableState?> { null }
487
-
488
- internal fun getInputSearchType(options: NavigationOptions): InputSearchType{
489
- return when (val headerType = options.headerType) {
490
- is HeaderType.DefaultOrExtended -> when {
491
- headerType.inputSearchProps == null -> InputSearchType.None
492
- headerType.useAnimated -> InputSearchType.Animated
493
- else -> InputSearchType.Header
494
- }
495
- else -> InputSearchType.None
496
- }
497
- }
@@ -1,162 +0,0 @@
1
- package vn.momo.kits.navigation.bottomtab
2
-
3
- import androidx.compose.animation.core.tween
4
- import androidx.compose.animation.fadeIn
5
- import androidx.compose.animation.fadeOut
6
- import androidx.compose.animation.scaleIn
7
- import androidx.compose.animation.scaleOut
8
- import androidx.compose.foundation.background
9
- import androidx.compose.foundation.layout.Box
10
- import androidx.compose.foundation.layout.Column
11
- import androidx.compose.foundation.layout.Spacer
12
- import androidx.compose.foundation.layout.fillMaxSize
13
- import androidx.compose.foundation.layout.fillMaxWidth
14
- import androidx.compose.foundation.layout.height
15
- import androidx.compose.foundation.layout.padding
16
- import androidx.compose.runtime.Composable
17
- import androidx.compose.runtime.LaunchedEffect
18
- import androidx.compose.ui.Alignment
19
- import androidx.compose.ui.Modifier
20
- import androidx.compose.ui.unit.dp
21
- import androidx.compose.ui.unit.min
22
- import androidx.navigation.compose.NavHost
23
- import androidx.navigation.compose.composable
24
- import androidx.navigation.compose.rememberNavController
25
- import vn.momo.kits.const.AppNavigationBar
26
- import vn.momo.kits.const.AppTheme
27
- import vn.momo.kits.const.Spacing
28
- import vn.momo.kits.navigation.LocalNavigation
29
- import vn.momo.kits.navigation.LocalNavigator
30
- import vn.momo.kits.navigation.NavigationOptions
31
- import vn.momo.kits.navigation.StackScreen
32
- import vn.momo.kits.navigation.component.HeaderType
33
- import vn.momo.kits.platform.getScreenHeight
34
-
35
- private var bottomTabOptionItems : MutableList<NavigationOptions?> = mutableListOf()
36
- fun setBottomTabOption(index: Int, options: NavigationOptions){
37
- if (index in bottomTabOptionItems.indices) {
38
- bottomTabOptionItems[index] = options
39
- }
40
- }
41
- fun getBottomTabOption(index: Int): NavigationOptions? {
42
- return if (index in bottomTabOptionItems.indices) {
43
- bottomTabOptionItems[index]
44
- } else null
45
- }
46
-
47
- @Composable
48
- fun BottomTab(
49
- items: List<BottomTabItem>,
50
- floatingButton: BottomTabFloatingButton? = null
51
- ) {
52
- val navigation = LocalNavigation.current
53
- val navigator = LocalNavigator.current
54
- val navController = rememberNavController()
55
-
56
- bottomTabOptionItems = items.mapIndexed { index, item ->
57
- item.options ?: NavigationOptions()
58
- }.toMutableList()
59
-
60
-
61
- LaunchedEffect(Unit){
62
- navigation.setOptions(
63
- headerType = HeaderType.None
64
- )
65
- }
66
-
67
- Box(modifier = Modifier.fillMaxWidth().height(getScreenHeight()), contentAlignment = Alignment.BottomCenter) {
68
- Box(modifier = Modifier
69
- .fillMaxSize()
70
- .padding(bottom = BOTTOM_TAB_BAR_HEIGHT.dp + AppNavigationBar.current)
71
- ) {
72
- NavHost(
73
- navController = navController,
74
- startDestination = "option0"
75
- ) {
76
- items.forEachIndexed { index, item ->
77
- composable(
78
- route = "option$index",
79
- enterTransition = {
80
- fadeIn(animationSpec = tween(200)) +
81
- scaleIn(
82
- initialScale = 0.97f,
83
- animationSpec = tween(200)
84
- )
85
- },
86
- exitTransition = {
87
- fadeOut(animationSpec = tween(200)) +
88
- scaleOut(
89
- targetScale = 0.97f,
90
- animationSpec = tween(200)
91
- )
92
- },
93
- popEnterTransition = {
94
- fadeIn(animationSpec = tween(200)) +
95
- scaleIn(
96
- initialScale = 0.97f,
97
- animationSpec = tween(200)
98
- )
99
- },
100
- popExitTransition = {
101
- fadeOut(animationSpec = tween(200)) +
102
- scaleOut(
103
- targetScale = 0.97f,
104
- animationSpec = tween(200)
105
- )
106
- }
107
- ) {
108
- val option = getBottomTabOption(index)
109
-
110
- StackScreen(
111
- content = item.screen,
112
- navigationOptions = option,
113
- bottomTabIndex = index,
114
- onBackHandler = {
115
- if (index != 0) {
116
- navController.popBackStack(
117
- navController.graph.startDestinationRoute!!,
118
- inclusive = false
119
- )
120
- } else {
121
- navigator.pop()
122
- }
123
- }
124
- )
125
- }
126
- }
127
- }
128
- }
129
- Column {
130
- BottomTabBar(
131
- items = items,
132
- floatingButton = floatingButton,
133
- navController = navController,
134
- onTabSelected = {
135
- val currentRoute = navController.currentBackStackEntry?.destination?.route
136
- val targetRoute = "option$it"
137
- if (currentRoute != targetRoute){
138
- navController.navigate(targetRoute)
139
- }
140
- }
141
- )
142
- Spacer(modifier = Modifier.fillMaxWidth().height(min(AppNavigationBar.current, 21.dp) + Spacing.S).background(AppTheme.current.colors.background.surface))
143
- }
144
- }
145
- }
146
-
147
- data class BottomTabItem(
148
- val name: String,
149
- val label: String,
150
- val icon: String,
151
- val showDot: Boolean = false,
152
- val badgeLabel: String? = null,
153
- val screen: @Composable () -> Unit,
154
- val options: NavigationOptions? = null,
155
- val initialParams: Any? = null
156
- )
157
-
158
- data class BottomTabFloatingButton(
159
- val icon: String,
160
- val label: String,
161
- val onPress: () -> Unit,
162
- )