@momo-kits/native-kits 0.152.4-beta.5 → 0.152.4-beta.7

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 (156) hide show
  1. package/CODE_OF_CONDUCT.md +133 -0
  2. package/CONTRIBUTING.md +114 -0
  3. package/LICENSE +20 -0
  4. package/README.md +7 -0
  5. package/build.gradle.kts +32 -0
  6. package/compose/MoMoComposeKits.podspec +54 -0
  7. package/compose/build.gradle.kts +149 -0
  8. package/compose/src/androidMain/AndroidManifest.xml +2 -0
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +105 -0
  10. package/compose/src/commonMain/composeResources/files/lottie_circle_loader.json +1 -0
  11. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  12. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  21. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  22. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  23. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  24. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +57 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +306 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +715 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +214 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +392 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +77 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +27 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +334 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +345 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +90 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +131 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +58 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +143 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +179 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +111 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +384 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +160 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +234 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +223 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +232 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +236 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +228 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +50 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +34 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +85 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +33 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +338 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +95 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +64 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +89 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +91 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +84 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +208 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +172 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +199 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +237 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +13 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +191 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +258 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +59 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +49 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +232 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +111 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +94 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +159 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +302 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScaleSizeScope.kt +17 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +484 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +169 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +216 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +180 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +251 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +31 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +385 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +123 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +38 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +62 -0
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +88 -0
  109. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +144 -0
  110. package/gradle.properties +19 -0
  111. package/gradlew +240 -0
  112. package/gradlew.bat +91 -0
  113. package/ios/Application/ApplicationEnvironment.swift +50 -0
  114. package/ios/Application/Components.swift +263 -0
  115. package/ios/Application/ComposeApi.swift +22 -0
  116. package/ios/Application/FloatingButton.swift +172 -0
  117. package/ios/Application/HeaderRight.swift +271 -0
  118. package/ios/Application/Screen.swift +249 -0
  119. package/ios/Badge/BadgeDot.swift +31 -0
  120. package/ios/Button/Button.swift +211 -0
  121. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
  122. package/ios/Checkbox/Checkbox.swift +81 -0
  123. package/ios/Chip/Chip.swift +96 -0
  124. package/ios/Colors+Radius+Spacing/Colors.swift +172 -0
  125. package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
  126. package/ios/Colors+Radius+Spacing/Spacing.swift +12 -0
  127. package/ios/Extensions/Color++.swift +25 -0
  128. package/ios/Icon/Icon.swift +51 -0
  129. package/ios/Image/Image.swift +70 -0
  130. package/ios/Input/Input.swift +207 -0
  131. package/ios/Input/InputPhoneNumber.swift +176 -0
  132. package/ios/Input/InputSearch.swift +238 -0
  133. package/ios/Input/InputTextArea.swift +242 -0
  134. package/ios/Lottie/LottieView.swift +86 -0
  135. package/ios/OTPKeyboard/KeyboardButton.swift +41 -0
  136. package/ios/OTPKeyboard/OTPKeyboard.swift +145 -0
  137. package/ios/Popup/PopupDisplay.swift +284 -0
  138. package/ios/Popup/PopupInput.swift +96 -0
  139. package/ios/Popup/PopupPromotion.swift +73 -0
  140. package/ios/PopupView/FullscreenPopup.swift +251 -0
  141. package/ios/PopupView/Modifiers.swift +158 -0
  142. package/ios/PopupView/PopupView.swift +289 -0
  143. package/ios/PopupView/Utils++.swift +281 -0
  144. package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
  145. package/ios/Swipeable/SwipeCell.swift +278 -0
  146. package/ios/Swipeable/SwipeCellModel.swift +86 -0
  147. package/ios/Switch/Switch.swift +44 -0
  148. package/ios/Template/Logo/Logo.swift +75 -0
  149. package/ios/Template/TrustBanner/TrustBanner.swift +120 -0
  150. package/ios/Theme.md +18 -0
  151. package/ios/Typography/Text.swift +140 -0
  152. package/ios/Typography/Typography.swift +95 -0
  153. package/ios/native-kits.podspec +18 -0
  154. package/package.json +6 -7
  155. package/settings.gradle.kts +25 -0
  156. package/shared/build.gradle.kts +0 -74
