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

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 -186
  4. package/compose/build.gradle.kts.backup +0 -186
  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 -57
  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 -201
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -222
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -48
  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 -305
  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 -921
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -121
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -403
  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 -85
  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 -340
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -198
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -357
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -123
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -94
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -136
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -224
  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 -148
  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 -116
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -452
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -172
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -255
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -235
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -233
  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 -241
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -364
  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 -92
  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 -352
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -103
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -338
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -70
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -17
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -96
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -348
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -256
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -494
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -131
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -215
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -96
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -531
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -92
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -130
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -214
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -590
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -177
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -192
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -205
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -239
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -191
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -306
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -285
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -2
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -35
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -2
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -57
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -68
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -14
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -50
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -253
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -133
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -100
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -145
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -345
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -556
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -161
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -243
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -187
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -279
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -80
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -306
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -32
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -370
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -131
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -167
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -62
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -66
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -70
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -105
  127. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -33
  128. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -186
  129. package/gradle/libs.versions.toml +0 -60
  130. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  131. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  132. package/gradle.properties +0 -26
  133. package/gradlew +0 -252
  134. package/gradlew.bat +0 -94
  135. package/settings.gradle.kts +0 -64
@@ -1,921 +0,0 @@
1
- package vn.momo.kits.application
2
-
3
- import androidx.annotation.FloatRange
4
- import androidx.compose.animation.animateContentSize
5
- import androidx.compose.foundation.ScrollState
6
- import androidx.compose.foundation.background
7
- import androidx.compose.foundation.border
8
- import androidx.compose.foundation.gestures.detectTapGestures
9
- import androidx.compose.foundation.interaction.FocusInteraction
10
- import androidx.compose.foundation.interaction.MutableInteractionSource
11
- import androidx.compose.foundation.layout.Arrangement
12
- import androidx.compose.foundation.layout.Box
13
- import androidx.compose.foundation.layout.Row
14
- import androidx.compose.foundation.layout.WindowInsets
15
- import androidx.compose.foundation.layout.asPaddingValues
16
- import androidx.compose.foundation.layout.fillMaxSize
17
- import androidx.compose.foundation.layout.fillMaxWidth
18
- import androidx.compose.foundation.layout.ime
19
- import androidx.compose.foundation.layout.navigationBars
20
- import androidx.compose.foundation.layout.offset
21
- import androidx.compose.foundation.layout.padding
22
- import androidx.compose.foundation.layout.size
23
- import androidx.compose.foundation.rememberScrollState
24
- import androidx.compose.foundation.shape.CircleShape
25
- import androidx.compose.foundation.text.BasicTextField
26
- import androidx.compose.foundation.text.KeyboardActions
27
- import androidx.compose.foundation.text.KeyboardOptions
28
- import androidx.compose.foundation.verticalScroll
29
- import androidx.compose.runtime.Composable
30
- import androidx.compose.runtime.LaunchedEffect
31
- import androidx.compose.runtime.MutableState
32
- import androidx.compose.runtime.Stable
33
- import androidx.compose.runtime.State
34
- import androidx.compose.runtime.derivedStateOf
35
- import androidx.compose.runtime.getValue
36
- import androidx.compose.runtime.mutableStateOf
37
- import androidx.compose.runtime.produceState
38
- import androidx.compose.runtime.remember
39
- import androidx.compose.runtime.rememberUpdatedState
40
- import androidx.compose.runtime.snapshotFlow
41
- import androidx.compose.runtime.staticCompositionLocalOf
42
- import androidx.compose.ui.Alignment
43
- import androidx.compose.ui.Modifier
44
- import androidx.compose.ui.composed
45
- import androidx.compose.ui.draw.clip
46
- import androidx.compose.ui.draw.drawBehind
47
- import androidx.compose.ui.draw.drawWithContent
48
- import androidx.compose.ui.geometry.Offset
49
- import androidx.compose.ui.geometry.Rect
50
- import androidx.compose.ui.graphics.Brush
51
- import androidx.compose.ui.graphics.Color
52
- import androidx.compose.ui.graphics.SolidColor
53
- import androidx.compose.ui.graphics.graphicsLayer
54
- import androidx.compose.ui.input.pointer.pointerInput
55
- import androidx.compose.ui.layout.Layout
56
- import androidx.compose.ui.layout.Measurable
57
- import androidx.compose.ui.layout.MeasurePolicy
58
- import androidx.compose.ui.layout.MeasureResult
59
- import androidx.compose.ui.layout.MeasureScope
60
- import androidx.compose.ui.layout.Placeable
61
- import androidx.compose.ui.layout.layoutId
62
- import androidx.compose.ui.platform.LocalDensity
63
- import androidx.compose.ui.platform.LocalFocusManager
64
- import androidx.compose.ui.platform.LocalSoftwareKeyboardController
65
- import androidx.compose.ui.text.TextStyle
66
- import androidx.compose.ui.text.style.TextOverflow
67
- import androidx.compose.ui.unit.Constraints
68
- import androidx.compose.ui.unit.Dp
69
- import androidx.compose.ui.unit.IntOffset
70
- import androidx.compose.ui.unit.LayoutDirection
71
- import androidx.compose.ui.unit.dp
72
- import androidx.compose.ui.unit.lerp
73
- import androidx.compose.ui.unit.sp
74
- import kotlinx.coroutines.flow.collectLatest
75
- import kotlinx.coroutines.flow.mapNotNull
76
- import vn.momo.kits.components.Icon
77
- import vn.momo.kits.components.Text
78
- import vn.momo.kits.const.AppTheme
79
- import vn.momo.kits.const.Colors
80
- import vn.momo.kits.const.Spacing
81
- import vn.momo.kits.const.Typography
82
- import vn.momo.kits.modifier.kitsAutomationId
83
- import vn.momo.kits.modifier.noFeedbackClickable
84
- import vn.momo.kits.modifier.setAutomationId
85
- import vn.momo.kits.modifier.shadow
86
- import vn.momo.kits.navigation.component.HEADER_HEIGHT
87
- import vn.momo.kits.utils.getAppStatusBarHeight
88
- import kotlin.math.max
89
- import kotlin.math.roundToInt
90
-
91
-
92
- data class AnimationOption(
93
- val targetBounds: Rect,
94
- val progress: State<Float>,
95
- @param:FloatRange(from = 0.0, to = 1.0)
96
- val opacityLimitFraction: Float = 0f,
97
- ) {
98
- val opacityCap: Float
99
- get() = 1f - opacityLimitFraction
100
-
101
- val animateOpacity: Float
102
- get() {
103
- if (progress.value < opacityLimitFraction) return 0f
104
- return androidx.compose.ui.util.lerp(
105
- 0f,
106
- 1f,
107
- (progress.value - opacityLimitFraction) / (opacityCap),
108
- )
109
- }
110
- }
111
-
112
- val LocalAnimationOption = staticCompositionLocalOf<AnimationOption?> { null }
113
-
114
- @Composable
115
- fun LiteScreen(
116
- scrollable: Boolean = true,
117
- scrollState: ScrollState? = null,
118
- headerType: HeaderType = HeaderType.DEFAULT,
119
- verticalArrangement: Arrangement.Vertical = Arrangement.Top,
120
- horizontalAlignment: Alignment.Horizontal = Alignment.Start,
121
- backgroundColor: Color = AppTheme.current.colors.background.default,
122
- /* Begin of header props */
123
- title: String? = null,
124
- inputSearchProps: LiteInputSearchProps? = null,
125
- goBack: (() -> Unit)? = null,
126
- headerRight: @Composable() (() -> Unit)? = null,
127
- useAnimationSearch: Boolean = true,
128
- titlePosition: TitlePosition = TitlePosition.LEFT,
129
- headerRightData: HeaderRightData? = null,
130
- headerTintColor: Color? = null,
131
- headerBackgroundColor: Color? = null,
132
- headerSpaceBetween: Dp? = null,
133
- /* End of header props */
134
-
135
- screenContent: @Composable () -> Unit,
136
- ) {
137
- val content by rememberUpdatedState(screenContent)
138
-
139
- val finalScrollState = scrollState ?: rememberScrollState()
140
-
141
- val contentModifier = remember(
142
- key1 = scrollable,
143
- key2 = finalScrollState,
144
- ) {
145
- var res: Modifier = Modifier
146
- .background(color = backgroundColor)
147
- if (scrollable) {
148
- res = res.verticalScroll(finalScrollState)
149
- }
150
- res
151
- }
152
-
153
- LiteScreenLayout(
154
- scrollState = finalScrollState,
155
- modifier = Modifier
156
- .fillMaxSize()
157
- .hideKeyboardOnTap(),
158
- contentModifier = contentModifier,
159
- verticalArrangement = verticalArrangement,
160
- horizontalAlignment = horizontalAlignment,
161
- title = title,
162
- headerRight = headerRight,
163
- headerType = headerType,
164
- onGoBack = goBack,
165
- inputSearchProps = inputSearchProps,
166
- titlePosition = titlePosition,
167
- useAnimationSearch = useAnimationSearch,
168
- headerRightData = headerRightData,
169
- tintColor = headerTintColor,
170
- headerBackgroundColor = headerBackgroundColor,
171
- headerSpaceBetween = headerSpaceBetween,
172
- ) {
173
- content()
174
- }
175
- }
176
-
177
- private object HeaderId {
178
- private const val PACKAGE_NAME = "vn.momo.compose.kits"
179
- const val CONTENT_ID = "${PACKAGE_NAME}.content"
180
- const val BACKGROUND_ID = "${PACKAGE_NAME}.background"
181
- const val BACK_ID = "${PACKAGE_NAME}.back"
182
- const val HEADER_RIGHT_ID = "${PACKAGE_NAME}.headerRight"
183
- const val INPUT_SEARCH_ID = "${PACKAGE_NAME}.inputSearch"
184
- const val TITLE_ID = "${PACKAGE_NAME}.title"
185
-
186
- val EXTENDED_HEADER_HEIGHT = 154.dp
187
- }
188
-
189
- @Composable
190
- private fun LiteScreenLayout(
191
- scrollState: ScrollState?,
192
- modifier: Modifier = Modifier,
193
- contentModifier: Modifier = Modifier,
194
- verticalArrangement: Arrangement.Vertical = Arrangement.Top,
195
- horizontalAlignment: Alignment.Horizontal = Alignment.Start,
196
- title: String? = null,
197
- tintColor: Color? = null,
198
- headerRightData: HeaderRightData? = null,
199
- headerType: HeaderType = HeaderType.DEFAULT,
200
- titlePosition: TitlePosition = TitlePosition.LEFT,
201
- useAnimationSearch: Boolean = true,
202
- onGoBack: (() -> Unit)? = null,
203
- headerBackgroundColor: Color? = null,
204
- headerSpaceBetween: Dp? = null,
205
- inputSearchProps: LiteInputSearchProps? = null,
206
- headerRight: @Composable (() -> Unit)? = null,
207
- content: @Composable () -> Unit,
208
- ) {
209
- val statusBarHeight = getAppStatusBarHeight()
210
- val isHeaderNone = remember(headerType) {
211
- headerType == HeaderType.NONE
212
- }
213
- val theme = AppTheme.current
214
- val density = LocalDensity.current
215
-
216
- val isHeaderExtend = remember(headerType) {
217
- headerType == HeaderType.EXTENDED
218
- }
219
- val backgroundHeight = remember(isHeaderNone, isHeaderExtend, statusBarHeight) {
220
- when {
221
- isHeaderNone -> statusBarHeight
222
- !isHeaderExtend -> statusBarHeight + HEADER_HEIGHT.dp
223
- else -> HeaderId.EXTENDED_HEADER_HEIGHT
224
- }
225
- }
226
- val listGradientColors = remember {
227
- listOf(
228
- Color(0xFFFDCADE),
229
- Color(0x00FDCADE),
230
- )
231
- }
232
-
233
- val headerColor = remember(tintColor, theme) {
234
- if (tintColor == Colors.black_01) HeaderColor(
235
- tintIconColor = tintColor,
236
- backgroundButton = Colors.black_20.copy(alpha = 0.6f),
237
- borderColor = Colors.black_01.copy(alpha = 0.2f)
238
- )
239
- else HeaderColor(
240
- tintIconColor = tintColor ?: theme.colors.text.default,
241
- backgroundButton = Colors.black_01.copy(alpha = 0.6f),
242
- borderColor = Colors.black_20.copy(alpha = 0.2f)
243
- )
244
- }
245
-
246
- val scrollPercentage = produceState(
247
- initialValue = 0f,
248
- key1 = useAnimationSearch,
249
- key2 = scrollState,
250
- key3 = backgroundHeight,
251
- ) {
252
- if (!useAnimationSearch) return@produceState
253
- scrollState ?: return@produceState
254
- val rangePx = with(density) { backgroundHeight.toPx() }
255
- snapshotFlow { scrollState.value }.collectLatest {
256
- value = (it / rangePx).coerceIn(0f, 1f)
257
- }
258
- }
259
-
260
- val titleStyle = remember {
261
- Typography.actionSBold.copy(
262
- fontSize = 15.sp,
263
- lineHeight = 22.sp,
264
- )
265
- }
266
-
267
- val animationOption = LocalAnimationOption.current
268
- val animationOpacityModifier = Modifier.graphicsLayer {
269
- alpha = animationOption?.animateOpacity ?: 1f
270
- }
271
- val titleModifier = Modifier
272
- .kitsAutomationId("title_navigation_header")
273
- .layoutId(HeaderId.TITLE_ID)
274
- .graphicsLayer {
275
- val titleAlpha = if (isHeaderExtend && inputSearchProps != null && useAnimationSearch)
276
- (1 - scrollPercentage.value * 2).coerceIn(0f, 1f)
277
- else 1f
278
- alpha = titleAlpha * (animationOption?.progress?.value ?: 1f)
279
- }
280
-
281
- val policy = remember(
282
- useAnimationSearch,
283
- isHeaderNone,
284
- isHeaderExtend,
285
- statusBarHeight,
286
- titlePosition,
287
- scrollPercentage,
288
- headerSpaceBetween,
289
- animationOption,
290
- verticalArrangement,
291
- horizontalAlignment,
292
- ) {
293
- LiteScreenLayoutPolicy(
294
- useAnimationSearch = useAnimationSearch,
295
- isHeaderNone = isHeaderNone,
296
- isHeaderExtend = isHeaderExtend,
297
- statusBarHeight = statusBarHeight,
298
- titlePosition = titlePosition,
299
- scrollPercentage = scrollPercentage,
300
- headerSpaceBetween = headerSpaceBetween,
301
- animationOption = animationOption,
302
- verticalArrangement = verticalArrangement,
303
- horizontalAlignment = horizontalAlignment,
304
- )
305
- }
306
-
307
- Layout(
308
- modifier = modifier
309
- .animateContentSize(),
310
- content = {
311
- Box(
312
- modifier = animationOpacityModifier
313
- .layoutId(HeaderId.CONTENT_ID)
314
- .then(contentModifier),
315
- contentAlignment = Alignment.TopCenter,
316
- ) {
317
- content()
318
- }
319
-
320
- if (!isHeaderNone) {
321
- Box(
322
- modifier = Modifier
323
- .layoutId(HeaderId.BACKGROUND_ID)
324
- .then(animationOpacityModifier)
325
- .drawBehind {
326
- val headerHeight = max(
327
- HeaderId.EXTENDED_HEADER_HEIGHT.toPx(),
328
- size.height,
329
- )
330
- headerBackgroundColor?.let {
331
- drawRect(color = it)
332
- } ?: run {
333
- drawRect(color = Colors.black_01)
334
- drawRect(
335
- brush = Brush.linearGradient(
336
- colors = listGradientColors,
337
- start = Offset.Zero,
338
- end = Offset(
339
- x = 0f,
340
- y = headerHeight * (1 - scrollPercentage.value),
341
- ),
342
- )
343
- )
344
- }
345
- },
346
- )
347
- }
348
-
349
- if (!isHeaderNone && onGoBack != null) {
350
- val coreModifier = Modifier
351
- .layoutId(HeaderId.BACK_ID)
352
- .then(animationOpacityModifier)
353
- .clip(CircleShape)
354
- .noFeedbackClickable(onClick = onGoBack)
355
- .setAutomationId("btn_navigation_back")
356
- inputSearchProps?.customBackIcon?.invoke(coreModifier) ?: Box(
357
- modifier = coreModifier
358
- .size(28.dp)
359
- .border(
360
- width = 0.2.dp,
361
- color = headerColor.borderColor,
362
- shape = CircleShape,
363
- )
364
- .background(color = headerColor.backgroundButton)
365
- .padding(Spacing.XS),
366
- ) {
367
- Icon(
368
- source = "arrow-back",
369
- color = headerColor.tintIconColor,
370
- size = 20.dp,
371
- )
372
- }
373
- }
374
-
375
- if (!isHeaderNone) {
376
- Box(
377
- modifier = Modifier
378
- .layoutId(HeaderId.HEADER_RIGHT_ID)
379
- .then(animationOpacityModifier)
380
- ) {
381
- if (headerRight != null) {
382
- headerRight()
383
- } else {
384
- HeaderRight(
385
- headerRight = headerRightData,
386
- tintColor = tintColor,
387
- )
388
- }
389
- }
390
- }
391
-
392
- if (!isHeaderNone && inputSearchProps != null) {
393
- LiteInputSearch(
394
- modifier = Modifier.layoutId(HeaderId.INPUT_SEARCH_ID),
395
- inputSearchProps = inputSearchProps,
396
- )
397
- }
398
- if (!isHeaderNone && title != null && (inputSearchProps == null || isHeaderExtend)) {
399
- Text(
400
- text = title,
401
- color = headerColor.tintIconColor,
402
- style = titleStyle,
403
- modifier = titleModifier,
404
- maxLines = 1,
405
- overflow = TextOverflow.Ellipsis
406
- )
407
- }
408
- },
409
- measurePolicy = policy,
410
- )
411
- }
412
-
413
- private class LiteScreenLayoutPolicy(
414
- private val useAnimationSearch: Boolean,
415
- private val isHeaderNone: Boolean,
416
- private val isHeaderExtend: Boolean,
417
- private val statusBarHeight: Dp,
418
- private val scrollPercentage: State<Float>,
419
- private val titlePosition: TitlePosition,
420
- private val headerSpaceBetween: Dp? = null,
421
- private val animationOption: AnimationOption?,
422
- private val verticalArrangement: Arrangement.Vertical,
423
- private val horizontalAlignment: Alignment.Horizontal,
424
- ) : MeasurePolicy {
425
-
426
- val searchStartPosition: IntOffset by lazy {
427
- if (animationOption == null) return@lazy IntOffset.Zero
428
- val offset = animationOption.targetBounds.topLeft
429
- IntOffset(
430
- x = offset.x.roundToInt(),
431
- y = offset.y.roundToInt(),
432
- )
433
- }
434
-
435
- override fun MeasureScope.measure(
436
- measurables: List<Measurable>,
437
- constraints: Constraints
438
- ): MeasureResult {
439
- val spacing12 = Spacing.M.roundToPx()
440
- val spaceBetween = headerSpaceBetween?.roundToPx() ?: spacing12
441
- val statusBarPx = statusBarHeight.roundToPx()
442
- val headerRowDefault = HEADER_HEIGHT.dp.roundToPx()
443
- val scrollPercent = scrollPercentage.value
444
-
445
- val contentMeasurable = measurables.find { it.layoutId == HeaderId.CONTENT_ID }
446
-
447
- val realConstraints = constraints.copy(
448
- minWidth = 0,
449
- minHeight = 0,
450
- maxWidth = (constraints.maxWidth - spacing12 * 2)
451
- .coerceAtLeast(0),
452
- )
453
- val backIconPlaceable =
454
- measurables.find { it.layoutId == HeaderId.BACK_ID }?.measure(realConstraints)
455
- val headerRightPlaceable =
456
- measurables.find { it.layoutId == HeaderId.HEADER_RIGHT_ID }?.measure(
457
- realConstraints.copy(
458
- maxWidth = realConstraints.maxWidth / 2,
459
- )
460
- )
461
- val baseInputSearchConstraints = if (isHeaderExtend) {
462
- val minWidth =
463
- if (useAnimationSearch) realConstraints.maxWidth - backIconPlaceable.safeWidth - headerRightPlaceable.safeWidth - spaceBetween * 2
464
- else realConstraints.maxWidth
465
- realConstraints.copy(
466
- maxWidth = (realConstraints.maxWidth * (1 - scrollPercent)).toInt()
467
- .coerceAtLeast(minWidth)
468
- )
469
- } else {
470
- var spaceConsumed = 0
471
- if (backIconPlaceable.safeWidth != 0) spaceConsumed += backIconPlaceable.safeWidth + spaceBetween
472
- if (headerRightPlaceable.safeWidth != 0) spaceConsumed += headerRightPlaceable.safeWidth + spaceBetween
473
- realConstraints.copy(
474
- maxWidth = realConstraints.maxWidth - spaceConsumed
475
- )
476
- }
477
- val inputSearchConstraints = baseInputSearchConstraints.withAnimationTargetBounds()
478
- val inputSearchPlaceable = measurables.find { it.layoutId == HeaderId.INPUT_SEARCH_ID }
479
- ?.measure(inputSearchConstraints)
480
- val titlePlaceable = measurables.find { it.layoutId == HeaderId.TITLE_ID }?.measure(
481
- constraints = realConstraints.copy(
482
- maxWidth = realConstraints.maxWidth - backIconPlaceable.safeWidth - headerRightPlaceable.safeWidth - spaceBetween * 2
483
- )
484
- )
485
-
486
- /**
487
- * replicate logic from [vn.momo.kits.navigation.component.HeaderBackground]
488
- * */
489
- var defaultHeight = statusBarPx + headerRowDefault
490
- if (isHeaderExtend) {
491
- defaultHeight = 154.dp.roundToPx()
492
- }
493
- val headerHeight = when {
494
- isHeaderNone -> statusBarPx
495
- !useAnimationSearch && !isHeaderExtend -> defaultHeight
496
- else -> {
497
- val collapsableSpace = defaultHeight - statusBarPx - headerRowDefault
498
- (defaultHeight - scrollPercent * collapsableSpace).toInt()
499
- }
500
- }
501
-
502
- val layoutWidth = constraints.maxWidth
503
- val layoutHeight = constraints.maxHeight
504
- val contentHeight = (layoutHeight - headerHeight).coerceAtLeast(0)
505
- val contentPlaceable = contentMeasurable?.measure(
506
- constraints.copy(
507
- minWidth = 0,
508
- minHeight = contentHeight,
509
- maxHeight = contentHeight,
510
- )
511
- )
512
- val backgroundPlaceable = measurables.find { it.layoutId == HeaderId.BACKGROUND_ID }
513
- ?.measure(
514
- Constraints.fixed(
515
- width = layoutWidth,
516
- height = headerHeight,
517
- )
518
- )
519
- val childrenHeights = intArrayOf(
520
- headerHeight,
521
- contentPlaceable.safeHeight,
522
- )
523
- val childrenY = IntArray(childrenHeights.size)
524
- with(verticalArrangement) {
525
- arrange(
526
- totalSize = layoutHeight,
527
- sizes = childrenHeights,
528
- outPositions = childrenY,
529
- )
530
- }
531
- val headerY = childrenY[0]
532
- val contentY = childrenY[1]
533
-
534
- return layout(
535
- width = layoutWidth,
536
- height = layoutHeight,
537
- ) {
538
- val progress = animationOption?.progress?.value ?: 1f
539
-
540
- val startX = spacing12
541
- val startY = headerY + statusBarPx
542
- var curX = startX
543
- var curY = startY
544
-
545
- contentPlaceable?.place(
546
- x = horizontalAlignment.align(
547
- size = contentPlaceable.width,
548
- space = layoutWidth,
549
- layoutDirection = layoutDirection,
550
- ),
551
- y = contentY,
552
- )
553
-
554
- backgroundPlaceable?.place(
555
- x = 0,
556
- y = headerY,
557
- )
558
-
559
- if (backIconPlaceable != null) {
560
- backIconPlaceable.place(
561
- x = startX,
562
- y = startY + backIconPlaceable.verticalCenterOffset(headerRowDefault),
563
- )
564
- curX += backIconPlaceable.safeWidth + spaceBetween
565
- }
566
-
567
- headerRightPlaceable?.place(
568
- x = layoutWidth - spacing12 - headerRightPlaceable.safeWidth,
569
- y = startY + headerRightPlaceable.verticalCenterOffset(headerRowDefault),
570
- )
571
-
572
- val titleOffset = IntOffset(
573
- x = if (titlePosition == TitlePosition.LEFT) curX
574
- else titlePlaceable.horizontalCenterOffset(
575
- space = layoutWidth,
576
- layoutDirection = layoutDirection,
577
- ),
578
- y = startY + titlePlaceable.verticalCenterOffset(headerRowDefault),
579
- )
580
-
581
- titlePlaceable?.place(titleOffset)
582
-
583
- if (backIconPlaceable != null || headerRightPlaceable != null || titlePlaceable != null) {
584
- curY += headerRowDefault
585
- }
586
-
587
- val inputSearchOffset = if (isHeaderExtend) {
588
- val baseY = curY + inputSearchPlaceable.verticalCenterOffset(headerRowDefault)
589
- val y = (baseY * (1 - scrollPercent)).toInt().coerceAtLeast(
590
- startY + inputSearchPlaceable.verticalCenterOffset(headerRowDefault)
591
- )
592
- IntOffset(
593
- x = startX + ((backIconPlaceable.safeWidth + spaceBetween) * (scrollPercent * 2f).coerceIn(
594
- 0f, 1f
595
- )).toInt(),
596
- y = y,
597
- )
598
- } else {
599
- IntOffset(
600
- x = curX,
601
- y = startY + inputSearchPlaceable.verticalCenterOffset(headerRowDefault),
602
- )
603
- }
604
- val finalPosition = lerp(
605
- searchStartPosition,
606
- inputSearchOffset,
607
- progress,
608
- )
609
-
610
- inputSearchPlaceable?.place(
611
- finalPosition
612
- )
613
- }
614
- }
615
-
616
- private val Placeable?.safeHeight
617
- get() = this?.height ?: 0
618
- private val Placeable?.safeWidth
619
- get() = this?.width ?: 0
620
-
621
- private fun Constraints.withAnimationTargetBounds(): Constraints {
622
- val option = animationOption ?: return this
623
- val progress = option.progress.value
624
- if (progress >= 1f) return this
625
-
626
- val targetWidth = option.targetBounds.width.roundToInt().coerceAtLeast(0)
627
- val targetHeight = option.targetBounds.height.roundToInt().coerceAtLeast(0)
628
- val animatedMinWidth = lerpPx(targetWidth, minWidth, progress)
629
- .coerceInBounds(maxWidth)
630
- val animatedMaxWidth = lerpMaxPx(targetWidth, maxWidth, progress)
631
- .coerceAtLeast(animatedMinWidth)
632
- val animatedMinHeight = lerpPx(targetHeight, minHeight, progress)
633
- .coerceInBounds(maxHeight)
634
- val animatedMaxHeight = lerpMaxPx(targetHeight, maxHeight, progress)
635
- .coerceAtLeast(animatedMinHeight)
636
-
637
- return copy(
638
- minWidth = animatedMinWidth,
639
- maxWidth = animatedMaxWidth,
640
- minHeight = animatedMinHeight,
641
- maxHeight = animatedMaxHeight,
642
- )
643
- }
644
-
645
- private fun lerpPx(
646
- start: Int,
647
- stop: Int,
648
- fraction: Float,
649
- ): Int = androidx.compose.ui.util.lerp(
650
- start.toFloat(),
651
- stop.toFloat(),
652
- fraction,
653
- ).roundToInt()
654
-
655
- private fun lerpMaxPx(
656
- start: Int,
657
- stop: Int,
658
- fraction: Float,
659
- ): Int {
660
- if (stop == Constraints.Infinity) return Constraints.Infinity
661
- return lerpPx(start, stop, fraction)
662
- }
663
-
664
- private fun Int.coerceInBounds(max: Int): Int {
665
- if (max == Constraints.Infinity) return coerceAtLeast(0)
666
- return coerceIn(0, max)
667
- }
668
-
669
- private fun Placeable?.verticalCenterOffset(space: Int): Int {
670
- if (this == null) return 0
671
- return Alignment.CenterVertically.align(safeHeight, space)
672
- }
673
-
674
- private fun Placeable?.horizontalCenterOffset(
675
- space: Int,
676
- layoutDirection: LayoutDirection
677
- ): Int {
678
- if (this == null) return 0
679
- return Alignment.CenterHorizontally.align(safeWidth, space, layoutDirection)
680
- }
681
- }
682
-
683
- private val EMPTY_FUNC = {}
684
-
685
- @Stable
686
- data class LiteInputSearchProps(
687
- val textFieldState: MutableState<String>,
688
- val onValueChange: (String) -> Unit,
689
- val onClear: () -> Unit = EMPTY_FUNC,
690
- val clearCondition: (() -> Boolean)? = null,
691
- val modifier: Modifier = Modifier,
692
- val onFocused: (() -> Unit) = EMPTY_FUNC,
693
- val keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
694
- val keyboardActions: KeyboardActions = KeyboardActions.Default,
695
- val onKeyboardAction: (() -> Unit) = EMPTY_FUNC,
696
-
697
- val btnText: String? = null,
698
- val isShowBtnText: Boolean = !btnText.isNullOrEmpty(),
699
- val onPressBtnText: (() -> Unit) = EMPTY_FUNC,
700
-
701
- val disabled: Boolean = false,
702
-
703
- val placeHolder: String? = null,
704
-
705
- val cursorBrush: Brush? = null,
706
- val customBackIcon: @Composable ((Modifier) -> Unit)? = null,
707
- val customSearchIcon: @Composable (() -> Unit)? = null,
708
- val customPlaceHolder: @Composable (() -> Unit)? = null,
709
- val customTextStyle: TextStyle? = null,
710
- val customIconClear: @Composable (() -> Unit)? = null,
711
- val iconRightTextField: @Composable ((Modifier) -> Unit)? = null,
712
- )
713
-
714
- @Composable
715
- private fun LiteInputSearch(
716
- modifier: Modifier = Modifier,
717
- inputSearchProps: LiteInputSearchProps? = null,
718
- ) {
719
- inputSearchProps ?: return
720
- val theme = AppTheme.current
721
-
722
- val isFocused = remember { mutableStateOf(false) }
723
- val interactionSource = remember { MutableInteractionSource() }
724
- val textState by remember { inputSearchProps.textFieldState }
725
-
726
- val isShowBtnText by remember(inputSearchProps.isShowBtnText, inputSearchProps.btnText) {
727
- derivedStateOf {
728
- inputSearchProps.isShowBtnText && !inputSearchProps.btnText.isNullOrEmpty()
729
- }
730
- }
731
- val inputFieldStyle = remember(theme) {
732
- Typography.bodyDefaultRegular.copy(
733
- color = theme.colors.text.default,
734
- )
735
- }
736
-
737
- LaunchedEffect(inputSearchProps.onFocused) {
738
- interactionSource.interactions.mapNotNull { it as? FocusInteraction }.collectLatest {
739
- val isFocus = it is FocusInteraction.Focus
740
- isFocused.value = isFocus
741
- if (isFocus) inputSearchProps.onFocused()
742
- }
743
- }
744
-
745
- Row(
746
- modifier = modifier,
747
- verticalAlignment = Alignment.CenterVertically,
748
- ) {
749
- val textFieldModifier = remember(inputSearchProps.modifier) {
750
- inputSearchProps.modifier
751
- .weight(1f)
752
- }
753
- BasicTextField(
754
- value = textState,
755
- onValueChange = inputSearchProps.onValueChange,
756
- enabled = !inputSearchProps.disabled,
757
- keyboardOptions = inputSearchProps.keyboardOptions,
758
- keyboardActions = inputSearchProps.keyboardActions,
759
- modifier = textFieldModifier,
760
- textStyle = inputSearchProps.customTextStyle ?: inputFieldStyle,
761
- singleLine = true,
762
- cursorBrush = inputSearchProps.cursorBrush ?: SolidColor(Color.Black),
763
- interactionSource = interactionSource,
764
- decorationBox = { innerTextField ->
765
- val isShowClear by remember(inputSearchProps.clearCondition, isFocused.value) {
766
- derivedStateOf {
767
- inputSearchProps.clearCondition?.invoke() == true || (isFocused.value && textState.isNotEmpty())
768
- }
769
- }
770
- val placeHolder by produceState<String?>(null, inputSearchProps.placeHolder) {
771
- if (inputSearchProps.placeHolder.isNullOrEmpty()) return@produceState
772
- snapshotFlow { textState }.collectLatest {
773
- value = if (it.isEmpty()) inputSearchProps.placeHolder else null
774
- }
775
- }
776
- val iconRightModifier = remember {
777
- Modifier
778
- .padding(start = Spacing.L)
779
- .drawWithContent {
780
- val offsetX = -Spacing.S.toPx()
781
- drawLine(
782
- start = Offset(
783
- x = offsetX,
784
- y = 0f,
785
- ),
786
- end = Offset(
787
- x = offsetX,
788
- y = size.height,
789
- ),
790
- color = theme.colors.primary,
791
- strokeWidth = 1.dp.toPx(),
792
- )
793
- drawContent()
794
- }
795
- }
796
-
797
- Row(
798
- modifier = Modifier
799
- .padding(
800
- horizontal = Spacing.M,
801
- vertical = Spacing.S,
802
- ),
803
- horizontalArrangement = Arrangement.Start,
804
- verticalAlignment = Alignment.CenterVertically,
805
- ) {
806
- inputSearchProps.customSearchIcon?.invoke() ?: Icon(
807
- source = "navigation_search",
808
- modifier = Modifier.padding(end = Spacing.XS),
809
- size = 24.dp,
810
- color = theme.colors.text.hint
811
- )
812
- Box(
813
- modifier = Modifier.weight(1f),
814
- contentAlignment = Alignment.CenterStart,
815
- ) {
816
- if (!placeHolder.isNullOrEmpty()) {
817
- inputSearchProps.customPlaceHolder?.invoke() ?: Text(
818
- text = placeHolder ?: "",
819
- style = inputSearchProps.customTextStyle
820
- ?: Typography.bodyDefaultRegular,
821
- maxLines = 1,
822
- color = theme.colors.text.hint,
823
- overflow = TextOverflow.Ellipsis
824
- )
825
- }
826
- innerTextField()
827
- }
828
-
829
- if (isShowClear) {
830
- inputSearchProps.customIconClear?.invoke() ?: Icon(
831
- source = "24_navigation_close_circle_full",
832
- size = 16.dp,
833
- color = theme.colors.text.hint,
834
- modifier = Modifier.padding(start = Spacing.XS)
835
- .noFeedbackClickable(onClick = inputSearchProps.onClear),
836
- )
837
- }
838
-
839
- inputSearchProps.iconRightTextField?.invoke(iconRightModifier)
840
- }
841
- }
842
- )
843
-
844
- if (isShowBtnText) {
845
- Text(
846
- text = inputSearchProps.btnText ?: "",
847
- style = Typography.actionDefaultBold,
848
- color = theme.colors.text.default,
849
- modifier = Modifier.padding(start = Spacing.L)
850
- .noFeedbackClickable(onClick = inputSearchProps.onPressBtnText)
851
- )
852
- }
853
- }
854
- }
855
-
856
- @Composable
857
- private fun footerOffset(
858
- useAvoidKeyboard: Boolean = true,
859
- ): State<IntOffset> {
860
- if (!useAvoidKeyboard) return remember { mutableStateOf(IntOffset.Zero) }
861
- val density = LocalDensity.current
862
- val navPaddingValue = WindowInsets.navigationBars.asPaddingValues()
863
- val keyboardSize = keyboardSizeState()
864
-
865
- return produceState(IntOffset.Zero, density, navPaddingValue) {
866
- val navSystemOffset = with(density) { navPaddingValue.calculateBottomPadding().roundToPx() }
867
- snapshotFlow { keyboardSize.value }.collectLatest {
868
- value = if (it == 0.dp) IntOffset.Zero
869
- else IntOffset(
870
- x = 0, y = with(density) {
871
- navSystemOffset - it.roundToPx()
872
- })
873
- }
874
- }
875
- }
876
-
877
- @Composable
878
- fun keyboardSizeState(): State<Dp> {
879
- val bottom = WindowInsets.ime.asPaddingValues()
880
- return rememberUpdatedState(bottom.calculateBottomPadding())
881
- }
882
-
883
- @Composable
884
- private fun Footer(
885
- useAvoidKeyboard: Boolean,
886
- footerContent: (@Composable () -> Unit)?,
887
- ) {
888
- footerContent ?: return
889
- val theme = AppTheme.current
890
- val navPaddingValue = WindowInsets.navigationBars.asPaddingValues()
891
- val offsetMove = footerOffset(useAvoidKeyboard)
892
-
893
- Box(
894
- modifier = Modifier.padding(navPaddingValue).fillMaxWidth().offset {
895
- offsetMove.value
896
- }.shadow(
897
- color = Colors.black_20.copy(alpha = 0.05f),
898
- blurRadius = 24f,
899
- offsetX = 0.dp,
900
- offsetY = (-4).dp
901
- ).background(theme.colors.background.surface).padding(
902
- start = Spacing.M,
903
- top = Spacing.M,
904
- end = Spacing.M,
905
- )
906
- ) {
907
- footerContent()
908
- }
909
- }
910
-
911
- fun Modifier.hideKeyboardOnTap() = composed {
912
- val focusManager = LocalFocusManager.current
913
- val keyboardManager = LocalSoftwareKeyboardController.current
914
-
915
- pointerInput(Unit) {
916
- detectTapGestures {
917
- keyboardManager?.hide()
918
- focusManager.clearFocus()
919
- }
920
- }
921
- }