@momo-kits/native-kits 0.162.3-debug → 0.162.3-fontscale.1-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 (130) hide show
  1. package/.codegraph/.gitignore +5 -0
  2. package/CLAUDE.md +78 -0
  3. package/compose/build.gradle.kts +12 -8
  4. package/compose/build.gradle.kts.backup +11 -7
  5. package/compose/compose.podspec +1 -1
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +2 -7
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +3 -11
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +6 -24
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +4 -19
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +1 -10
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +2 -2
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +1 -1
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +1 -1
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +6 -17
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +1 -1
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +6 -101
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +5 -19
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +8 -33
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +1 -1
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +1 -6
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +27 -29
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +3 -26
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +27 -26
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +3 -13
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -5
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +3 -11
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +3 -18
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +11 -11
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +3 -11
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +69 -26
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +1 -5
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +84 -59
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +13 -71
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +10 -51
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +6 -1
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +4 -21
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +1 -1
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +16 -75
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +5 -26
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +1 -1
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +3 -11
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +16 -40
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +3 -9
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -28
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +2 -13
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +4 -10
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +3 -28
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +8 -47
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +4 -25
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +2 -11
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +1 -17
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +1 -6
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +50 -111
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +1 -5
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +1 -5
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +1 -12
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +4 -96
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +5 -7
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +2 -12
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +9 -21
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +2 -2
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +9 -14
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +8 -11
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +1 -1
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +3 -18
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +1 -1
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -5
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -2
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +94 -4
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -2
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +2 -2
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +3 -7
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +5 -15
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +42 -24
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +48 -33
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +58 -57
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +28 -25
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +13 -31
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +1 -1
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +6 -24
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +11 -6
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +2 -1
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +9 -6
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +1 -1
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +3 -13
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +3 -2
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +1 -40
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -2
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -8
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +2 -17
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +1 -1
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +3 -3
  94. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +2 -3
  95. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -2
  96. package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Example.xcscheme +32 -0
  97. package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  98. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  99. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/WorkspaceSettings.xcsettings +16 -0
  100. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +6 -0
  101. package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
  102. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +58 -0
  103. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Pods-Example.xcscheme +58 -0
  104. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImage.xcscheme +58 -0
  105. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +58 -0
  106. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SkeletonUI.xcscheme +58 -0
  107. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios-LottiePrivacyInfo.xcscheme +58 -0
  108. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios.xcscheme +58 -0
  109. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +60 -0
  110. package/gradle/libs.versions.toml +2 -0
  111. package/gradle.properties +1 -1
  112. package/ios/Application/Components.swift +1 -0
  113. package/ios/Application/FloatingButton.swift +1 -0
  114. package/ios/Badge/Badge.swift +1 -0
  115. package/ios/Badge/BadgeRibbon.swift +2 -0
  116. package/ios/Button/Button.swift +1 -1
  117. package/ios/Checkbox/Checkbox.swift +1 -0
  118. package/ios/Information/Information.swift +151 -0
  119. package/ios/Input/Input.swift +1 -0
  120. package/ios/Input/InputPhoneNumber.swift +1 -0
  121. package/ios/Input/InputSearch.swift +3 -0
  122. package/ios/Input/InputTextArea.swift +1 -0
  123. package/ios/OTPKeyboard/KeyboardButton.swift +1 -1
  124. package/ios/Popup/PopupDisplay.swift +6 -0
  125. package/ios/Popup/PopupInput.swift +2 -0
  126. package/ios/Template/TrustBanner/TrustBanner.swift +2 -0
  127. package/ios/Typography/Text.swift +1 -0
  128. package/ios/Typography/Typography.swift +14 -5
  129. package/local.properties +8 -0
  130. package/package.json +1 -1
@@ -1,5 +1,7 @@
1
1
  package vn.momo.kits.components
2
2
 
3
+ import vn.momo.kits.modifier.InternalApi
4
+
3
5
  import androidx.compose.animation.core.animateDpAsState
