@momo-kits/native-kits 0.161.2-beta.8-debug → 0.161.2-nocompotie.999-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 (23) hide show
  1. package/compose/build.gradle.kts +3 -9
  2. package/compose/build.gradle.kts.backup +2 -8
  3. package/compose/compose.podspec +1 -1
  4. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +1 -7
  5. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +24 -30
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -4
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +1 -5
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -12
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +26 -16
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +9 -45
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +2 -4
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +1 -9
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +4 -12
  14. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +1 -7
  15. package/example/ios/Example.xcodeproj/xcuserdata/thanhle.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
  16. package/example/ios/Example.xcworkspace/xcuserdata/thanhle.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  17. package/example/ios/Example.xcworkspace/xcuserdata/thanhle.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
  18. package/gradle/libs.versions.toml +0 -2
  19. package/gradle.properties +1 -1
  20. package/local.properties +8 -0
  21. package/package.json +1 -1
  22. package/settings.gradle.kts +3 -15
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -62
@@ -30,7 +30,7 @@ kotlin {
30
30
  }
31
31
 
32
32
  val fwName = gitlabArtifactId
33
- val iosTargets = listOf(iosArm64(), iosSimulatorArm64())
33
+ val iosTargets = listOf(iosX64(), iosArm64(), iosSimulatorArm64())
34
34
  iosTargets.forEach {
35
35
  it.binaries.framework {
36
36
  baseName = fwName
@@ -40,7 +40,7 @@ kotlin {
40
40
  }
41
41
 
42
42
  cocoapods {
43
- version = "0.161.2-beta.8-debug"
43
+ version = "0.161.2-nocompotie.999-debug"
44
44
  summary = "IOS Shared module"
45
45
  homepage = "https://momo.vn"
46
46
  ios.deploymentTarget = "15.0"
@@ -73,7 +73,6 @@ kotlin {
73
73
  implementation(libs.jetbrains.serialization.json)
74
74
  implementation(libs.kotlinx.datetime)
75
75
  api(libs.native.max.api)
76
- implementation(libs.compottie)
77
76
  }
78
77
  androidMain.dependencies {
79
78
  implementation(libs.ktor.client.okhttp)
@@ -109,17 +108,12 @@ repositories {
109
108
  }
110
109
  }
111
110
  mavenCentral()
112
- maven { url = uri("https://maven.pkg.jetbrains.space/public/p/compose/dev") }
113
111
  maven {
114
112
  url = uri("https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven")
115
113
  credentials {username = "download_packages"; password = "gldt-bjDqLpU_sPcHDuXau2ws" }
116
114
  }
117
115
  maven {
118
- url = uri("https://artifacts.mservice.com.vn/repository/maven-momo-app/")
119
- credentials {
120
- username = "viewer"
121
- password = "viewer"
122
- }
116
+ url = uri("http://nexus.mservice.com.vn:8081/repository/maven-public/")
123
117
  isAllowInsecureProtocol = true
124
118
  }
125
119
  }
@@ -30,7 +30,7 @@ kotlin {
30
30
  }
31
31
 
32
32
  val fwName = gitlabArtifactId
33
- val iosTargets = listOf(iosArm64(), iosSimulatorArm64())
33
+ val iosTargets = listOf(iosX64(), iosArm64(), iosSimulatorArm64())
34
34
  iosTargets.forEach {
35
35
  it.binaries.framework {
36
36
  baseName = fwName
@@ -73,7 +73,6 @@ kotlin {
73
73
  implementation(libs.jetbrains.serialization.json)
74
74
  implementation(libs.kotlinx.datetime)
75
75
  api(libs.native.max.api)
76
- implementation(libs.compottie)
77
76
  }
78
77
  androidMain.dependencies {
79
78
  implementation(libs.ktor.client.okhttp)
@@ -109,17 +108,12 @@ repositories {
109
108
  }
110
109
  }
111
110
  mavenCentral()
112
- maven { url = uri("https://maven.pkg.jetbrains.space/public/p/compose/dev") }
113
111
  maven {
114
112
  url = uri("https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven")
115
113
  credentials {username = "download_packages"; password = "gldt-bjDqLpU_sPcHDuXau2ws" }
116
114
  }
117
115
  maven {
118
- url = uri("https://artifacts.mservice.com.vn/repository/maven-momo-app/")
119
- credentials {
120
- username = "viewer"
121
- password = "viewer"
122
- }
116
+ url = uri("http://nexus.mservice.com.vn:8081/repository/maven-public/")
123
117
  isAllowInsecureProtocol = true
124
118
  }
125
119
  }
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |spec|
2
2
  spec.name = 'compose'
3
- spec.version = '0.161.2-beta.1'
3
+ spec.version = '0.161.2-search-header.1'
4
4
  spec.homepage = 'https://momo.vn'
5
5
  spec.source = { :http=> ''}
6
6
  spec.authors = ''
@@ -78,14 +78,8 @@ actual fun LottieAnimation(
78
78
  tintColor: Color?,
79
79
  bgColor: Color?,
80
80
  placedAsOverlay: Boolean,
81
- modifier: Modifier,
82
- useCompose: Boolean
81
+ modifier: Modifier
83
82
  ) {
84
- if (useCompose) {
85
- ComposeLottieAnimation(path, tintColor, bgColor, modifier)
86
- return
87
- }
88
-
89
83
  val json = readJson(path)
90
84
 
91
85
  if (json.isEmpty()) {
@@ -38,6 +38,7 @@ import androidx.compose.runtime.produceState
38
38
  import androidx.compose.runtime.remember
39
39
  import androidx.compose.runtime.rememberUpdatedState
40
40
  import androidx.compose.runtime.snapshotFlow
41
+ import androidx.compose.runtime.staticCompositionLocalOf
41
42
  import androidx.compose.ui.Alignment
42
43
  import androidx.compose.ui.Modifier
43
44
  import androidx.compose.ui.composed
@@ -48,6 +49,7 @@ import androidx.compose.ui.geometry.Offset
48
49
  import androidx.compose.ui.geometry.Rect
49
50
  import androidx.compose.ui.graphics.Brush
50
51
  import androidx.compose.ui.graphics.Color
52
+ import androidx.compose.ui.graphics.SolidColor
51
53
  import androidx.compose.ui.graphics.graphicsLayer
52
54
  import androidx.compose.ui.input.pointer.pointerInput
53
55
  import androidx.compose.ui.layout.Layout
@@ -60,19 +62,15 @@ import androidx.compose.ui.layout.layoutId
60
62
  import androidx.compose.ui.platform.LocalDensity
61
63
  import androidx.compose.ui.platform.LocalFocusManager
62
64
  import androidx.compose.ui.platform.LocalSoftwareKeyboardController
63
- import androidx.compose.ui.text.style.TextOverflow
64
65
  import androidx.compose.ui.text.TextStyle
66
+ import androidx.compose.ui.text.style.TextOverflow
65
67
  import androidx.compose.ui.unit.Constraints
66
68
  import androidx.compose.ui.unit.Dp
67
69
  import androidx.compose.ui.unit.IntOffset
68
70
  import androidx.compose.ui.unit.LayoutDirection
69
71
  import androidx.compose.ui.unit.dp
70
- import androidx.compose.ui.unit.sp
71
- import androidx.compose.runtime.staticCompositionLocalOf
72
- import androidx.compose.ui.graphics.Color.Companion
73
- import androidx.compose.ui.graphics.SolidColor
74
72
  import androidx.compose.ui.unit.lerp
75
- import kotlinx.coroutines.flow.StateFlow
73
+ import androidx.compose.ui.unit.sp
76
74
  import kotlinx.coroutines.flow.collectLatest
77
75
  import kotlinx.coroutines.flow.mapNotNull
78
76
  import vn.momo.kits.components.Icon
@@ -81,11 +79,11 @@ import vn.momo.kits.const.AppTheme
81
79
  import vn.momo.kits.const.Colors
82
80
  import vn.momo.kits.const.Spacing
83
81
  import vn.momo.kits.const.Typography
84
- import vn.momo.kits.modifier.conditional
85
82
  import vn.momo.kits.modifier.kitsAutomationId
86
83
  import vn.momo.kits.modifier.noFeedbackClickable
87
84
  import vn.momo.kits.modifier.setAutomationId
88
85
  import vn.momo.kits.modifier.shadow
86
+ import vn.momo.kits.navigation.component.HEADER_HEIGHT
89
87
  import vn.momo.kits.utils.getAppStatusBarHeight
90
88
  import kotlin.math.max
91
89
  import kotlin.math.roundToInt
@@ -441,6 +439,7 @@ private class LiteScreenLayoutPolicy(
441
439
  val spacing12 = Spacing.M.roundToPx()
442
440
  val spaceBetween = headerSpaceBetween?.roundToPx() ?: spacing12
443
441
  val statusBarPx = statusBarHeight.roundToPx()
442
+ val headerRowDefault = HEADER_HEIGHT.dp.roundToPx()
444
443
  val scrollPercent = scrollPercentage.value
445
444
 
446
445
  val contentMeasurable = measurables.find { it.layoutId == HeaderId.CONTENT_ID }
@@ -484,26 +483,20 @@ private class LiteScreenLayoutPolicy(
484
483
  )
485
484
  )
486
485
 
487
- val firstRowMaxHeight = buildList {
488
- add(backIconPlaceable.safeHeight)
489
- add(headerRightPlaceable.safeHeight)
490
- if (!isHeaderExtend) {
491
- add(inputSearchPlaceable.safeHeight)
492
- }
493
- add(HEADER_HEIGHT.dp.roundToPx())
494
- if (isHeaderExtend) {
495
- add(titlePlaceable.safeHeight)
496
- }
497
- }.max()
498
-
499
- var defaultHeight = statusBarPx + spacing12 + firstRowMaxHeight + spacing12
486
+ /**
487
+ * replicate logic from [vn.momo.kits.navigation.component.HeaderBackground]
488
+ * */
489
+ var defaultHeight = statusBarPx + headerRowDefault
500
490
  if (isHeaderExtend) {
501
- defaultHeight += inputSearchPlaceable.safeHeight + spacing12
491
+ defaultHeight = 154.dp.roundToPx()
502
492
  }
503
493
  val headerHeight = when {
504
494
  isHeaderNone -> statusBarPx
505
495
  !useAnimationSearch && !isHeaderExtend -> defaultHeight
506
- else -> (defaultHeight - scrollPercent * (defaultHeight - statusBarPx - HEADER_HEIGHT.dp.roundToPx())).toInt()
496
+ else -> {
497
+ val collapsableSpace = defaultHeight - statusBarPx - headerRowDefault
498
+ (defaultHeight - scrollPercent * collapsableSpace).toInt()
499
+ }
507
500
  }
508
501
 
509
502
  val layoutWidth = constraints.maxWidth
@@ -566,14 +559,14 @@ private class LiteScreenLayoutPolicy(
566
559
  if (backIconPlaceable != null) {
567
560
  backIconPlaceable.place(
568
561
  x = startX,
569
- y = startY + backIconPlaceable.verticalCenterOffset(firstRowMaxHeight),
562
+ y = startY + backIconPlaceable.verticalCenterOffset(headerRowDefault),
570
563
  )
571
564
  curX += backIconPlaceable.safeWidth + spaceBetween
572
565
  }
573
566
 
574
567
  headerRightPlaceable?.place(
575
568
  x = layoutWidth - spacing12 - headerRightPlaceable.safeWidth,
576
- y = startY + headerRightPlaceable.verticalCenterOffset(firstRowMaxHeight),
569
+ y = startY + headerRightPlaceable.verticalCenterOffset(headerRowDefault),
577
570
  )
578
571
 
579
572
  val titleOffset = IntOffset(
@@ -582,19 +575,19 @@ private class LiteScreenLayoutPolicy(
582
575
  space = layoutWidth,
583
576
  layoutDirection = layoutDirection,
584
577
  ),
585
- y = startY + titlePlaceable.verticalCenterOffset(firstRowMaxHeight),
578
+ y = startY + titlePlaceable.verticalCenterOffset(headerRowDefault),
586
579
  )
587
580
 
588
581
  titlePlaceable?.place(titleOffset)
589
582
 
590
583
  if (backIconPlaceable != null || headerRightPlaceable != null || titlePlaceable != null) {
591
- curY += firstRowMaxHeight
584
+ curY += headerRowDefault
592
585
  }
593
586
 
594
587
  val inputSearchOffset = if (isHeaderExtend) {
595
- val baseY = curY + inputSearchPlaceable.verticalCenterOffset(firstRowMaxHeight)
588
+ val baseY = curY + inputSearchPlaceable.verticalCenterOffset(headerRowDefault)
596
589
  val y = (baseY * (1 - scrollPercent)).toInt().coerceAtLeast(
597
- startY + inputSearchPlaceable.verticalCenterOffset(firstRowMaxHeight)
590
+ startY + inputSearchPlaceable.verticalCenterOffset(headerRowDefault)
598
591
  )
599
592
  IntOffset(
600
593
  x = startX + ((backIconPlaceable.safeWidth + spaceBetween) * (scrollPercent * 2f).coerceIn(
@@ -605,7 +598,7 @@ private class LiteScreenLayoutPolicy(
605
598
  } else {
606
599
  IntOffset(
607
600
  x = curX,
608
- y = startY + inputSearchPlaceable.verticalCenterOffset(firstRowMaxHeight),
601
+ y = startY + inputSearchPlaceable.verticalCenterOffset(headerRowDefault),
609
602
  )
610
603
  }
611
604
  val finalPosition = lerp(
@@ -823,7 +816,8 @@ private fun LiteInputSearch(
823
816
  if (!placeHolder.isNullOrEmpty()) {
824
817
  inputSearchProps.customPlaceHolder?.invoke() ?: Text(
825
818
  text = placeHolder ?: "",
826
- style = inputSearchProps.customTextStyle ?: Typography.bodyDefaultRegular,
819
+ style = inputSearchProps.customTextStyle
820
+ ?: Typography.bodyDefaultRegular,
827
821
  maxLines = 1,
828
822
  color = theme.colors.text.hint,
829
823
  overflow = TextOverflow.Ellipsis
@@ -13,7 +13,6 @@ import vn.momo.kits.navigation.component.HeaderBackProps
13
13
  import vn.momo.kits.navigation.component.HeaderRight
14
14
  import vn.momo.kits.navigation.component.HeaderTitle
15
15
  import vn.momo.kits.navigation.component.HeaderType
16
- import vn.momo.kits.navigation.component.TitlePosition
17
16
 
18
17
  class Navigation(
19
18
  val id: Int = -1,
@@ -29,7 +28,6 @@ class Navigation(
29
28
  hiddenBack: Boolean? = null,
30
29
  headerBackProps: HeaderBackProps? = null,
31
30
  headerTitle: HeaderTitle? = null,
32
- titlePosition: TitlePosition? = null,
33
31
  headerRight: HeaderRight? = null,
34
32
  headerType: HeaderType? = null,
35
33
  scrollData: ScrollData? = null,
@@ -45,7 +43,6 @@ class Navigation(
45
43
  hiddenBack = hiddenBack ?: options.hiddenBack,
46
44
  headerBackProps = headerBackProps ?: options.headerBackProps,
47
45
  headerTitle = headerTitle ?: options.headerTitle,
48
- titlePosition = titlePosition ?: options.titlePosition,
49
46
  headerRight = headerRight ?: options.headerRight,
50
47
  headerType = headerType ?: options.headerType,
51
48
  scrollData = scrollData ?: options.scrollData,
@@ -80,7 +77,6 @@ data class NavigationOptions(
80
77
  val hiddenBack: Boolean = false,
81
78
  val headerBackProps: HeaderBackProps = HeaderBackProps(),
82
79
  val headerTitle: HeaderTitle = HeaderTitle.Default("Stack"),
83
- val titlePosition: TitlePosition = TitlePosition.LEFT,
84
80
  val headerRight: HeaderRight = HeaderRight.Toolkit(),
85
81
  val headerType: HeaderType = HeaderType.Default(),
86
82
  val scrollData: ScrollData = ScrollData(),
@@ -3,7 +3,6 @@ package vn.momo.kits.navigation
3
3
  import androidx.compose.animation.*
4
4
  import androidx.compose.animation.core.tween
5
5
  import androidx.compose.runtime.*
6
- import androidx.compose.runtime.saveable.rememberSaveable
7
6
  import androidx.compose.ui.unit.Dp
8
7
  import androidx.navigation.compose.NavHost
9
8
  import androidx.navigation.compose.composable
@@ -50,9 +49,7 @@ fun NavigationContainer(
50
49
  }
51
50
  }
52
51
 
53
- val screenId = rememberSaveable { DynamicScreenRegistry.nextId() }
54
- DynamicScreenRegistry.bind(screenId, initialScreenName, initialScreen, options)
55
- val startDestination = remember(screenId) { DynamicScreenRoute(screenId) }
52
+ val startDestination = DynamicScreenRegistry.register(initialScreenName, initialScreen, options)
56
53
 
57
54
  ProvideNavigationEventDispatcherOwner {
58
55
  CompositionLocalProvider(
@@ -135,7 +132,6 @@ fun NavigationContainer(
135
132
  DisposableEffect(Unit) {
136
133
  onDispose {
137
134
  navigator.dispose()
138
- DynamicScreenRegistry.unregisterScreen(screenId)
139
135
  }
140
136
  }
141
137
  }
@@ -196,18 +196,6 @@ object DynamicScreenRegistry {
196
196
  return DynamicScreenRoute(id)
197
197
  }
198
198
 
199
- fun nextId(): Int = idCounter++
200
-
201
- fun bind(id: Int, screenName: String, content: @Composable () -> Unit, options: NavigationOptions?) {
202
- screens[id] = DynamicScreen(
203
- id = id,
204
- name = screenName,
205
- content = content,
206
- options = options
207
- )
208
- if (id >= idCounter) idCounter = id + 1 // keep counter ahead after process-death restore
209
- }
210
-
211
199
  fun unregisterScreen(id: Int) {
212
200
  screens.remove(id)
213
201
  }
@@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.Column
11
11
  import androidx.compose.foundation.layout.ColumnScope
12
12
  import androidx.compose.foundation.layout.Spacer
13
13
  import androidx.compose.foundation.layout.WindowInsets
14
- import androidx.compose.foundation.layout.asPaddingValues
15
14
  import androidx.compose.foundation.layout.aspectRatio
16
15
  import androidx.compose.foundation.layout.fillMaxSize
17
16
  import androidx.compose.foundation.layout.fillMaxWidth
@@ -28,12 +27,10 @@ import androidx.compose.material.ExperimentalMaterialApi
28
27
  import androidx.compose.runtime.Composable
29
28
  import androidx.compose.runtime.CompositionLocalProvider
30
29
  import androidx.compose.runtime.LaunchedEffect
31
- import androidx.compose.runtime.State
32
30
  import androidx.compose.runtime.getValue
33
31
  import androidx.compose.runtime.mutableIntStateOf
34
32
  import androidx.compose.runtime.mutableStateOf
35
33
  import androidx.compose.runtime.remember
36
- import androidx.compose.runtime.rememberUpdatedState
37
34
  import androidx.compose.runtime.snapshotFlow
38
35
  import androidx.compose.runtime.staticCompositionLocalOf
39
36
  import androidx.compose.ui.Alignment
@@ -182,20 +179,23 @@ internal fun StackScreen(
182
179
  HeaderBackground()
183
180
  }
184
181
 
185
- Box(Modifier.zIndex(4f)) {
182
+ Box(Modifier.zIndex(5f)) {
186
183
  Header(onBackHandler)
187
184
  }
188
185
 
189
- Column(Modifier.zIndex(5f)) {
186
+ Column(Modifier.zIndex(6f)) {
190
187
  SearchAnimated(isScrollInProgress = scrollInProcess)
191
188
  }
192
189
 
193
190
  Column(Modifier.zIndex(2f).fillMaxSize()) {
194
191
  MainContent(content = content)
192
+ }
193
+
194
+ Box(Modifier.zIndex(4f).align(Alignment.BottomCenter)) {
195
195
  FooterContent()
196
196
  }
197
197
 
198
- Box(Modifier.zIndex(6f)) {
198
+ Box(Modifier.zIndex(7f)) {
199
199
  FloatingContent()
200
200
  }
201
201
 
@@ -261,6 +261,11 @@ fun ColumnScope.MainContent(content: @Composable () -> Unit) {
261
261
  ScreenContent(content = content)
262
262
  }
263
263
 
264
+ if (options.footerComponent != null) {
265
+ val footerHeight = LocalFooterHeightPx.current
266
+ val footerHeightDp = with(density) { footerHeight.value.toDp() }
267
+ Spacer(Modifier.height(footerHeightDp))
268
+ }
264
269
  }
265
270
 
266
271
  @Composable
@@ -274,7 +279,7 @@ fun ScreenContent(content: @Composable () -> Unit) {
274
279
  Box(Modifier.fillMaxWidth().aspectRatio(animatedHeader.aspectRatio.value)) {
275
280
  animatedHeader.composable.invoke(scrollState.value)
276
281
  }
277
- Box(Modifier.padding(top = AppStatusBar.current + HEADER_HEIGHT.dp + animatedHeader.layoutOffSet)) {
282
+ Box(Modifier.offset(x = 0.dp, y = AppStatusBar.current + HEADER_HEIGHT.dp + animatedHeader.layoutOffSet)) {
278
283
  content()
279
284
  }
280
285
  }
@@ -287,24 +292,22 @@ fun ScreenContent(content: @Composable () -> Unit) {
287
292
  fun FooterContent() {
288
293
  val options = LocalOptions.current
289
294
  if (options.footerComponent != null) {
290
- val keyboardSize = keyboardSizeState()
291
- val bottomPadding = (AppNavigationBar.current - keyboardSize.value).coerceAtLeast(0.dp)
295
+ val ime = WindowInsets.ime
296
+ val density = LocalDensity.current
297
+ val imeBottom = ime.getBottom(density)
298
+ val thresholdPx = with(density) { 50.dp.toPx() }
299
+ val isKeyboardVisible = imeBottom > thresholdPx
300
+ val bottomPadding = if (isKeyboardVisible) 0.dp else AppNavigationBar.current
292
301
  Footer(footerComponent = options.footerComponent, bottomPadding = bottomPadding)
293
302
  }
294
303
  }
295
304
 
296
- @Composable
297
- fun keyboardSizeState(): State<Dp> {
298
- val bottom = WindowInsets.ime.asPaddingValues()
299
- return rememberUpdatedState(bottom.calculateBottomPadding())
300
- }
301
-
302
305
  @Composable
303
306
  fun OverplayView(bottomTabIndex: Int, id: Int) {
304
307
  val overplayType = OverplayComponentRegistry.getOverplayType()
305
308
 
306
309
  if (overplayType != null) {
307
- Box(Modifier.zIndex(if (overplayType == OverplayComponentType.SNACK_BAR) 3f else 7f).fillMaxSize()) {
310
+ Box(Modifier.zIndex(if (overplayType == OverplayComponentType.SNACK_BAR) 3f else 8f).fillMaxSize()) {
308
311
  if (bottomTabIndex != -1) return@Box
309
312
  if (OverplayComponentRegistry.currentRootId() != id) return@Box
310
313
  OverplayComponentRegistry.OverlayComponent()
@@ -463,6 +466,13 @@ fun SearchAnimated(
463
466
  }
464
467
  }
465
468
 
469
+ @Composable
470
+ internal fun isKeyboardVisible(): Boolean {
471
+ val ime = WindowInsets.ime
472
+ val density = LocalDensity.current
473
+ return ime.getBottom(density) > 0
474
+ }
475
+
466
476
  private fun quantize(value: Int, stepPx: Int): Int {
467
477
  if (stepPx <= 1) return value
468
478
  return (value / stepPx) * stepPx
@@ -6,6 +6,7 @@ import androidx.compose.foundation.border
6
6
  import androidx.compose.foundation.layout.Arrangement
7
7
  import androidx.compose.foundation.layout.Box
8
8
  import androidx.compose.foundation.layout.Row
9
+ import androidx.compose.foundation.layout.RowScope
9
10
  import androidx.compose.foundation.layout.Spacer
10
11
  import androidx.compose.foundation.layout.fillMaxWidth
11
12
  import androidx.compose.foundation.layout.height
@@ -22,7 +23,6 @@ import androidx.compose.ui.graphics.Brush
22
23
  import androidx.compose.ui.graphics.Color
23
24
  import androidx.compose.ui.layout.onGloballyPositioned
24
25
  import androidx.compose.ui.platform.LocalDensity
25
- import androidx.compose.ui.text.style.TextAlign
26
26
  import androidx.compose.ui.unit.Dp
27
27
  import androidx.compose.ui.unit.dp
28
28
  import vn.momo.kits.components.Icon
@@ -44,7 +44,6 @@ import vn.momo.kits.navigation.getInputSearchType
44
44
 
45
45
  const val HEADER_HEIGHT = 52
46
46
  enum class InputSearchType { None, Header, Animated }
47
- enum class TitlePosition { LEFT, CENTER }
48
47
 
49
48
  @Composable
50
49
  fun Header(onBackHandler: (() -> Unit)? = null) {
@@ -77,13 +76,6 @@ fun Header(onBackHandler: (() -> Unit)? = null) {
77
76
  AppTheme.current.colors.background.surface
78
77
 
79
78
  if (options.headerType == HeaderType.None) return
80
-
81
- val titlePosition = options.titlePosition
82
- val titleColor = headerColor.tintIconColor
83
- .copy(alpha = if (inputSearchType == InputSearchType.Animated) 1f - animatedAlpha else 1f)
84
- // Centered title needs a full-width overlay to stay screen-centered, not boxed between back button and header right.
85
- val centerTitle = titlePosition == TitlePosition.CENTER && options.headerTitle is HeaderTitle.Default
86
-
87
79
  Box(
88
80
  Modifier.height(AppStatusBar.current + HEADER_HEIGHT.dp)
89
81
  .fillMaxWidth()
@@ -112,37 +104,17 @@ fun Header(onBackHandler: (() -> Unit)? = null) {
112
104
  Spacer(Modifier.width(Spacing.M))
113
105
  }
114
106
 
115
- if (centerTitle) {
116
- Spacer(Modifier.weight(1f))
117
- } else {
118
- HeaderContent(
119
- headerTitle = options.headerTitle,
120
- tintIconColor = titleColor,
121
- titlePosition = titlePosition,
122
- modifier = Modifier.weight(1f)
123
- )
124
- }
107
+ HeaderContent(
108
+ options.headerTitle,
109
+ headerColor.tintIconColor
110
+ .copy(alpha = if (inputSearchType == InputSearchType.Animated) 1f - animatedAlpha else 1f)
111
+ )
125
112
  Box(Modifier.onGloballyPositioned {
126
113
  if(headerRightWidthPx.intValue != it.size.width) headerRightWidthPx.intValue = it.size.width
127
114
  }){
128
115
  HeaderRight(options.headerRight, options.tintColor, headerColor)
129
116
  }
130
117
  }
131
- if (centerTitle) {
132
- Box(
133
- modifier = Modifier.height(HEADER_HEIGHT.dp)
134
- .fillMaxWidth()
135
- .padding(horizontal = Spacing.M),
136
- contentAlignment = Alignment.Center
137
- ) {
138
- HeaderContent(
139
- headerTitle = options.headerTitle,
140
- tintIconColor = titleColor,
141
- titlePosition = titlePosition,
142
- modifier = Modifier.fillMaxWidth()
143
- )
144
- }
145
- }
146
118
  VerticalShadow(opacity)
147
119
  }
148
120
  }
@@ -168,23 +140,15 @@ private fun BackButton(borderColor: Color, backgroundButton: Color, tintIconColo
168
140
  }
169
141
 
170
142
  @Composable
171
- fun HeaderContent(
172
- headerTitle: HeaderTitle,
173
- tintIconColor: Color,
174
- titlePosition: TitlePosition = TitlePosition.LEFT,
175
- modifier: Modifier = Modifier,
176
- ){
143
+ fun RowScope.HeaderContent(headerTitle: HeaderTitle, tintIconColor: Color){
177
144
  Box(
178
- modifier = modifier,
179
- contentAlignment = if (titlePosition == TitlePosition.CENTER) Alignment.Center else Alignment.CenterStart
145
+ Modifier.weight(1f)
180
146
  ) {
181
147
  when (headerTitle){
182
148
  is HeaderTitle.Default -> {
183
149
  HeaderTitle(
184
150
  title = headerTitle.title,
185
- color = tintIconColor,
186
- modifier = Modifier.fillMaxWidth(fraction = if (titlePosition == TitlePosition.CENTER) 0.5f else 1f),
187
- textAlign = if (titlePosition == TitlePosition.CENTER) TextAlign.Center else TextAlign.Start
151
+ color = tintIconColor
188
152
  )
189
153
  }
190
154
  is HeaderTitle.Journey -> {}
@@ -16,13 +16,11 @@ import vn.momo.kits.modifier.setAutomationId
16
16
  fun HeaderTitle(
17
17
  title: String = "",
18
18
  color: Color? = null,
19
- modifier: Modifier = Modifier.fillMaxWidth(),
20
- textAlign: TextAlign = TextAlign.Start,
21
19
  ) {
22
20
  Text(
23
- modifier = modifier.zIndex(1f).setAutomationId("title_navigation_header"),
21
+ modifier = Modifier.fillMaxWidth().zIndex(1f).setAutomationId("title_navigation_header"),
24
22
  text = title,
25
- textAlign = textAlign,
23
+ textAlign = TextAlign.Start,
26
24
  style = Typography.actionSBold.copy(
27
25
  fontSize = 15.sp,
28
26
  lineHeight = 22.sp,
@@ -44,21 +44,13 @@ fun supportsImePadding(): Boolean = when (val v = getOSVersion()) {
44
44
  is OSVersion.IOS -> true
45
45
  }
46
46
 
47
- /**
48
- * @param useCompose when `true`, renders via the pure-Compose Compottie engine instead of the
49
- * platform-native engine (airbnb-lottie on Android, lottie-ios on iOS). Defaults to `false` for
50
- * backward compatibility. Note: when `useCompose = true`, `tintColor` recolors only the fill/stroke
51
- * color slots (matching the native lottie-ios per-keypath tint), so gradient and text-layer colors
52
- * are left untinted; `placedAsOverlay` is a no-op.
53
- */
54
47
  @Composable
55
48
  expect fun LottieAnimation(
56
49
  path: String,
57
50
  tintColor: Color? = null,
58
51
  bgColor: Color? = null,
59
52
  placedAsOverlay: Boolean = false,
60
- modifier: Modifier = Modifier,
61
- useCompose: Boolean = false
53
+ modifier: Modifier = Modifier
62
54
  )
63
55
 
64
56
  expect fun NativePaint.setColor(
@@ -24,21 +24,13 @@ fun getResource(name: String): DrawableResource {
24
24
  @Composable
25
25
  fun readJson(name: String): String {
26
26
  val path = name.plus(".json")
27
- val candidatePaths = listOf(
28
- path,
29
- "composeResources/vn.momo.compose.resources/$path",
30
- )
31
27
 
32
28
  val jsonContent by rememberState(path, { "" }) {
33
29
  val cached = resourceCache.getOrPut(path) {
34
- var content = ""
35
- for (candidate in candidatePaths) {
36
- try {
37
- content = readResourceBytes(candidate).decodeToString()
38
- break
39
- } catch (_: Exception) {
40
- // try next candidate
41
- }
30
+ val content = try {
31
+ readResourceBytes(path).decodeToString()
32
+ } catch (_: Exception) {
33
+ ""
42
34
  }
43
35
  ResourceCache.JSON(content)
44
36
  } as ResourceCache.JSON
@@ -98,14 +98,8 @@ actual fun LottieAnimation(
98
98
  tintColor: Color?,
99
99
  bgColor: Color?,
100
100
  placedAsOverlay: Boolean,
101
- modifier: Modifier,
102
- useCompose: Boolean
101
+ modifier: Modifier
103
102
  ) {
104
- if (useCompose) {
105
- ComposeLottieAnimation(path, tintColor, bgColor, modifier)
106
- return
107
- }
108
-
109
103
  var animation by remember { mutableStateOf<CompatibleAnimation?>(null) }
110
104
 
111
105
  LaunchedEffect(Unit) {
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict />
5
+ </plist>
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict />
5
+ </plist>
@@ -13,7 +13,6 @@ androidGradlePlugin = "8.13.2"
13
13
  r8 = "8.9.35"
14
14
  kotlinx-datetime = "0.7.1"
15
15
  airbnb-lottie = "5.2.0"
16
- compottie = "2.2.1"
17
16
  androidx-activity = "1.9.1"
18
17
  androidx-appcompat = "1.7.0"
19
18
  material = "1.10.0"
@@ -39,7 +38,6 @@ coil-multiplatform-compose = { module = "io.coil-kt.coil3:coil-compose", version
39
38
  coil-multiplatform-network-ktor = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil3-multiplatform" }
40
39
  r8 = { module = "com.android.tools:r8", version.ref = "r8" }
41
40
  airbnb-lottie = { group = "com.airbnb.android", name = "lottie-compose", version.ref = "airbnb-lottie" }
42
- compottie = { module = "io.github.alexzhirkevich:compottie", version.ref = "compottie" }
43
41
  native-max-api = { group = "vn.momo.maxapi", name = "NativeMaxApi", version.ref = "nativemaxapi" }
44
42
  kits = { module = "vn.momo.kits:kits", version.ref = "kits" }
45
43
  androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
package/gradle.properties CHANGED
@@ -18,7 +18,7 @@ kotlin.apple.xcodeCompatibility.nowarn=true
18
18
  name="ComposeKits"
19
19
  group=vn.momo.kits
20
20
  artifact.id=kits
21
- version=0.161.2-beta.5
21
+ version=0.161.2-nocompotie.999
22
22
 
23
23
  repo=GitLab
24
24
  url=https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven
@@ -0,0 +1,8 @@
1
+ ## This file must *NOT* be checked into Version Control Systems,
2
+ # as it contains information specific to your local configuration.
3
+ #
4
+ # Location of the SDK. This is only used by Gradle.
5
+ # For customization when using a Version Control System, please read the
6
+ # header note.
7
+ #Tue Jun 17 09:25:26 ICT 2025
8
+ sdk.dir=/Users/thanhle/Library/Android/sdk
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.161.2-beta.8-debug",
3
+ "version": "0.161.2-nocompotie.999-debug",
4
4
  "private": false,
5
5
  "dependencies": {},
6
6
  "devDependencies": {},
@@ -19,11 +19,7 @@ pluginManagement {
19
19
  credentials {username = "download_packages"; password = "gldt-bjDqLpU_sPcHDuXau2ws" }
20
20
  }
21
21
  maven {
22
- url = uri("https://artifacts.mservice.com.vn/repository/maven-momo-app/")
23
- credentials {
24
- username = "viewer"
25
- password = "viewer"
26
- }
22
+ url = uri("http://nexus.mservice.com.vn:8081/repository/maven-public/")
27
23
  isAllowInsecureProtocol = true
28
24
  }
29
25
  }
@@ -39,20 +35,12 @@ dependencyResolutionManagement {
39
35
  }
40
36
  }
41
37
  mavenCentral()
42
- maven { url = uri("https://maven.pkg.jetbrains.space/public/p/compose/dev") }
43
38
  maven {
44
39
  url = uri("https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven")
45
- credentials {
46
- username = "download_packages";
47
- password = "gldt-bjDqLpU_sPcHDuXau2ws"
48
- }
40
+ credentials {username = "download_packages"; password = "gldt-bjDqLpU_sPcHDuXau2ws" }
49
41
  }
50
42
  maven {
51
- url = uri("https://artifacts.mservice.com.vn/repository/maven-momo-app/")
52
- credentials {
53
- username = "viewer"
54
- password = "viewer"
55
- }
43
+ url = uri("http://nexus.mservice.com.vn:8081/repository/maven-public/")
56
44
  isAllowInsecureProtocol = true
57
45
  }
58
46
  }
@@ -1,62 +0,0 @@
1
- package vn.momo.kits.platform
2
-
3
- import androidx.compose.foundation.Image
4
- import androidx.compose.foundation.background
5
- import androidx.compose.foundation.layout.Box
6
- import androidx.compose.foundation.layout.fillMaxSize
7
- import androidx.compose.runtime.Composable
8
- import androidx.compose.runtime.getValue
9
- import androidx.compose.ui.Modifier
10
- import androidx.compose.ui.graphics.Color
11
- import io.github.alexzhirkevich.compottie.Compottie
12
- import io.github.alexzhirkevich.compottie.ExperimentalCompottieApi
13
- import io.github.alexzhirkevich.compottie.LottieCompositionSpec
14
- import io.github.alexzhirkevich.compottie.dynamic.rememberLottieDynamicProperties
15
- import io.github.alexzhirkevich.compottie.rememberLottieComposition
16
- import io.github.alexzhirkevich.compottie.rememberLottiePainter
17
- import vn.momo.kits.utils.readJson
18
-
19
- @OptIn(ExperimentalCompottieApi::class)
20
- @Composable
21
- internal fun ComposeLottieAnimation(
22
- path: String,
23
- tintColor: Color?,
24
- bgColor: Color?,
25
- modifier: Modifier,
26
- ) {
27
- val json = readJson(path)
28
-
29
- if (json.isEmpty()) {
30
- Box(modifier.background(bgColor ?: Color.Transparent))
31
- return
32
- }
33
-
34
- val composition by rememberLottieComposition(json) {
35
- LottieCompositionSpec.JsonString(json)
36
- }
37
-
38
- // Recolor only the fill/stroke color slots (matching the native lottie-ios per-keypath tint)
39
- // instead of a global ColorFilter.tint, which would flatten a multicolor animation to a silhouette.
40
- val dynamicProperties = if (tintColor != null) {
41
- rememberLottieDynamicProperties(tintColor) {
42
- shapeLayer("**") {
43
- fill("**") { color { tintColor } }
44
- stroke("**") { color { tintColor } }
45
- }
46
- }
47
- } else {
48
- null
49
- }
50
-
51
- Box(modifier.background(bgColor ?: Color.Transparent)) {
52
- Image(
53
- painter = rememberLottiePainter(
54
- composition = composition,
55
- iterations = Compottie.IterateForever,
56
- dynamicProperties = dynamicProperties,
57
- ),
58
- contentDescription = null,
59
- modifier = Modifier.fillMaxSize(),
60
- )
61
- }
62
- }