@momo-kits/native-kits 0.168.1-beta.2 → 0.168.1-beta.3-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/CLAUDE.md +4 -4
- package/README.md +10 -2
- 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 +19 -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 +124 -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 +16 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +18 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +22 -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 +283 -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 +309 -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 +98 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +312 -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 +13 -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 +40 -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 +36 -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 +94 -0
- package/gradle/libs.versions.toml +76 -0
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +10 -0
- package/gradle.properties +26 -0
- package/gradlew +252 -0
- package/gradlew.bat +94 -0
- package/ios-demo/README.md +120 -0
- package/package.json +1 -1
- package/publish.sh +7 -2
- package/settings.gradle.kts +64 -0
- package/.claude/settings.local.json +0 -9
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
package vn.momo.kits.navigation.component
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Box
|
|
4
|
+
import androidx.compose.foundation.layout.Column
|
|
5
|
+
import androidx.compose.foundation.layout.Row
|
|
6
|
+
import androidx.compose.foundation.layout.Spacer
|
|
7
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
8
|
+
import androidx.compose.foundation.layout.height
|
|
9
|
+
import androidx.compose.foundation.layout.width
|
|
10
|
+
import androidx.compose.foundation.layout.widthIn
|
|
11
|
+
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
12
|
+
import androidx.compose.runtime.Composable
|
|
13
|
+
import androidx.compose.ui.Alignment
|
|
14
|
+
import androidx.compose.ui.Modifier
|
|
15
|
+
import androidx.compose.ui.draw.clip
|
|
16
|
+
import androidx.compose.ui.graphics.Color
|
|
17
|
+
import androidx.compose.ui.text.style.TextOverflow
|
|
18
|
+
import androidx.compose.ui.unit.dp
|
|
19
|
+
import vn.momo.kits.components.Icon
|
|
20
|
+
import vn.momo.kits.components.Skeleton
|
|
21
|
+
import vn.momo.kits.components.Text
|
|
22
|
+
import vn.momo.kits.const.Spacing
|
|
23
|
+
import vn.momo.kits.const.Typography
|
|
24
|
+
import vn.momo.kits.modifier.activeOpacityClickable
|
|
25
|
+
|
|
26
|
+
@Composable
|
|
27
|
+
internal fun HeaderLocation(
|
|
28
|
+
data: HeaderTitle,
|
|
29
|
+
tintIconColor: Color,
|
|
30
|
+
) {
|
|
31
|
+
if (data !is HeaderTitle.Location) return
|
|
32
|
+
if (data.isLoading) return TitleLocationShimmer()
|
|
33
|
+
|
|
34
|
+
val maxWidth = headerTitleMaxWidth()
|
|
35
|
+
val tint = parseHeaderTint(data.tintColor) ?: tintIconColor
|
|
36
|
+
|
|
37
|
+
Column(
|
|
38
|
+
modifier = Modifier
|
|
39
|
+
.widthIn(max = maxWidth)
|
|
40
|
+
.activeOpacityClickable(enabled = data.onPress != null, onClick = { data.onPress?.invoke() }),
|
|
41
|
+
horizontalAlignment = Alignment.Start,
|
|
42
|
+
) {
|
|
43
|
+
if (!data.description.isNullOrEmpty()) {
|
|
44
|
+
Text(
|
|
45
|
+
text = data.description,
|
|
46
|
+
color = tint,
|
|
47
|
+
style = Typography.descriptionXsRegular,
|
|
48
|
+
maxLines = 1,
|
|
49
|
+
overflow = TextOverflow.Ellipsis,
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
53
|
+
Text(
|
|
54
|
+
text = data.location,
|
|
55
|
+
color = tint,
|
|
56
|
+
style = Typography.actionXsBold,
|
|
57
|
+
maxLines = 1,
|
|
58
|
+
overflow = TextOverflow.Ellipsis,
|
|
59
|
+
modifier = Modifier.weight(1f, fill = false),
|
|
60
|
+
)
|
|
61
|
+
Spacer(Modifier.width(Spacing.XS))
|
|
62
|
+
Icon(source = "16_arrow_chevron_down_small", size = 16.dp, color = tint)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@Composable
|
|
68
|
+
private fun TitleLocationShimmer() {
|
|
69
|
+
Column(modifier = Modifier.fillMaxWidth()) {
|
|
70
|
+
Box(modifier = Modifier.height(12.dp).width(120.dp).clip(RoundedCornerShape(8.dp))) { Skeleton() }
|
|
71
|
+
Spacer(Modifier.height(Spacing.XXS))
|
|
72
|
+
Box(modifier = Modifier.height(18.dp).width(120.dp).clip(RoundedCornerShape(8.dp))) { Skeleton() }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
package vn.momo.kits.navigation.component
|
|
2
|
+
|
|
3
|
+
import vn.momo.kits.modifier.InternalApi
|
|
4
|
+
|
|
5
|
+
import androidx.compose.foundation.background
|
|
6
|
+
import androidx.compose.foundation.border
|
|
7
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
8
|
+
import androidx.compose.foundation.layout.Box
|
|
9
|
+
import androidx.compose.foundation.layout.Column
|
|
10
|
+
import androidx.compose.foundation.layout.Row
|
|
11
|
+
import androidx.compose.foundation.layout.height
|
|
12
|
+
import androidx.compose.foundation.layout.offset
|
|
13
|
+
import androidx.compose.foundation.layout.padding
|
|
14
|
+
import androidx.compose.foundation.layout.size
|
|
15
|
+
import androidx.compose.foundation.layout.width
|
|
16
|
+
import androidx.compose.foundation.shape.CircleShape
|
|
17
|
+
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
18
|
+
import androidx.compose.runtime.Composable
|
|
19
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
20
|
+
// AI-GENERATED START: dispose toolkit requests with their UI owner
|
|
21
|
+
import androidx.compose.runtime.DisposableEffect
|
|
22
|
+
import kotlinx.serialization.json.booleanOrNull
|
|
23
|
+
import kotlinx.serialization.json.jsonPrimitive
|
|
24
|
+
import vn.momo.maxapi.contract.navigation.model.DismissTarget
|
|
25
|
+
import vn.momo.maxapi.contract.toolkit.model.ToolAction
|
|
26
|
+
import vn.momo.maxapi.contract.toolkit.model.ToolkitOptions
|
|
27
|
+
import vn.momo.maxapi.contract.toolkit.model.ToolkitToolGroup
|
|
28
|
+
import vn.momo.maxapi.contract.toolkit.model.ToolkitTool
|
|
29
|
+
import vn.momo.maxapi.runtime.ApiResult
|
|
30
|
+
// AI-GENERATED END: dispose toolkit requests with their UI owner
|
|
31
|
+
import androidx.compose.runtime.derivedStateOf
|
|
32
|
+
import androidx.compose.runtime.getValue
|
|
33
|
+
import androidx.compose.runtime.mutableStateOf
|
|
34
|
+
import androidx.compose.runtime.remember
|
|
35
|
+
import androidx.compose.runtime.setValue
|
|
36
|
+
import androidx.compose.ui.Alignment
|
|
37
|
+
import androidx.compose.ui.Modifier
|
|
38
|
+
import androidx.compose.ui.draw.clip
|
|
39
|
+
import androidx.compose.ui.graphics.Color
|
|
40
|
+
import androidx.compose.ui.unit.Dp
|
|
41
|
+
import androidx.compose.ui.unit.dp
|
|
42
|
+
import vn.momo.kits.layout.DuoMetrics
|
|
43
|
+
import vn.momo.kits.application.LocalContext
|
|
44
|
+
import vn.momo.kits.application.MiniAppContext
|
|
45
|
+
import vn.momo.kits.components.BadgeDot
|
|
46
|
+
import vn.momo.kits.components.DotSize
|
|
47
|
+
import vn.momo.kits.components.Icon
|
|
48
|
+
import vn.momo.kits.const.Colors
|
|
49
|
+
import vn.momo.kits.const.Spacing
|
|
50
|
+
import vn.momo.kits.modifier.activeOpacityClickable
|
|
51
|
+
import vn.momo.kits.navigation.LocalMaxApi
|
|
52
|
+
|
|
53
|
+
@Composable
|
|
54
|
+
@InternalApi
|
|
55
|
+
fun HeaderRight(
|
|
56
|
+
headerRight: HeaderRight,
|
|
57
|
+
tintColor: Color? = null,
|
|
58
|
+
headerColor: HeaderColor
|
|
59
|
+
) {
|
|
60
|
+
when (headerRight) {
|
|
61
|
+
is HeaderRight.None -> {}
|
|
62
|
+
is HeaderRight.Custom -> {
|
|
63
|
+
headerRight.content()
|
|
64
|
+
}
|
|
65
|
+
is HeaderRight.OnBoarding -> {}
|
|
66
|
+
is HeaderRight.Toolkit -> {
|
|
67
|
+
Toolkit(
|
|
68
|
+
headerRight = headerRight,
|
|
69
|
+
tintColor = tintColor,
|
|
70
|
+
headerColor = headerColor
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private const val HELP_CENTER_APP_ID = "vn.momo.helpcenter"
|
|
77
|
+
|
|
78
|
+
private fun usesHelpCenter(context: MiniAppContext?): Boolean =
|
|
79
|
+
context != null && context.appId != HELP_CENTER_APP_ID
|
|
80
|
+
|
|
81
|
+
private fun showsShortcut(headerRight: HeaderRight.Toolkit, context: MiniAppContext?): Boolean =
|
|
82
|
+
headerRight.useShortcut && !(headerRight.useMore && context == null)
|
|
83
|
+
|
|
84
|
+
// Height of the vertical toolkit: the optional shortcut, then the help/home capsule.
|
|
85
|
+
@Composable
|
|
86
|
+
internal fun toolkitColumnHeight(headerRight: HeaderRight.Toolkit): Dp {
|
|
87
|
+
val context = LocalContext.current
|
|
88
|
+
val shortcut = if (showsShortcut(headerRight, context)) DuoMetrics.controlSize + Spacing.M else 0.dp
|
|
89
|
+
val groupCount = if (usesHelpCenter(context)) 2 else 1
|
|
90
|
+
return shortcut + if (groupCount > 1) DuoMetrics.itemPitch * groupCount else DuoMetrics.controlSize
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// SideBarColumn: the iPhone Duo side bar; SideBarRow: the Duo header row on the status bar, same 48pt controls.
|
|
94
|
+
internal enum class ToolkitLayout { Bar, SideBarColumn, SideBarRow }
|
|
95
|
+
|
|
96
|
+
@Composable
|
|
97
|
+
internal fun Toolkit(
|
|
98
|
+
headerRight: HeaderRight.Toolkit,
|
|
99
|
+
tintColor: Color? = null,
|
|
100
|
+
headerColor: HeaderColor,
|
|
101
|
+
layout: ToolkitLayout = ToolkitLayout.Bar,
|
|
102
|
+
) {
|
|
103
|
+
val api = LocalMaxApi.current
|
|
104
|
+
val context = LocalContext.current
|
|
105
|
+
|
|
106
|
+
var isFavorite by remember { mutableStateOf(false) }
|
|
107
|
+
val isLoading by remember { mutableStateOf(false) }
|
|
108
|
+
|
|
109
|
+
// AI-GENERATED START: retain custom tool data and typed callback outcomes
|
|
110
|
+
val requests = remember(api, context?.appCode) { ToolkitRequests() }
|
|
111
|
+
DisposableEffect(requests) { onDispose { requests.close() } }
|
|
112
|
+
|
|
113
|
+
LaunchedEffect(requests) {
|
|
114
|
+
val client = api ?: return@LaunchedEffect
|
|
115
|
+
requests.launch<Boolean>({ callback -> client.checkFavorite(context?.appCode, callback) }) { result ->
|
|
116
|
+
if (result is ApiResult.Success) isFavorite = result.value
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fun onPressShortcut() {
|
|
121
|
+
val client = api ?: return
|
|
122
|
+
requests.launch({ callback ->
|
|
123
|
+
client.performToolAction(ToolAction.FAVORITE, context?.appCode, callback)
|
|
124
|
+
}) { result ->
|
|
125
|
+
if (result is ApiResult.Success) {
|
|
126
|
+
result.value.jsonPrimitive.booleanOrNull?.let { isFavorite = it }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fun onPressMore() {
|
|
132
|
+
val client = api ?: return
|
|
133
|
+
val options = ToolkitOptions(
|
|
134
|
+
customToolGroups = headerRight.tools.map { group ->
|
|
135
|
+
ToolkitToolGroup(group.title, group.items.map { tool ->
|
|
136
|
+
ToolkitTool(tool.key, tool.icon, tool.showBadge, tool.name, tool.showRightIcon)
|
|
137
|
+
})
|
|
138
|
+
},
|
|
139
|
+
useSystemTools = headerRight.useSystemTools,
|
|
140
|
+
)
|
|
141
|
+
requests.launch({ callback -> client.showToolkit(options, callback) }) { result ->
|
|
142
|
+
if (result is ApiResult.Success) headerRight.toolCallback?.invoke(result.value.actionKey)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// AI-GENERATED END: retain custom tool data and typed callback outcomes
|
|
146
|
+
|
|
147
|
+
fun onPressHelpCenter() {
|
|
148
|
+
if (context == null) return
|
|
149
|
+
// AI-GENERATED START: preserve Help Center context and own its event subscription
|
|
150
|
+
val client = api ?: return
|
|
151
|
+
requests.observe({ callback -> client.showBottomSheet(context.helpCenterRequest(), callback) }) {}
|
|
152
|
+
// AI-GENERATED END: preserve Help Center context and own its event subscription
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
fun onPressClose() {
|
|
156
|
+
// AI-GENERATED START: preserve current-container and whole-stack dismissal
|
|
157
|
+
api?.dismiss(if (headerRight.useCloseIcon) DismissTarget.Current() else DismissTarget.All) {}
|
|
158
|
+
// AI-GENERATED END: preserve current-container and whole-stack dismissal
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
val useHelpCenter = usesHelpCenter(context)
|
|
162
|
+
val closeIcon = if (headerRight.useCloseIcon) "16_navigation_close_circle" else "16_basic_home"
|
|
163
|
+
|
|
164
|
+
val navButtonConfig = getNavigationButtonConfig(
|
|
165
|
+
headerRight,
|
|
166
|
+
::onPressShortcut,
|
|
167
|
+
::onPressMore
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
val showBadge = headerRight.tools.any { group ->
|
|
171
|
+
group.items.any { it.showBadge }
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
val isShowShortcut = showsShortcut(headerRight, context)
|
|
175
|
+
|
|
176
|
+
val icon by remember(navButtonConfig.icon, isFavorite) {
|
|
177
|
+
derivedStateOf {
|
|
178
|
+
navButtonConfig.icon.takeUnless { it == "star" }
|
|
179
|
+
?: if (isFavorite) "pin_star_checked" else "pin_star"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (layout != ToolkitLayout.Bar) {
|
|
184
|
+
val horizontal = layout == ToolkitLayout.SideBarRow
|
|
185
|
+
val controls = @Composable {
|
|
186
|
+
if (isShowShortcut) {
|
|
187
|
+
SideBarButton(
|
|
188
|
+
icon = icon,
|
|
189
|
+
headerColor = headerColor,
|
|
190
|
+
enabled = !isLoading,
|
|
191
|
+
showBadge = showBadge,
|
|
192
|
+
onClick = navButtonConfig.onPress,
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
SideBarGroup(headerColor = headerColor, itemCount = if (useHelpCenter) 2 else 1, horizontal = horizontal) { item ->
|
|
196
|
+
if (useHelpCenter) {
|
|
197
|
+
SideBarGroupItem(
|
|
198
|
+
icon = "help_center",
|
|
199
|
+
headerColor = headerColor,
|
|
200
|
+
automationId = "btn_navigation_help_center",
|
|
201
|
+
onClick = ::onPressHelpCenter,
|
|
202
|
+
modifier = item,
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
SideBarGroupItem(
|
|
206
|
+
icon = closeIcon,
|
|
207
|
+
headerColor = headerColor,
|
|
208
|
+
automationId = "btn_navigation_close",
|
|
209
|
+
onClick = ::onPressClose,
|
|
210
|
+
modifier = item,
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (horizontal) {
|
|
215
|
+
Row(horizontalArrangement = Arrangement.spacedBy(Spacing.M), verticalAlignment = Alignment.CenterVertically) {
|
|
216
|
+
controls()
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
Column(verticalArrangement = Arrangement.spacedBy(Spacing.M)) { controls() }
|
|
220
|
+
}
|
|
221
|
+
return
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
Row(
|
|
225
|
+
verticalAlignment = Alignment.CenterVertically
|
|
226
|
+
) {
|
|
227
|
+
if (isShowShortcut) {
|
|
228
|
+
NavigationButton(
|
|
229
|
+
disabled = isLoading,
|
|
230
|
+
icon = icon,
|
|
231
|
+
showBadge = showBadge,
|
|
232
|
+
onClick = navButtonConfig.onPress,
|
|
233
|
+
headerColor = headerColor
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
Row(
|
|
238
|
+
verticalAlignment = Alignment.CenterVertically,
|
|
239
|
+
horizontalArrangement = Arrangement.Center,
|
|
240
|
+
modifier = Modifier
|
|
241
|
+
.padding(start = Spacing.S)
|
|
242
|
+
.border(0.2.dp, headerColor.borderColor, shape = RoundedCornerShape(14.dp))
|
|
243
|
+
.height(28.dp)
|
|
244
|
+
.clip(shape = RoundedCornerShape(14.dp))
|
|
245
|
+
.background(headerColor.backgroundButton)
|
|
246
|
+
) {
|
|
247
|
+
if (useHelpCenter) {
|
|
248
|
+
Icon(
|
|
249
|
+
source = "help_center",
|
|
250
|
+
size = 20.dp,
|
|
251
|
+
color = headerColor.tintIconColor,
|
|
252
|
+
modifier = Modifier.padding(4.dp).activeOpacityClickable(onClick = ::onPressHelpCenter)
|
|
253
|
+
)
|
|
254
|
+
Box(
|
|
255
|
+
modifier = Modifier
|
|
256
|
+
.width(0.5.dp)
|
|
257
|
+
.height(12.dp)
|
|
258
|
+
.background(tintColor ?: Colors.black_20)
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
Icon(
|
|
262
|
+
source = closeIcon,
|
|
263
|
+
size = 20.dp,
|
|
264
|
+
color = headerColor.tintIconColor,
|
|
265
|
+
modifier = Modifier.padding(4.dp).activeOpacityClickable(onClick = ::onPressClose)
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
// Colors follow the enclosing header, so it fits a `HeaderRight.Custom` next to the toolkit.
|
|
274
|
+
@Composable
|
|
275
|
+
fun NavigationButton(
|
|
276
|
+
icon: String,
|
|
277
|
+
onClick: () -> Unit,
|
|
278
|
+
showBadge: Boolean = false,
|
|
279
|
+
disabled: Boolean = false,
|
|
280
|
+
modifier: Modifier = Modifier,
|
|
281
|
+
) {
|
|
282
|
+
NavigationButton(
|
|
283
|
+
disabled = disabled,
|
|
284
|
+
icon = icon,
|
|
285
|
+
showBadge = showBadge,
|
|
286
|
+
onClick = onClick,
|
|
287
|
+
headerColor = LocalHeaderColor.current ?: getHeaderColor(HeaderType.Default(), 1f, null, Colors.black_17),
|
|
288
|
+
modifier = modifier,
|
|
289
|
+
)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
@Composable
|
|
293
|
+
internal fun NavigationButton(
|
|
294
|
+
disabled: Boolean,
|
|
295
|
+
icon: String,
|
|
296
|
+
showBadge: Boolean? = false,
|
|
297
|
+
onClick: () -> Unit,
|
|
298
|
+
headerColor: HeaderColor,
|
|
299
|
+
modifier: Modifier = Modifier,
|
|
300
|
+
) {
|
|
301
|
+
Box(
|
|
302
|
+
modifier = modifier
|
|
303
|
+
.size(28.dp)
|
|
304
|
+
.activeOpacityClickable(enabled = !disabled, onClick = onClick)
|
|
305
|
+
) {
|
|
306
|
+
Box(
|
|
307
|
+
modifier = Modifier
|
|
308
|
+
.matchParentSize()
|
|
309
|
+
.clip(CircleShape)
|
|
310
|
+
.background(headerColor.backgroundButton)
|
|
311
|
+
.border(0.2.dp, headerColor.borderColor, CircleShape)
|
|
312
|
+
)
|
|
313
|
+
Box(
|
|
314
|
+
modifier = Modifier.matchParentSize(),
|
|
315
|
+
contentAlignment = Alignment.Center
|
|
316
|
+
) {
|
|
317
|
+
Icon(
|
|
318
|
+
source = icon,
|
|
319
|
+
size = 20.dp,
|
|
320
|
+
color = headerColor.tintIconColor
|
|
321
|
+
)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (showBadge == true) {
|
|
325
|
+
BadgeDot(
|
|
326
|
+
size = DotSize.Small,
|
|
327
|
+
modifier = Modifier
|
|
328
|
+
.align(Alignment.TopEnd)
|
|
329
|
+
.offset(x = -Spacing.XXS, y = -Spacing.XXS)
|
|
330
|
+
)
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
private fun getNavigationButtonConfig(
|
|
336
|
+
headerRight: HeaderRight.Toolkit,
|
|
337
|
+
onPressShortcut: () -> Unit,
|
|
338
|
+
onPressMore: () -> Unit
|
|
339
|
+
): NavigationButtonConfig {
|
|
340
|
+
val totalTools = headerRight.tools.sumOf { it.items.size }
|
|
341
|
+
val config = NavigationButtonConfig(icon = "star", onPress = onPressShortcut)
|
|
342
|
+
return if (totalTools > 1 || headerRight.useMore == true) {
|
|
343
|
+
NavigationButtonConfig(
|
|
344
|
+
icon = "navigation_more_icon",
|
|
345
|
+
onPress = onPressMore
|
|
346
|
+
)
|
|
347
|
+
} else if (totalTools == 1 && headerRight.tools.isNotEmpty()) {
|
|
348
|
+
val singleTool = headerRight.tools.first().items.firstOrNull()
|
|
349
|
+
return if (singleTool != null){
|
|
350
|
+
NavigationButtonConfig(
|
|
351
|
+
icon = singleTool.icon,
|
|
352
|
+
onPress = {
|
|
353
|
+
headerRight.toolCallback?.invoke(singleTool.key)
|
|
354
|
+
}
|
|
355
|
+
)
|
|
356
|
+
} else {
|
|
357
|
+
config
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
config
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
sealed interface HeaderRight {
|
|
365
|
+
data object None : HeaderRight
|
|
366
|
+
data class Custom(
|
|
367
|
+
val content: @Composable () -> Unit
|
|
368
|
+
) : HeaderRight
|
|
369
|
+
data object OnBoarding : HeaderRight
|
|
370
|
+
data class Toolkit(
|
|
371
|
+
val useShortcut: Boolean = false,
|
|
372
|
+
val useMore: Boolean = false,
|
|
373
|
+
val useSystemTools: Boolean = true,
|
|
374
|
+
val tools: List<ToolGroup> = emptyList(),
|
|
375
|
+
val toolCallback: ((String) -> Unit)? = { _ -> },
|
|
376
|
+
// Close dismisses only this mini app instead of returning home.
|
|
377
|
+
val useCloseIcon: Boolean = false,
|
|
378
|
+
) : HeaderRight
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
data class ToolGroup(
|
|
382
|
+
val title: Map<String, String> = emptyMap(),
|
|
383
|
+
val items: List<Tool>
|
|
384
|
+
) {
|
|
385
|
+
fun toMap(): Map<String, Any> {
|
|
386
|
+
return mapOf(
|
|
387
|
+
"title" to title,
|
|
388
|
+
"items" to items.map { it.toMap() }
|
|
389
|
+
)
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
data class Tool(
|
|
393
|
+
val key: String,
|
|
394
|
+
val icon: String,
|
|
395
|
+
val showBadge: Boolean = false,
|
|
396
|
+
val name: Map<String, String> = emptyMap(),
|
|
397
|
+
val showRightIcon: Boolean = true,
|
|
398
|
+
) {
|
|
399
|
+
fun toMap(): Map<String, Any> {
|
|
400
|
+
return mapOf(
|
|
401
|
+
"key" to key,
|
|
402
|
+
"icon" to icon,
|
|
403
|
+
"showBadge" to showBadge,
|
|
404
|
+
"name" to name,
|
|
405
|
+
"showRightIcon" to showRightIcon
|
|
406
|
+
)
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
private data class NavigationButtonConfig(
|
|
411
|
+
val icon: String,
|
|
412
|
+
val onPress: () -> Unit
|
|
413
|
+
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
package vn.momo.kits.navigation.component
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
4
|
+
import androidx.compose.runtime.Composable
|
|
5
|
+
import androidx.compose.ui.Modifier
|
|
6
|
+
import androidx.compose.ui.graphics.Color
|
|
7
|
+
import androidx.compose.ui.text.style.TextAlign
|
|
8
|
+
import androidx.compose.ui.text.style.TextOverflow
|
|
9
|
+
import androidx.compose.ui.unit.sp
|
|
10
|
+
import androidx.compose.ui.zIndex
|
|
11
|
+
import vn.momo.kits.components.Text
|
|
12
|
+
import vn.momo.kits.const.KitDesignSystem
|
|
13
|
+
import vn.momo.kits.const.Typography
|
|
14
|
+
import vn.momo.kits.modifier.setAutomationId
|
|
15
|
+
|
|
16
|
+
internal val headerFontFamily: String?
|
|
17
|
+
get() = if (KitDesignSystem.isWhiteList) "MoMoTrustDisplay" else null
|
|
18
|
+
|
|
19
|
+
@Composable
|
|
20
|
+
internal fun HeaderTitle(
|
|
21
|
+
title: String = "",
|
|
22
|
+
color: Color? = null,
|
|
23
|
+
modifier: Modifier = Modifier.fillMaxWidth(),
|
|
24
|
+
textAlign: TextAlign = TextAlign.Start,
|
|
25
|
+
) {
|
|
26
|
+
Text(
|
|
27
|
+
modifier = modifier.zIndex(1f).setAutomationId("title_navigation_header"),
|
|
28
|
+
text = title,
|
|
29
|
+
textAlign = textAlign,
|
|
30
|
+
style = Typography.actionSBold.copy(
|
|
31
|
+
fontSize = 15.sp,
|
|
32
|
+
lineHeight = 22.sp,
|
|
33
|
+
),
|
|
34
|
+
fontFamily = headerFontFamily,
|
|
35
|
+
color = color,
|
|
36
|
+
maxLines = 1,
|
|
37
|
+
overflow = TextOverflow.Ellipsis
|
|
38
|
+
)
|
|
39
|
+
}
|