@@ -0,0 +1,143 @@
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.Box
7
+ import androidx.compose.foundation.layout.size
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.graphics.Color
15
+ import androidx.compose.ui.unit.Dp
16
+ import androidx.compose.ui.unit.dp
17
+ import vn.momo.kits.const.AppTheme
18
+ import vn.momo.kits.const.Colors
19
+ import vn.momo.kits.const.Radius
20
+
21
+ data class IconSpecs(
22
+ val width: Dp,
23
+ val height: Dp,
24
+ val radius: Dp,
25
+ val size: Dp
26
+ )
27
+
28
+ enum class IconSize(val value: IconSpecs) {
29
+ LARGE(
30
+ IconSpecs(
31
+ height = 48.dp,
32
+ radius = Radius.XL,
33
+ width = 48.dp,
34
+ size = 48.dp
35
+ )
36
+ ),
37
+ SMALL(
38
+ IconSpecs(
39
+ height = 40.dp,
40
+ radius = Radius.XL,
41
+ width = 40.dp,
42
+ size = 40.dp
43
+ )
44
+ )
45
+ }
46
+
47
+ // Pre-computed shape to avoid repeated creation
48
+ private val iconButtonShape = RoundedCornerShape(Radius.XL)
49
+
50
+ // Cache for icon sizes to avoid repeated calculations
51
+ private val iconSizeMap = mapOf(
52
+ IconSize.SMALL to 16.dp,
53
+ IconSize.LARGE to 24.dp
54
+ )
55
+
56
+ @Composable
57
+ fun getIconStyle(type: ButtonType, color: Color? = null): Modifier {
58
+ val theme = AppTheme.current
59
+
60
+ return remember(type, color, theme) {
61
+ when (type) {
62
+ ButtonType.DISABLED -> Modifier
63
+ .background(theme.colors.background.disable, iconButtonShape)
64
+ .border(0.dp, Color.Unspecified, iconButtonShape)
65
+
66
+ ButtonType.PRIMARY -> Modifier
67
+ .background(theme.colors.primary, iconButtonShape)
68
+ .border(0.dp, Color.Unspecified, iconButtonShape)
69
+
70
+ ButtonType.SECONDARY -> Modifier
71
+ .background(theme.colors.background.surface, iconButtonShape)
72
+ .border(1.dp, theme.colors.border.default, iconButtonShape)
73
+
74
+ ButtonType.OUTLINE -> Modifier
75
+ .background(theme.colors.background.surface, iconButtonShape)
76
+ .border(1.dp, color ?: theme.colors.primary, iconButtonShape)
77
+
78
+ ButtonType.TONAL -> Modifier
79
+ .background(theme.colors.background.tonal, iconButtonShape)
80
+ .border(0.dp, Color.Unspecified, iconButtonShape)
81
+
82
+ ButtonType.DANGER -> Modifier
83
+ .background(theme.colors.error.primary, iconButtonShape)
84
+ .border(0.dp, Color.Unspecified, iconButtonShape)
85
+
86
+ ButtonType.TEXT -> Modifier
87
+ }
88
+ }
89
+ }
90
+
91
+ @Composable
92
+ fun getIconColor(type: ButtonType): Color {
93
+ val theme = AppTheme.current
94
+ return remember(type, theme) {
95
+ when (type) {
96
+ ButtonType.DISABLED -> theme.colors.text.disable
97
+ ButtonType.PRIMARY -> Colors.black_01
98
+ ButtonType.SECONDARY -> theme.colors.text.default
99
+ ButtonType.OUTLINE -> theme.colors.primary
100
+ ButtonType.TONAL -> theme.colors.primary
101
+ ButtonType.DANGER -> Colors.black_01
102
+ ButtonType.TEXT -> theme.colors.primary
103
+ }
104
+ }
105
+ }
106
+
107
+ @Composable
108
+ fun IconButton(
109
+ onClick: () -> Unit,
110
+ type: ButtonType = ButtonType.PRIMARY,
111
+ size: IconSize = IconSize.SMALL,
112
+ icon: String = "",
113
+ ) {
114
+ // Memoize icon size calculation
115
+ val iconSize = remember(size) {
116
+ iconSizeMap[size] ?: 16.dp
117
+ }
118
+
119
+ // Memoize enabled state
120
+ val isEnabled = remember(type) {
121
+ type != ButtonType.DISABLED
122
+ }
123
+
124
+ // Memoize radius for clipping
125
+ val radius = remember(size) {
126
+ size.value.radius
127
+ }
128
+
129
+ Box(
130
+ modifier = Modifier
131
+ .size(size.value.size)
132
+ .then(getIconStyle(type))
133
+ .clip(RoundedCornerShape(radius))
134
+ .clickable(enabled = isEnabled, onClick = onClick),
135
+ contentAlignment = Alignment.Center
136
+ ) {
137
+ Icon(
138
+ source = icon,
139
+ color = getIconColor(type),
140
+ size = iconSize,
141
+ )
142
+ }
143
+ }
@@ -0,0 +1,179 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.foundation.layout.BoxWithConstraints
4
+ import androidx.compose.runtime.Composable
5
+ import androidx.compose.runtime.getValue
6
+ import androidx.compose.runtime.mutableStateOf
7
+ import androidx.compose.runtime.remember
8
+ import androidx.compose.runtime.setValue
9
+ import androidx.compose.ui.Alignment
10
+ import androidx.compose.ui.Modifier
11
+ import androidx.compose.ui.graphics.ColorFilter
12
+ import androidx.compose.ui.graphics.DefaultAlpha
13
+ import androidx.compose.ui.graphics.painter.Painter
14
+ import androidx.compose.ui.layout.ContentScale
15
+ import androidx.compose.ui.semantics.contentDescription
16
+ import androidx.compose.ui.semantics.semantics
17
+ import androidx.compose.ui.platform.LocalDensity
18
+ import coil3.compose.AsyncImage
19
+ import vn.momo.kits.const.AppTheme
20
+
21
+ data class Options(
22
+ val alignment: Alignment = Alignment.TopStart,
23
+ val contentScale: ContentScale = ContentScale.Crop,
24
+ val colorFilter: ColorFilter? = null,
25
+ val alpha: Float = DefaultAlpha,
26
+ )
27
+
28
+ enum class ImageState {
29
+ Loading, Success, Error
30
+ }
31
+
32
+ // Cached domain set for better performance
33
+ private val supportedDomains = setOf(
34
+ "static.momocdn.net",
35
+ "img.mservice.com.vn",
36
+ "cdn.mservice.com.vn",
37
+ "img.mservice.io",
38
+ "image.momocdn.net"
39
+ )
40
+
41
+ // Pre-computed size chart for optimal image sizing
42
+ private val sizeChart = mapOf(
43
+ 64 to "XXS",
44
+ 128 to "XS",
45
+ 256 to "S",
46
+ 512 to "M",
47
+ 768 to "L",
48
+ 1024 to "XL",
49
+ 2048 to "XXL"
50
+ )
51
+
52
+ // Optimized size selection using binary search approach
53
+ private fun closestSizeForWidth(width: Float): String {
54
+ val targetWidth = width.toInt()
55
+ return sizeChart.entries
56
+ .minByOrNull { kotlin.math.abs(it.key - targetWidth) }
57
+ ?.value ?: "M"
58
+ }
59
+
60
+ // Cached regex for better URL parsing performance
61
+ private val urlHostRegex = Regex("^(?:https?://)?([^:/\\s]+)")
62
+
63
+ private fun getHostFromUrl(url: String): String? {
64
+ return try {
65
+ urlHostRegex.find(url)?.groupValues?.get(1)
66
+ } catch (_: Exception) {
67
+ null
68
+ }
69
+ }
70
+
71
+ // Optimized query parameter appending
72
+ private fun appendSizeQueryParam(url: String, value: String): String {
73
+ val fragmentIndex = url.indexOf('#')
74
+ val (baseUrl, fragment) = if (fragmentIndex != -1) {
75
+ url.take(fragmentIndex) to url.substring(fragmentIndex)
76
+ } else {
77
+ url to ""
78
+ }
79
+
80
+ val separator = if (baseUrl.contains('?')) "&" else "?"
81
+ return "${baseUrl}${separator}size=$value$fragment"
82
+ }
83
+
84
+ // Cache for processed URLs to avoid repeated calculations
85
+ private val urlCache = mutableMapOf<String, String>()
86
+
87
+ @Composable
88
+ fun Image(
89
+ source: Any,
90
+ modifier: Modifier = Modifier,
91
+ options: Options? = null,
92
+ loading: Boolean = true,
93
+ ) {
94
+ val imageOptions = remember(options) {
95
+ options ?: Options()
96
+ }
97
+
98
+ var imageState by remember { mutableStateOf(ImageState.Loading) }
99
+ val density = LocalDensity.current
100
+
101
+ BoxWithConstraints(
102
+ modifier = modifier.semantics { contentDescription = "img|$source" },
103
+ ) {
104
+ val urlToLoad = remember(source, maxWidth, maxHeight, density) {
105
+ when (source) {
106
+ is String -> {
107
+ // Check cache first
108
+ val cacheKey = "$source|${maxWidth}|${density.density}"
109
+ urlCache[cacheKey] ?: run {
110
+ val processedUrl = processImageUrl(source, maxWidth, density)
111
+ urlCache[cacheKey] = processedUrl
112
+ processedUrl
113
+ }
114
+ }
115
+ else -> source
116
+ }
117
+ }
118
+
119
+ AsyncImage(
120
+ modifier = Modifier.matchParentSize(),
121
+ model = urlToLoad,
122
+ contentDescription = null,
123
+ contentScale = imageOptions.contentScale,
124
+ alignment = imageOptions.alignment,
125
+ colorFilter = imageOptions.colorFilter,
126
+ alpha = imageOptions.alpha,
127
+ onLoading = { imageState = ImageState.Loading },
128
+ onSuccess = { imageState = ImageState.Success },
129
+ onError = { imageState = ImageState.Error },
130
+ )
131
+
132
+ when (imageState) {
133
+ ImageState.Loading -> if (loading) Skeleton()
134
+ ImageState.Error -> {
135
+ val theme = AppTheme.current
136
+ Icon(
137
+ source = "media_fail",
138
+ color = theme.colors.text.disable,
139
+ modifier = Modifier.align(Alignment.Center)
140
+ )
141
+ }
142
+ ImageState.Success -> {}
143
+ }
144
+ }
145
+ }
146
+
147
+ // Extracted URL processing logic for better performance
148
+ private fun processImageUrl(url: String, maxWidth: androidx.compose.ui.unit.Dp, density: androidx.compose.ui.unit.Density): String {
149
+ val host = getHostFromUrl(url)
150
+ return if (host != null && supportedDomains.contains(host)) {
151
+ val widthPx = with(density) { maxWidth.roundToPx() }
152
+ val pixelRatio = density.density
153
+ val pixelFitForWidth = widthPx * pixelRatio
154
+ val sizeKey = closestSizeForWidth(pixelFitForWidth)
155
+ appendSizeQueryParam(url, sizeKey)
156
+ } else {
157
+ url
158
+ }
159
+ }
160
+
161
+ @Composable
162
+ fun Image(
163
+ source: Painter,
164
+ modifier: Modifier = Modifier,
165
+ colorFilter: ColorFilter? = null,
166
+ alpha: Float = DefaultAlpha,
167
+ contentScale: ContentScale = ContentScale.Crop,
168
+ alignment: Alignment = Alignment.Center,
169
+ ) {
170
+ androidx.compose.foundation.Image(
171
+ modifier = modifier,
172
+ painter = source,
173
+ contentDescription = null,
174
+ contentScale = contentScale,
175
+ alignment = alignment,
176
+ colorFilter = colorFilter,
177
+ alpha = alpha,
178
+ )
179
+ }
@@ -0,0 +1,111 @@
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.Column
7
+ import androidx.compose.foundation.layout.Row
8
+ import androidx.compose.foundation.layout.height
9
+ import androidx.compose.foundation.layout.padding
10
+ import androidx.compose.foundation.layout.width
11
+ import androidx.compose.foundation.shape.RoundedCornerShape
12
+ import androidx.compose.runtime.Composable
13
+ import androidx.compose.ui.Modifier
14
+ import androidx.compose.ui.draw.clip
15
+ import androidx.compose.ui.text.style.TextAlign
16
+ import androidx.compose.ui.unit.dp
17
+ import vn.momo.kits.const.Colors
18
+ import vn.momo.kits.const.Radius
19
+ import vn.momo.kits.const.Spacing
20
+ import vn.momo.kits.const.Typography
21
+
22
+ enum class InformationState {
23
+ DEFAULT,
24
+ WARNING,
25
+ ERROR
26
+ }
27
+
28
+ @Composable
29
+ fun Information(
30
+ title: String? = null,
31
+ description: String = "Description",
32
+ state: InformationState = InformationState.DEFAULT,
33
+ image: String? = null,
34
+ onPressAction: (() -> Unit)? = null,
35
+ showIcon: Boolean = true,
36
+ action: String? = null,
37
+ showIconClose: Boolean = true,
38
+ onPressClose: (() -> Unit)? = null,
39
+ ) {
40
+ var borderColor = Colors.blue_07
41
+ var backgroundColor = Colors.blue_10
42
+ var color = Colors.blue_03
43
+ var iconSource = "notifications_info"
44
+
45
+ if (state === InformationState.WARNING) {
46
+ borderColor = Colors.yellow_06
47
+ backgroundColor = Colors.yellow_09
48
+ color = Colors.orange_03
49
+ iconSource = "24_notifications_alert_triangle"
50
+ }
51
+
52
+ if (state === InformationState.ERROR) {
53
+ borderColor = Colors.red_07
54
+ backgroundColor = Colors.red_10
55
+ color = Colors.red_03
56
+ iconSource = "24_notifications_alert_octagon"
57
+ }
58
+
59
+ Column(
60
+ modifier = Modifier.border(
61
+ width = 0.5.dp,
62
+ shape = RoundedCornerShape(Radius.S),
63
+ color = borderColor
64
+ ).background(color = backgroundColor)
65
+ .padding(Spacing.M)
66
+ ) {
67
+ Row {
68
+ if (image != null) {
69
+ Image(
70
+ source = image,
71
+ modifier = Modifier.padding(end = Spacing.S).width(40.dp).height(40.dp).clip(
72
+ RoundedCornerShape(Radius.S)
73
+ )
74
+ )
75
+ }
76
+ if (image == null && showIcon) {
77
+ Icon(
78
+ source = iconSource,
79
+ size = 16.dp,
80
+ color = color,
81
+ modifier = Modifier.padding(end = Spacing.S)
82
+ )
83
+ }
84
+ Column(modifier = Modifier.weight(1f)) {
85
+ if (title != null) {
86
+ Text(title, style = Typography.labelDefaultMedium)
87
+ }
88
+ Text(description, style = Typography.descriptionDefaultRegular)
89
+ }
90
+ if (onPressClose != null && showIconClose) {
91
+ Icon(
92
+ source = "navigation_close",
93
+ size = 16.dp,
94
+ modifier = Modifier.clickable(onClick = onPressClose)
95
+ )
96
+ }
97
+ }
98
+ if (action != null && onPressAction != null) {
99
+ Row(modifier = Modifier.padding(top = Spacing.S)) {
100
+ Text(
101
+ action,
102
+ modifier = Modifier.weight(1f).clickable(onClick = onPressAction),
103
+ textAlign = TextAlign.End,
104
+ style = Typography.actionXsBold,
105
+ color = color
106
+ )
107
+ }
108
+ }
109
+ }
110
+
111
+ }