@momo-kits/native-kits 0.155.1-hello.2 → 0.155.1-hello.2-debug

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 (117) hide show
  1. package/.gitlab-ci.yml +15 -0
  2. package/.npmignore.backup +22 -0
  3. package/build.gradle.kts +11 -0
  4. package/compose/build.gradle.kts +180 -0
  5. package/compose/compose.podspec +54 -0
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +113 -0
  7. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  8. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  9. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  10. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  11. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  12. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +57 -0
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +95 -0
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +305 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +715 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +121 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +405 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +85 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +35 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +343 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +353 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +98 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +138 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +78 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +151 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +190 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +119 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +447 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +175 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +244 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +233 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +233 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +257 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +240 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +59 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +44 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +95 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +43 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +355 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +106 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +72 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +17 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +99 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +99 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +95 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +132 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +217 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +180 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +208 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +239 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +13 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +189 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +285 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +59 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +15 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +50 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +241 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +122 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +98 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +163 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +331 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +499 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +162 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +233 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +190 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +277 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +31 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +370 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +135 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +42 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +62 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +88 -0
  107. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +152 -0
  108. package/gradle/libs.versions.toml +57 -0
  109. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  110. package/gradle/wrapper/gradle-wrapper.properties +8 -0
  111. package/gradle.properties +26 -0
  112. package/gradlew +252 -0
  113. package/gradlew.bat +94 -0
  114. package/local.properties +8 -0
  115. package/package.json +1 -1
  116. package/publish_release.sh +103 -0
  117. package/settings.gradle.kts +52 -0
