@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.
- 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/application/LiteScreen.kt +24 -30
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +1 -5
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +26 -16
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +9 -45
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +2 -4
- 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/example/ios/Example.xcodeproj/xcuserdata/thanhle.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
- package/example/ios/Example.xcworkspace/xcuserdata/thanhle.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcworkspace/xcuserdata/thanhle.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
- package/gradle/libs.versions.toml +0 -2
- package/gradle.properties +1 -1
- package/local.properties +8 -0
- package/package.json +1 -1
- package/settings.gradle.kts +3 -15
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -62
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.161.2-
|
|
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("
|
|
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()) {
|
|
@@ -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
|
|
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
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
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
|
|
491
|
+
defaultHeight = 154.dp.roundToPx()
|
|
502
492
|
}
|
|
503
493
|
val headerHeight = when {
|
|
504
494
|
isHeaderNone -> statusBarPx
|
|
505
495
|
!useAnimationSearch && !isHeaderExtend -> defaultHeight
|
|
506
|
-
else ->
|
|
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(
|
|
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(
|
|
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(
|
|
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 +=
|
|
584
|
+
curY += headerRowDefault
|
|
592
585
|
}
|
|
593
586
|
|
|
594
587
|
val inputSearchOffset = if (isHeaderExtend) {
|
|
595
|
-
val baseY = curY + inputSearchPlaceable.verticalCenterOffset(
|
|
588
|
+
val baseY = curY + inputSearchPlaceable.verticalCenterOffset(headerRowDefault)
|
|
596
589
|
val y = (baseY * (1 - scrollPercent)).toInt().coerceAtLeast(
|
|
597
|
-
startY + inputSearchPlaceable.verticalCenterOffset(
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
182
|
+
Box(Modifier.zIndex(5f)) {
|
|
186
183
|
Header(onBackHandler)
|
|
187
184
|
}
|
|
188
185
|
|
|
189
|
-
Column(Modifier.zIndex(
|
|
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(
|
|
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.
|
|
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
|
|
291
|
-
val
|
|
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
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
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 =
|
|
21
|
+
modifier = Modifier.fillMaxWidth().zIndex(1f).setAutomationId("title_navigation_header"),
|
|
24
22
|
text = title,
|
|
25
|
-
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
|
-
|
|
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) {
|
|
Binary file
|
|
@@ -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
package/local.properties
ADDED
|
@@ -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
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
|
-
}
|