4
6
  import androidx.compose.animation.core.animateFloatAsState
5
7
  import androidx.compose.animation.core.tween
@@ -8,14 +10,7 @@ import androidx.compose.foundation.border
8
10
  import androidx.compose.foundation.clickable
9
11
  import androidx.compose.foundation.interaction.MutableInteractionSource
10
12
  import androidx.compose.foundation.interaction.collectIsPressedAsState
11
- import androidx.compose.foundation.layout.Arrangement
12
- import androidx.compose.foundation.layout.Box
13
- import androidx.compose.foundation.layout.Row
14
- import androidx.compose.foundation.layout.fillMaxWidth
15
- import androidx.compose.foundation.layout.height
16
- import androidx.compose.foundation.layout.padding
17
- import androidx.compose.foundation.layout.size
18
- import androidx.compose.foundation.layout.wrapContentHeight
13
+ import androidx.compose.foundation.layout.*
19
14
  import androidx.compose.foundation.shape.RoundedCornerShape
20
15
  import androidx.compose.runtime.Composable
21
16
  import androidx.compose.runtime.getValue
@@ -30,11 +25,7 @@ import androidx.compose.ui.text.style.TextOverflow
30
25
  import androidx.compose.ui.unit.Dp
31
26
  import androidx.compose.ui.unit.dp
32
27
  import vn.momo.kits.application.IsShowBaseLineDebug
33
- import vn.momo.kits.const.AppTheme
34
- import vn.momo.kits.const.Colors
35
- import vn.momo.kits.const.Radius
36
- import vn.momo.kits.const.Spacing
37
- import vn.momo.kits.const.Typography
28
+ import vn.momo.kits.const.*
38
29
  import vn.momo.kits.modifier.conditional
39
30
  import vn.momo.kits.platform.LottieAnimation
40
31
 
@@ -100,32 +91,39 @@ private val iconSpaceCache = mapOf(
100
91
  Size.LARGE to Spacing.S
101
92
  )
102
93
 
