@momo-kits/native-kits 0.300.4 → 0.300.5-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/build.gradle.kts +13 -0
- package/compose/build.gradle.kts +197 -0
- package/compose/build.gradle.kts.backup +197 -0
- package/compose/compose.podspec +47 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +20 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +6 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +12 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +7 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +153 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +6 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +110 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/DesignSystemKits.kt +62 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +1071 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +65 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +157 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +81 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +175 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +357 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +115 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +89 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +128 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +209 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +542 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +49 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +125 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +231 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +189 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +478 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +114 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +265 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +235 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +223 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +265 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +185 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +343 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +108 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +84 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +361 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +108 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +308 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +59 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +87 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +21 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +90 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +330 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +220 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +473 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +122 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +207 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +92 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +560 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +125 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +207 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +501 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +176 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +182 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +193 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +236 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +180 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +325 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +17 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +16 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +194 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +287 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +54 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +50 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +52 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +66 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +104 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +48 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +58 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +137 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +116 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +215 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +404 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +8 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +732 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +148 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +40 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +233 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +217 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +97 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +377 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +169 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +455 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +103 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +106 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +74 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +413 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +39 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +363 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HelpCenterRequest.kt +37 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +192 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +133 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/ToolkitRequests.kt +41 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +135 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +12 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +91 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +9 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +74 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +20 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +55 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +15 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +118 -0
- package/compose/src/commonTest/kotlin/vn/momo/kits/navigation/component/HelpCenterRequestTest.kt +44 -0
- package/compose/src/commonTest/kotlin/vn/momo/kits/navigation/component/ToolkitRequestsTest.kt +62 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +42 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +45 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +34 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +38 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +66 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +217 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +138 -0
- package/gradle/libs.versions.toml +68 -0
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +8 -0
- package/gradle.properties +26 -0
- package/gradlew +252 -0
- package/gradlew.bat +94 -0
- package/ios/native-kits.podspec +1 -1
- package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
- package/ios-demo/README.md +120 -0
- package/package.json +1 -1
- package/settings.gradle.kts +64 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
package vn.momo.kits.navigation.component
|
|
2
|
+
|
|
3
|
+
import androidx.compose.animation.core.Animatable
|
|
4
|
+
import androidx.compose.animation.core.tween
|
|
5
|
+
import androidx.compose.foundation.border
|
|
6
|
+
import androidx.compose.foundation.layout.Box
|
|
7
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
8
|
+
import androidx.compose.foundation.layout.offset
|
|
9
|
+
import androidx.compose.runtime.Composable
|
|
10
|
+
import androidx.compose.runtime.DisposableEffect
|
|
11
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
12
|
+
import androidx.compose.runtime.getValue
|
|
13
|
+
import androidx.compose.runtime.mutableStateOf
|
|
14
|
+
import androidx.compose.runtime.remember
|
|
15
|
+
import androidx.compose.runtime.rememberCoroutineScope
|
|
16
|
+
import androidx.compose.runtime.setValue
|
|
17
|
+
import androidx.compose.ui.Modifier
|
|
18
|
+
import androidx.compose.ui.layout.onGloballyPositioned
|
|
19
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
20
|
+
import androidx.compose.ui.unit.IntOffset
|
|
21
|
+
import androidx.compose.ui.unit.dp
|
|
22
|
+
import kotlinx.coroutines.delay
|
|
23
|
+
import vn.momo.kits.application.IsShowBaseLineDebug
|
|
24
|
+
import vn.momo.kits.const.Colors
|
|
25
|
+
import vn.momo.kits.modifier.conditional
|
|
26
|
+
import kotlinx.coroutines.launch
|
|
27
|
+
import vn.momo.kits.const.AppNavigationBar
|
|
28
|
+
import vn.momo.kits.navigation.LocalFooterHeightPx
|
|
29
|
+
import vn.momo.kits.navigation.LocalNavigator
|
|
30
|
+
import vn.momo.kits.navigation.LocalOptions
|
|
31
|
+
import vn.momo.kits.navigation.OverplayComponentRegistry
|
|
32
|
+
import kotlin.time.Duration.Companion.milliseconds
|
|
33
|
+
|
|
34
|
+
sealed class SnackBar(open val duration: Long? = null) {
|
|
35
|
+
data class Custom(
|
|
36
|
+
val content: @Composable () -> Unit,
|
|
37
|
+
override val duration: Long? = 3000L
|
|
38
|
+
) : SnackBar(duration)
|
|
39
|
+
|
|
40
|
+
data class Toast(
|
|
41
|
+
override val duration: Long? = 3000L
|
|
42
|
+
) : SnackBar(duration)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Composable
|
|
46
|
+
internal fun SnackBar(
|
|
47
|
+
data: SnackBar,
|
|
48
|
+
onDismiss: (() -> Unit)?
|
|
49
|
+
) {
|
|
50
|
+
val navigator = LocalNavigator.current
|
|
51
|
+
val options = LocalOptions.current
|
|
52
|
+
val density = LocalDensity.current
|
|
53
|
+
val footerHeightPxState = LocalFooterHeightPx.current
|
|
54
|
+
val navigationBar = AppNavigationBar.current
|
|
55
|
+
|
|
56
|
+
val footerHeight = if (options.footerComponent != null) {
|
|
57
|
+
footerHeightPxState.value
|
|
58
|
+
} else {
|
|
59
|
+
with(density){ navigationBar.toPx() }
|
|
60
|
+
}.toInt()
|
|
61
|
+
|
|
62
|
+
var startPosition by remember { mutableStateOf(Float.MAX_VALUE) }
|
|
63
|
+
val targetPosition = 0f
|
|
64
|
+
|
|
65
|
+
var offsetY by remember { mutableStateOf(Animatable(startPosition)) }
|
|
66
|
+
val coroutineScope = rememberCoroutineScope()
|
|
67
|
+
|
|
68
|
+
suspend fun openEvent() {
|
|
69
|
+
offsetY.snapTo(startPosition)
|
|
70
|
+
offsetY.animateTo(
|
|
71
|
+
targetValue = targetPosition,
|
|
72
|
+
animationSpec = tween(
|
|
73
|
+
durationMillis = 350,
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fun closeEvent() {
|
|
79
|
+
coroutineScope.launch {
|
|
80
|
+
offsetY.animateTo(
|
|
81
|
+
targetValue = startPosition,
|
|
82
|
+
animationSpec = tween(
|
|
83
|
+
durationMillis = 200,
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
// hideSnackBar() would call clear() -> this close again while still bound
|
|
87
|
+
OverplayComponentRegistry.hardClearAfterDismiss()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
LaunchedEffect(startPosition) {
|
|
92
|
+
if (startPosition != Float.MAX_VALUE){
|
|
93
|
+
openEvent()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
LaunchedEffect(data.duration) {
|
|
98
|
+
val duration = data.duration
|
|
99
|
+
if (duration != null) {
|
|
100
|
+
delay(duration.milliseconds)
|
|
101
|
+
navigator.hideSnackBar()
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
DisposableEffect(Unit) {
|
|
106
|
+
OverplayComponentRegistry.bindClose {
|
|
107
|
+
closeEvent()
|
|
108
|
+
}
|
|
109
|
+
onDispose {
|
|
110
|
+
onDismiss?.invoke()
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
Box(
|
|
115
|
+
modifier = Modifier
|
|
116
|
+
.offset { IntOffset(0, offsetY.value.toInt() - footerHeight) }
|
|
117
|
+
.onGloballyPositioned {
|
|
118
|
+
if (startPosition != it.size.height.toFloat()) {
|
|
119
|
+
startPosition = it.size.height.toFloat()
|
|
120
|
+
offsetY = Animatable(startPosition)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
.fillMaxWidth()
|
|
124
|
+
.conditional(IsShowBaseLineDebug) {
|
|
125
|
+
border(1.dp, Colors.blue_03)
|
|
126
|
+
}
|
|
127
|
+
) {
|
|
128
|
+
when (data) {
|
|
129
|
+
is SnackBar.Custom -> data.content()
|
|
130
|
+
is SnackBar.Toast -> {}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// File: ToolkitRequests.kt
|
|
2
|
+
// Created At: 2026-10-12 +07:00 | Created By: AI | AI Agent: Codex | Model: GPT-6
|
|
3
|
+
// AI-GENERATED START: cancel only toolkit requests owned by this composition
|
|
4
|
+
package vn.momo.kits.navigation.component
|
|
5
|
+
|
|
6
|
+
import vn.momo.maxapi.runtime.ApiCallback
|
|
7
|
+
import vn.momo.maxapi.runtime.ApiRequestHandle
|
|
8
|
+
|
|
9
|
+
internal class ToolkitRequests {
|
|
10
|
+
private var active = true
|
|
11
|
+
private val handles = mutableSetOf<ApiRequestHandle>()
|
|
12
|
+
|
|
13
|
+
fun <T> launch(request: (ApiCallback<T>) -> ApiRequestHandle, onResult: ApiCallback<T>) {
|
|
14
|
+
if (!active) return
|
|
15
|
+
var completed = false
|
|
16
|
+
var handle: ApiRequestHandle? = null
|
|
17
|
+
val created = request { result ->
|
|
18
|
+
completed = true
|
|
19
|
+
handle?.let(handles::remove)
|
|
20
|
+
if (active) onResult(result)
|
|
21
|
+
}
|
|
22
|
+
handle = created
|
|
23
|
+
if (!active) created.cancel() else if (!completed) handles.add(created)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// AI-GENERATED START: retain subscriptions across nonterminal sheet events
|
|
27
|
+
fun <T> observe(request: (ApiCallback<T>) -> ApiRequestHandle, onResult: ApiCallback<T>) {
|
|
28
|
+
if (!active) return
|
|
29
|
+
val handle = request { result -> if (active) onResult(result) }
|
|
30
|
+
if (active) handles.add(handle) else handle.cancel()
|
|
31
|
+
}
|
|
32
|
+
// AI-GENERATED END: retain subscriptions across nonterminal sheet events
|
|
33
|
+
|
|
34
|
+
fun close() {
|
|
35
|
+
active = false
|
|
36
|
+
val pending = handles.toList()
|
|
37
|
+
handles.clear()
|
|
38
|
+
pending.forEach { it.cancel() }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// AI-GENERATED END: cancel only toolkit requests owned by this composition
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
package vn.momo.kits.navigation.tracking
|
|
2
|
+
|
|
3
|
+
import vn.momo.kits.application.MiniAppContext
|
|
4
|
+
import vn.momo.maxapi.IMaxApi
|
|
5
|
+
// AI-GENERATED START: serialize tracking attributes with their existing value types
|
|
6
|
+
import kotlinx.serialization.json.JsonNull
|
|
7
|
+
import kotlinx.serialization.json.JsonElement
|
|
8
|
+
import kotlinx.serialization.json.JsonObject
|
|
9
|
+
import kotlinx.serialization.json.JsonPrimitive
|
|
10
|
+
// AI-GENERATED END: serialize tracking attributes with their existing value types
|
|
11
|
+
import kotlin.time.Clock
|
|
12
|
+
import kotlin.time.ExperimentalTime
|
|
13
|
+
|
|
14
|
+
class ScreenTrackingState {
|
|
15
|
+
@OptIn(ExperimentalTime::class)
|
|
16
|
+
var time: Long = Clock.System.now().toEpochMilliseconds()
|
|
17
|
+
var releaseNavigated: Boolean = false
|
|
18
|
+
var releaseLoad: Boolean = false
|
|
19
|
+
var releaseInteraction: Boolean = false
|
|
20
|
+
var previousScreenName: String? = null
|
|
21
|
+
var action: String = "push"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// AI-GENERATED START: retain screen event names and typed tracking attributes
|
|
25
|
+
object ScreenTracker {
|
|
26
|
+
|
|
27
|
+
private var lastScreenName: String? = null
|
|
28
|
+
|
|
29
|
+
fun trackScreenNavigated(
|
|
30
|
+
maxApi: IMaxApi?,
|
|
31
|
+
context: MiniAppContext?,
|
|
32
|
+
screenName: String,
|
|
33
|
+
action: String,
|
|
34
|
+
state: ScreenTrackingState
|
|
35
|
+
) {
|
|
36
|
+
if (state.releaseNavigated) return
|
|
37
|
+
|
|
38
|
+
val previousScreen = lastScreenName
|
|
39
|
+
lastScreenName = screenName
|
|
40
|
+
|
|
41
|
+
maxApi?.trackEvent(
|
|
42
|
+
eventName = "auto_screen_navigated",
|
|
43
|
+
attributes = JsonObject(buildBaseParams(context, screenName).apply {
|
|
44
|
+
put("pre_screen_name", JsonPrimitive(previousScreen))
|
|
45
|
+
put("state", JsonPrimitive("navigated"))
|
|
46
|
+
put("action", JsonPrimitive(action))
|
|
47
|
+
})
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
state.releaseNavigated = true
|
|
51
|
+
state.previousScreenName = previousScreen
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fun trackScreenDisplayed(
|
|
55
|
+
maxApi: IMaxApi?,
|
|
56
|
+
context: MiniAppContext?,
|
|
57
|
+
screenName: String,
|
|
58
|
+
duration: Long,
|
|
59
|
+
state: ScreenTrackingState
|
|
60
|
+
) {
|
|
61
|
+
if (state.releaseLoad) return
|
|
62
|
+
|
|
63
|
+
maxApi?.trackEvent(
|
|
64
|
+
eventName = "auto_screen_displayed",
|
|
65
|
+
attributes = JsonObject(buildBaseParams(context, screenName).apply {
|
|
66
|
+
put("state", JsonPrimitive("load"))
|
|
67
|
+
put("duration", JsonPrimitive(duration))
|
|
68
|
+
})
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
state.releaseLoad = true
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fun trackScreenInteracted(
|
|
75
|
+
maxApi: IMaxApi?,
|
|
76
|
+
context: MiniAppContext?,
|
|
77
|
+
screenName: String,
|
|
78
|
+
duration: Long,
|
|
79
|
+
totalDuration: Long,
|
|
80
|
+
state: ScreenTrackingState
|
|
81
|
+
) {
|
|
82
|
+
if (state.releaseInteraction) return
|
|
83
|
+
|
|
84
|
+
maxApi?.trackEvent(
|
|
85
|
+
eventName = "auto_screen_interacted",
|
|
86
|
+
attributes = JsonObject(buildBaseParams(context, screenName).apply {
|
|
87
|
+
put("state", JsonPrimitive("interaction"))
|
|
88
|
+
put("duration", JsonPrimitive(duration))
|
|
89
|
+
put("total_duration", JsonPrimitive(totalDuration))
|
|
90
|
+
})
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
state.releaseInteraction = true
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private fun buildBaseParams(
|
|
97
|
+
context: MiniAppContext?,
|
|
98
|
+
screenName: String,
|
|
99
|
+
componentName: String = "Screen"
|
|
100
|
+
): MutableMap<String, JsonElement> {
|
|
101
|
+
return mutableMapOf(
|
|
102
|
+
"app_id" to JsonPrimitive(context?.appId),
|
|
103
|
+
"feature_code" to JsonPrimitive(context?.appCode),
|
|
104
|
+
"screen_name" to JsonPrimitive(screenName),
|
|
105
|
+
"component_name" to JsonPrimitive(componentName),
|
|
106
|
+
"tracking_source" to JsonPrimitive(1)
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
fun trackPopupDisplayed(
|
|
111
|
+
maxApi: IMaxApi?,
|
|
112
|
+
context: MiniAppContext?,
|
|
113
|
+
parentScreenName: String?
|
|
114
|
+
) {
|
|
115
|
+
maxApi?.trackEvent(
|
|
116
|
+
eventName = "auto_popup_displayed",
|
|
117
|
+
attributes = JsonObject(mapOf(
|
|
118
|
+
"screen_name" to JsonPrimitive(parentScreenName),
|
|
119
|
+
"tracking_source" to JsonPrimitive(1),
|
|
120
|
+
"app_id" to JsonPrimitive(context?.appId),
|
|
121
|
+
"feature_code" to JsonPrimitive(context?.appCode),
|
|
122
|
+
"kits_version" to JsonNull,
|
|
123
|
+
"component_name" to JsonPrimitive("Modal")
|
|
124
|
+
))
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fun getLastScreenName(): String? = lastScreenName
|
|
129
|
+
|
|
130
|
+
@Suppress("UNUSED")
|
|
131
|
+
fun reset() {
|
|
132
|
+
lastScreenName = null
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// AI-GENERATED END: retain screen event names and typed tracking attributes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
package vn.momo.kits.platform
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import androidx.compose.runtime.State
|
|
5
|
+
|
|
6
|
+
/** Fraction of container width, `null` when idle. Observe only — consuming would steal the
|
|
7
|
+
* gesture from NavHost. Always `null` on Android. */
|
|
8
|
+
@Composable
|
|
9
|
+
expect fun rememberBackGestureProgress(): State<Float?>
|
|
10
|
+
|
|
11
|
+
/** Android is a no-op: no host-owned recogniser to hand the gesture to. */
|
|
12
|
+
expect fun reportFloatingArrowBack(shouldUse: Boolean)
|
|
@@ -0,0 +1,91 @@
|
|
|
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.LaunchedEffect
|
|
9
|
+
import androidx.compose.runtime.getValue
|
|
10
|
+
import androidx.compose.runtime.rememberUpdatedState
|
|
11
|
+
import androidx.compose.runtime.snapshotFlow
|
|
12
|
+
import androidx.compose.ui.Modifier
|
|
13
|
+
import androidx.compose.ui.graphics.Color
|
|
14
|
+
import io.github.alexzhirkevich.compottie.ExperimentalCompottieApi
|
|
15
|
+
import io.github.alexzhirkevich.compottie.LottieCompositionSpec
|
|
16
|
+
import io.github.alexzhirkevich.compottie.animateLottieCompositionAsState
|
|
17
|
+
import io.github.alexzhirkevich.compottie.dynamic.rememberLottieDynamicProperties
|
|
18
|
+
import io.github.alexzhirkevich.compottie.rememberLottieComposition
|
|
19
|
+
import io.github.alexzhirkevich.compottie.rememberLottiePainter
|
|
20
|
+
import vn.momo.kits.utils.readJson
|
|
21
|
+
|
|
22
|
+
@OptIn(ExperimentalCompottieApi::class)
|
|
23
|
+
@Composable
|
|
24
|
+
internal fun ComposeLottieAnimation(
|
|
25
|
+
path: String,
|
|
26
|
+
tintColor: Color?,
|
|
27
|
+
bgColor: Color?,
|
|
28
|
+
iterations: Int,
|
|
29
|
+
isPlaying: Boolean,
|
|
30
|
+
onEvent: ((String) -> Unit)?,
|
|
31
|
+
modifier: Modifier,
|
|
32
|
+
) {
|
|
33
|
+
val json = readJson(path)
|
|
34
|
+
|
|
35
|
+
if (json.isEmpty()) {
|
|
36
|
+
Box(modifier.background(bgColor ?: Color.Transparent))
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
val composition by rememberLottieComposition(json) {
|
|
41
|
+
LottieCompositionSpec.JsonString(json)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
val dynamicProperties = if (tintColor != null) {
|
|
45
|
+
rememberLottieDynamicProperties(tintColor) {
|
|
46
|
+
shapeLayer("**") {
|
|
47
|
+
fill("**") { color { tintColor } }
|
|
48
|
+
stroke("**") { color { tintColor } }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
val lottieState = animateLottieCompositionAsState(
|
|
56
|
+
composition = composition,
|
|
57
|
+
iterations = iterations,
|
|
58
|
+
isPlaying = isPlaying,
|
|
59
|
+
restartOnPlay = false,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
val currentOnEvent by rememberUpdatedState(onEvent)
|
|
63
|
+
|
|
64
|
+
LaunchedEffect(isPlaying) {
|
|
65
|
+
currentOnEvent?.invoke(if (isPlaying) LottieEvent.Start else LottieEvent.Pause)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
LaunchedEffect(lottieState) {
|
|
69
|
+
var armed = false
|
|
70
|
+
snapshotFlow { lottieState.isAtEnd }.collect { atEnd ->
|
|
71
|
+
if (!atEnd) armed = true
|
|
72
|
+
else if (armed) { armed = false; currentOnEvent?.invoke(LottieEvent.Finish) }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Box(modifier.background(bgColor ?: Color.Transparent)) {
|
|
77
|
+
Image(
|
|
78
|
+
painter = rememberLottiePainter(
|
|
79
|
+
composition = composition,
|
|
80
|
+
progress = lottieState::value,
|
|
81
|
+
dynamicProperties = dynamicProperties,
|
|
82
|
+
enableExpressions = false,
|
|
83
|
+
expressionEngineFactory = { _, _ ->
|
|
84
|
+
error("Lottie JS expressions are disabled in MoMo kits")
|
|
85
|
+
},
|
|
86
|
+
),
|
|
87
|
+
contentDescription = null,
|
|
88
|
+
modifier = Modifier.fillMaxSize(),
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
package vn.momo.kits.platform
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
|
|
5
|
+
// Overrides LocalDensity.fontScale with the live OS Dynamic Type scale so text re-scales while a
|
|
6
|
+
// screen is visible. Wrapped inside the containers so every screen is covered, not just callers of
|
|
7
|
+
// the app-level wrappers.
|
|
8
|
+
@Composable
|
|
9
|
+
expect fun ProvideOsFontScale(content: @Composable () -> Unit)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
package vn.momo.kits.platform
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import androidx.compose.ui.Modifier
|
|
5
|
+
import androidx.compose.ui.graphics.Color
|
|
6
|
+
import androidx.compose.ui.graphics.NativePaint
|
|
7
|
+
import androidx.compose.ui.unit.Dp
|
|
8
|
+
import vn.momo.kits.navigation.Navigator
|
|
9
|
+
|
|
10
|
+
data class ScreenDimension(
|
|
11
|
+
val width: Int,
|
|
12
|
+
val height: Int,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
expect fun getPlatformName(): String
|
|
16
|
+
|
|
17
|
+
// iPhone idiom only; iPad windows and Android never get the iPhone / iPhone Duo layout.
|
|
18
|
+
expect fun isPhoneIdiom(): Boolean
|
|
19
|
+
|
|
20
|
+
@Composable
|
|
21
|
+
expect fun getScreenDimensions(): ScreenDimension
|
|
22
|
+
|
|
23
|
+
expect fun NativePaint.setMaskFilter(blurRadius: Float)
|
|
24
|
+
|
|
25
|
+
@Composable
|
|
26
|
+
expect fun getStatusBarHeight(): Dp
|
|
27
|
+
|
|
28
|
+
@Composable
|
|
29
|
+
expect fun BackHandler(enabled: Boolean, onBack: () -> Unit)
|
|
30
|
+
|
|
31
|
+
@Suppress("ParamsComparedByRef")
|
|
32
|
+
@Composable
|
|
33
|
+
expect fun ProvideNavigationEventDispatcherOwner(navigator: Navigator, content: @Composable () -> Unit)
|
|
34
|
+
|
|
35
|
+
@Composable
|
|
36
|
+
expect fun getScreenHeight(): Dp
|
|
37
|
+
|
|
38
|
+
sealed interface OSVersion {
|
|
39
|
+
val value: Int
|
|
40
|
+
data class Android(val sdk: Int) : OSVersion { override val value: Int get() = sdk }
|
|
41
|
+
data class IOS(val major: Int) : OSVersion { override val value: Int get() = major }
|
|
42
|
+
|
|
43
|
+
operator fun compareTo(other: Int): Int = value.compareTo(other)
|
|
44
|
+
}
|
|
45
|
+
expect fun getOSVersion(): OSVersion
|
|
46
|
+
|
|
47
|
+
fun supportsImePadding(): Boolean = when (val v = getOSVersion()) {
|
|
48
|
+
is OSVersion.Android -> v.sdk > 29
|
|
49
|
+
is OSVersion.IOS -> true
|
|
50
|
+
}
|
|
51
|
+
const val LottieIterateForever: Int = Int.MAX_VALUE
|
|
52
|
+
|
|
53
|
+
object LottieEvent {
|
|
54
|
+
const val Start = "start"
|
|
55
|
+
const val Pause = "pause"
|
|
56
|
+
const val Finish = "finish"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Composable
|
|
60
|
+
expect fun LottieAnimation(
|
|
61
|
+
path: String,
|
|
62
|
+
tintColor: Color? = null,
|
|
63
|
+
bgColor: Color? = null,
|
|
64
|
+
placedAsOverlay: Boolean = false,
|
|
65
|
+
iterations: Int = LottieIterateForever,
|
|
66
|
+
isPlaying: Boolean = true,
|
|
67
|
+
onEvent: ((String) -> Unit)? = null,
|
|
68
|
+
modifier: Modifier = Modifier,
|
|
69
|
+
useCompose: Boolean = false
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
expect fun NativePaint.setColor(
|
|
73
|
+
color: Color = Color.Black
|
|
74
|
+
)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
package vn.momo.kits.platform
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import androidx.compose.runtime.Immutable
|
|
5
|
+
import androidx.compose.ui.unit.Dp
|
|
6
|
+
|
|
7
|
+
@Immutable
|
|
8
|
+
internal data class ReservedRegion(val x: Dp, val y: Dp, val width: Dp, val height: Dp)
|
|
9
|
+
|
|
10
|
+
// occlusion: regions the system occludes (iOS 27.1+), in the coordinates of the Compose root view:
|
|
11
|
+
// the iPhone Duo camera, and the status bar cluster as it grows for a call or a Live Activity.
|
|
12
|
+
// isFoldable: the device reports a `.division` (hinge) region, Apple's foldable check.
|
|
13
|
+
@Immutable
|
|
14
|
+
internal data class ReservedRegions(
|
|
15
|
+
val occlusion: List<ReservedRegion> = emptyList(),
|
|
16
|
+
val isFoldable: Boolean = false,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
@Composable
|
|
20
|
+
internal expect fun rememberReservedRegions(): ReservedRegions
|