@momo-kits/native-kits 0.152.4-scale.4 → 0.152.5-klib.1

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