103
- fun getStyle(size: Size): TextStyle {
94
+ private fun getStyle(size: Size): TextStyle {
104
95
  return styleCache[size] ?: Typography.actionDefaultBold
105
96
  }
106
97
 
98
+ @InternalApi
107
99
  fun getIconSize(size: Size): Dp = iconSizeCache[size] ?: 24.dp
108
- fun getIconSpace(size: Size): Dp = iconSpaceCache[size] ?: Spacing.S
100
+ private fun getIconSpace(size: Size): Dp = iconSpaceCache[size] ?: Spacing.S
109
101
 
102
+ @InternalApi
110
103
  @Composable
111
104
  fun getTextColor(loading: Boolean, type: ButtonType): Color {
112
105
  val theme = AppTheme.current
113
106
 
114
107
  return remember(type, theme, loading) {
115
- when (type) {
116
- ButtonType.DISABLED -> theme.colors.text.disable
117
- ButtonType.PRIMARY -> Colors.black_01
118
- ButtonType.SECONDARY -> theme.colors.text.default
119
- ButtonType.OUTLINE -> theme.colors.primary
120
- ButtonType.TONAL -> theme.colors.primary
121
- ButtonType.DANGER -> Colors.black_01
122
- ButtonType.TEXT -> theme.colors.primary
123
- }.withLoading(loading)
108
+ getButtonColor(type, theme).withLoading(loading)
109
+ }
110
+ }
111
+
112
+ internal fun getButtonColor(type: ButtonType, theme: Theme): Color {
113
+ return when (type) {
114
+ ButtonType.DISABLED -> theme.colors.text.disable
115
+ ButtonType.PRIMARY -> Colors.black_01
116
+ ButtonType.SECONDARY -> theme.colors.text.default
117
+ ButtonType.OUTLINE -> theme.colors.primary
118
+ ButtonType.TONAL -> theme.colors.primary
119
+ ButtonType.DANGER -> Colors.black_01
120
+ ButtonType.TEXT -> theme.colors.primary
124
121
  }
125
122
  }
126
123
 
124
+
127
125
  @Composable
128
- fun RenderTitle(size: Size, title: String = "", textColor: Color) {
126
+ internal fun RenderTitle(size: Size, title: String = "", textColor: Color) {
129
127
  val style = remember(size) { getStyle(size) }
130
128
  Text(
131
129
  style = style,
@@ -137,6 +135,7 @@ fun RenderTitle(size: Size, title: String = "", textColor: Color) {
137
135
  }
138
136
 
139
137
  @Composable
138
+ @InternalApi
140
139
  fun RenderIcon(
141
140
  size: Size,
142
141
  isIconLeft: Boolean,
@@ -186,6 +185,7 @@ private fun shouldLoadingOnLeft(iconLeft: String, iconRight: String): Boolean {
186
185
  }
187
186
  }
188
187
 
188
+ @InternalApi
189
189
  @Composable
190
190
  fun getTypeStyle(
191
191
  type: ButtonType,
@@ -222,6 +222,7 @@ fun getTypeStyle(
222
222
  }
223
223
  }
224
224
 
225
+ @InternalApi
225
226
  @Composable
226
227
  fun getButtonBackgroundColor(
227
228
  loading: Boolean,
@@ -242,7 +243,7 @@ fun getButtonBackgroundColor(
242
243
  }
243
244
  }
244
245
 
245
- fun Color.withLoading(loading: Boolean): Color =
246
+ private fun Color.withLoading(loading: Boolean): Color =
246
247
  this.copy(alpha = if (loading) 0.75f else 1f)
247
248
 
248
249
  @Composable
@@ -8,13 +8,7 @@ import androidx.compose.foundation.layout.PaddingValues
8
8
  import androidx.compose.foundation.layout.fillMaxWidth
9
9
  import androidx.compose.foundation.pager.HorizontalPager
10
10
  import androidx.compose.foundation.pager.rememberPagerState
11
- import androidx.compose.runtime.Composable
12
- import androidx.compose.runtime.LaunchedEffect
13
- import androidx.compose.runtime.getValue
14
- import androidx.compose.runtime.mutableStateOf
15
- import androidx.compose.runtime.remember
16
- import androidx.compose.runtime.setValue
17
- import androidx.compose.runtime.snapshotFlow
11
+ import androidx.compose.runtime.*
18
12
  import androidx.compose.ui.Modifier
19
13
  import androidx.compose.ui.graphics.graphicsLayer
20
14
  import androidx.compose.ui.unit.dp
@@ -24,6 +18,7 @@ import vn.momo.kits.application.IsShowBaseLineDebug
24
18
  import vn.momo.kits.const.Colors
25
19
  import vn.momo.kits.modifier.conditional
26
20
  import kotlin.math.absoluteValue
21
+ import kotlin.time.Duration.Companion.milliseconds
27
22
 
28
23
  @Composable
29
24
  fun Carousel(
@@ -32,7 +27,6 @@ fun Carousel(
32
27
  loop: Boolean = false,
33
28
  autoplay: Boolean = false,
34
29
  autoplayInterval: Long = 3000L,
35
- enableSnap: Boolean = true,
36
30
  scrollEnabled: Boolean = true,
37
31
  inactiveSlideOpacity: Float = 1f,
38
32
  inactiveSlideScale: Float = 1f,
@@ -48,18 +42,15 @@ fun Carousel(
48
42
 
49
43
  val pagerState = rememberPagerState(initialPage = startPage) { virtualPageCount }
50
44
 
51
- // Map virtual page to real index
52
45
  val realIndex: (Int) -> Int = { page -> page % itemCount }
53
46
 
54
- // Track user interaction for autoplay pause
55
47
  var isUserScrolling by remember { mutableStateOf(false) }
56
48
 
57
- // Autoplay
58
49
  if (autoplay && itemCount > 1) {
59
50
  LaunchedEffect(autoplayInterval, isUserScrolling) {
60
51
  if (isUserScrolling) return@LaunchedEffect
61
52
  while (isActive) {
62
- delay(autoplayInterval)
53
+ delay(autoplayInterval.milliseconds)
63
54
  if (!isUserScrolling) {
64
55
  val nextPage = pagerState.currentPage + 1
65
56
  if (nextPage < virtualPageCount) {
@@ -70,7 +61,6 @@ fun Carousel(
70
61
  }
71
62
  }
72
63
 
73
- // Track scroll state for callbacks
74
64
  LaunchedEffect(pagerState) {
75
65
  snapshotFlow { pagerState.isScrollInProgress }.collect { scrolling ->
76
66
  isUserScrolling = scrolling
@@ -22,7 +22,6 @@ import vn.momo.kits.const.Typography
22
22
  import vn.momo.kits.modifier.activeOpacityClickable
23
23
  import vn.momo.kits.modifier.conditional
24
24
 
25
- // Pre-computed shape for performance
26
25
  private val checkboxShape = RoundedCornerShape(Radius.XS)
27
26
 
28
27
  @Composable
@@ -33,10 +32,8 @@ fun CheckBox(
33
32
  indeterminate: Boolean = false,
34
33
  title: String = "",
35
34
  ) {
36
- // Cache theme access
37
35
  val theme = AppTheme.current
38
36
 
39
- // Memoize color calculations to avoid repeated conditional logic
40
37
  val colors = remember(checked, disabled, theme) {
41
38
  when {
42
39
  disabled && checked -> Pair(theme.colors.background.tonal, theme.colors.background.tonal)
@@ -48,12 +45,10 @@ fun CheckBox(
48
45
 
49
46
  val (borderColor, backgroundColor) = colors
50
47
 
51
- // Memoize icon source to avoid repeated conditional check
52
48
  val iconSource = remember(indeterminate) {
53
49
  if (indeterminate) "navigation_minus" else "ic_checked"
54
50
  }
55
51
 
56
- // Memoize click handler to avoid lambda recreation
57
52
  val onClickHandler = remember(onCheckedChange, checked) {
58
53
  { onCheckedChange(!checked) }
59
54
  }
@@ -2,11 +2,7 @@ package vn.momo.kits.components
2
2
 
3
3
  import androidx.compose.foundation.background
4
4
  import androidx.compose.foundation.border
5
- import androidx.compose.foundation.layout.Arrangement
6
- import androidx.compose.foundation.layout.Row
7
- import androidx.compose.foundation.layout.height
8
- import androidx.compose.foundation.layout.padding
9
- import androidx.compose.foundation.layout.wrapContentWidth
5
+ import androidx.compose.foundation.layout.*
10
6
  import androidx.compose.foundation.shape.RoundedCornerShape
11
7
  import androidx.compose.runtime.Composable
12
8
  import androidx.compose.runtime.Immutable
@@ -17,12 +13,8 @@ import androidx.compose.ui.graphics.Color
17
13
  import androidx.compose.ui.text.style.TextAlign
18
14
  import androidx.compose.ui.text.style.TextOverflow
19
15
  import androidx.compose.ui.unit.dp
20
- import vn.momo.kits.const.AppTheme
21
- import vn.momo.kits.const.Colors
22
- import vn.momo.kits.const.Radius
23
- import vn.momo.kits.const.Typography
24
16
  import vn.momo.kits.application.IsShowBaseLineDebug
25
- import vn.momo.kits.const.scaleSize
17
+ import vn.momo.kits.const.*
26
18
  import vn.momo.kits.modifier.activeOpacityClickable
27
19
  import vn.momo.kits.modifier.conditional
28
20
  import vn.momo.kits.modifier.setAutomationId
@@ -111,7 +103,7 @@ fun Chip(
111
103
 
112
104
  enum class ChipSize { SMALL, LARGE }
113
105
 
114
- object ChipDefaults {
106
+ private object ChipDefaults {
115
107
  @Immutable
116
108
  data class Dimensions(
117
109
  val height: Float,
@@ -7,20 +7,9 @@ import androidx.compose.animation.expandVertically
7
7
  import androidx.compose.animation.shrinkVertically
8
8
  import androidx.compose.foundation.background
9
9
  import androidx.compose.foundation.border
10
- import androidx.compose.foundation.layout.Box
11
- import androidx.compose.foundation.layout.Column
12
- import androidx.compose.foundation.layout.Row
13
- import androidx.compose.foundation.layout.Spacer
14
- import androidx.compose.foundation.layout.fillMaxWidth
15
- import androidx.compose.foundation.layout.padding
16
- import androidx.compose.foundation.layout.size
17
- import androidx.compose.foundation.layout.width
10
+ import androidx.compose.foundation.layout.*
18
11
  import androidx.compose.foundation.shape.RoundedCornerShape
19
- import androidx.compose.runtime.Composable
20
- import androidx.compose.runtime.getValue
21
- import androidx.compose.runtime.mutableStateOf
22
- import androidx.compose.runtime.remember
23
- import androidx.compose.runtime.setValue
12
+ import androidx.compose.runtime.*
24
13
  import androidx.compose.ui.Alignment
25
14
  import androidx.compose.ui.Modifier
26
15
  import androidx.compose.ui.draw.clip
@@ -29,11 +18,7 @@ import androidx.compose.ui.graphics.Color
29
18
  import androidx.compose.ui.text.TextStyle
30
19
  import androidx.compose.ui.unit.dp
31
20
  import vn.momo.kits.application.IsShowBaseLineDebug
32
- import vn.momo.kits.const.AppTheme
33
- import vn.momo.kits.const.Colors
34
- import vn.momo.kits.const.Radius
35
- import vn.momo.kits.const.Spacing
36
- import vn.momo.kits.const.Typography
21
+ import vn.momo.kits.const.*
37
22
  import vn.momo.kits.modifier.activeOpacityClickable
38
23
  import vn.momo.kits.modifier.conditional
39
24
  import vn.momo.kits.modifier.setAutomationId
@@ -42,8 +42,8 @@ import androidx.compose.ui.unit.toOffset
42
42
  import androidx.compose.ui.unit.toSize
43
43
  import kotlinx.coroutines.CoroutineScope
44
44
  import kotlinx.coroutines.cancel
45
+ import kotlinx.coroutines.currentCoroutineContext
45
46
  import kotlinx.coroutines.isActive
46
- import kotlin.coroutines.coroutineContext
47
47
  import kotlin.math.abs
48
48
  import kotlin.math.sign
49
49
 
@@ -103,7 +103,7 @@ internal class CupertinoOverscrollEffect(
103
103
  * end at the same time, which is not the case:
104
104
  * Spring->Fling->Spring, Fling->Spring, Spring->Fling effects can have different timing per dimension
105
105
  * (see Notes of https://github.com/JetBrains/compose-multiplatform-core/pull/609),
106
- * which is not possible to express without changing API. Hence this effect will be fixed to latest
106
+ * which is not possible to express without changing API. Hence, this effect will be fixed to latest
107
107
  * received delta.
108
108
  */
109
109
  private var direction: CupertinoOverscrollDirection = CupertinoOverscrollDirection.UNKNOWN
@@ -151,7 +151,7 @@ internal class CupertinoOverscrollEffect(
151
151
  override val node: DelegatableNode get() = overscrollNode
152
152
 
153
153
  private fun onDraw() {
154
- // Fix an issue where scrolling was cancelled but the overscroll effect was not completed.
154
+ // Fix an issue where scrolling was canceled but the overscroll effect was not completed.
155
155
  // Reset the overscroll effect when no ongoing animation or interaction is applied.
156
156
  if (!drawCallScheduledByOffsetChange && isInProgress && overscrollNode.pointersDown == 0) {
157
157
  overscrollOffsetState.value = Offset.Zero
@@ -289,7 +289,7 @@ internal class CupertinoOverscrollEffect(
289
289
  }
290
290
 
291
291
  private fun applyPullToRefresh() {
292
- val (isRefresh, refresh, threshHold, _, sendHaptic) = pullRefreshState ?: return
292
+ val (isRefresh, refresh, threshHold, _, _) = pullRefreshState ?: return
293
293
  val overscrollY = overscrollOffset.y
294
294
  if (isRefresh.value || overscrollY < threshHold.value * density) return
295
295
  refresh.invoke()
@@ -398,7 +398,7 @@ internal class CupertinoOverscrollEffect(
398
398
  }
399
399
 
400
400
  springAnimationScope?.cancel()
401
- springAnimationScope = CoroutineScope(coroutineContext)
401
+ springAnimationScope = CoroutineScope(currentCoroutineContext())
402
402
  springAnimationScope?.run {
403
403
  AnimationState(
404
404
  Float.VectorConverter,
@@ -414,7 +414,7 @@ internal class CupertinoOverscrollEffect(
414
414
  } ?: (value * density).toOffset()
415
415
  currentVelocity = velocity * density
416
416
 
417
- // If it was fling from overscroll, cancel animation and return velocity
417
+ // If it was flung from overscroll, cancel animation and return velocity
418
418
  if (reason == CupertinoSpringAnimationReason.FLING_FROM_OVERSCROLL &&
419
419
  initialSign != 0f &&
420
420
  sign(value) != initialSign
@@ -425,7 +425,7 @@ internal class CupertinoOverscrollEffect(
425
425
  springAnimationScope = null
426
426
  }
427
427
 
428
- if (coroutineContext.isActive) {
428
+ if (currentCoroutineContext().isActive) {
429
429
  // The spring is critically damped, so in case spring-fling-spring sequence is slightly
430
430
  // offset and velocity is of the opposite sign, it will end up with no animation
431
431
  overscrollOffset = Offset.Zero
@@ -447,8 +447,8 @@ internal class CupertinoOverscrollEffect(
447
447
  val dpSize = scrollSize / density
448
448
 
449
449
  return Offset(
450
- rubberBandedValue(dpOffset.x, dpSize.width, RUBBER_BAND_COEFFICIENT),
451
- rubberBandedValue(dpOffset.y, dpSize.height, RUBBER_BAND_COEFFICIENT)
450
+ rubberBandedValue(dpOffset.x, dpSize.width),
451
+ rubberBandedValue(dpOffset.y, dpSize.height)
452
452
  ) * density
453
453
  }
454
454
 
@@ -456,8 +456,8 @@ internal class CupertinoOverscrollEffect(
456
456
  * Maps raw delta offset [value] on an axis within scroll container with [dimension]
457
457
  * to actual visible offset
458
458
  */
459
- private fun rubberBandedValue(value: Float, dimension: Float, coefficient: Float) =
460
- sign(value) * (1f - (1f / (abs(value) * coefficient / dimension + 1f))) * dimension
459
+ private fun rubberBandedValue(value: Float, dimension: Float) =
460
+ sign(value) * (1f - (1f / (abs(value) * RUBBER_BAND_COEFFICIENT / dimension + 1f))) * dimension
461
461
 
462
462
  companion object Companion {
463
463
  private const val RUBBER_BAND_COEFFICIENT = 0.55f
@@ -56,7 +56,7 @@ private val iconSizeMap = mapOf(
56
56
  )
57
57
 
58
58
  @Composable
59
- fun getIconStyle(type: ButtonType, color: Color? = null): Modifier {
59
+ internal fun getIconStyle(type: ButtonType, color: Color? = null): Modifier {
60
60
  val theme = AppTheme.current
61
61
 
62
62
  return remember(type, color, theme) {
@@ -91,18 +91,10 @@ fun getIconStyle(type: ButtonType, color: Color? = null): Modifier {
91
91
  }
92
92
 
93
93
  @Composable
94
- fun getIconColor(type: ButtonType): Color {
94
+ internal fun getIconColor(type: ButtonType): Color {
95
95
  val theme = AppTheme.current
96
96
  return remember(type, theme) {
97
- when (type) {
98
- ButtonType.DISABLED -> theme.colors.text.disable
99
- ButtonType.PRIMARY -> Colors.black_01
100
- ButtonType.SECONDARY -> theme.colors.text.default
101
- ButtonType.OUTLINE -> theme.colors.primary
102
- ButtonType.TONAL -> theme.colors.primary
103
- ButtonType.DANGER -> Colors.black_01
104
- ButtonType.TEXT -> theme.colors.primary
105
- }
97
+ getButtonColor(type, theme)
106
98
  }
107
99
  }
108
100
 
@@ -1,7 +1,9 @@
1
1
  package vn.momo.kits.components
2
2
 
3
3
  import androidx.compose.foundation.border
4
+ import androidx.compose.foundation.layout.Box
4
5
  import androidx.compose.foundation.layout.BoxWithConstraints
6
+ import androidx.compose.foundation.layout.fillMaxSize
5
7
  import androidx.compose.runtime.Composable
6
8
  import androidx.compose.runtime.getValue
7
9
  import androidx.compose.runtime.mutableStateOf
@@ -17,10 +19,12 @@ import androidx.compose.ui.semantics.contentDescription
17
19
  import androidx.compose.ui.semantics.semantics
18
20
  import androidx.compose.ui.platform.LocalDensity
19
21
  import androidx.compose.ui.unit.dp
20
- import coil3.compose.AsyncImage
22
+ import coil3.compose.AsyncImage as CoilAsyncImage
21
23
  import vn.momo.kits.application.IsShowBaseLineDebug
22
24
  import vn.momo.kits.const.AppTheme
23
25
  import vn.momo.kits.const.Colors
26
+ import vn.momo.kits.gifimage.GifImage
27
+ import vn.momo.kits.gifimage.GifImageState
24
28
  import vn.momo.kits.modifier.conditional
25
29
 
26
30
  data class Options(
@@ -73,6 +77,19 @@ private fun getHostFromUrl(url: String): String? {
73
77
  }
74
78
  }
75
79
 
80
+ private fun isGifUrl(url: String): Boolean {
81
+ val path = url.substringBefore('#').substringBefore('?')
82
+ return path.endsWith(".gif", ignoreCase = true)
83
+ }
84
+
85
+ private fun GifImageState.toImageState(): ImageState {
86
+ return when (this) {
87
+ GifImageState.Success -> ImageState.Success
88
+ GifImageState.Error -> ImageState.Error
89
+ GifImageState.Loading -> ImageState.Loading
90
+ }
91
+ }
92
+
76
93
  // Optimized query parameter appending
77
94
  private fun appendSizeQueryParam(url: String, value: String): String {
78
95
  val fragmentIndex = url.indexOf('#')
@@ -95,12 +112,12 @@ fun Image(
95
112
  modifier: Modifier = Modifier,
96
113
  options: Options? = null,
97
114
  loading: Boolean = true,
115
+ onStateChanged: (ImageState) -> Unit = {},
98
116
  ) {
99
117
  val imageOptions = remember(options) {
100
118
  options ?: Options()
101
119
  }
102
120
 
103
- var imageState by remember { mutableStateOf(ImageState.Loading) }
104
121
  val density = LocalDensity.current
105
122
 
106
123
  BoxWithConstraints(
@@ -121,34 +138,46 @@ fun Image(
121
138
  processedUrl
122
139
  }
123
140
  }
124
- else -> source
141
+ else -> source.toString()
125
142
  }
126
143
  }
127
144
 
128
- AsyncImage(
129
- modifier = Modifier.matchParentSize(),
130
- model = urlToLoad,
131
- contentDescription = null,
132
- contentScale = imageOptions.contentScale,
133
- alignment = imageOptions.alignment,
134
- colorFilter = imageOptions.colorFilter,
135
- alpha = imageOptions.alpha,
136
- onLoading = { imageState = ImageState.Loading },
137
- onSuccess = { imageState = ImageState.Success },
138
- onError = { imageState = ImageState.Error },
139
- )
145
+ var imageState by remember(urlToLoad) { mutableStateOf(ImageState.Loading) }
146
+ fun updateImageState(state: ImageState) {
147
+ imageState = state
148
+ onStateChanged(state)
149
+ }
150
+
151
+ if (isGifUrl(urlToLoad)) {
152
+ GifImage(
153
+ modifier = Modifier.matchParentSize(),
154
+ url = urlToLoad,
155
+ contentDescription = null,
156
+ contentScale = imageOptions.contentScale,
157
+ alignment = imageOptions.alignment,
158
+ colorFilter = imageOptions.colorFilter,
159
+ alpha = imageOptions.alpha,
160
+ onStateChanged = { updateImageState(it.toImageState()) },
161
+ )
162
+ } else {
163
+ CoilAsyncImage(
164
+ modifier = Modifier.matchParentSize(),
165
+ model = urlToLoad,
166
+ contentDescription = null,
167
+ contentScale = imageOptions.contentScale,
168
+ alignment = imageOptions.alignment,
169
+ colorFilter = imageOptions.colorFilter,
170
+ alpha = imageOptions.alpha,
171
+ onLoading = { updateImageState(ImageState.Loading) },
172
+ onSuccess = { updateImageState(ImageState.Success) },
173
+ onError = { updateImageState(ImageState.Error) },
174
+ )
175
+ }
140
176
 
141
177
  when (imageState) {
142
- ImageState.Loading -> if (loading) Skeleton()
143
- ImageState.Error -> {
144
- val theme = AppTheme.current
145
- Icon(
146
- source = "media_fail",
147
- color = theme.colors.text.disable,
148
- modifier = Modifier.align(Alignment.Center)
149
- )
150
- }
151
178
  ImageState.Success -> {}
179
+ ImageState.Error -> ImageError()
180
+ ImageState.Loading -> if (loading) Skeleton()
152
181
  }
153
182
  }
154
183
  }
@@ -156,7 +185,7 @@ fun Image(
156
185
  // Extracted URL processing logic for better performance
157
186
  private fun processImageUrl(url: String, maxWidth: androidx.compose.ui.unit.Dp, density: androidx.compose.ui.unit.Density): String {
158
187
  val host = getHostFromUrl(url)
159
- return if (host != null && supportedDomains.contains(host)) {
188
+ return if (!isGifUrl(url) && host != null && supportedDomains.contains(host)) {
160
189
  val widthPx = with(density) { maxWidth.roundToPx() }
161
190
  val pixelRatio = density.density
162
191
  val pixelFitForWidth = widthPx * pixelRatio
@@ -167,6 +196,20 @@ private fun processImageUrl(url: String, maxWidth: androidx.compose.ui.unit.Dp,
167
196
  }
168
197
  }
169
198
 
199
+ @Composable
200
+ private fun ImageError() {
201
+ val theme = AppTheme.current
202
+ Box(
203
+ modifier = Modifier.fillMaxSize(),
204
+ contentAlignment = Alignment.Center
205
+ ) {
206
+ Icon(
207
+ source = "media_fail",
208
+ color = theme.colors.text.disable,
209
+ )
210
+ }
211
+ }
212
+
170
213
  @Composable
171
214
  fun Image(
172
215
  source: Painter,
@@ -185,4 +228,4 @@ fun Image(
185
228
  colorFilter = colorFilter,
186
229
  alpha = alpha,
187
230
  )
188
- }
231
+ }
@@ -3,11 +3,7 @@ package vn.momo.kits.components
3
3
  import androidx.compose.foundation.background
4
4
  import androidx.compose.foundation.border
5
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
6
+ import androidx.compose.foundation.layout.*
11
7
  import androidx.compose.foundation.shape.RoundedCornerShape
12
8
  import androidx.compose.runtime.Composable
13
9
  import androidx.compose.ui.Modifier