@momo-kits/native-kits 0.162.0-debug → 0.162.1-beta.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 (104) hide show
  1. package/.claude/settings.local.json +32 -0
  2. package/compose/build.gradle.kts +66 -63
  3. package/compose/build.gradle.kts.backup +66 -63
  4. package/compose/compose.podspec +1 -1
  5. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +2 -7
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +1 -1
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +6 -24
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +4 -19
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +1 -10
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +2 -2
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +1 -1
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +1 -1
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +5 -16
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +1 -1
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +6 -101
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +4 -16
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +9 -34
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +1 -1
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +1 -6
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +27 -29
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +3 -26
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +27 -30
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +3 -13
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -5
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +3 -11
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +3 -18
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +11 -11
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +3 -11
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +1 -5
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +84 -59
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +13 -71
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +10 -51
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +6 -1
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +4 -21
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +1 -1
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +15 -76
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +5 -26
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +1 -1
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +3 -11
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +15 -36
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +3 -9
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -28
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +2 -13
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +4 -10
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +3 -28
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +8 -47
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +4 -25
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +2 -11
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +1 -17
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +1 -6
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +50 -111
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +1 -5
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +1 -5
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +1 -12
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +4 -96
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +2 -12
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +9 -21
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +2 -2
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +9 -14
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +8 -11
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +1 -1
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +3 -18
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +1 -1
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -5
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -2
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -2
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +1 -5
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +5 -12
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +6 -5
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +55 -55
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +3 -9
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +12 -32
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +1 -1
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +6 -24
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +55 -15
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +2 -1
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +6 -3
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +5 -3
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +3 -13
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +3 -2
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +1 -40
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -2
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -8
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Deprecated.kt +107 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +3 -8
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +1 -1
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +3 -3
  88. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +2 -3
  89. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -2
  90. package/gradle.properties +1 -1
  91. package/local.properties +2 -2
  92. package/package.json +1 -1
  93. package/publish.sh +2 -2
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -17
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -14
  96. package/example/ios/Example.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  97. package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  98. package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -5
  99. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
  100. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
  101. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImage.xcscheme +0 -58
  102. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +0 -58
  103. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SkeletonUI.xcscheme +0 -58
  104. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +0 -46
@@ -45,8 +45,8 @@ import androidx.compose.ui.layout.onGloballyPositioned
45
45
  import androidx.compose.ui.platform.LocalDensity
46
46
  import androidx.compose.ui.unit.Dp
47
47
  import androidx.compose.ui.unit.dp
48
- import androidx.compose.ui.unit.min
49
48
  import androidx.compose.ui.zIndex
49
+ import kotlinx.coroutines.flow.Flow
50
50
  import vn.momo.kits.components.InputSearch
51
51
  import vn.momo.kits.const.AppNavigationBar
52
52
  import vn.momo.kits.const.AppStatusBar
@@ -71,6 +71,7 @@ import vn.momo.kits.navigation.tracking.ScreenTrackingState
71
71
  import kotlinx.coroutines.delay
72
72
  import vn.momo.kits.application.ApplicationContext
73
73
  import kotlin.time.Clock
74
+ import kotlin.time.Duration.Companion.milliseconds
74
75
  import kotlin.time.ExperimentalTime
75
76
 
76
77
  internal val LocalFooterHeightPx = staticCompositionLocalOf { mutableIntStateOf(0) }
