@momo-kits/native-kits 0.163.1-beta.3 → 0.163.1-beta.7-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 (136) hide show
  1. package/build.gradle.kts +11 -0
  2. package/compose/build.gradle.kts +189 -0
  3. package/compose/build.gradle.kts.backup +189 -0
  4. package/compose/compose.podspec +47 -0
  5. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +6 -0
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +123 -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 +52 -0
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +108 -0
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +183 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +207 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +39 -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 +294 -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 +826 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +107 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +378 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +82 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +338 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +175 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +354 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +113 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +89 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +128 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +209 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +76 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +140 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +188 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +112 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +477 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +114 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +214 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +240 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +216 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +259 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +182 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +343 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +84 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +328 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +97 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +310 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +59 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +90 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +323 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +217 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +473 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +122 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +199 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +91 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +470 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +88 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +134 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +203 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +498 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +175 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +182 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +193 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +234 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +188 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +188 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +269 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +52 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +66 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +104 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +48 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +253 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +129 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +94 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +175 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +360 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +557 -0
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +155 -0
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +225 -0
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +169 -0
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +320 -0
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +81 -0
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +309 -0
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +34 -0
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +360 -0
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +132 -0
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +128 -0
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +70 -0
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +58 -0
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +55 -0
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +105 -0
  126. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +32 -0
  127. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +184 -0
  128. package/gradle/libs.versions.toml +67 -0
  129. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  130. package/gradle/wrapper/gradle-wrapper.properties +8 -0
  131. package/gradle.properties +26 -0
  132. package/gradlew +252 -0
  133. package/gradlew.bat +94 -0
  134. package/local.properties +8 -0
  135. package/package.json +1 -1
  136. package/settings.gradle.kts +64 -0
