@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.
- package/compose/build.gradle.kts +3 -9
- package/compose/build.gradle.kts.backup +2 -8
- package/compose/compose.podspec +1 -1
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +1 -7
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +48 -62
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +1 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +4 -12
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +1 -7
- package/gradle/libs.versions.toml +0 -2
- package/gradle.properties +1 -1
- package/ios/native-kits.podspec +1 -2
- package/package.json +1 -1
- package/publish.sh +0 -0
- package/settings.gradle.kts +3 -15
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -62
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -33
- package/ios/StatusBarTap/StatusBarTap.h +0 -13
- package/ios/StatusBarTap/StatusBarTap.m +0 -75
package/compose/build.gradle.kts
CHANGED
|
@@ -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.
|
|
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("
|
|
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("
|
|
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
|
}
|
package/compose/compose.podspec
CHANGED
|
@@ -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()) {
|
|
@@ -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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
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 ()
|
|
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
|
-
|
|
240
|
-
|
|
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
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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.
|
|
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
|
package/ios/native-kits.podspec
CHANGED
|
@@ -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 = "**/*.
|
|
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
package/publish.sh
CHANGED
|
File without changes
|
package/settings.gradle.kts
CHANGED
|
@@ -19,11 +19,7 @@ pluginManagement {
|
|
|
19
19
|
credentials {username = "download_packages"; password = "gldt-bjDqLpU_sPcHDuXau2ws" }
|
|
20
20
|
}
|
|
21
21
|
maven {
|
|
22
|
-
url = uri("
|
|
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("
|
|
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
|
-
}
|
|
@@ -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
|