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