@@ -0,0 +1,175 @@
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.LocalLocalize
22
+ import vn.momo.kits.application.IsShowBaseLineDebug
23
+ import vn.momo.kits.const.Colors
24
+ import vn.momo.kits.const.Typography
25
+ import vn.momo.kits.modifier.conditional
26
+ import vn.momo.kits.modifier.noFeedbackClickable
27
+
28
+ val defaultBanner = TrustBannerData(
29
+ content = mapOf(
30
+ "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.",
31
+ "en" to "Ensuring financial security and data privacy is MoMo's highest priority."
32
+ ),
33
+ subContent = mapOf(
34
+ "vi" to "Tìm hiểu thêm",
35
+ "en" to "Learn more"
36
+ ),
37
+ pciImage = "https://static.momocdn.net/app/img/kits/trustBanner/pci_dss.png",
38
+ sslImage = "https://static.momocdn.net/app/img/kits/trustBanner/ssl.png",
39
+ urlConfig = "login_and_security",
40
+ icons = listOf(
41
+ "https://static.momocdn.net/app/img/kits/trustBanner/ic_viettinbank.png",
42
+ "https://static.momocdn.net/app/img/kits/trustBanner/ic_agribank.png",
43
+ "https://static.momocdn.net/app/img/kits/trustBanner/ic_vietcombank.png",
44
+ "https://static.momocdn.net/app/img/kits/trustBanner/ic_bidv.png"
45
+ ),
46
+ momoImage = "https://static.momocdn.net/app/img/kits/trustBanner/ic_secu.png"
47
+ )
48
+
49
+ const val backgroundBlue = 0xFFF2F8FF
50
+ const val contentColor = 0xFF484848
51
+ const val subContentColor = 0xFFEB2F96
52
+
53
+ data class TrustBannerData(
54
+ val content: Map<String, String> = mapOf("vi" to "", "en" to ""),
55
+ val subContent: Map<String, String> = mapOf("vi" to "", "en" to ""),
56
+ val pciImage: String? = null,
57
+ val momoImage: String? = null,
58
+ val sslImage: String? = null,
59
+ val icons: List<String>? = null,
60
+ val urlConfig: String = ""
61
+ )
62
+
63
+ @Composable
64
+ fun TrustBanner(
65
+ serviceName: String = "",
66
+ screenName: String = "",
67
+ onPress: ((Map<String, String>) -> Unit)? = null,
68
+ trackEvent: ((String, Map<String, String>) -> Unit)? = null
69
+ ) {
70
+ val localize = LocalLocalize.current
71
+ val trustBanner = defaultBanner
72
+ val trackParams = mapOf(
73
+ "service_name" to serviceName,
74
+ "screen_name" to screenName,
75
+ "component_name" to "logo_trust",
76
+ "url_config" to trustBanner.urlConfig
77
+ )
78
+
79
+ Row(
80
+ modifier = Modifier
81
+ .clip(RoundedCornerShape(12.dp))
82
+ .background(color = Color(backgroundBlue))
83
+ .conditional(IsShowBaseLineDebug) {
84
+ border(1.dp, Colors.blue_03)
85
+ }
86
+ .padding(12.dp)
87
+ .then(
88
+ if (onPress != null) {
89
+ Modifier.clickable {
90
+ trackEvent?.invoke(
91
+ "service_component_clicked", trackParams
92
+ )
93
+
94
+ onPress(
95
+ mapOf(
96
+ "service_name" to serviceName,
97
+ "screen_name" to screenName,
98
+ "url_config" to trustBanner.urlConfig,
99
+ )
100
+ )
101
+
102
+ }
103
+ } else {
104
+ Modifier.noFeedbackClickable {
105
+ trackEvent?.invoke(
106
+ "service_component_clicked", trackParams
107
+ )
108
+ }
109
+ }
110
+ )
111
+ ) {
112
+ if (trustBanner.momoImage != null) {
113
+ Image(
114
+ source = trustBanner.momoImage,
115
+ modifier = Modifier
116
+ .width(64.dp)
117
+ .height(64.dp)
118
+ )
119
+ }
120
+ Column(
121
+ modifier = Modifier
122
+ .padding(start = 10.dp)
123
+ ) {
124
+ Text(
125
+ text = localize.translateData(trustBanner.content),
126
+ modifier = Modifier.padding(bottom = 8.dp),
127
+ color = Color(contentColor),
128
+ style = Typography.descriptionDefaultRegular,
129
+ maxLines = 2
130
+ )
131
+ Row(
132
+ modifier = Modifier.fillMaxWidth(),
133
+ horizontalArrangement = Arrangement.SpaceBetween
134
+ ) {
135
+ Row(
136
+ verticalAlignment = Alignment.CenterVertically,
137
+ ) {
138
+ Text(
139
+ text = localize.translateData(trustBanner.subContent),
140
+ color = Color(subContentColor),
141
+ style = Typography.actionXsBold,
142
+ maxLines = 2
143
+ )
144
+ Icon(
145
+ source = "https://img.mservice.io/momo_app_v2/new_version/img/appx_icon/16_arrow_chevron_right_small.png",
146
+ color = Color(subContentColor),
147
+ )
148
+ }
149
+ Row {
150
+ if (trustBanner.pciImage != null) {
151
+ Image(
152
+ source = trustBanner.pciImage, modifier = Modifier
153
+ .padding(end = 4.dp)
154
+ .width(27.dp)
155
+ .height(20.dp), options = Options(
156
+ contentScale = ContentScale.Fit,
157
+ )
158
+ )
159
+ }
160
+ if (trustBanner.sslImage != null) {
161
+ Image(
162
+ source = trustBanner.sslImage, modifier = Modifier
163
+ .width(52.dp)
164
+ .height(20.dp),
165
+ options = Options(
166
+ contentScale = ContentScale.Fit,
167
+ )
168
+ )
169
+ }
170
+
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }
@@ -0,0 +1,182 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.border
5
+ import androidx.compose.foundation.horizontalScroll
6
+ import androidx.compose.foundation.layout.*
7
+ import androidx.compose.foundation.rememberScrollState
8
+ import androidx.compose.foundation.shape.RoundedCornerShape
9
+ import androidx.compose.runtime.Composable
10
+ import androidx.compose.runtime.remember
11
+ import androidx.compose.ui.Alignment
12
+ import androidx.compose.ui.Modifier
13
+ import androidx.compose.ui.draw.clip
14
+ import androidx.compose.ui.draw.drawBehind
15
+ import androidx.compose.ui.geometry.CornerRadius
16
+ import androidx.compose.ui.graphics.Color
17
+ import androidx.compose.ui.graphics.PathEffect
18
+ import androidx.compose.ui.graphics.drawscope.Stroke
19
+ import androidx.compose.ui.unit.Dp
20
+ import androidx.compose.ui.unit.dp
21
+ import vn.momo.kits.application.IsShowBaseLineDebug
22
+ import vn.momo.kits.const.*
23
+ import vn.momo.kits.modifier.activeOpacityClickable
24
+ import vn.momo.kits.modifier.conditional
25
+
26
+ data class UploadImage(
27
+ val uri: String? = null,
28
+ val loading: Boolean = false,
29
+ )
30
+
31
+ @Composable
32
+ fun Uploader(
33
+ images: List<UploadImage>,
34
+ modifier: Modifier = Modifier,
35
+ numberOfImages: Int = 1,
36
+ disabled: Boolean = false,
37
+ width: Dp = 64.dp,
38
+ height: Dp = 64.dp,
39
+ onAdd: () -> Unit = {},
40
+ onCancel: ((image: UploadImage, index: Int) -> Unit)? = null,
41
+ onPressImage: (image: UploadImage, index: Int) -> Unit = { _, _ -> },
42
+ ) {
43
+ val shouldShowPicker = remember(images.size, numberOfImages) {
44
+ images.size < numberOfImages
45
+ }
46
+
47
+ Row(
48
+ modifier = modifier
49
+ .conditional(IsShowBaseLineDebug) { border(1.dp, Colors.blue_03) },
50
+ horizontalArrangement = Arrangement.spacedBy(Spacing.S),
51
+ verticalAlignment = Alignment.Top,
52
+ ) {
53
+ if (shouldShowPicker) {
54
+ UploaderPickerCell(
55
+ disabled = disabled,
56
+ width = width,
57
+ height = height,
58
+ onAdd = onAdd,
59
+ )
60
+ }
61
+
62
+ Row(
63
+ modifier = Modifier.horizontalScroll(rememberScrollState()),
64
+ horizontalArrangement = Arrangement.spacedBy(Spacing.S),
65
+ ) {
66
+ images.forEachIndexed { index, image ->
67
+ UploaderImageItem(
68
+ image = image,
69
+ width = width,
70
+ height = height,
71
+ index = index,
72
+ onCancel = onCancel,
73
+ onPressImage = { onPressImage(image, index) },
74
+ )
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ @Composable
81
+ private fun UploaderPickerCell(
82
+ disabled: Boolean,
83
+ width: Dp,
84
+ height: Dp,
85
+ onAdd: () -> Unit,
86
+ ) {
87
+ val theme = AppTheme.current
88
+ val mainColor = if (disabled) theme.colors.text.disable else theme.colors.text.hint
89
+ val borderColor = if (disabled) theme.colors.border.disable else theme.colors.border.default
90
+
91
+ Box(
92
+ modifier = Modifier
93
+ .size(width = width, height = height)
94
+ .clip(RoundedCornerShape(Radius.XS))
95
+ .dashedBorder(color = borderColor, radius = Radius.XS)
96
+ .activeOpacityClickable(enabled = !disabled, onClick = onAdd),
97
+ contentAlignment = Alignment.Center,
98
+ ) {
99
+ Column(
100
+ horizontalAlignment = Alignment.CenterHorizontally,
101
+ verticalArrangement = Arrangement.spacedBy(Spacing.XXS),
102
+ ) {
103
+ Icon(
104
+ source = "16_navigation_plus",
105
+ color = mainColor,
106
+ size = 16.dp,
107
+ )
108
+ Text(
109
+ text = "Thêm hình",
110
+ style = Typography.descriptionXsRegular,
111
+ color = mainColor,
112
+ )
113
+ }
114
+ }
115
+ }
116
+
117
+ @Composable
118
+ private fun UploaderImageItem(
119
+ image: UploadImage,
120
+ width: Dp,
121
+ height: Dp,
122
+ index: Int,
123
+ onCancel: ((image: UploadImage, index: Int) -> Unit)?,
124
+ onPressImage: () -> Unit,
125
+ ) {
126
+ Box(
127
+ modifier = Modifier
128
+ .size(width = width, height = height)
129
+ .activeOpacityClickable(onClick = onPressImage),
130
+ ) {
131
+ Image(
132
+ source = image.uri ?: "",
133
+ modifier = Modifier
134
+ .fillMaxSize()
135
+ .clip(RoundedCornerShape(Radius.XS)),
136
+ )
137
+
138
+ if (onCancel != null && !image.loading) {
139
+ Icon(
140
+ source = "navigation_close_circle_full",
141
+ size = 16.dp,
142
+ color = null,
143
+ modifier = Modifier
144
+ .align(Alignment.TopEnd)
145
+ .padding(top = Spacing.XXS, end = Spacing.XXS)
146
+ .activeOpacityClickable { onCancel(image, index) },
147
+ )
148
+ }
149
+
150
+ if (image.loading) {
151
+ Box(
152
+ modifier = Modifier
153
+ .fillMaxSize()
154
+ .clip(RoundedCornerShape(Radius.XS))
155
+ .background(Color(0x66FFFFFF)),
156
+ contentAlignment = Alignment.Center,
157
+ ) {
158
+ Skeleton()
159
+ }
160
+ }
161
+ }
162
+ }
163
+
164
+ private fun Modifier.dashedBorder(
165
+ color: Color,
166
+ radius: Dp,
167
+ strokeWidth: Dp = 1.dp,
168
+ dashWidth: Float = 10f,
169
+ dashGap: Float = 6f,
170
+ ): Modifier = this.drawBehind {
171
+ val strokePx = strokeWidth.toPx()
172
+ val pathEffect = PathEffect.dashPathEffect(floatArrayOf(dashWidth, dashGap), 0f)
173
+ val cornerRadiusPx = radius.toPx()
174
+ drawRoundRect(
175
+ color = color,
176
+ style = Stroke(
177
+ width = strokePx,
178
+ pathEffect = pathEffect,
179
+ ),
180
+ cornerRadius = CornerRadius(cornerRadiusPx, cornerRadiusPx),
181
+ )
182
+ }
@@ -0,0 +1,193 @@
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.*
6
+ import androidx.compose.runtime.*
7
+ import androidx.compose.ui.Alignment
8
+ import androidx.compose.ui.Modifier
9
+ import androidx.compose.ui.unit.dp
10
+ import kotlinx.coroutines.flow.collect
11
+ import kotlinx.coroutines.flow.mapNotNull
12
+ import kotlinx.coroutines.flow.onEach
13
+ import kotlinx.datetime.LocalDateTime
14
+ import kotlinx.datetime.number
15
+ import vn.momo.kits.application.IsShowBaseLineDebug
16
+ import vn.momo.kits.components.Text
17
+ import vn.momo.kits.const.AppTheme
18
+ import vn.momo.kits.const.Colors
19
+ import vn.momo.kits.const.Spacing
20
+ import vn.momo.kits.const.Typography
21
+ import vn.momo.kits.modifier.conditional
22
+
23
+ private val datePickerHeight = 210.dp
24
+ private val datePickerWithLabelsHeight = 238.dp
25
+
26
+ @Composable
27
+ fun DateTimePicker(
28
+ modifier: Modifier = Modifier,
29
+ format: String = "DD-MM-YYYY",
30
+ minuteInterval: Int = 1,
31
+ onChange: (LocalDateTime) -> Unit,
32
+ selectedValue: LocalDateTime? = null,
33
+ minDate: LocalDateTime? = null,
34
+ maxDate: LocalDateTime? = null,
35
+ arrayLabelTime: List<String> = emptyList()
36
+ ) {
37
+ val effectiveSelectedValue = remember(selectedValue) {
38
+ selectedValue ?: getCurrentDateTime()
39
+ }
40
+
41
+ val effectiveMinDate = remember(minDate) {
42
+ minDate ?: createRelativeDate(-10)
43
+ }
44
+
45
+ val effectiveMaxDate = remember(maxDate) {
46
+ maxDate ?: createRelativeDate(10)
47
+ }
48
+
49
+ val needCheckRange = remember(minDate, maxDate) {
50
+ minDate == null && maxDate == null
51
+ }
52
+
53
+ val initialValue = remember(effectiveMinDate, effectiveMaxDate, effectiveSelectedValue) {
54
+ when {
55
+ !needCheckRange -> effectiveSelectedValue
56
+ effectiveSelectedValue < effectiveMinDate -> effectiveMinDate
57
+ effectiveSelectedValue > effectiveMaxDate -> effectiveMaxDate
58
+ else -> effectiveSelectedValue
59
+ }
60
+ }
61
+
62
+ var currentDate by remember(initialValue) {
63
+ mutableStateOf(
64
+ PickerData(
65
+ day = initialValue.day,
66
+ month = initialValue.month.number,
67
+ year = initialValue.year,
68
+ hour = initialValue.hour,
69
+ minute = initialValue.minute
70
+ )
71
+ )
72
+ }
73
+
74
+ val onWheelChangeValue = remember(currentDate, effectiveMinDate, effectiveMaxDate) {
75
+ { name: String, value: String ->
76
+ var day = if (name == "day") value.toInt() else currentDate.day
77
+ var month = if (name == "month") value.toInt() else currentDate.month
78
+ val year = if (name == "year") value.toInt() else currentDate.year
79
+ val hour = if (name == "hour") value.toInt() else currentDate.hour
80
+ val minute = if (name == "minute") value.toInt() else currentDate.minute
81
+ val timeMode = if (name == "timeMode") value else currentDate.timeMode
82
+ if (name == "year") {
83
+ month = when (year) {
84
+ effectiveMaxDate.year -> month.coerceIn(
85
+ 1,
86
+ effectiveMaxDate.month.number
87
+ )
88
+ effectiveMinDate.year -> month.coerceIn(
89
+ effectiveMinDate.month.number,
90
+ 12,
91
+ )
92
+ else -> month
93
+ }
94
+ }
95
+ if (name == "month" || name == "year") {
96
+ val maxDayOfMonth = when (month) {
97
+ 4, 6, 9, 11 -> 30
98
+ 2 -> if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) 29 else 28
99
+ else -> 31
100
+ }
101
+
102
+ day = when {
103
+ year == effectiveMaxDate.year && month == effectiveMaxDate.month.number ->
104
+ day.coerceIn(1, effectiveMaxDate.day)
105
+
106
+ year == effectiveMinDate.year && month == effectiveMinDate.month.number ->
107
+ day.coerceIn(effectiveMinDate.day, maxDayOfMonth)
108
+
109
+ day > maxDayOfMonth -> maxDayOfMonth
110
+ else -> day
111
+ }
112
+ }
113
+ currentDate = PickerData(
114
+ day = day,
115
+ month = month,
116
+ year = year,
117
+ hour = hour,
118
+ minute = minute,
119
+ timeMode = timeMode,
120
+ )
121
+ }
122
+ }
123
+
124
+ LaunchedEffect(effectiveMinDate, effectiveMaxDate) {
125
+ snapshotFlow { currentDate }
126
+ .mapNotNull {
127
+ val dateTime = it.toLocalDateTime()
128
+ if (!needCheckRange || dateTime in effectiveMinDate..effectiveMaxDate) dateTime
129
+ else null
130
+ }
131
+ .onEach(onChange)
132
+ .collect()
133
+ }
134
+
135
+ val pickerHeight = if (arrayLabelTime.isNotEmpty())
136
+ datePickerWithLabelsHeight else
137
+ datePickerHeight
138
+
139
+ Row(
140
+ modifier = modifier
141
+ .fillMaxWidth()
142
+ .height(pickerHeight)
143
+ .background(AppTheme.current.colors.background.surface)
144
+ .conditional(IsShowBaseLineDebug) {
145
+ border(1.dp, Colors.blue_03)
146
+ }
147
+ .padding(horizontal = Spacing.M),
148
+ verticalAlignment = Alignment.CenterVertically
149
+ ) {
150
+ val dateComponents = getDateComponents(
151
+ format,
152
+ currentDate,
153
+ effectiveMinDate,
154
+ effectiveMaxDate,
155
+ minuteInterval,
156
+ )
157
+ dateComponents.forEachIndexed { index, component ->
158
+ val hasLabel = index < arrayLabelTime.size && arrayLabelTime[index].isNotEmpty()
159
+
160
+ Column(
161
+ horizontalAlignment = Alignment.CenterHorizontally,
162
+ modifier = Modifier.weight(1f)
163
+ ) {
164
+ if (hasLabel) {
165
+ Text(
166
+ text = arrayLabelTime[index],
167
+ style = Typography.actionSBold,
168
+ modifier = Modifier.padding(bottom = Spacing.S)
169
+ )
170
+ }
171
+
172
+ WheelPicker(
173
+ name = component.name,
174
+ data = component.data,
175
+ selectedData = when (component.name) {
176
+ "day" -> paddingNum(currentDate.day)
177
+ "month" -> paddingNum(currentDate.month)
178
+ "year" -> currentDate.year.toString()
179
+ "hour" -> paddingNum(currentDate.hour)
180
+ "minute" -> paddingNum(currentDate.minute)
181
+ "timeMode" -> currentDate.timeMode
182
+ else -> ""
183
+ },
184
+ onChange = onWheelChangeValue,
185
+ )
186
+ }
187
+
188
+ if (index < dateComponents.size - 1) {
189
+ Spacer(modifier = Modifier.width(Spacing.M))
190
+ }
191
+ }
192
+ }
193
+ }
@@ -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
+ month = month,
17
+ day = 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
+ )