@@ -98,7 +99,7 @@ internal fun StackScreen(
98
99
  // Auto tracking state
99
100
  val trackingState = remember {
100
101
  ScreenTrackingState().apply {
101
- startTime = Clock.System.now().toEpochMilliseconds()
102
+ time = Clock.System.now().toEpochMilliseconds()
102
103
  }
103
104
  }
104
105
 
@@ -119,8 +120,8 @@ internal fun StackScreen(
119
120
  )
120
121
 
121
122
  // Track screen displayed after 2 seconds (debounce)
122
- delay(2000)
123
- val loadTime = Clock.System.now().toEpochMilliseconds() - trackingState.startTime
123
+ delay(2000.milliseconds)
124
+ val loadTime = Clock.System.now().toEpochMilliseconds() - trackingState.time
124
125
  ScreenTracker.trackScreenDisplayed(
125
126
  maxApi = maxApi,
126
127
  context = context,
@@ -130,7 +131,7 @@ internal fun StackScreen(
130
131
  )
131
132
 
132
133
  // Track screen interacted after displayed
133
- val interactionTime = Clock.System.now().toEpochMilliseconds() - trackingState.startTime
134
+ val interactionTime = Clock.System.now().toEpochMilliseconds() - trackingState.time
134
135
  ScreenTracker.trackScreenInteracted(
135
136
  maxApi = maxApi,
136
137
  context = context,
@@ -204,8 +205,9 @@ internal fun StackScreen(
204
205
  }
205
206
  }
206
207
 
208
+ @Suppress("FrequentlyChangingValue")
207
209
  @Composable
208
- fun FloatingContent() {
210
+ internal fun FloatingContent() {
209
211
  val options = LocalOptions.current
210
212
  val density = LocalDensity.current
211
213
  val footerHeightPx = LocalFooterHeightPx.current
@@ -229,7 +231,7 @@ fun FloatingContent() {
229
231
  }
230
232
 
231
233
  @Composable
232
- fun ColumnScope.MainContent(content: @Composable () -> Unit) {
234
+ internal fun ColumnScope.MainContent(content: @Composable () -> Unit) {
233
235
  val options = LocalOptions.current
234
236
  val inputSearchType = getInputSearchType(options)
235
237
  val density = LocalDensity.current
@@ -264,7 +266,7 @@ fun ColumnScope.MainContent(content: @Composable () -> Unit) {
264
266
  }
265
267
 
266
268
  @Composable
267
- fun ScreenContent(content: @Composable () -> Unit) {
269
+ internal fun ScreenContent(content: @Composable () -> Unit) {
268
270
  val scrollState = LocalScrollState.current
269
271
  val options = LocalOptions.current
270
272
 
@@ -284,7 +286,7 @@ fun ScreenContent(content: @Composable () -> Unit) {
284
286
  }
285
287
 
286
288
  @Composable
287
- fun FooterContent() {
289
+ internal fun FooterContent() {
288
290
  val options = LocalOptions.current
289
291
  if (options.footerComponent != null) {
290
292
  val keyboardSize = keyboardSizeState()
@@ -294,13 +296,13 @@ fun FooterContent() {
294
296
  }
295
297
 
296
298
  @Composable
297
- fun keyboardSizeState(): State<Dp> {
299
+ internal fun keyboardSizeState(): State<Dp> {
298
300
  val bottom = WindowInsets.ime.asPaddingValues()
299
301
  return rememberUpdatedState(bottom.calculateBottomPadding())
300
302
  }
301
303
 
302
304
  @Composable
303
- fun OverplayView(bottomTabIndex: Int, id: Int) {
305
+ internal fun OverplayView(bottomTabIndex: Int, id: Int) {
304
306
  val overplayType = OverplayComponentRegistry.getOverplayType()
305
307
 
306
308
  if (overplayType != null) {
@@ -355,8 +357,9 @@ data class InputSearchLayoutParams(
355
357
  val endPadding: Dp
356
358
  )
357
359
 
360
+ @Suppress("FrequentlyChangingValue")
358
361
  @Composable
359
- fun SearchAnimated(
362
+ internal fun SearchAnimated(
360
363
  isScrollInProgress: Boolean
361
364
  ) {
362
365
  val scrollState = LocalScrollState.current
@@ -376,7 +379,7 @@ fun SearchAnimated(
376
379
  val minTopPadding = AppStatusBar.current
377
380
  val maxTopPadding = AppStatusBar.current + HEADER_HEIGHT.dp
378
381
  val minStartPadding = Spacing.M
379
- val maxStartPadding = if (options.hiddenBack) Spacing.M else 52.dp
382
+ val maxStartPadding = if (options.hiddenBack) Spacing.M else 48.dp // button back: size + left +right = 28 + 12 + 8 = 48
380
383
  val minEndPadding = Spacing.M
381
384
  val maxEndPadding = headerRightWidthDp + if (options.headerRight is HeaderRight.None) Spacing.M else Spacing.M * 2
382
385
 
@@ -469,64 +472,61 @@ private fun quantize(value: Int, stepPx: Int): Int {
469
472
  }
470
473
 
471
474
  @Composable
472
- fun LazyListState.proxyScrollState(
475
+ internal fun LazyListState.proxyScrollState(
473
476
  thresholdPx: Int = 200,
474
477
  stepPx: Int = 4
475
- ): Pair<ScrollState, Boolean> {
476
- val scrollState = rememberScrollState()
477
- val locked = remember { mutableStateOf(false) }
478
-
479
- LaunchedEffect(this, scrollState, thresholdPx, stepPx) {
480
- snapshotFlow { firstVisibleItemIndex to firstVisibleItemScrollOffset }
481
- .collect { (index, offset) ->
482
- val rawTarget = if (index == 0) offset else SCROLLED_PAST_FIRST_ITEM_THRESHOLD
483
- val shouldLock = rawTarget > thresholdPx
484
- if (locked.value != shouldLock) locked.value = shouldLock
485
-
486
- val desired = if (shouldLock) thresholdPx else quantize(rawTarget, stepPx)
487
-
488
- if (scrollState.value != desired) {
489
- scrollState.scrollTo(desired.coerceAtLeast(0))
490
- }
491
- }
492
- }
493
-
494
- val inProgress = remember { mutableStateOf(false) }
495
- LaunchedEffect(this, thresholdPx) {
496
- snapshotFlow { isScrollInProgress }
497
- .collect { progressing ->
498
- inProgress.value = if (locked.value) false else progressing
499
- }
500
- }
501
-
502
- return scrollState to inProgress.value
503
- }
478
+ ): Pair<ScrollState, Boolean> = proxyScroll(
479
+ source = this,
480
+ thresholdPx = thresholdPx,
481
+ stepPx = stepPx,
482
+ isScrollInProgress = { isScrollInProgress },
483
+ rawTargetFlow = {
484
+ snapshotFlow {
485
+ if (firstVisibleItemIndex == 0) firstVisibleItemScrollOffset
486
+ else SCROLLED_PAST_FIRST_ITEM_THRESHOLD
487
+ }
488
+ },
489
+ )
504
490
 
505
491
  @Composable
506
- fun ScrollState.proxyLimitedScrollState(
492
+ internal fun ScrollState.proxyLimitedScrollState(
507
493
  thresholdPx: Int = 200,
508
494
  stepPx: Int = 4
495
+ ): Pair<ScrollState, Boolean> = proxyScroll(
496
+ source = this,
497
+ thresholdPx = thresholdPx,
498
+ stepPx = stepPx,
499
+ isScrollInProgress = { isScrollInProgress },
500
+ rawTargetFlow = { snapshotFlow { value } },
501
+ )
502
+
503
+ @Composable
504
+ private fun proxyScroll(
505
+ source: Any,
506
+ thresholdPx: Int,
507
+ stepPx: Int,
508
+ isScrollInProgress: () -> Boolean,
509
+ rawTargetFlow: () -> Flow<Int>,
509
510
  ): Pair<ScrollState, Boolean> {
510
511
  val proxy = rememberScrollState()
511
512
  val locked = remember { mutableStateOf(false) }
512
513
 
513
- LaunchedEffect(this, proxy, thresholdPx, stepPx) {
514
- snapshotFlow { value }
515
- .collect { rawTarget ->
516
- val shouldLock = rawTarget > thresholdPx
517
- if (locked.value != shouldLock) locked.value = shouldLock
514
+ LaunchedEffect(source, proxy, thresholdPx, stepPx) {
515
+ rawTargetFlow().collect { rawTarget ->
516
+ val shouldLock = rawTarget > thresholdPx
517
+ if (locked.value != shouldLock) locked.value = shouldLock
518
518
 
519
- val desired = if (shouldLock) thresholdPx else quantize(rawTarget, stepPx)
519
+ val desired = if (shouldLock) thresholdPx else quantize(rawTarget, stepPx)
520
520
 
521
- if (proxy.value != desired) {
522
- proxy.scrollTo(desired.coerceAtLeast(0))
523
- }
521
+ if (proxy.value != desired) {
522
+ proxy.scrollTo(desired.coerceAtLeast(0))
524
523
  }
524
+ }
525
525
  }
526
526
 
527
527
  val inProgress = remember { mutableStateOf(false) }
528
- LaunchedEffect(this, thresholdPx) {
529
- snapshotFlow { isScrollInProgress }
528
+ LaunchedEffect(source, thresholdPx) {
529
+ snapshotFlow { isScrollInProgress() }
530
530
  .collect { progressing ->
531
531
  inProgress.value = if (locked.value) false else progressing
532
532
  }
@@ -6,13 +6,7 @@ import androidx.compose.animation.fadeOut
6
6
  import androidx.compose.animation.scaleIn
7
7
  import androidx.compose.animation.scaleOut
8
8
  import androidx.compose.foundation.background
9
- import androidx.compose.foundation.layout.Box
10
- import androidx.compose.foundation.layout.Column
11
- import androidx.compose.foundation.layout.Spacer
12
- import androidx.compose.foundation.layout.fillMaxSize
13
- import androidx.compose.foundation.layout.fillMaxWidth
14
- import androidx.compose.foundation.layout.height
15
- import androidx.compose.foundation.layout.padding
9
+ import androidx.compose.foundation.layout.*
16
10
  import androidx.compose.runtime.Composable
17
11
  import androidx.compose.runtime.LaunchedEffect
18
12
  import androidx.compose.ui.Alignment
@@ -32,12 +26,12 @@ import vn.momo.kits.navigation.component.HeaderType
32
26
  import vn.momo.kits.platform.getScreenHeight
33
27
 
34
28
  private var bottomTabOptionItems : MutableList<NavigationOptions?> = mutableListOf()
35
- fun setBottomTabOption(index: Int, options: NavigationOptions){
29
+ internal fun setBottomTabOption(index: Int, options: NavigationOptions){
36
30
  if (index in bottomTabOptionItems.indices) {
37
31
  bottomTabOptionItems[index] = options
38
32
  }
39
33
  }
40
- fun getBottomTabOption(index: Int): NavigationOptions? {
34
+ internal fun getBottomTabOption(index: Int): NavigationOptions? {
41
35
  return if (index in bottomTabOptionItems.indices) {
42
36
  bottomTabOptionItems[index]
43
37
  } else null
@@ -5,19 +5,7 @@ import androidx.compose.animation.core.animateDpAsState
5
5
  import androidx.compose.animation.core.tween
6
6
  import androidx.compose.foundation.background
7
7
  import androidx.compose.foundation.border
8
- import androidx.compose.foundation.layout.Arrangement
9
- import androidx.compose.foundation.layout.Box
10
- import androidx.compose.foundation.layout.Column
11
- import androidx.compose.foundation.layout.Row
12
- import androidx.compose.foundation.layout.RowScope
13
- import androidx.compose.foundation.layout.Spacer
14
- import androidx.compose.foundation.layout.fillMaxSize
15
- import androidx.compose.foundation.layout.fillMaxWidth
16
- import androidx.compose.foundation.layout.height
17
- import androidx.compose.foundation.layout.offset
18
- import androidx.compose.foundation.layout.padding
19
- import androidx.compose.foundation.layout.size
20
- import androidx.compose.foundation.layout.width
8
+ import androidx.compose.foundation.layout.*
21
9
  import androidx.compose.foundation.shape.CircleShape
22
10
  import androidx.compose.foundation.shape.RoundedCornerShape
23
11
  import androidx.compose.runtime.Composable
@@ -32,26 +20,18 @@ import androidx.compose.ui.text.style.TextOverflow
32
20
  import androidx.compose.ui.unit.dp
33
21
  import androidx.navigation.NavController
34
22
  import androidx.navigation.compose.currentBackStackEntryAsState
35
- import vn.momo.kits.components.Badge
36
- import vn.momo.kits.components.Icon
37
- import vn.momo.kits.components.Text
38
- import vn.momo.kits.const.AppTheme
39
- import vn.momo.kits.const.Colors
40
- import vn.momo.kits.const.Radius
41
- import vn.momo.kits.const.Spacing
42
23
  import vn.momo.kits.application.IsShowBaseLineDebug
43
- import vn.momo.kits.components.BadgeDot
44
- import vn.momo.kits.components.DotSize
45
- import vn.momo.kits.const.Typography
24
+ import vn.momo.kits.components.*
25
+ import vn.momo.kits.const.*
46
26
  import vn.momo.kits.modifier.conditional
47
27
  import vn.momo.kits.modifier.noFeedbackClickable
48
28
  import vn.momo.kits.platform.getScreenDimensions
49
29
 
50
- val floatingButtonWidth = 75.dp
51
- const val BOTTOM_TAB_BAR_HEIGHT = 64
30
+ internal val floatingButtonWidth = 75.dp
31
+ internal const val BOTTOM_TAB_BAR_HEIGHT = 64
52
32
 
53
33
  @Composable
54
- fun BottomTabBar(
34
+ internal fun BottomTabBar(
55
35
  items: List<BottomTabItem>,
56
36
  floatingButton: BottomTabFloatingButton? = null,
57
37
  navController: NavController,
@@ -91,11 +71,11 @@ fun BottomTabBar(
91
71
  horizontalArrangement = Arrangement.SpaceAround,
92
72
  ) {
93
73
  if (floatingButton == null) {
94
- renderTabBarItem(items, 0, items.size, selectedIndex, onTabSelected)
74
+ RenderTabBarItem(items, 0, items.size, selectedIndex, onTabSelected)
95
75
  } else {
96
- renderTabBarItem(items, 0, mid, selectedIndex, onTabSelected)
76
+ RenderTabBarItem(items, 0, mid, selectedIndex, onTabSelected)
97
77
  Spacer(modifier = Modifier.width(floatingButtonWidth).padding(horizontal = Spacing.XXS))
98
- renderTabBarItem(items, mid, items.size, selectedIndex, onTabSelected)
78
+ RenderTabBarItem(items, mid, items.size, selectedIndex, onTabSelected)
99
79
  }
100
80
  }
101
81
 
@@ -124,7 +104,7 @@ fun BottomTabBar(
124
104
  }
125
105
 
126
106
  @Composable
127
- fun RowScope.renderTabBarItem(
107
+ internal fun RowScope.RenderTabBarItem(
128
108
  items: List<BottomTabItem>,
129
109
  fromIndex: Int,
130
110
  toIndex: Int,
@@ -143,7 +123,7 @@ fun RowScope.renderTabBarItem(
143
123
  }
144
124
 
145
125
  @Composable
146
- fun TabBarItem(item: BottomTabItem, selected: Boolean, onClick: () -> Unit) {
126
+ internal fun TabBarItem(item: BottomTabItem, selected: Boolean, onClick: () -> Unit) {
147
127
  fun isNumber(label: String): Boolean {
148
128
  val numberRegex = "^\\d+$".toRegex()
149
129
  return numberRegex.matches(label)
@@ -203,7 +183,7 @@ fun TabBarItem(item: BottomTabItem, selected: Boolean, onClick: () -> Unit) {
203
183
  }
204
184
 
205
185
  @Composable
206
- fun FloatingButton(data: BottomTabFloatingButton) {
186
+ internal fun FloatingButton(data: BottomTabFloatingButton) {
207
187
  Column(
208
188
  modifier = Modifier
209
189
  .width(floatingButtonWidth)
@@ -17,7 +17,7 @@ import androidx.compose.ui.zIndex
17
17
  import vn.momo.kits.const.AppTheme
18
18
 
19
19
  @Composable
20
- fun CurvedContainer(
20
+ internal fun CurvedContainer(
21
21
  circleSize: Dp = 48.dp,
22
22
  tabBarItemIconSize: Dp = 28.dp,
23
23
  circleOverSize: Dp = 2.dp,
@@ -1,40 +1,21 @@
1
1
  package vn.momo.kits.navigation.component
2
2
 
3
- import androidx.compose.animation.AnimatedVisibility
3
+ import androidx.compose.animation.*
4
4
  import androidx.compose.animation.core.CubicBezierEasing
5
5
  import androidx.compose.animation.core.LinearEasing
6
6
  import androidx.compose.animation.core.animateDpAsState
7
7
  import androidx.compose.animation.core.tween
8
- import androidx.compose.animation.expandHorizontally
9
- import androidx.compose.animation.fadeIn
10
- import androidx.compose.animation.fadeOut
11
- import androidx.compose.animation.shrinkHorizontally
12
8
  import androidx.compose.foundation.ScrollState
13
9
  import androidx.compose.foundation.background
14
10
  import androidx.compose.foundation.border
15
11
  import androidx.compose.foundation.interaction.MutableInteractionSource
16
- import androidx.compose.foundation.layout.Arrangement
17
- import androidx.compose.foundation.layout.Box
18
- import androidx.compose.foundation.layout.Row
19
- import androidx.compose.foundation.layout.Spacer
20
- import androidx.compose.foundation.layout.fillMaxSize
21
- import androidx.compose.foundation.layout.height
22
- import androidx.compose.foundation.layout.offset
23
- import androidx.compose.foundation.layout.padding
24
- import androidx.compose.foundation.layout.sizeIn
25
- import androidx.compose.foundation.layout.width
12
+ import androidx.compose.foundation.layout.*
26
13
  import androidx.compose.material3.AlertDialogDefaults
27
14
  import androidx.compose.material3.FloatingActionButton
28
15
  import androidx.compose.material3.FloatingActionButtonDefaults
29
16
  import androidx.compose.material3.FloatingActionButtonElevation
30
- import androidx.compose.runtime.Composable
31
- import androidx.compose.runtime.LaunchedEffect
32
- import androidx.compose.runtime.getValue
33
- import androidx.compose.runtime.mutableStateOf
34
- import androidx.compose.runtime.remember
35
- import androidx.compose.runtime.rememberCoroutineScope
17
+ import androidx.compose.runtime.*
36
18
  import androidx.compose.runtime.saveable.rememberSaveable
37
- import androidx.compose.runtime.setValue
38
19
  import androidx.compose.ui.Alignment
39
20
  import androidx.compose.ui.Modifier
40
21
  import androidx.compose.ui.graphics.Color
@@ -50,6 +31,7 @@ import vn.momo.kits.components.Text
50
31
  import vn.momo.kits.const.Colors
51
32
  import vn.momo.kits.const.Typography
52
33
  import vn.momo.kits.modifier.conditional
34
+ import kotlin.time.Duration.Companion.milliseconds
53
35
 
54
36
  enum class FABSize { SMALL, DEFAULT }
55
37
  enum class FABPosition { END, CENTER }
@@ -73,7 +55,7 @@ private val FabIconSizeDefault = 24.dp
73
55
  private val FabPaddingHorizontal = 12.dp
74
56
 
75
57
  @Composable
76
- fun FloatingButton(
58
+ internal fun FloatingButton(
77
59
  scrollPosition: Int,
78
60
  bottom: Dp,
79
61
  onClick: () -> Unit,
@@ -106,7 +88,7 @@ fun FloatingButton(
106
88
  coroutineScope.launch {
107
89
  scrollStateFlow.collectLatest { newScroll ->
108
90
  isExpanded = newScroll <= lastScrollPosition
109
- delay(100)
91
+ delay(100.milliseconds)
110
92
  lastScrollPosition = newScroll
111
93
  }
112
94
  }
@@ -1,12 +1,13 @@
1
1
  package vn.momo.kits.navigation.component
2
2
 
3
+ import vn.momo.kits.utils.Deprecated.InternalApi
4
+
3
5
  import androidx.compose.animation.core.animateFloatAsState
4
6
  import androidx.compose.foundation.background
5
7
  import androidx.compose.foundation.border
6
8
  import androidx.compose.foundation.layout.Arrangement
7
9
  import androidx.compose.foundation.layout.Box
8
10
  import androidx.compose.foundation.layout.Row
9
- import androidx.compose.foundation.layout.RowScope
10
11
  import androidx.compose.foundation.layout.Spacer
11
12
  import androidx.compose.foundation.layout.fillMaxWidth
12
13
  import androidx.compose.foundation.layout.height
@@ -23,6 +24,7 @@ import androidx.compose.ui.graphics.Brush
23
24
  import androidx.compose.ui.graphics.Color
24
25
  import androidx.compose.ui.layout.onGloballyPositioned
25
26
  import androidx.compose.ui.platform.LocalDensity
27
+ import androidx.compose.ui.text.style.TextAlign
26
28
  import androidx.compose.ui.unit.Dp
27
29
  import androidx.compose.ui.unit.dp
28
30
  import vn.momo.kits.components.Icon
@@ -42,11 +44,13 @@ import vn.momo.kits.navigation.LocalOptions
42
44
  import vn.momo.kits.navigation.LocalScrollState
43
45
  import vn.momo.kits.navigation.getInputSearchType
44
46
 
45
- const val HEADER_HEIGHT = 52
46
- enum class InputSearchType { None, Header, Animated }
47
+ internal const val HEADER_HEIGHT = 52
48
+ internal enum class InputSearchType { None, Header, Animated }
49
+ enum class TitlePosition { LEFT, CENTER }
47
50
 
51
+ @Suppress("FrequentlyChangingValue")
48
52
  @Composable
49
- fun Header(onBackHandler: (() -> Unit)? = null) {
53
+ internal fun Header(onBackHandler: (() -> Unit)? = null) {
50
54
  val options = LocalOptions.current
51
55
  val navigator = LocalNavigator.current
52
56
  val scrollState = LocalScrollState.current
@@ -76,6 +80,13 @@ fun Header(onBackHandler: (() -> Unit)? = null) {
76
80
  AppTheme.current.colors.background.surface
77
81
 
78
82
  if (options.headerType == HeaderType.None) return
83
+
84
+ val titlePosition = options.titlePosition
85
+ val titleColor = headerColor.tintIconColor
86
+ .copy(alpha = if (inputSearchType == InputSearchType.Animated) 1f - animatedAlpha else 1f)
87
+ // Centered title needs a full-width overlay to stay screen-centered, not boxed between back button and header right.
88
+ val centerTitle = titlePosition == TitlePosition.CENTER && options.headerTitle is HeaderTitle.Default
89
+
79
90
  Box(
80
91
  Modifier.height(AppStatusBar.current + HEADER_HEIGHT.dp)
81
92
  .fillMaxWidth()
@@ -101,20 +112,40 @@ fun Header(onBackHandler: (() -> Unit)? = null) {
101
112
  onBackHandler?.invoke() ?: navigator.onBackSafe { }
102
113
  }
103
114
  )
104
- Spacer(Modifier.width(Spacing.M))
115
+ Spacer(Modifier.width(Spacing.S))
105
116
  }
106
117
 
107
- HeaderContent(
108
- options.headerTitle,
109
- headerColor.tintIconColor
110
- .copy(alpha = if (inputSearchType == InputSearchType.Animated) 1f - animatedAlpha else 1f)
111
- )
118
+ if (centerTitle) {
119
+ Spacer(Modifier.weight(1f))
120
+ } else {
121
+ HeaderContent(
122
+ headerTitle = options.headerTitle,
123
+ tintIconColor = titleColor,
124
+ titlePosition = titlePosition,
125
+ modifier = Modifier.weight(1f)
126
+ )
127
+ }
112
128
  Box(Modifier.onGloballyPositioned {
113
129
  if(headerRightWidthPx.intValue != it.size.width) headerRightWidthPx.intValue = it.size.width
114
130
  }){
115
131
  HeaderRight(options.headerRight, options.tintColor, headerColor)
116
132
  }
117
133
  }
134
+ if (centerTitle) {
135
+ Box(
136
+ modifier = Modifier.height(HEADER_HEIGHT.dp)
137
+ .fillMaxWidth()
138
+ .padding(horizontal = Spacing.M),
139
+ contentAlignment = Alignment.Center
140
+ ) {
141
+ HeaderContent(
142
+ headerTitle = options.headerTitle,
143
+ tintIconColor = titleColor,
144
+ titlePosition = titlePosition,
145
+ modifier = Modifier.fillMaxWidth()
146
+ )
147
+ }
148
+ }
118
149
  VerticalShadow(opacity)
119
150
  }
120
151
  }
@@ -140,15 +171,23 @@ private fun BackButton(borderColor: Color, backgroundButton: Color, tintIconColo
140
171
  }
141
172
 
142
173
  @Composable
143
- fun RowScope.HeaderContent(headerTitle: HeaderTitle, tintIconColor: Color){
174
+ internal fun HeaderContent(
175
+ headerTitle: HeaderTitle,
176
+ tintIconColor: Color,
177
+ titlePosition: TitlePosition = TitlePosition.LEFT,
178
+ modifier: Modifier = Modifier,
179
+ ){
144
180
  Box(
145
- Modifier.weight(1f)
181
+ modifier = modifier,
182
+ contentAlignment = if (titlePosition == TitlePosition.CENTER) Alignment.Center else Alignment.CenterStart
146
183
  ) {
147
184
  when (headerTitle){
148
185
  is HeaderTitle.Default -> {
149
186
  HeaderTitle(
150
187
  title = headerTitle.title,
151
- color = tintIconColor
188
+ color = tintIconColor,
189
+ modifier = Modifier.fillMaxWidth(fraction = if (titlePosition == TitlePosition.CENTER) 0.5f else 1f),
190
+ textAlign = if (titlePosition == TitlePosition.CENTER) TextAlign.Center else TextAlign.Start
152
191
  )
153
192
  }
154
193
  is HeaderTitle.Journey -> {}
@@ -163,7 +202,7 @@ fun RowScope.HeaderContent(headerTitle: HeaderTitle, tintIconColor: Color){
163
202
  }
164
203
 
165
204
  @Composable
166
- fun VerticalShadow(opacity: Float){
205
+ internal fun VerticalShadow(opacity: Float){
167
206
  if(opacity == 1f){
168
207
  Box(modifier = Modifier
169
208
  .fillMaxWidth()
@@ -246,8 +285,9 @@ data class HeaderBackProps(
246
285
  val preventBack: PopupNotifyProps? = null,
247
286
  )
248
287
 
288
+ @InternalApi
249
289
  data class HeaderColor(val tintIconColor: Color, val backgroundButton: Color, val borderColor: Color)
250
- fun getHeaderColor(headerType: HeaderType, opacity: Float, tintColor: Color?, defaultColor: Color): HeaderColor{
290
+ internal fun getHeaderColor(headerType: HeaderType, opacity: Float, tintColor: Color?, defaultColor: Color): HeaderColor{
251
291
  return if(headerType is HeaderType.Animated) {
252
292
  if (opacity == 1f || !headerType.isSurface)
253
293
  HeaderColor(
@@ -27,8 +27,9 @@ enum class AnimatedHeaderRatio(val value: Float){
27
27
  RATIO_3_2(3f / 2f)
28
28
  }
29
29
 
30
+ @Suppress("FrequentlyChangingValue")
30
31
  @Composable
31
- fun HeaderBackground() {
32
+ internal fun HeaderBackground() {
32
33
  val density = LocalDensity.current
33
34
  val theme = AppTheme.current
34
35
  val options = LocalOptions.current
@@ -1,5 +1,7 @@
1
1
  package vn.momo.kits.navigation.component
2
2
 
3
+ import vn.momo.kits.utils.Deprecated.InternalApi
4
+
3
5
  import androidx.compose.foundation.background
4
6
  import androidx.compose.foundation.border
5
7
  import androidx.compose.foundation.layout.Arrangement
@@ -35,6 +37,7 @@ import vn.momo.kits.modifier.activeOpacityClickable
35
37
  import vn.momo.kits.navigation.LocalMaxApi
36
38
 
37
39
  @Composable
40
+ @InternalApi
38
41
  fun HeaderRight(
39
42
  headerRight: HeaderRight,
40
43
  tintColor: Color? = null,
@@ -57,7 +60,7 @@ fun HeaderRight(
57
60
  }
58
61
 
59
62
  @Composable
60
- fun Toolkit(
63
+ internal fun Toolkit(
61
64
  headerRight: HeaderRight.Toolkit,
62
65
  tintColor: Color? = null,
63
66
  headerColor: HeaderColor
@@ -186,7 +189,7 @@ fun Toolkit(
186
189
 
187
190
 
188
191
  @Composable
189
- fun NavigationButton(
192
+ internal fun NavigationButton(
190
193
  disabled: Boolean,
191
194
  icon: String,
192
195
  showBadge: Boolean? = false,
@@ -300,7 +303,7 @@ data class Tool(
300
303
  }
301
304
  }
302
305
 
303
- data class NavigationButtonConfig(
306
+ private data class NavigationButtonConfig(
304
307
  val icon: String,
305
308
  val onPress: () -> Unit
306
309
  )
@@ -13,14 +13,16 @@ import vn.momo.kits.const.Typography
13
13
  import vn.momo.kits.modifier.setAutomationId
14
14
 
15
15
  @Composable
16
- fun HeaderTitle(
16
+ internal fun HeaderTitle(
17
17
  title: String = "",
18
18
  color: Color? = null,
19
+ modifier: Modifier = Modifier.fillMaxWidth(),
20
+ textAlign: TextAlign = TextAlign.Start,
19
21
  ) {
20
22
  Text(
21
- modifier = Modifier.fillMaxWidth().zIndex(1f).setAutomationId("title_navigation_header"),
23
+ modifier = modifier.zIndex(1f).setAutomationId("title_navigation_header"),
22
24
  text = title,
23
- textAlign = TextAlign.Start,
25
+ textAlign = textAlign,
24
26
  style = Typography.actionSBold.copy(
25
27
  fontSize = 15.sp,
26
28
  lineHeight = 22.sp,
@@ -2,17 +2,7 @@ package vn.momo.kits.navigation.component
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.Box
7
- import androidx.compose.foundation.layout.Column
8
- import androidx.compose.foundation.layout.Row
9
- import androidx.compose.foundation.layout.Spacer
10
- import androidx.compose.foundation.layout.fillMaxWidth
11
- import androidx.compose.foundation.layout.height
12
- import androidx.compose.foundation.layout.padding
13
- import androidx.compose.foundation.layout.size
14
- import androidx.compose.foundation.layout.width
15
- import androidx.compose.foundation.layout.widthIn
5
+ import androidx.compose.foundation.layout.*
16
6
  import androidx.compose.foundation.shape.CircleShape
17
7
  import androidx.compose.foundation.shape.RoundedCornerShape
18
8
  import androidx.compose.foundation.text.BasicText
@@ -43,7 +33,7 @@ import vn.momo.kits.navigation.component.HeaderTitle.User
43
33
  import vn.momo.kits.platform.getScreenDimensions
44
34
 
45
35
  @Composable
46
- fun HeaderUser(
36
+ internal fun HeaderUser(
47
37
  data: HeaderTitle
48
38
  ) {
49
39
  if (data !is User) return
@@ -367,4 +357,4 @@ private fun RemoteIcon16(url: String) {
367
357
  }
368
358
 
369
359
  @Immutable
370
- data class AvatarUrls(val items: List<String>)
360
+ private data class AvatarUrls(val items: List<String>)