@momo-kits/native-kits 0.152.4-beta.3 → 0.152.5

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 (155) hide show
  1. package/package.json +7 -6
  2. package/shared/build.gradle.kts +74 -0
  3. package/CODE_OF_CONDUCT.md +0 -133
  4. package/CONTRIBUTING.md +0 -114
  5. package/LICENSE +0 -20
  6. package/README.md +0 -7
  7. package/build.gradle.kts +0 -32
  8. package/compose/MoMoComposeKits.podspec +0 -54
  9. package/compose/build.gradle.kts +0 -149
  10. package/compose/src/androidMain/AndroidManifest.xml +0 -2
  11. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -105
  12. package/compose/src/commonMain/composeResources/files/lottie_circle_loader.json +0 -1
  13. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  14. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  21. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  22. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  23. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  24. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  25. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  26. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -57
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -201
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -222
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -48
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -306
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -715
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -214
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -236
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -77
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -27
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -334
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -345
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -90
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -131
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -543
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -23
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -69
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -143
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -179
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -111
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -384
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -160
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -234
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -223
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -232
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -236
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -228
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -364
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -50
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -34
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -85
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -33
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -338
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -95
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -64
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -89
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -86
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -84
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -208
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -172
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -199
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -237
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -191
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -306
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -13
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -191
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -258
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -2
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -35
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -2
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -59
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -68
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -49
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -232
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -111
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -94
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -159
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -232
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScaleSizeScope.kt +0 -17
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -459
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -169
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -216
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -180
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -251
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -80
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -306
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -31
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -385
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -38
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -62
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -88
  110. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -144
  111. package/gradle.properties +0 -19
  112. package/gradlew +0 -240
  113. package/gradlew.bat +0 -91
  114. package/ios/Application/ApplicationEnvironment.swift +0 -50
  115. package/ios/Application/Components.swift +0 -263
  116. package/ios/Application/ComposeApi.swift +0 -22
  117. package/ios/Application/FloatingButton.swift +0 -172
  118. package/ios/Application/HeaderRight.swift +0 -271
  119. package/ios/Application/Screen.swift +0 -249
  120. package/ios/Badge/BadgeDot.swift +0 -31
  121. package/ios/Button/Button.swift +0 -211
  122. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +0 -126
  123. package/ios/Checkbox/Checkbox.swift +0 -81
  124. package/ios/Chip/Chip.swift +0 -96
  125. package/ios/Colors+Radius+Spacing/Colors.swift +0 -172
  126. package/ios/Colors+Radius+Spacing/Radius.swift +0 -22
  127. package/ios/Colors+Radius+Spacing/Spacing.swift +0 -12
  128. package/ios/Extensions/Color++.swift +0 -25
  129. package/ios/Icon/Icon.swift +0 -51
  130. package/ios/Image/Image.swift +0 -70
  131. package/ios/Input/Input.swift +0 -207
  132. package/ios/Input/InputPhoneNumber.swift +0 -176
  133. package/ios/Input/InputSearch.swift +0 -238
  134. package/ios/Input/InputTextArea.swift +0 -242
  135. package/ios/Lottie/LottieView.swift +0 -86
  136. package/ios/OTPKeyboard/KeyboardButton.swift +0 -41
  137. package/ios/OTPKeyboard/OTPKeyboard.swift +0 -145
  138. package/ios/Popup/PopupDisplay.swift +0 -284
  139. package/ios/Popup/PopupInput.swift +0 -96
  140. package/ios/Popup/PopupPromotion.swift +0 -73
  141. package/ios/PopupView/FullscreenPopup.swift +0 -251
  142. package/ios/PopupView/Modifiers.swift +0 -158
  143. package/ios/PopupView/PopupView.swift +0 -289
  144. package/ios/PopupView/Utils++.swift +0 -281
  145. package/ios/ScrollIndicator/ScrollIndicator.swift +0 -110
  146. package/ios/Swipeable/SwipeCell.swift +0 -278
  147. package/ios/Swipeable/SwipeCellModel.swift +0 -86
  148. package/ios/Switch/Switch.swift +0 -44
  149. package/ios/Template/Logo/Logo.swift +0 -75
  150. package/ios/Template/TrustBanner/TrustBanner.swift +0 -120
  151. package/ios/Theme.md +0 -18
  152. package/ios/Typography/Text.swift +0 -140
  153. package/ios/Typography/Typography.swift +0 -95
  154. package/ios/native-kits.podspec +0 -18
  155. package/settings.gradle.kts +0 -25
