@momo-kits/native-kits 0.164.1-beta.17-debug → 0.164.1-beta.18

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