@momo-kits/native-kits 0.160.1-search-animation.1-debug → 0.160.1-search-animation.2-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.
@@ -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.160.1-search-animation.1-debug"
43
+ version = "0.160.1-search-animation.2-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.159.1-beta.16'
3
+ spec.version = '0.160.1-search-animation.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()) {
@@ -96,5 +96,4 @@ data class KeyboardOptions(
96
96
  data class ScrollData(
97
97
  val scrollable: Boolean = true,
98
98
  val scrollState: ScrollableState? = null,
99
- val scrollToTopCallback: (() -> Unit)? = null,
100
99
  )
@@ -150,10 +150,6 @@ internal fun StackScreen(
150
150
  val footerHeightPx = remember { mutableIntStateOf(0) }
151
151
  val headerRightWidthPx = remember { mutableIntStateOf(0) }
152
152
 
153
- if (navigation.options.scrollData.scrollToTopCallback != null) {
154
- RegisterScrollToTop(navigation.options.scrollData.scrollToTopCallback)
155
- }
156
-
157
153
  BackHandler(true) { navigator.onBackSafe() }
158
154
 
159
155
  CompositionLocalProvider(
@@ -164,16 +160,15 @@ internal fun StackScreen(
164
160
  LocalFooterHeightPx provides footerHeightPx,
165
161
  LocalHeaderRightWidthPx provides headerRightWidthPx
166
162
  ) {
167
- Box(
168
- Modifier
169
- .fillMaxSize()
170
- .background(options.backgroundColor ?: AppTheme.current.colors.background.default)
171
- .conditional(options.keyboardOptions.keyboardShouldPersistTaps) {
172
- hideKeyboardOnTap()
173
- }
174
- .conditional(options.keyboardOptions.useAvoidKeyboard && supportsImePadding()) {
175
- imePadding()
176
- }
163
+ Box(Modifier
164
+ .fillMaxSize()
165
+ .background(options.backgroundColor ?: AppTheme.current.colors.background.default)
166
+ .conditional(options.keyboardOptions.keyboardShouldPersistTaps) {
167
+ hideKeyboardOnTap()
168
+ }
169
+ .conditional(options.keyboardOptions.useAvoidKeyboard && supportsImePadding()) {
170
+ imePadding()
171
+ }
177
172
  ) {
178
173
  Box(Modifier.zIndex(1f)) {
179
174
  HeaderBackground()
@@ -183,7 +178,7 @@ internal fun StackScreen(
183
178
  Header(onBackHandler)
184
179
  }
185
180
 
186
- Column(Modifier.zIndex(6f)) {
181
+ Column (Modifier.zIndex(6f)) {
187
182
  SearchAnimated(isScrollInProgress = scrollInProcess)
188
183
  }
189
184
 
@@ -195,7 +190,7 @@ internal fun StackScreen(
195
190
  FooterContent()
196
191
  }
197
192
 
198
- Box(Modifier.zIndex(7f)) {
193
+ Box(Modifier.zIndex(7f)){
199
194
  FloatingContent()
200
195
  }
201
196
 
@@ -205,15 +200,15 @@ internal fun StackScreen(
205
200
  }
206
201
 
207
202
  @Composable
208
- fun FloatingContent() {
203
+ fun FloatingContent(){
209
204
  val options = LocalOptions.current
210
205
  val density = LocalDensity.current
211
206
  val footerHeightPx = LocalFooterHeightPx.current
212
207
  val scrollState = LocalScrollState.current
213
208
 
214
209
  val fabProps = options.floatingButtonProps ?: return
215
- val bottomPadding = fabProps.bottom
216
- ?: (Spacing.M + if (options.footerComponent != null) with(density) { footerHeightPx.intValue.toDp() } else 0.dp)
210
+ val bottomPadding = fabProps.bottom ?:
211
+ (Spacing.M + if (options.footerComponent != null) with(density){ footerHeightPx.intValue.toDp() } else 0.dp)
217
212
 
218
213
  FloatingButton(
219
214
  scrollPosition = fabProps.scrollState?.value ?: scrollState.value,
@@ -229,19 +224,17 @@ fun FloatingContent() {
229
224
  }
230
225
 
231
226
  @Composable
232
- fun ColumnScope.MainContent(content: @Composable () -> Unit) {
227
+ fun ColumnScope.MainContent(content: @Composable ()-> Unit){
233
228
  val options = LocalOptions.current
234
229
  val inputSearchType = getInputSearchType(options)
235
230
  val density = LocalDensity.current
236
231
  val scrollState = LocalScrollState.current
237
232
 
238
- Spacer(
239
- Modifier.height(
240
- if (options.headerType is HeaderType.DefaultOrExtended || (options.headerType is HeaderType.Transparent && !options.headerType.isFullScreenContent))
241
- AppStatusBar.current + HEADER_HEIGHT.dp else 0.dp
242
- )
233
+ Spacer(Modifier.height(
234
+ if (options.headerType is HeaderType.DefaultOrExtended || (options.headerType is HeaderType.Transparent && !options.headerType.isFullScreenContent))
235
+ AppStatusBar.current + HEADER_HEIGHT.dp else 0.dp)
243
236
  )
244
- if (inputSearchType == InputSearchType.Animated) {
237
+ if (inputSearchType == InputSearchType.Animated){
245
238
  val scrollDp = with(density) { scrollState.value.toDp() }
246
239
 
247
240
  val animatedTopPadding by animateDpAsState(
@@ -250,18 +243,17 @@ fun ColumnScope.MainContent(content: @Composable () -> Unit) {
250
243
  )
251
244
  Spacer(Modifier.height(animatedTopPadding))
252
245
  }
253
- Column(
254
- Modifier
255
- .fillMaxWidth()
256
- .weight(1f)
257
- .conditional(options.scrollData.scrollable && options.scrollData.scrollState is ScrollState) {
258
- verticalScroll(scrollState)
259
- }
246
+ Column (Modifier
247
+ .fillMaxWidth()
248
+ .weight(1f)
249
+ .conditional(options.scrollData.scrollable && options.scrollData.scrollState is ScrollState) {
250
+ verticalScroll(scrollState)
251
+ }
260
252
  ) {
261
253
  ScreenContent(content = content)
262
254
  }
263
255
 
264
- if (options.footerComponent != null) {
256
+ if (options.footerComponent != null){
265
257
  val footerHeight = LocalFooterHeightPx.current
266
258
  val footerHeightDp = with(density) { footerHeight.value.toDp() }
267
259
  Spacer(Modifier.height(footerHeightDp))
@@ -269,17 +261,17 @@ fun ColumnScope.MainContent(content: @Composable () -> Unit) {
269
261
  }
270
262
 
271
263
  @Composable
272
- fun ScreenContent(content: @Composable () -> Unit) {
264
+ fun ScreenContent(content: @Composable () -> Unit){
273
265
  val scrollState = LocalScrollState.current
274
266
  val options = LocalOptions.current
275
267
 
276
- if (options.headerType is HeaderType.Animated) {
268
+ if (options.headerType is HeaderType.Animated){
277
269
  val animatedHeader = options.headerType
278
270
  Box {
279
- Box(Modifier.fillMaxWidth().aspectRatio(animatedHeader.aspectRatio.value)) {
271
+ Box(Modifier.fillMaxWidth().aspectRatio(animatedHeader.aspectRatio.value)){
280
272
  animatedHeader.composable.invoke(scrollState.value)
281
273
  }
282
- Box(Modifier.offset(x = 0.dp, y = AppStatusBar.current + HEADER_HEIGHT.dp + animatedHeader.layoutOffSet)) {
274
+ Box(Modifier.offset(x = 0.dp, y = AppStatusBar.current + HEADER_HEIGHT.dp + animatedHeader.layoutOffSet)){
283
275
  content()
284
276
  }
285
277
  }
@@ -289,9 +281,9 @@ fun ScreenContent(content: @Composable () -> Unit) {
289
281
  }
290
282
 
291
283
  @Composable
292
- fun FooterContent() {
284
+ fun FooterContent(){
293
285
  val options = LocalOptions.current
294
- if (options.footerComponent != null) {
286
+ if (options.footerComponent != null){
295
287
  val ime = WindowInsets.ime
296
288
  val density = LocalDensity.current
297
289
  val imeBottom = ime.getBottom(density)
@@ -303,11 +295,11 @@ fun FooterContent() {
303
295
  }
304
296
 
305
297
  @Composable
306
- fun OverplayView(bottomTabIndex: Int, id: Int) {
298
+ fun OverplayView(bottomTabIndex: Int, id: Int){
307
299
  val overplayType = OverplayComponentRegistry.getOverplayType()
308
300
 
309
301
  if (overplayType != null) {
310
- Box(Modifier.zIndex(if (overplayType == OverplayComponentType.SNACK_BAR) 3f else 8f).fillMaxSize()) {
302
+ Box(Modifier.zIndex(if (overplayType == OverplayComponentType.SNACK_BAR) 3f else 8f).fillMaxSize()){
311
303
  if (bottomTabIndex != -1) return@Box
312
304
  if (OverplayComponentRegistry.currentRootId() != id) return@Box
313
305
  OverplayComponentRegistry.OverlayComponent()
@@ -330,24 +322,22 @@ fun Footer(footerComponent: @Composable (() -> Unit)?, bottomPadding: Dp) {
330
322
  Box(Modifier.onGloballyPositioned {
331
323
  if (footerHeightPx.intValue != it.size.height) footerHeightPx.intValue = it.size.height
332
324
  }) {
333
- Box(
334
- Modifier
335
- .fillMaxWidth()
336
- .background(AppTheme.current.colors.background.surface)
337
- .conditional(IsShowBaseLineDebug) {
338
- border(1.dp, Colors.blue_03)
339
- }
340
- .padding(top = Spacing.S, start = Spacing.M, end = Spacing.M, bottom = bottomPadding + Spacing.S)
341
- ) {
325
+ Box(Modifier
326
+ .fillMaxWidth()
327
+ .background(AppTheme.current.colors.background.surface)
328
+ .conditional(IsShowBaseLineDebug) {
329
+ border(1.dp, Colors.blue_03)
330
+ }
331
+ .padding(top = Spacing.S, start = Spacing.M, end = Spacing.M, bottom = bottomPadding + Spacing.S)
332
+ ){
342
333
  footerComponent.invoke()
343
334
  }
344
335
 
345
- Box(
346
- modifier = Modifier
347
- .fillMaxWidth()
348
- .height(6.dp)
349
- .offset(x = 0.dp, y = (-6).dp)
350
- .background(shadowBrush)
336
+ Box(modifier = Modifier
337
+ .fillMaxWidth()
338
+ .height(6.dp)
339
+ .offset(x = 0.dp, y = (-6).dp)
340
+ .background(shadowBrush)
351
341
  )
352
342
  }
353
343
  }
@@ -357,7 +347,6 @@ data class InputSearchLayoutParams(
357
347
  val startPadding: Dp,
358
348
  val endPadding: Dp
359
349
  )
360
-
361
350
  @Composable
362
351
  fun SearchAnimated(
363
352
  isScrollInProgress: Boolean
@@ -472,7 +461,6 @@ internal fun isKeyboardVisible(): Boolean {
472
461
  val density = LocalDensity.current
473
462
  return ime.getBottom(density) > 0
474
463
  }
475
-
476
464
  private fun quantize(value: Int, stepPx: Int): Int {
477
465
  if (stepPx <= 1) return value
478
466
  return (value / stepPx) * stepPx
@@ -552,15 +540,13 @@ internal val LocalOptions = staticCompositionLocalOf<NavigationOptions> { error(
552
540
 
553
541
  val StackScreenScrollableState = staticCompositionLocalOf<ScrollableState?> { null }
554
542
 
555
- internal fun getInputSearchType(options: NavigationOptions): InputSearchType {
543
+ internal fun getInputSearchType(options: NavigationOptions): InputSearchType{
556
544
  return when (val headerType = options.headerType) {
557
545
  is HeaderType.DefaultOrExtended -> when {
558
546
  headerType.inputSearchProps == null -> InputSearchType.None
559
547
  headerType.useAnimated -> InputSearchType.Animated
560
548
  else -> InputSearchType.Header
561
549
  }
562
-
563
550
  else -> InputSearchType.None
564
551
  }
565
552
  }
566
-
@@ -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) {
@@ -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.0"
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.160.1-search-animation.1
21
+ version=0.160.1-search-animation.2
22
22
 
23
23
  repo=GitLab
24
24
  url=https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven
@@ -10,8 +10,7 @@ Pod::Spec.new do |s|
10
10
  s.ios.deployment_target = '15.0'
11
11
  s.swift_version = '5.0'
12
12
 
13
- s.source_files = "**/*.{swift,m,h}"
14
- s.public_header_files = "StatusBarTap/*.h"
13
+ s.source_files = "**/*.swift"
15
14
  s.framework = 'SwiftUI', 'Combine'
16
15
  s.dependency 'SDWebImageSwiftUI'
17
16
  s.dependency 'lottie-ios'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.160.1-search-animation.1-debug",
3
+ "version": "0.160.1-search-animation.2-debug",
4
4
  "private": false,
5
5
  "dependencies": {},
6
6
  "devDependencies": {},
package/publish.sh CHANGED
File without changes
@@ -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,6 +0,0 @@
1
- package vn.momo.kits.navigation
2
-
3
- import androidx.compose.runtime.Composable
4
-
5
- @Composable
6
- internal actual fun RegisterScrollToTop(callback: (() -> Unit)?) = Unit
@@ -1,8 +0,0 @@
1
- package vn.momo.kits.navigation
2
-
3
- import androidx.compose.runtime.Composable
4
-
5
- @Composable
6
- internal expect fun RegisterScrollToTop(callback: (() -> Unit)?)
7
-
8
-
@@ -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
- }
@@ -1,33 +0,0 @@
1
- package vn.momo.kits.navigation
2
-
3
- import androidx.compose.runtime.Composable
4
- import androidx.compose.runtime.DisposableEffect
5
- import platform.Foundation.NSNotification
6
- import platform.Foundation.NSNotificationCenter
7
- import platform.Foundation.NSOperationQueue
8
- import platform.darwin.NSObjectProtocol
9
-
10
- private const val STATUS_BAR_TAPPED_NOTIFICATION = "statusBarSelected"
11
-
12
- @Composable
13
- internal actual fun RegisterScrollToTop(callback: (() -> Unit)?) {
14
- val maxApi = LocalMaxApi.current
15
- DisposableEffect(callback) {
16
- val cb = callback
17
- val token: NSObjectProtocol? = if (cb != null) {
18
- NSNotificationCenter.defaultCenter.addObserverForName(
19
- name = STATUS_BAR_TAPPED_NOTIFICATION,
20
- `object` = null,
21
- queue = NSOperationQueue.mainQueue,
22
- ) { _: NSNotification? ->
23
- runCatching { cb() }.onFailure {
24
- maxApi?.logFile("[ScrollToTop] callback threw: ${it.message}") {}
25
-
26
- }
27
- }
28
- } else null
29
- onDispose {
30
- token?.let { NSNotificationCenter.defaultCenter.removeObserver(it) }
31
- }
32
- }
33
- }
@@ -1,13 +0,0 @@
1
- #import <Foundation/Foundation.h>
2
-
3
- NS_ASSUME_NONNULL_BEGIN
4
-
5
- /// Posts `MoMoStatusBarTap.notificationName` on every status-bar tap.
6
- /// The swizzle installs automatically at framework load (`+load`) — calling
7
- /// `install` is a no-op kept for explicit/manual triggering.
8
- @interface MoMoStatusBarTap : NSObject
9
- @property (class, nonatomic, readonly) NSNotificationName notificationName;
10
- + (void)install;
11
- @end
12
-
13
- NS_ASSUME_NONNULL_END
@@ -1,75 +0,0 @@
1
- #import <UIKit/UIKit.h>
2
- #import <objc/message.h>
3
- #import <objc/runtime.h>
4
- #import "StatusBarTap.h"
5
-
6
- // Performs the actual swizzle once per process. Safe to call multiple times.
7
- static void mm_installStatusBarTapSwizzleOnce(void) {
8
- static dispatch_once_t onceToken;
9
- dispatch_once(&onceToken, ^{
10
- Class cls = [UIStatusBarManager class];
11
- SEL originalSelector = NSSelectorFromString(@"handleTapAction:");
12
- SEL swizzledSelector = NSSelectorFromString(@"mm_handleTapAction:");
13
-
14
- Method originalMethod = class_getInstanceMethod(cls, originalSelector);
15
- Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
16
- if (!originalMethod || !swizzledMethod) return;
17
-
18
- // Verify the original method matches the (id) -> void shape we expect.
19
- // Encoding may include byte offsets (e.g. "v32@0:8@16") so we filter
20
- // digits out before comparing.
21
- const char *encPtr = method_getTypeEncoding(originalMethod);
22
- if (encPtr) {
23
- NSMutableString *enc = [NSMutableString string];
24
- for (const char *p = encPtr; *p; p++) {
25
- if (!(*p >= '0' && *p <= '9')) [enc appendFormat:@"%c", *p];
26
- }
27
- if (![enc isEqualToString:@"v@:@"]) return;
28
- }
29
-
30
- BOOL didAdd = class_addMethod(cls,
31
- originalSelector,
32
- method_getImplementation(swizzledMethod),
33
- method_getTypeEncoding(swizzledMethod));
34
- if (didAdd) {
35
- class_replaceMethod(cls,
36
- swizzledSelector,
37
- method_getImplementation(originalMethod),
38
- method_getTypeEncoding(originalMethod));
39
- } else {
40
- method_exchangeImplementations(originalMethod, swizzledMethod);
41
- }
42
- });
43
- }
44
-
45
- @implementation MoMoStatusBarTap
46
- + (NSNotificationName)notificationName { return @"statusBarSelected"; }
47
- + (void)install { mm_installStatusBarTapSwizzleOnce(); }
48
- @end
49
-
50
- // MARK: - Swizzle target on UIStatusBarManager
51
- // `mm_handleTapAction:` is the replacement IMP. After the add/exchange,
52
- // this selector points at the original UIKit IMP — calling it inside
53
- // the body invokes UIKit's real handler so UIScrollView.scrollsToTop
54
- // and any other side effects continue to work.
55
-
56
- @interface UIStatusBarManager (MoMoStatusBarTap)
57
- @end
58
-
59
- @implementation UIStatusBarManager (MoMoStatusBarTap)
60
-
61
- // Auto-install at framework load. Commented out so the swizzle stays
62
- // opt-in via `[MoMoStatusBarTap install]`. Uncomment to revert to
63
- // auto-installation before main().
64
- //
65
- // + (void)load {
66
- // mm_installStatusBarTapSwizzleOnce();
67
- // }
68
-
69
- - (void)mm_handleTapAction:(id)action {
70
- [self mm_handleTapAction:action];
71
- [[NSNotificationCenter defaultCenter] postNotificationName:MoMoStatusBarTap.notificationName
72
- object:nil];
73
- }
74
-
75
- @end