@@ -1,715 +0,0 @@
1
- package vn.momo.kits.application
2
-
3
- import androidx.compose.animation.animateContentSize
4
- import androidx.compose.foundation.ScrollState
5
- import androidx.compose.foundation.background
6
- import androidx.compose.foundation.border
7
- import androidx.compose.foundation.gestures.detectTapGestures
8
- import androidx.compose.foundation.interaction.FocusInteraction
9
- import androidx.compose.foundation.interaction.MutableInteractionSource
10
- import androidx.compose.foundation.layout.Arrangement
11
- import androidx.compose.foundation.layout.Box
12
- import androidx.compose.foundation.layout.Column
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.height
19
- import androidx.compose.foundation.layout.ime
20
- import androidx.compose.foundation.layout.navigationBars
21
- import androidx.compose.foundation.layout.offset
22
- import androidx.compose.foundation.layout.padding
23
- import androidx.compose.foundation.layout.size
24
- import androidx.compose.foundation.layout.sizeIn
25
- import androidx.compose.foundation.rememberScrollState
26
- import androidx.compose.foundation.shape.CircleShape
27
- import androidx.compose.foundation.shape.RoundedCornerShape
28
- import androidx.compose.foundation.text.BasicTextField
29
- import androidx.compose.foundation.text.KeyboardActions
30
- import androidx.compose.foundation.text.KeyboardOptions
31
- import androidx.compose.foundation.verticalScroll
32
- import androidx.compose.runtime.Composable
33
- import androidx.compose.runtime.LaunchedEffect
34
- import androidx.compose.runtime.MutableState
35
- import androidx.compose.runtime.Stable
36
- import androidx.compose.runtime.State
37
- import androidx.compose.runtime.derivedStateOf
38
- import androidx.compose.runtime.getValue
39
- import androidx.compose.runtime.mutableStateOf
40
- import androidx.compose.runtime.produceState
41
- import androidx.compose.runtime.remember
42
- import androidx.compose.runtime.rememberUpdatedState
43
- import androidx.compose.runtime.snapshotFlow
44
- import androidx.compose.ui.Alignment
45
- import androidx.compose.ui.Modifier
46
- import androidx.compose.ui.composed
47
- import androidx.compose.ui.draw.clip
48
- import androidx.compose.ui.draw.drawBehind
49
- import androidx.compose.ui.draw.drawWithContent
50
- import androidx.compose.ui.geometry.Offset
51
- import androidx.compose.ui.graphics.Brush
52
- import androidx.compose.ui.graphics.Color
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.style.TextOverflow
66
- import androidx.compose.ui.unit.Constraints
67
- import androidx.compose.ui.unit.Dp
68
- import androidx.compose.ui.unit.IntOffset
69
- import androidx.compose.ui.unit.LayoutDirection
70
- import androidx.compose.ui.unit.dp
71
- import androidx.compose.ui.unit.sp
72
- import kotlinx.coroutines.flow.collectLatest
73
- import kotlinx.coroutines.flow.mapNotNull
74
- import vn.momo.kits.components.Icon
75
- import vn.momo.kits.components.Text
76
- import vn.momo.kits.const.AppTheme
77
- import vn.momo.kits.const.Colors
78
- import vn.momo.kits.const.Radius
79
- import vn.momo.kits.const.Spacing
80
- import vn.momo.kits.const.Typography
81
- import vn.momo.kits.modifier.kitsAutomationId
82
- import vn.momo.kits.modifier.noFeedbackClickable
83
- import vn.momo.kits.modifier.setAutomationId
84
- import vn.momo.kits.modifier.shadow
85
- import vn.momo.kits.utils.getAppStatusBarHeight
86
- import kotlin.math.max
87
-
88
- @Deprecated("Use NavigationContainer(StackScreen) instead", ReplaceWith("NavigationContainer(StackScreen)"))
89
- @Composable
90
- fun LiteScreen(
91
- scrollable: Boolean = true,
92
- scrollState: ScrollState? = null,
93
- headerType: HeaderType = HeaderType.DEFAULT,
94
- verticalArrangement: Arrangement.Vertical = Arrangement.Top,
95
- horizontalAlignment: Alignment.Horizontal = Alignment.Start,
96
- backgroundColor: Color = AppTheme.current.colors.background.default,
97
- /* Begin of header props */
98
- title: String? = null,
99
- inputSearchProps: LiteInputSearchProps? = null,
100
- goBack: (() -> Unit)? = null,
101
- headerRight: @Composable() (() -> Unit)? = null,
102
- useAnimationSearch: Boolean = true,
103
- titlePosition: TitlePosition = TitlePosition.LEFT,
104
- headerRightData: HeaderRightData? = null,
105
- /* End of header props */
106
-
107
- screenContent: @Composable () -> Unit,
108
- ) {
109
- val content by rememberUpdatedState(screenContent)
110
-
111
- val finalScrollState = scrollState ?: rememberScrollState()
112
-
113
- Column(
114
- modifier = Modifier
115
- .fillMaxSize()
116
- .background(color = backgroundColor)
117
- .hideKeyboardOnTap(),
118
- verticalArrangement = verticalArrangement,
119
- horizontalAlignment = horizontalAlignment,
120
- ) {
121
- val contentModifier = remember(scrollable, finalScrollState) {
122
- var res = Modifier.weight(1f)
123
- if (scrollable) {
124
- res = res.verticalScroll(finalScrollState)
125
- }
126
- res
127
- }
128
-
129
- LiteScreenHeader(
130
- scrollState = finalScrollState,
131
- title = title,
132
- headerRight = headerRight,
133
- headerType = headerType,
134
- onGoBack = goBack,
135
- inputSearchProps = inputSearchProps,
136
- titlePosition = titlePosition,
137
- useAnimationSearch = useAnimationSearch,
138
- headerRightData = headerRightData,
139
- )
140
-
141
- Box(
142
- modifier = contentModifier,
143
- contentAlignment = Alignment.TopCenter,
144
- ) {
145
- content()
146
- }
147
- }
148
- }
149
-
150
- private object HeaderId {
151
- private const val PACKAGE_NAME = "vn.momo.compose.kits"
152
- const val BACK_ID = "${PACKAGE_NAME}.back"
153
- const val HEADER_RIGHT_ID = "${PACKAGE_NAME}.headerRight"
154
- const val INPUT_SEARCH_ID = "${PACKAGE_NAME}.inputSearch"
155
- const val TITLE_ID = "${PACKAGE_NAME}.title"
156
-
157
- val EXTENDED_HEADER_HEIGHT = 154.dp
158
- }
159
-
160
- @Composable
161
- private fun LiteScreenHeader(
162
- scrollState: ScrollState?,
163
- title: String? = null,
164
- tintColor: Color? = null,
165
- headerRightData: HeaderRightData? = null,
166
- headerType: HeaderType = HeaderType.DEFAULT,
167
- titlePosition: TitlePosition = TitlePosition.LEFT,
168
- useAnimationSearch: Boolean = true,
169
- onGoBack: (() -> Unit)? = null,
170
- inputSearchProps: LiteInputSearchProps? = null,
171
- headerRight: @Composable (() -> Unit)? = null,
172
- ) {
173
- val statusBarHeight = getAppStatusBarHeight()
174
- if (headerType == HeaderType.NONE) {
175
- Box(modifier = Modifier.height(statusBarHeight))
176
- return
177
- }
178
- val theme = AppTheme.current
179
- val density = LocalDensity.current
180
-
181
- val isHeaderExtend = remember(headerType) {
182
- headerType == HeaderType.EXTENDED
183
- }
184
- val backgroundHeight = remember(isHeaderExtend, statusBarHeight) {
185
- if (!isHeaderExtend) statusBarHeight + HEADER_HEIGHT.dp
186
- else HeaderId.EXTENDED_HEADER_HEIGHT
187
- }
188
- val listGradientColors = remember {
189
- listOf(
190
- Color(0xFFFDCADE),
191
- Color(0x00FDCADE),
192
- )
193
- }
194
-
195
- val headerColor = remember(tintColor, theme) {
196
- if (tintColor == Colors.black_01) HeaderColor(
197
- tintIconColor = tintColor,
198
- backgroundButton = Colors.black_20.copy(alpha = 0.6f),
199
- borderColor = Colors.black_01.copy(alpha = 0.2f)
200
- )
201
- else HeaderColor(
202
- tintIconColor = tintColor ?: theme.colors.text.default,
203
- backgroundButton = Colors.black_01.copy(alpha = 0.6f),
204
- borderColor = Colors.black_20.copy(alpha = 0.2f)
205
- )
206
- }
207
-
208
- val scrollPercentage = produceState(
209
- initialValue = 0f,
210
- key1 = useAnimationSearch,
211
- key2 = scrollState,
212
- key3 = backgroundHeight,
213
- ) {
214
- if (!useAnimationSearch) return@produceState
215
- scrollState ?: return@produceState
216
- val rangePx = with(density) { backgroundHeight.toPx() }
217
- snapshotFlow { scrollState.value }.collectLatest {
218
- value = (it / rangePx).coerceIn(0f, 1f)
219
- }
220
- }
221
-
222
- val titleStyle = remember {
223
- Typography.actionSBold.copy(
224
- fontSize = 15.sp,
225
- lineHeight = 22.sp,
226
- )
227
- }
228
-
229
- val titleModifier = remember {
230
- Modifier
231
- .kitsAutomationId("title_navigation_header")
232
- .layoutId(HeaderId.TITLE_ID)
233
- .graphicsLayer {
234
- alpha = if (isHeaderExtend && inputSearchProps != null && useAnimationSearch)
235
- (1 - scrollPercentage.value * 2).coerceIn(0f, 1f)
236
- else 1f
237
- }
238
- }
239
-
240
- val policy = remember(
241
- useAnimationSearch,
242
- isHeaderExtend,
243
- statusBarHeight,
244
- titlePosition,
245
- scrollPercentage,
246
- ) {
247
- LiteScreenHeaderPolicy(
248
- useAnimationSearch = useAnimationSearch,
249
- isHeaderExtend = isHeaderExtend,
250
- statusBarHeight = statusBarHeight,
251
- titlePosition = titlePosition,
252
- scrollPercentage = scrollPercentage,
253
- )
254
- }
255
-
256
- Layout(
257
- modifier = Modifier
258
- .animateContentSize()
259
- .drawBehind {
260
- val headerHeight = max(
261
- HeaderId.EXTENDED_HEADER_HEIGHT.toPx(),
262
- size.height,
263
- )
264
- drawRect(color = Colors.black_01)
265
- drawRect(
266
- brush = Brush.linearGradient(
267
- colors = listGradientColors,
268
- start = Offset.Zero,
269
- end = Offset(
270
- x = 0f,
271
- y = headerHeight * (1 - scrollPercentage.value),
272
- ),
273
- )
274
- )
275
- },
276
- content = {
277
- if (onGoBack != null) {
278
- Box(
279
- modifier = Modifier
280
- .size(28.dp)
281
- .layoutId(HeaderId.BACK_ID)
282
- .clip(CircleShape)
283
- .border(
284
- width = 0.2.dp,
285
- color = headerColor.borderColor,
286
- shape = CircleShape,
287
- )
288
- .background(color = headerColor.backgroundButton)
289
- .noFeedbackClickable(onClick = onGoBack)
290
- .setAutomationId("btn_navigation_back")
291
- .padding(Spacing.XS),
292
- ) {
293
- Icon(
294
- source = "arrow-back",
295
- color = headerColor.tintIconColor,
296
- size = 20.dp,
297
- )
298
- }
299
- }
300
-
301
- Box(
302
- modifier = Modifier
303
- .layoutId(HeaderId.HEADER_RIGHT_ID)
304
- ) {
305
- if (headerRight != null) {
306
- headerRight()
307
- } else {
308
- HeaderRight(
309
- headerRight = headerRightData,
310
- tintColor = tintColor,
311
- )
312
- }
313
- }
314
-
315
- if (inputSearchProps != null) {
316
- LiteInputSearch(
317
- modifier = Modifier.layoutId(HeaderId.INPUT_SEARCH_ID),
318
- inputSearchProps = inputSearchProps,
319
- )
320
- }
321
- if (title != null && (inputSearchProps == null || isHeaderExtend)) {
322
- Text(
323
- text = title,
324
- color = headerColor.tintIconColor,
325
- style = titleStyle,
326
- modifier = titleModifier,
327
- maxLines = 1,
328
- overflow = TextOverflow.Ellipsis
329
- )
330
- }
331
- },
332
- measurePolicy = policy,
333
- )
334
- }
335
-
336
- private class LiteScreenHeaderPolicy(
337
- private val useAnimationSearch: Boolean,
338
- private val isHeaderExtend: Boolean,
339
- private val statusBarHeight: Dp,
340
- private val scrollPercentage: State<Float>,
341
- private val titlePosition: TitlePosition,
342
- ) : MeasurePolicy {
343
-
344
- override fun MeasureScope.measure(
345
- measurables: List<Measurable>,
346
- constraints: Constraints
347
- ): MeasureResult {
348
- val spacing12 = Spacing.M.roundToPx()
349
- val statusBarPx = statusBarHeight.roundToPx()
350
- val scrollPercent = scrollPercentage.value
351
-
352
- val realConstraints = constraints.copy(
353
- minWidth = 0,
354
- minHeight = 0,
355
- maxWidth = constraints.maxWidth - spacing12 * 2,
356
- )
357
- val backIconPlaceable =
358
- measurables.find { it.layoutId == HeaderId.BACK_ID }?.measure(realConstraints)
359
- val headerRightPlaceable =
360
- measurables.find { it.layoutId == HeaderId.HEADER_RIGHT_ID }?.measure(
361
- realConstraints.copy(
362
- maxWidth = realConstraints.maxWidth / 2,
363
- )
364
- )
365
- val inputSearchConstraints = if (isHeaderExtend) {
366
- val minWidth =
367
- if (useAnimationSearch) realConstraints.maxWidth - backIconPlaceable.safeWidth - headerRightPlaceable.safeWidth - spacing12 * 2
368
- else realConstraints.maxWidth
369
- realConstraints.copy(
370
- maxWidth = (realConstraints.maxWidth * (1 - scrollPercent)).toInt()
371
- .coerceAtLeast(minWidth)
372
- )
373
- } else realConstraints.copy(
374
- maxWidth = realConstraints.maxWidth - backIconPlaceable.safeWidth - headerRightPlaceable.safeWidth - spacing12 * 2
375
- )
376
- val inputSearchPlaceable = measurables.find { it.layoutId == HeaderId.INPUT_SEARCH_ID }
377
- ?.measure(inputSearchConstraints)
378
- val titlePlaceable = measurables.find { it.layoutId == HeaderId.TITLE_ID }?.measure(
379
- constraints = realConstraints.copy(
380
- maxWidth = realConstraints.maxWidth - backIconPlaceable.safeWidth - headerRightPlaceable.safeWidth - spacing12 * 2
381
- )
382
- )
383
-
384
- val firstRowMaxHeight = buildList {
385
- add(backIconPlaceable.safeHeight)
386
- add(headerRightPlaceable.safeHeight)
387
- if (!isHeaderExtend) {
388
- add(inputSearchPlaceable.safeHeight)
389
- }
390
- if (isHeaderExtend) {
391
- add(titlePlaceable.safeHeight)
392
- }
393
- }.max()
394
-
395
- var defaultHeight = statusBarPx + spacing12 + firstRowMaxHeight + spacing12
396
- if (isHeaderExtend) {
397
- defaultHeight += inputSearchPlaceable.safeHeight + spacing12
398
- }
399
- val height = when {
400
- !useAnimationSearch && !isHeaderExtend -> defaultHeight
401
- else -> (defaultHeight - scrollPercent * (defaultHeight - statusBarPx - HEADER_HEIGHT.dp.roundToPx())).toInt()
402
- }
403
-
404
- return layout(
405
- width = constraints.maxWidth,
406
- height = height,
407
- ) {
408
- val startX = spacing12
409
- val startY = statusBarPx + spacing12
410
- var curX = startX
411
- var curY = startY
412
-
413
- if (backIconPlaceable != null) {
414
- backIconPlaceable.place(
415
- x = startX,
416
- y = startY + backIconPlaceable.verticalCenterOffset(firstRowMaxHeight),
417
- )
418
- curX += backIconPlaceable.safeWidth + spacing12
419
- }
420
-
421
- headerRightPlaceable?.place(
422
- x = constraints.maxWidth - spacing12 - headerRightPlaceable.safeWidth,
423
- y = startY + headerRightPlaceable.verticalCenterOffset(firstRowMaxHeight),
424
- )
425
-
426
- val titleOffset = IntOffset(
427
- x = if (titlePosition == TitlePosition.LEFT) curX
428
- else titlePlaceable.horizontalCenterOffset(
429
- space = constraints.maxWidth,
430
- layoutDirection = layoutDirection,
431
- ),
432
- y = startY + titlePlaceable.verticalCenterOffset(firstRowMaxHeight),
433
- )
434
-
435
- titlePlaceable?.place(titleOffset)
436
-
437
- if (backIconPlaceable != null || headerRightPlaceable != null || titlePlaceable != null) {
438
- curY += firstRowMaxHeight + spacing12
439
- }
440
-
441
- val inputSearchOffset = if (isHeaderExtend) {
442
- IntOffset(
443
- x = startX + ((backIconPlaceable.safeWidth + spacing12) * (scrollPercent * 2f).coerceIn(
444
- 0f, 1f
445
- )).toInt(),
446
- y = (curY * (1 - scrollPercent)).toInt().coerceAtLeast(
447
- startY + inputSearchPlaceable.verticalCenterOffset(firstRowMaxHeight)
448
- ),
449
- )
450
- } else {
451
- IntOffset(
452
- x = curX,
453
- y = startY + inputSearchPlaceable.verticalCenterOffset(firstRowMaxHeight),
454
- )
455
- }
456
-
457
- inputSearchPlaceable?.place(inputSearchOffset)
458
- }
459
- }
460
-
461
- private val Placeable?.safeHeight
462
- get() = this?.height ?: 0
463
- private val Placeable?.safeWidth
464
- get() = this?.width ?: 0
465
-
466
- private fun Placeable?.verticalCenterOffset(space: Int): Int {
467
- if (this == null) return 0
468
- return Alignment.CenterVertically.align(safeHeight, space)
469
- }
470
-
471
- private fun Placeable?.horizontalCenterOffset(
472
- space: Int,
473
- layoutDirection: LayoutDirection
474
- ): Int {
475
- if (this == null) return 0
476
- return Alignment.CenterHorizontally.align(safeWidth, space, layoutDirection)
477
- }
478
- }
479
-
480
- private val EMPTY_FUNC = {}
481
-
482
- @Stable
483
- data class LiteInputSearchProps(
484
- val textFieldState: MutableState<String>,
485
- val onValueChange: (String) -> Unit,
486
- val onClear: () -> Unit = EMPTY_FUNC,
487
- val clearCondition: (() -> Boolean)? = null,
488
- val modifier: Modifier = Modifier,
489
- val onFocused: (() -> Unit) = EMPTY_FUNC,
490
- val keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
491
- val keyboardActions: KeyboardActions = KeyboardActions.Default,
492
- val onKeyboardAction: (() -> Unit) = EMPTY_FUNC,
493
-
494
- val btnText: String? = null,
495
- val isShowBtnText: Boolean = !btnText.isNullOrEmpty(),
496
- val onPressBtnText: (() -> Unit) = EMPTY_FUNC,
497
-
498
- val disabled: Boolean = false,
499
-
500
- val placeHolder: String? = null,
501
-
502
- val iconRightTextField: @Composable ((Modifier) -> Unit)? = null,
503
- )
504
-
505
- @Composable
506
- private fun LiteInputSearch(
507
- modifier: Modifier = Modifier,
508
- inputSearchProps: LiteInputSearchProps? = null,
509
- ) {
510
- inputSearchProps ?: return
511
- val theme = AppTheme.current
512
-
513
- val isFocused = remember { mutableStateOf(false) }
514
- val interactionSource = remember { MutableInteractionSource() }
515
- val textState by remember { inputSearchProps.textFieldState }
516
-
517
- val isShowBtnText by remember(inputSearchProps.isShowBtnText, inputSearchProps.btnText) {
518
- derivedStateOf {
519
- inputSearchProps.isShowBtnText && inputSearchProps.btnText.isNullOrEmpty()
520
- }
521
- }
522
- val inputFieldStyle = remember(theme) {
523
- Typography.bodyDefaultRegular.copy(
524
- color = theme.colors.text.default,
525
- )
526
- }
527
-
528
- LaunchedEffect(inputSearchProps.onFocused) {
529
- interactionSource.interactions.mapNotNull { it as? FocusInteraction }.collectLatest {
530
- val isFocus = it is FocusInteraction.Focus
531
- isFocused.value = isFocus
532
- if (isFocus) inputSearchProps.onFocused()
533
- }
534
- }
535
-
536
- Row(
537
- modifier = modifier,
538
- verticalAlignment = Alignment.CenterVertically,
539
- ) {
540
- val textFieldModifier = remember(inputSearchProps.modifier) {
541
- inputSearchProps.modifier
542
- .weight(1f)
543
- .sizeIn(minHeight = 36.dp)
544
- }
545
- BasicTextField(
546
- value = textState,
547
- onValueChange = inputSearchProps.onValueChange,
548
- enabled = !inputSearchProps.disabled,
549
- keyboardOptions = inputSearchProps.keyboardOptions,
550
- keyboardActions = inputSearchProps.keyboardActions,
551
- modifier = textFieldModifier,
552
- textStyle = inputFieldStyle,
553
- singleLine = true,
554
- interactionSource = interactionSource,
555
- decorationBox = { innerTextField ->
556
- val isShowClear by remember(inputSearchProps.clearCondition, isFocused.value) {
557
- derivedStateOf {
558
- inputSearchProps.clearCondition?.invoke() == true || (isFocused.value && textState.isNotEmpty())
559
- }
560
- }
561
- val placeHolder by produceState<String?>(null, inputSearchProps.placeHolder) {
562
- if (inputSearchProps.placeHolder.isNullOrEmpty()) return@produceState
563
- snapshotFlow { textState }.collectLatest {
564
- value = if (it.isEmpty()) inputSearchProps.placeHolder else null
565
- }
566
- }
567
- val iconRightModifier = remember {
568
- Modifier
569
- .padding(start = Spacing.L)
570
- .drawWithContent {
571
- val offsetX = -Spacing.S.toPx()
572
- drawLine(
573
- start = Offset(
574
- x = offsetX,
575
- y = 0f,
576
- ),
577
- end = Offset(
578
- x = offsetX,
579
- y = size.height,
580
- ),
581
- color = theme.colors.primary,
582
- strokeWidth = 1.dp.toPx(),
583
- )
584
- drawContent()
585
- }
586
- }
587
-
588
- Row(
589
- modifier = Modifier
590
- .background(
591
- color = theme.colors.background.surface,
592
- shape = RoundedCornerShape(Radius.XL),
593
- )
594
- .padding(
595
- horizontal = Spacing.M,
596
- vertical = Spacing.S,
597
- ),
598
- horizontalArrangement = Arrangement.Start,
599
- verticalAlignment = Alignment.CenterVertically,
600
- ) {
601
- Icon(
602
- source = "navigation_search",
603
- modifier = Modifier.padding(end = Spacing.XS),
604
- size = 24.dp,
605
- color = theme.colors.text.hint
606
- )
607
- Box(
608
- modifier = Modifier.weight(1f),
609
- contentAlignment = Alignment.CenterStart,
610
- ) {
611
- if (!placeHolder.isNullOrEmpty()) {
612
- Text(
613
- text = placeHolder ?: "",
614
- style = Typography.bodyDefaultRegular,
615
- maxLines = 1,
616
- color = theme.colors.text.hint,
617
- overflow = TextOverflow.Ellipsis
618
- )
619
- }
620
- innerTextField()
621
- }
622
-
623
- if (isShowClear) {
624
- Icon(
625
- source = "24_navigation_close_circle_full",
626
- size = 16.dp,
627
- color = theme.colors.text.hint,
628
- modifier = Modifier.padding(start = Spacing.XS)
629
- .noFeedbackClickable(onClick = inputSearchProps.onClear),
630
- )
631
- }
632
-
633
- inputSearchProps.iconRightTextField?.invoke(iconRightModifier)
634
- }
635
- }
636
- )
637
-
638
- if (isShowBtnText) {
639
- Text(
640
- text = inputSearchProps.btnText ?: "",
641
- style = Typography.actionDefaultBold,
642
- color = theme.colors.text.default,
643
- modifier = Modifier.padding(start = Spacing.L)
644
- .noFeedbackClickable(onClick = inputSearchProps.onPressBtnText)
645
- )
646
- }
647
- }
648
- }
649
-
650
- @Composable
651
- private fun footerOffset(
652
- useAvoidKeyboard: Boolean = true,
653
- ): State<IntOffset> {
654
- if (!useAvoidKeyboard) return remember { mutableStateOf(IntOffset.Zero) }
655
- val density = LocalDensity.current
656
- val navPaddingValue = WindowInsets.navigationBars.asPaddingValues()
657
- val keyboardSize = keyboardSizeState()
658
-
659
- return produceState(IntOffset.Zero, density, navPaddingValue) {
660
- val navSystemOffset = with(density) { navPaddingValue.calculateBottomPadding().roundToPx() }
661
- snapshotFlow { keyboardSize.value }.collectLatest {
662
- value = if (it == 0.dp) IntOffset.Zero
663
- else IntOffset(
664
- x = 0, y = with(density) {
665
- navSystemOffset - it.roundToPx()
666
- })
667
- }
668
- }
669
- }
670
-
671
- @Composable
672
- fun keyboardSizeState(): State<Dp> {
673
- val bottom = WindowInsets.ime.asPaddingValues()
674
- return rememberUpdatedState(bottom.calculateBottomPadding())
675
- }
676
-
677
- @Composable
678
- private fun Footer(
679
- useAvoidKeyboard: Boolean,
680
- footerContent: (@Composable () -> Unit)?,
681
- ) {
682
- footerContent ?: return
683
- val theme = AppTheme.current
684
- val navPaddingValue = WindowInsets.navigationBars.asPaddingValues()
685
- val offsetMove = footerOffset(useAvoidKeyboard)
686
-
687
- Box(
688
- modifier = Modifier.padding(navPaddingValue).fillMaxWidth().offset {
689
- offsetMove.value
690
- }.shadow(
691
- color = Colors.black_20.copy(alpha = 0.05f),
692
- blurRadius = 24f,
693
- offsetX = 0.dp,
694
- offsetY = (-4).dp
695
- ).background(theme.colors.background.surface).padding(
696
- start = Spacing.M,
697
- top = Spacing.M,
698
- end = Spacing.M,
699
- )
700
- ) {
701
- footerContent()
702
- }
703
- }
704
-
705
- fun Modifier.hideKeyboardOnTap() = composed {
706
- val focusManager = LocalFocusManager.current
707
- val keyboardManager = LocalSoftwareKeyboardController.current
708
-
709
- pointerInput(Unit) {
710
- detectTapGestures {
711
- keyboardManager?.hide()
712
- focusManager.clearFocus()
713
- }
714
- }
715
- }