@@ -0,0 +1,217 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.border
5
+ import androidx.compose.foundation.clickable
6
+ import androidx.compose.foundation.layout.Arrangement
7
+ import androidx.compose.foundation.layout.Box
8
+ import androidx.compose.foundation.layout.Column
9
+ import androidx.compose.foundation.layout.IntrinsicSize
10
+ import androidx.compose.foundation.layout.Row
11
+ import androidx.compose.foundation.layout.Spacer
12
+ import androidx.compose.foundation.layout.fillMaxHeight
13
+ import androidx.compose.foundation.layout.fillMaxWidth
14
+ import androidx.compose.foundation.layout.height
15
+ import androidx.compose.foundation.layout.padding
16
+ import androidx.compose.foundation.layout.size
17
+ import androidx.compose.foundation.layout.width
18
+ import androidx.compose.foundation.shape.RoundedCornerShape
19
+ import androidx.compose.runtime.Composable
20
+ import androidx.compose.ui.Alignment
21
+ import androidx.compose.ui.Modifier
22
+ import androidx.compose.ui.graphics.Color
23
+ import androidx.compose.ui.text.TextStyle
24
+ import androidx.compose.ui.text.font.FontWeight
25
+ import androidx.compose.ui.unit.dp
26
+ import androidx.compose.ui.unit.sp
27
+ import vn.momo.kits.application.ApplicationContext
28
+ import vn.momo.kits.application.MiniAppContext.Companion.isShowBaselineDebug
29
+ import vn.momo.kits.const.AppTheme
30
+ import vn.momo.kits.const.Colors
31
+ import vn.momo.kits.const.Spacing
32
+ import vn.momo.kits.const.Typography
33
+ import vn.momo.kits.modifier.conditional
34
+
35
+ enum class TitleType { Card, Section }
36
+ enum class TitleSize { Small, Medium, Large }
37
+ enum class IconAlign { Top, Center, Bottom }
38
+ enum class ButtonSize { Small, Large }
39
+
40
+ @Composable
41
+ fun Title(
42
+ title: String,
43
+ type: TitleType = TitleType.Section,
44
+ size: TitleSize = TitleSize.Medium,
45
+ icon: String? = null,
46
+ iconColor: Color? = null,
47
+ iconAlign: IconAlign = IconAlign.Top,
48
+ showRightAction: Boolean = false,
49
+ showTrailingAction: Boolean = false,
50
+ badgeLabel: String? = null,
51
+ buttonTitle: String? = null,
52
+ buttonSize: ButtonSize = ButtonSize.Small,
53
+ onPressRightAction: () -> Unit = {},
54
+ onPressTrailingAction: () -> Unit = {},
55
+ textOnly: Boolean = false,
56
+ description: String? = null,
57
+ modifier: Modifier = Modifier
58
+ ) {
59
+ val theme = AppTheme.current
60
+ val textStyle: TextStyle = when (type) {
61
+ TitleType.Card -> when (size) {
62
+ TitleSize.Small -> TextStyle(fontSize = 14.sp, lineHeight = 20.sp)
63
+ TitleSize.Medium -> TextStyle(fontSize = 16.sp, lineHeight = 22.sp)
64
+ TitleSize.Large -> TextStyle(fontSize = 18.sp, lineHeight = 26.sp)
65
+ }
66
+
67
+ TitleType.Section -> when (size) {
68
+ TitleSize.Small -> TextStyle(
69
+ fontSize = 16.sp,
70
+ lineHeight = 24.sp,
71
+ fontWeight = FontWeight.Bold
72
+ )
73
+
74
+ TitleSize.Medium -> TextStyle(
75
+ fontSize = 18.sp,
76
+ lineHeight = 26.sp,
77
+ fontWeight = FontWeight.Bold
78
+ )
79
+
80
+ TitleSize.Large -> TextStyle(
81
+ fontSize = 20.sp,
82
+ lineHeight = 28.sp,
83
+ fontWeight = FontWeight.Bold
84
+ )
85
+ }
86
+ }
87
+
88
+ if (textOnly) {
89
+ Text(
90
+ text = title,
91
+ style = textStyle,
92
+ modifier = modifier
93
+ )
94
+ return
95
+ }
96
+
97
+ val application = ApplicationContext.current
98
+
99
+ Row(
100
+ modifier = modifier
101
+ .fillMaxWidth()
102
+ .height(IntrinsicSize.Min)
103
+ .conditional(application.isShowBaselineDebug()) {
104
+ border(1.dp, Colors.blue_03)
105
+ }
106
+ .padding(8.dp),
107
+ verticalAlignment = Alignment.CenterVertically
108
+ ) {
109
+ icon?.let {
110
+ Column(
111
+ modifier = Modifier.fillMaxHeight().padding(end = Spacing.S),
112
+ verticalArrangement = when (iconAlign) {
113
+ IconAlign.Top -> Arrangement.Top
114
+ IconAlign.Center -> Arrangement.Center
115
+ IconAlign.Bottom -> Arrangement.Bottom
116
+ },
117
+ ) {
118
+ // Icon
119
+ Icon(
120
+ source = it,
121
+ color = iconColor ?: theme.colors.text.default,
122
+ modifier = Modifier.size(24.dp)
123
+ )
124
+ }
125
+ }
126
+
127
+ Column(
128
+ modifier = Modifier.weight(1f)
129
+ ) {
130
+ Row(
131
+ verticalAlignment = Alignment.CenterVertically
132
+ ) {
133
+ Row(
134
+ verticalAlignment = Alignment.CenterVertically,
135
+ modifier = if (showTrailingAction) Modifier else Modifier.weight(1f),
136
+ ) {
137
+ Text(
138
+ text = title,
139
+ style = textStyle,
140
+ maxLines = if (showTrailingAction || badgeLabel != null) 1 else 2,
141
+ )
142
+
143
+ // Badge
144
+ badgeLabel?.let {
145
+ Spacer(modifier = Modifier.width(4.dp))
146
+ Badge(
147
+ label = it
148
+ )
149
+ }
150
+
151
+ }
152
+
153
+ // Trailing action (icon)
154
+ if (showTrailingAction && !showRightAction) {
155
+ Spacer(modifier = Modifier.width(8.dp))
156
+ Box(
157
+ modifier = Modifier
158
+ .size(24.dp)
159
+ .background(
160
+ color = if (type == TitleType.Section) Colors.black_06.copy(0.6f) else Colors.black_06.copy(
161
+ 0.3f
162
+ ),
163
+ shape = RoundedCornerShape(12.dp)
164
+ )
165
+ .clickable { onPressTrailingAction() },
166
+ contentAlignment = Alignment.Center
167
+ ) {
168
+ Icon(
169
+ source = "arrow_chevron_right_small",
170
+ size = 18.dp
171
+ )
172
+ }
173
+ }
174
+ }
175
+
176
+ // Description
177
+ description?.let {
178
+ Spacer(modifier = Modifier.height(4.dp))
179
+ Text(
180
+ text = it,
181
+ style = Typography.descriptionDefaultRegular,
182
+ color = theme.colors.text.secondary
183
+ )
184
+ }
185
+ }
186
+
187
+ // Right action (button or icon)
188
+ if (showRightAction && !showTrailingAction) {
189
+ Spacer(modifier = Modifier.width(8.dp))
190
+ if (buttonTitle != null) {
191
+ Text(
192
+ text = buttonTitle,
193
+ style = if (buttonSize === ButtonSize.Small) Typography.actionXsBold else Typography.actionSBold,
194
+ color = theme.colors.primary,
195
+ modifier = Modifier.clickable { onPressRightAction() }
196
+ )
197
+ } else {
198
+ Box(
199
+ modifier = Modifier
200
+ .size(24.dp)
201
+ .background(
202
+ color = Colors.pink_03.copy(alpha = 0.1f),
203
+ shape = RoundedCornerShape(12.dp)
204
+ )
205
+ .clickable { onPressRightAction() },
206
+ contentAlignment = Alignment.Center
207
+ ) {
208
+ Icon(
209
+ source = "arrow_chevron_right_small",
210
+ modifier = Modifier.size(22.dp),
211
+ color = theme.colors.primary
212
+ )
213
+ }
214
+ }
215
+ }
216
+ }
217
+ }
@@ -0,0 +1,180 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.border
5
+ import androidx.compose.foundation.clickable
6
+ import androidx.compose.foundation.layout.Arrangement
7
+ import androidx.compose.foundation.layout.Column
8
+ import androidx.compose.foundation.layout.Row
9
+ import androidx.compose.foundation.layout.fillMaxWidth
10
+ import androidx.compose.foundation.layout.height
11
+ import androidx.compose.foundation.layout.padding
12
+ import androidx.compose.foundation.layout.width
13
+ import androidx.compose.foundation.shape.RoundedCornerShape
14
+ import androidx.compose.runtime.Composable
15
+ import androidx.compose.ui.Alignment
16
+ import androidx.compose.ui.Modifier
17
+ import androidx.compose.ui.draw.clip
18
+ import androidx.compose.ui.graphics.Color
19
+ import androidx.compose.ui.layout.ContentScale
20
+ import androidx.compose.ui.unit.dp
21
+ import vn.momo.kits.application.AppConfig
22
+ import vn.momo.kits.application.AppLanguage
23
+ import vn.momo.kits.application.ApplicationContext
24
+ import vn.momo.kits.application.MiniAppContext.Companion.isShowBaselineDebug
25
+ import vn.momo.kits.const.Colors
26
+ import vn.momo.kits.const.Typography
27
+ import vn.momo.kits.modifier.conditional
28
+ import vn.momo.kits.modifier.noFeedbackClickable
29
+
30
+ val defaultBanner = TrustBannerData(
31
+ content = mapOf(
32
+ "vi" to "An toàn tài sản & Bảo mật thông tin của bạn là ưu tiên hàng đầu của MoMo.",
33
+ "en" to "Ensuring financial security and data privacy is MoMo's highest priority."
34
+ ),
35
+ subContent = mapOf(
36
+ "vi" to "Tìm hiểu thêm",
37
+ "en" to "Learn more"
38
+ ),
39
+ pciImage = "https://static.momocdn.net/app/img/kits/trustBanner/pci_dss.png",
40
+ sslImage = "https://static.momocdn.net/app/img/kits/trustBanner/ssl.png",
41
+ urlConfig = "login_and_security",
42
+ icons = listOf(
43
+ "https://static.momocdn.net/app/img/kits/trustBanner/ic_viettinbank.png",
44
+ "https://static.momocdn.net/app/img/kits/trustBanner/ic_agribank.png",
45
+ "https://static.momocdn.net/app/img/kits/trustBanner/ic_vietcombank.png",
46
+ "https://static.momocdn.net/app/img/kits/trustBanner/ic_bidv.png"
47
+ ),
48
+ momoImage = "https://static.momocdn.net/app/img/kits/trustBanner/ic_secu.png"
49
+ )
50
+
51
+ const val backgroundBlue = 0xFFF2F8FF
52
+ const val contentColor = 0xFF484848
53
+ const val subContentColor = 0xFFEB2F96
54
+
55
+ data class TrustBannerData(
56
+ val content: Map<String, String> = mapOf("vi" to "", "en" to ""),
57
+ val subContent: Map<String, String> = mapOf("vi" to "", "en" to ""),
58
+ val pciImage: String? = null,
59
+ val momoImage: String? = null,
60
+ val sslImage: String? = null,
61
+ val icons: List<String>? = null,
62
+ val urlConfig: String = ""
63
+ )
64
+
65
+ @Composable
66
+ fun TrustBanner(
67
+ serviceName: String = "",
68
+ screenName: String = "",
69
+ onPress: ((Map<String, String>) -> Unit)? = null,
70
+ trackEvent: ((String, Map<String, String>) -> Unit)? = null
71
+ ) {
72
+ val appConfig = AppConfig.current
73
+ val language = AppLanguage.current ?: "vi"
74
+ val trustBanner = appConfig?.trustBanner ?: defaultBanner
75
+ val trackParams = mapOf(
76
+ "service_name" to serviceName,
77
+ "screen_name" to screenName,
78
+ "component_name" to "logo_trust",
79
+ "url_config" to trustBanner.urlConfig
80
+ )
81
+
82
+ val application = ApplicationContext.current
83
+
84
+ Row(
85
+ modifier = Modifier
86
+ .clip(RoundedCornerShape(12.dp))
87
+ .background(color = Color(backgroundBlue))
88
+ .conditional(application.isShowBaselineDebug()) {
89
+ border(1.dp, Colors.blue_03)
90
+ }
91
+ .padding(12.dp)
92
+ .then(
93
+ if (onPress != null) {
94
+ Modifier.clickable {
95
+ trackEvent?.invoke(
96
+ "service_component_clicked", trackParams
97
+ )
98
+
99
+ onPress(
100
+ mapOf(
101
+ "service_name" to serviceName,
102
+ "screen_name" to screenName,
103
+ "url_config" to trustBanner.urlConfig,
104
+ )
105
+ )
106
+
107
+ }
108
+ } else {
109
+ Modifier.noFeedbackClickable {
110
+ trackEvent?.invoke(
111
+ "service_component_clicked", trackParams
112
+ )
113
+ }
114
+ }
115
+ )
116
+ ) {
117
+ if (trustBanner.momoImage != null) {
118
+ Image(
119
+ source = trustBanner.momoImage,
120
+ modifier = Modifier
121
+ .width(64.dp)
122
+ .height(64.dp)
123
+ )
124
+ }
125
+ Column(
126
+ modifier = Modifier
127
+ .padding(start = 10.dp)
128
+ ) {
129
+ Text(
130
+ text = trustBanner.content[language] ?: "",
131
+ modifier = Modifier.padding(bottom = 8.dp),
132
+ color = Color(contentColor),
133
+ style = Typography.descriptionDefaultRegular,
134
+ maxLines = 2
135
+ )
136
+ Row(
137
+ modifier = Modifier.fillMaxWidth(),
138
+ horizontalArrangement = Arrangement.SpaceBetween
139
+ ) {
140
+ Row(
141
+ verticalAlignment = Alignment.CenterVertically,
142
+ ) {
143
+ Text(
144
+ text = trustBanner.subContent[language] ?: "",
145
+ color = Color(subContentColor),
146
+ style = Typography.actionXsBold,
147
+ maxLines = 2
148
+ )
149
+ Icon(
150
+ source = "https://img.mservice.io/momo_app_v2/new_version/img/appx_icon/16_arrow_chevron_right_small.png",
151
+ color = Color(subContentColor),
152
+ )
153
+ }
154
+ Row {
155
+ if (trustBanner.pciImage != null) {
156
+ Image(
157
+ source = trustBanner.pciImage, modifier = Modifier
158
+ .padding(end = 4.dp)
159
+ .width(27.dp)
160
+ .height(20.dp), options = Options(
161
+ contentScale = ContentScale.Fit,
162
+ )
163
+ )
164
+ }
165
+ if (trustBanner.sslImage != null) {
166
+ Image(
167
+ source = trustBanner.sslImage, modifier = Modifier
168
+ .width(52.dp)
169
+ .height(20.dp),
170
+ options = Options(
171
+ contentScale = ContentScale.Fit,
172
+ )
173
+ )
174
+ }
175
+
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,208 @@
1
+ package vn.momo.kits.components.datetimepicker
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.border
5
+ import androidx.compose.foundation.layout.Column
6
+ import androidx.compose.foundation.layout.Row
7
+ import androidx.compose.foundation.layout.Spacer
8
+ import androidx.compose.foundation.layout.fillMaxWidth
9
+ import androidx.compose.foundation.layout.height
10
+ import androidx.compose.foundation.layout.padding
11
+ import androidx.compose.foundation.layout.width
12
+ import androidx.compose.runtime.Composable
13
+ import androidx.compose.runtime.LaunchedEffect
14
+ import androidx.compose.runtime.getValue
15
+ import androidx.compose.runtime.mutableStateOf
16
+ import androidx.compose.runtime.remember
17
+ import androidx.compose.runtime.setValue
18
+ import androidx.compose.runtime.snapshotFlow
19
+ import androidx.compose.ui.Alignment
20
+ import androidx.compose.ui.Modifier
21
+ import androidx.compose.ui.unit.dp
22
+ import kotlinx.coroutines.flow.collect
23
+ import kotlinx.coroutines.flow.mapNotNull
24
+ import kotlinx.coroutines.flow.onEach
25
+ import kotlinx.datetime.LocalDateTime
26
+ import kotlinx.datetime.number
27
+ import vn.momo.kits.application.ApplicationContext
28
+ import vn.momo.kits.application.MiniAppContext.Companion.isShowBaselineDebug
29
+ import vn.momo.kits.components.Text
30
+ import vn.momo.kits.const.AppTheme
31
+ import vn.momo.kits.const.Colors
32
+ import vn.momo.kits.const.Spacing
33
+ import vn.momo.kits.const.Typography
34
+ import vn.momo.kits.modifier.conditional
35
+
36
+ private val datePickerHeight = 210.dp
37
+ private val datePickerWithLabelsHeight = 238.dp
38
+
39
+ @Composable
40
+ fun DateTimePicker(
41
+ modifier: Modifier = Modifier,
42
+ format: String = "DD-MM-YYYY",
43
+ minuteInterval: Int = 1,
44
+ onChange: (LocalDateTime) -> Unit,
45
+ selectedValue: LocalDateTime? = null,
46
+ minDate: LocalDateTime? = null,
47
+ maxDate: LocalDateTime? = null,
48
+ arrayLabelTime: List<String> = emptyList()
49
+ ) {
50
+ val effectiveSelectedValue = remember(selectedValue) {
51
+ selectedValue ?: getCurrentDateTime()
52
+ }
53
+
54
+ val effectiveMinDate = remember(minDate) {
55
+ minDate ?: createRelativeDate(-10)
56
+ }
57
+
58
+ val effectiveMaxDate = remember(maxDate) {
59
+ maxDate ?: createRelativeDate(10)
60
+ }
61
+
62
+ val needCheckRange = remember(minDate, maxDate) {
63
+ minDate == null && maxDate == null
64
+ }
65
+
66
+ val initialValue = remember(effectiveMinDate, effectiveMaxDate, effectiveSelectedValue) {
67
+ when {
68
+ !needCheckRange -> effectiveSelectedValue
69
+ effectiveSelectedValue < effectiveMinDate -> effectiveMinDate
70
+ effectiveSelectedValue > effectiveMaxDate -> effectiveMaxDate
71
+ else -> effectiveSelectedValue
72
+ }
73
+ }
74
+
75
+ var currentDate by remember(initialValue) {
76
+ mutableStateOf(
77
+ PickerData(
78
+ day = initialValue.dayOfMonth,
79
+ month = initialValue.month.number,
80
+ year = initialValue.year,
81
+ hour = initialValue.hour,
82
+ minute = initialValue.minute
83
+ )
84
+ )
85
+ }
86
+
87
+ val onWheelChangeValue = remember(currentDate, effectiveMinDate, effectiveMaxDate) {
88
+ { name: String, value: String ->
89
+ var day = if (name == "day") value.toInt() else currentDate.day
90
+ var month = if (name == "month") value.toInt() else currentDate.month
91
+ val year = if (name == "year") value.toInt() else currentDate.year
92
+ val hour = if (name == "hour") value.toInt() else currentDate.hour
93
+ val minute = if (name == "minute") value.toInt() else currentDate.minute
94
+ val timeMode = if (name == "timeMode") value else currentDate.timeMode
95
+ if (name == "year") {
96
+ month = when (year) {
97
+ effectiveMaxDate.year -> month.coerceIn(
98
+ 1,
99
+ effectiveMaxDate.monthNumber
100
+ )
101
+ effectiveMinDate.year -> month.coerceIn(
102
+ effectiveMinDate.monthNumber,
103
+ 12,
104
+ )
105
+ else -> month
106
+ }
107
+ }
108
+ if (name == "month" || name == "year") {
109
+ val maxDayOfMonth = when (month) {
110
+ 4, 6, 9, 11 -> 30
111
+ 2 -> if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) 29 else 28
112
+ else -> 31
113
+ }
114
+
115
+ day = when {
116
+ year == effectiveMaxDate.year && month == effectiveMaxDate.monthNumber ->
117
+ day.coerceIn(1, effectiveMaxDate.dayOfMonth)
118
+
119
+ year == effectiveMinDate.year && month == effectiveMinDate.monthNumber ->
120
+ day.coerceIn(effectiveMinDate.dayOfMonth, maxDayOfMonth)
121
+
122
+ day > maxDayOfMonth -> maxDayOfMonth
123
+ else -> day
124
+ }
125
+ }
126
+ currentDate = PickerData(
127
+ day = day,
128
+ month = month,
129
+ year = year,
130
+ hour = hour,
131
+ minute = minute,
132
+ timeMode = timeMode,
133
+ )
134
+ }
135
+ }
136
+
137
+ LaunchedEffect(effectiveMinDate, effectiveMaxDate) {
138
+ snapshotFlow { currentDate }
139
+ .mapNotNull {
140
+ val dateTime = it.toLocalDateTime()
141
+ if (!needCheckRange || dateTime in effectiveMinDate..effectiveMaxDate) dateTime
142
+ else null
143
+ }
144
+ .onEach(onChange)
145
+ .collect()
146
+ }
147
+
148
+ val pickerHeight = if (arrayLabelTime.isNotEmpty())
149
+ datePickerWithLabelsHeight else
150
+ datePickerHeight
151
+
152
+ val application = ApplicationContext.current
153
+
154
+ Row(
155
+ modifier = modifier
156
+ .fillMaxWidth()
157
+ .height(pickerHeight)
158
+ .background(AppTheme.current.colors.background.surface)
159
+ .conditional(application.isShowBaselineDebug()) {
160
+ border(1.dp, Colors.blue_03)
161
+ }
162
+ .padding(horizontal = Spacing.M),
163
+ verticalAlignment = Alignment.CenterVertically
164
+ ) {
165
+ val dateComponents = getDateComponents(
166
+ format,
167
+ currentDate,
168
+ effectiveMinDate,
169
+ effectiveMaxDate,
170
+ minuteInterval,
171
+ )
172
+ dateComponents.forEachIndexed { index, component ->
173
+ val hasLabel = index < arrayLabelTime.size && arrayLabelTime[index].isNotEmpty()
174
+
175
+ Column(
176
+ horizontalAlignment = Alignment.CenterHorizontally,
177
+ modifier = Modifier.weight(1f)
178
+ ) {
179
+ if (hasLabel) {
180
+ Text(
181
+ text = arrayLabelTime[index],
182
+ style = Typography.actionSBold,
183
+ modifier = Modifier.padding(bottom = Spacing.S)
184
+ )
185
+ }
186
+
187
+ WheelPicker(
188
+ name = component.name,
189
+ data = component.data,
190
+ selectedData = when (component.name) {
191
+ "day" -> paddingNum(currentDate.day)
192
+ "month" -> paddingNum(currentDate.month)
193
+ "year" -> currentDate.year.toString()
194
+ "hour" -> paddingNum(currentDate.hour)
195
+ "minute" -> paddingNum(currentDate.minute)
196
+ "timeMode" -> currentDate.timeMode
197
+ else -> ""
198
+ },
199
+ onChange = onWheelChangeValue,
200
+ )
201
+ }
202
+
203
+ if (index < dateComponents.size - 1) {
204
+ Spacer(modifier = Modifier.width(Spacing.M))
205
+ }
206
+ }
207
+ }
208
+ }
@@ -0,0 +1,29 @@
1
+ package vn.momo.kits.components.datetimepicker
2
+
3
+ import kotlinx.datetime.LocalDateTime
4
+
5
+ data class PickerData(
6
+ var day: Int,
7
+ var month: Int,
8
+ var year: Int,
9
+ var hour: Int = 0,
10
+ var minute: Int = 0,
11
+ var timeMode: String = ""
12
+ ) {
13
+ fun toLocalDateTime(): LocalDateTime {
14
+ return LocalDateTime(
15
+ year = year,
16
+ monthNumber = month,
17
+ dayOfMonth = day,
18
+ hour = hour,
19
+ minute = minute,
20
+ second = 0,
21
+ nanosecond = 0
22
+ )
23
+ }
24
+ }
25
+
26
+ data class DateComponent(
27
+ val name: String,
28
+ val data: List<String>
29
+ )