@momo-kits/native-kits 0.160.1-beta.16-debug → 0.160.1-beta.17-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.
@@ -40,7 +40,7 @@ kotlin {
40
40
  }
41
41
 
42
42
  cocoapods {
43
- version = "0.160.1-beta.16-debug"
43
+ version = "0.160.1-beta.17-debug"
44
44
  summary = "IOS Shared module"
45
45
  homepage = "https://momo.vn"
46
46
  ios.deploymentTarget = "15.0"
@@ -73,6 +73,9 @@ kotlin {
73
73
  implementation(libs.jetbrains.serialization.json)
74
74
  implementation(libs.kotlinx.datetime)
75
75
  api(libs.native.max.api)
76
+ // AI-GENERATED START: compottie multiplatform lottie engine for LottieEngine.Compose
77
+ implementation(libs.compottie)
78
+ // AI-GENERATED END: compottie multiplatform lottie engine for LottieEngine.Compose
76
79
  }
77
80
  androidMain.dependencies {
78
81
  implementation(libs.ktor.client.okhttp)
@@ -73,6 +73,9 @@ kotlin {
73
73
  implementation(libs.jetbrains.serialization.json)
74
74
  implementation(libs.kotlinx.datetime)
75
75
  api(libs.native.max.api)
76
+ // AI-GENERATED START: compottie multiplatform lottie engine for LottieEngine.Compose
77
+ implementation(libs.compottie)
78
+ // AI-GENERATED END: compottie multiplatform lottie engine for LottieEngine.Compose
76
79
  }
77
80
  androidMain.dependencies {
78
81
  implementation(libs.ktor.client.okhttp)
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |spec|
2
2
  spec.name = 'compose'
3
- spec.version = '0.159.1-beta.12'
3
+ spec.version = '0.159.1-beta.16'
4
4
  spec.homepage = 'https://momo.vn'
5
5
  spec.source = { :http=> ''}
6
6
  spec.authors = ''
@@ -14,13 +14,14 @@ import androidx.compose.ui.graphics.Color
14
14
  import androidx.compose.ui.graphics.NativePaint
15
15
  import androidx.compose.ui.graphics.toArgb
16
16
  import androidx.compose.ui.platform.LocalConfiguration
17
+ import androidx.compose.ui.semantics.contentDescription
18
+ import androidx.compose.ui.semantics.semantics
17
19
  import androidx.compose.ui.unit.Dp
18
20
  import androidx.compose.ui.unit.dp
19
21
  import com.airbnb.lottie.LottieProperty
20
22
  import com.airbnb.lottie.compose.LottieAnimation
21
23
  import com.airbnb.lottie.compose.LottieCompositionSpec
22
24
  import com.airbnb.lottie.compose.LottieConstants
23
- import com.airbnb.lottie.compose.animateLottieCompositionAsState
24
25
  import com.airbnb.lottie.compose.rememberLottieComposition
25
26
  import com.airbnb.lottie.compose.rememberLottieDynamicProperties
26
27
  import com.airbnb.lottie.compose.rememberLottieDynamicProperty
@@ -77,9 +78,16 @@ actual fun LottieAnimation(
77
78
  tintColor: Color?,
78
79
  bgColor: Color?,
79
80
  placedAsOverlay: Boolean,
80
- isPlaying: Boolean,
81
+ useCompose: Boolean,
81
82
  modifier: Modifier
82
83
  ) {
84
+ // AI-GENERATED START: dispatch to Compottie renderer when useCompose
85
+ if (useCompose) {
86
+ ComposeLottieAnimation(path, tintColor, bgColor, placedAsOverlay, modifier)
87
+ return
88
+ }
89
+ // AI-GENERATED END: dispatch to Compottie renderer when useCompose
90
+
83
91
  val json = readJson(path)
84
92
 
85
93
  if (json.isEmpty()) {
@@ -91,13 +99,6 @@ actual fun LottieAnimation(
91
99
  LottieCompositionSpec.JsonString(json)
92
100
  )
93
101
 
94
- val progress by animateLottieCompositionAsState(
95
- composition = composition,
96
- iterations = LottieConstants.IterateForever,
97
- isPlaying = isPlaying,
98
- restartOnPlay = false,
99
- )
100
-
101
102
  val colorFilter = PorterDuffColorFilter(
102
103
  tintColor?.toArgb() ?: Color.White.toArgb(),
103
104
  PorterDuff.Mode.SRC_ATOP
@@ -113,7 +114,7 @@ actual fun LottieAnimation(
113
114
 
114
115
  LottieAnimation(
115
116
  composition = composition,
116
- progress = { progress },
117
+ iterations = LottieConstants.IterateForever,
117
118
  dynamicProperties = if (tintColor != null) dynamicProperties else null,
118
119
  modifier = modifier
119
120
  )
@@ -97,7 +97,6 @@ fun Screen(
97
97
  inputSearchProps: InputSearchProps? = null,
98
98
  useAnimationSearch: Boolean = false,
99
99
  headerRightWidth: Dp = 0.dp,
100
- usePlaceAsOverlay: Boolean = false,
101
100
  content: @Composable () -> Unit,
102
101
  ) {
103
102
  val statusBarHeight = getAppStatusBarHeight()
@@ -173,7 +172,7 @@ fun Screen(
173
172
  Column(
174
173
  modifier = Modifier.fillMaxSize()
175
174
  .padding( top = when {
176
- animatedHeader != null && !usePlaceAsOverlay -> 0.dp
175
+ animatedHeader != null -> 0.dp
177
176
  headerType == HeaderType.NONE -> 0.dp
178
177
  fullScreenContent -> 0.dp
179
178
  else -> statusBarHeight + HEADER_HEIGHT.dp
@@ -197,10 +196,10 @@ fun Screen(
197
196
  horizontalAlignment = horizontalAlignment
198
197
  ) {
199
198
  Box {
200
- if (!usePlaceAsOverlay && animatedHeader !== null) headerAnimated()
199
+ if (animatedHeader !== null) headerAnimated()
201
200
  Column {
202
201
  if (animatedHeader !== null) {
203
- Spacer(modifier = Modifier.padding(top = if (usePlaceAsOverlay) layoutOffset else statusBarHeight + HEADER_HEIGHT.dp + layoutOffset))
202
+ Spacer(modifier = Modifier.padding(top = statusBarHeight + HEADER_HEIGHT.dp + layoutOffset))
204
203
  }
205
204
 
206
205
  if (useAnimationSearch && inputSearchProps != null && headerType == HeaderType.EXTENDED) {
@@ -218,16 +217,6 @@ fun Screen(
218
217
  }
219
218
  }
220
219
 
221
- if (animatedHeader !== null && usePlaceAsOverlay) {
222
- Box(
223
- modifier = Modifier
224
- .fillMaxWidth()
225
- .zIndex(1.5f)
226
- ) {
227
- headerAnimated()
228
- }
229
- }
230
-
231
220
  Box(Modifier.zIndex(4f).align(Alignment.BottomCenter)) {
232
221
  footer?.let {
233
222
  Footer(
@@ -351,7 +340,7 @@ fun ScreenSnackBarHost(footerHeightPx: Int) {
351
340
  val navigationBar = AppNavigationBar.current
352
341
 
353
342
  val footerHeight = if (footerHeightPx > 0) {
354
- footerHeightPx
343
+ footerHeightPx
355
344
  } else {
356
345
  with(density) {
357
346
  navigationBar.toPx()
@@ -406,4 +395,9 @@ fun ScreenSnackBarHost(footerHeightPx: Int) {
406
395
  is SnackBar.Toast -> {}
407
396
  }
408
397
  }
409
- }
398
+ }
399
+
400
+
401
+
402
+
403
+
@@ -174,10 +174,6 @@ internal fun StackScreen(
174
174
  HeaderBackground()
175
175
  }
176
176
 
177
- Box(Modifier.zIndex(1.5f)) {
178
- AnimatedHeaderImage()
179
- }
180
-
181
177
  Box(Modifier.zIndex(5f)) {
182
178
  Header(onBackHandler)
183
179
  }
@@ -235,10 +231,9 @@ fun ColumnScope.MainContent(content: @Composable ()-> Unit){
235
231
  val scrollState = LocalScrollState.current
236
232
 
237
233
  Spacer(Modifier.height(
238
- if (options.headerType is HeaderType.DefaultOrExtended || (options.headerType is HeaderType.Transparent && !options.headerType.isFullScreenContent) || options.headerType is HeaderType.Animated)
234
+ if (options.headerType is HeaderType.DefaultOrExtended || (options.headerType is HeaderType.Transparent && !options.headerType.isFullScreenContent))
239
235
  AppStatusBar.current + HEADER_HEIGHT.dp else 0.dp)
240
236
  )
241
-
242
237
  if (inputSearchType == InputSearchType.Animated){
243
238
  val scrollDp = with(density) { scrollState.value.toDp() }
244
239
 
@@ -267,37 +262,24 @@ fun ColumnScope.MainContent(content: @Composable ()-> Unit){
267
262
 
268
263
  @Composable
269
264
  fun ScreenContent(content: @Composable () -> Unit){
265
+ val scrollState = LocalScrollState.current
270
266
  val options = LocalOptions.current
271
267
 
272
268
  if (options.headerType is HeaderType.Animated){
273
269
  val animatedHeader = options.headerType
274
- Column {
275
- Spacer(Modifier.height(animatedHeader.layoutOffSet))
276
- content()
270
+ Box {
271
+ Box(Modifier.fillMaxWidth().aspectRatio(animatedHeader.aspectRatio.value)){
272
+ animatedHeader.composable.invoke(scrollState.value)
273
+ }
274
+ Box(Modifier.offset(x = 0.dp, y = AppStatusBar.current + HEADER_HEIGHT.dp + animatedHeader.layoutOffSet)){
275
+ content()
276
+ }
277
277
  }
278
278
  } else {
279
279
  content()
280
280
  }
281
281
  }
282
282
 
283
- @Composable
284
- fun AnimatedHeaderImage() {
285
- val options = LocalOptions.current
286
- val scrollState = LocalScrollState.current
287
- val animatedHeader = options.headerType as? HeaderType.Animated ?: return
288
- val density = LocalDensity.current
289
- val scrollDp = with(density) { scrollState.value.toDp() }
290
-
291
- Box(
292
- Modifier
293
- .fillMaxWidth()
294
- .offset(y = -scrollDp)
295
- .aspectRatio(animatedHeader.aspectRatio.value)
296
- ) {
297
- animatedHeader.composable.invoke(scrollState.value)
298
- }
299
- }
300
-
301
283
  @Composable
302
284
  fun FooterContent(){
303
285
  val options = LocalOptions.current
@@ -230,10 +230,6 @@ sealed class HeaderType {
230
230
 
231
231
  data object None : HeaderType()
232
232
 
233
- data class Transparent(
234
- val isFullScreenContent: Boolean = false
235
- ) : HeaderType()
236
-
237
233
  data class Animated(
238
234
  val aspectRatio: AnimatedHeaderRatio = AnimatedHeaderRatio.RATIO_16_9,
239
235
  val isSurface: Boolean = true,
@@ -241,6 +237,9 @@ sealed class HeaderType {
241
237
  val composable: @Composable (scrollState: Int) -> Unit = {}
242
238
  ) : HeaderType()
243
239
 
240
+ data class Transparent(
241
+ val isFullScreenContent: Boolean = false
242
+ ) : HeaderType()
244
243
  }
245
244
 
246
245
  data class HeaderBackProps(
@@ -0,0 +1,57 @@
1
+ /*
2
+ File: compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt
3
+ Created At: 2026-05-25 11:30:00 +07:00
4
+ Created By: AI
5
+ AI Agent: Claude Code
6
+ Model: claude-opus-4-7
7
+ */
8
+ package vn.momo.kits.platform
9
+
10
+ import androidx.compose.foundation.Image
11
+ import androidx.compose.foundation.background
12
+ import androidx.compose.foundation.layout.Box
13
+ import androidx.compose.foundation.layout.fillMaxSize
14
+ import androidx.compose.runtime.Composable
15
+ import androidx.compose.runtime.getValue
16
+ import androidx.compose.ui.Modifier
17
+ import androidx.compose.ui.graphics.Color
18
+ import androidx.compose.ui.graphics.ColorFilter
19
+ import io.github.alexzhirkevich.compottie.Compottie
20
+ import io.github.alexzhirkevich.compottie.LottieCompositionSpec
21
+ import io.github.alexzhirkevich.compottie.rememberLottieComposition
22
+ import io.github.alexzhirkevich.compottie.rememberLottiePainter
23
+ import vn.momo.kits.utils.readJson
24
+
25
+ // AI-GENERATED START: internal compottie renderer used when LottieEngine.Compose is selected
26
+ @Composable
27
+ internal fun ComposeLottieAnimation(
28
+ path: String,
29
+ tintColor: Color?,
30
+ bgColor: Color?,
31
+ @Suppress("UNUSED_PARAMETER") placedAsOverlay: Boolean,
32
+ modifier: Modifier,
33
+ ) {
34
+ val json = readJson(path)
35
+
36
+ if (json.isEmpty()) {
37
+ Box(modifier.background(bgColor ?: Color.Transparent))
38
+ return
39
+ }
40
+
41
+ val composition by rememberLottieComposition {
42
+ LottieCompositionSpec.JsonString(json)
43
+ }
44
+
45
+ Box(modifier.background(bgColor ?: Color.Transparent)) {
46
+ Image(
47
+ painter = rememberLottiePainter(
48
+ composition = composition,
49
+ iterations = Compottie.IterateForever,
50
+ ),
51
+ contentDescription = null,
52
+ colorFilter = tintColor?.let { ColorFilter.tint(it) },
53
+ modifier = Modifier.fillMaxSize(),
54
+ )
55
+ }
56
+ }
57
+ // AI-GENERATED END: internal compottie renderer used when LottieEngine.Compose is selected
@@ -44,15 +44,23 @@ fun supportsImePadding(): Boolean = when (val v = getOSVersion()) {
44
44
  is OSVersion.IOS -> true
45
45
  }
46
46
 
47
+ // AI-GENERATED START: useCompose flag to switch between native and Compose (compottie) renderer
48
+ /**
49
+ * @param useCompose when `true`, renders via the pure-Compose Compottie engine instead of the
50
+ * platform-native engine (airbnb-lottie on Android, lottie-ios on iOS). Defaults to `false` for
51
+ * backward compatibility. Note: `tintColor` becomes a single global `ColorFilter.tint` and
52
+ * `placedAsOverlay` is a no-op when `useCompose = true`.
53
+ */
47
54
  @Composable
48
55
  expect fun LottieAnimation(
49
56
  path: String,
50
57
  tintColor: Color? = null,
51
58
  bgColor: Color? = null,
52
59
  placedAsOverlay: Boolean = false,
53
- isPlaying: Boolean = true,
60
+ useCompose: Boolean = false,
54
61
  modifier: Modifier = Modifier
55
62
  )
63
+ // AI-GENERATED END: useCompose flag to switch between native and Compose (compottie) renderer
56
64
 
57
65
  expect fun NativePaint.setColor(
58
66
  color: Color = Color.Black
@@ -19,18 +19,20 @@ import androidx.compose.ui.backhandler.LocalCompatNavigationEventDispatcherOwner
19
19
  import androidx.compose.ui.graphics.Color
20
20
  import androidx.compose.ui.graphics.NativePaint
21
21
  import androidx.compose.ui.graphics.toArgb
22
+ import androidx.compose.ui.semantics.SemanticsPropertyKey
23
+ import androidx.compose.ui.semantics.semantics
22
24
  import androidx.compose.ui.unit.Dp
23
25
  import androidx.compose.ui.unit.dp
24
26
  import androidx.compose.ui.viewinterop.UIKitInteropProperties
25
27
  import androidx.compose.ui.viewinterop.UIKitView
26
- import androidx.navigationevent.NavigationEventDispatcher
27
- import androidx.navigationevent.NavigationEventDispatcherOwner
28
28
  import cocoapods.lottie_ios.CompatibleAnimation
29
29
  import cocoapods.lottie_ios.CompatibleAnimationKeypath
30
30
  import cocoapods.lottie_ios.CompatibleAnimationView
31
31
  import kotlinx.cinterop.ExperimentalForeignApi
32
32
  import kotlinx.cinterop.get
33
33
  import kotlinx.cinterop.memScoped
34
+ import androidx.navigationevent.NavigationEventDispatcher
35
+ import androidx.navigationevent.NavigationEventDispatcherOwner
34
36
  import org.jetbrains.skia.FilterBlurMode
35
37
  import org.jetbrains.skia.MaskFilter
36
38
  import platform.Foundation.NSBundle
@@ -96,9 +98,16 @@ actual fun LottieAnimation(
96
98
  tintColor: Color?,
97
99
  bgColor: Color?,
98
100
  placedAsOverlay: Boolean,
99
- isPlaying: Boolean,
101
+ useCompose: Boolean,
100
102
  modifier: Modifier
101
103
  ) {
104
+ // AI-GENERATED START: dispatch to Compottie renderer when useCompose
105
+ if (useCompose) {
106
+ ComposeLottieAnimation(path, tintColor, bgColor, placedAsOverlay, modifier)
107
+ return
108
+ }
109
+ // AI-GENERATED END: dispatch to Compottie renderer when useCompose
110
+
102
111
  var animation by remember { mutableStateOf<CompatibleAnimation?>(null) }
103
112
 
104
113
  LaunchedEffect(Unit) {
@@ -114,10 +123,7 @@ actual fun LottieAnimation(
114
123
  Box(modifier) {
115
124
  UIKitView(
116
125
  modifier = Modifier.fillMaxSize(),
117
- properties = UIKitInteropProperties(
118
- interactionMode = null,
119
- placedAsOverlay = placedAsOverlay,
120
- ),
126
+ properties = UIKitInteropProperties(placedAsOverlay = placedAsOverlay),
121
127
  factory = {
122
128
  CompatibleAnimationView(value).apply {
123
129
  translatesAutoresizingMaskIntoConstraints = true
@@ -138,7 +144,7 @@ actual fun LottieAnimation(
138
144
  setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke.Color"))
139
145
  }
140
146
 
141
- if (isPlaying) play() else pause()
147
+ play()
142
148
  }
143
149
  },
144
150
 
@@ -154,8 +160,6 @@ actual fun LottieAnimation(
154
160
  view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke 1.Color"))
155
161
  view.setColorValue(uiColor, CompatibleAnimationKeypath("**.Stroke.Color"))
156
162
  }
157
-
158
- if (isPlaying) view.play() else view.pause()
159
163
  }
160
164
  )
161
165
  }
@@ -13,6 +13,7 @@ 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.0.0-rc04"
16
17
  androidx-activity = "1.9.1"
17
18
  androidx-appcompat = "1.7.0"
18
19
  material = "1.10.0"
@@ -38,6 +39,7 @@ coil-multiplatform-compose = { module = "io.coil-kt.coil3:coil-compose", version
38
39
  coil-multiplatform-network-ktor = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref = "coil3-multiplatform" }
39
40
  r8 = { module = "com.android.tools:r8", version.ref = "r8" }
40
41
  airbnb-lottie = { group = "com.airbnb.android", name = "lottie-compose", version.ref = "airbnb-lottie" }
42
+ compottie = { module = "io.github.alexzhirkevich:compottie", version.ref = "compottie" }
41
43
  native-max-api = { group = "vn.momo.maxapi", name = "NativeMaxApi", version.ref = "nativemaxapi" }
42
44
  kits = { module = "vn.momo.kits:kits", version.ref = "kits" }
43
45
  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.160.1-beta.14
21
+ version=0.159.1-beta.16
22
22
 
23
23
  repo=GitLab
24
24
  url=https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.160.1-beta.16-debug",
3
+ "version": "0.160.1-beta.17-debug",
4
4
  "private": false,
5
5
  "dependencies": {},
6
6
  "devDependencies": {},