@momo-kits/native-kits 0.167.1-duo.17-debug → 0.167.1-duo.18

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