@momo-kits/native-kits 0.167.1-duo.20-debug → 0.167.1-duo.21

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