@momo-kits/native-kits 0.167.1-duo.15-debug → 0.167.1-duo.16

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.
Files changed (151) hide show
  1. package/.claude/settings.local.json +185 -0
  2. package/ios/native-kits.podspec +1 -1
  3. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  4. package/package.json +1 -1
  5. package/build.gradle.kts +0 -11
  6. package/compose/build.gradle.kts +0 -204
  7. package/compose/build.gradle.kts.backup +0 -204
  8. package/compose/compose.podspec +0 -47
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
  10. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  11. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
  12. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
  13. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -153
  14. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +0 -6
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -124
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -831
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -81
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -357
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -115
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -478
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -265
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -235
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -265
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -361
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -108
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -308
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -330
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -207
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -92
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -560
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -86
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -501
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -236
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -180
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -16
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +0 -18
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -297
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -54
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -50
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +0 -260
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -41
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -338
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -137
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -106
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -205
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -393
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -708
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -218
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -231
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +0 -98
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +0 -312
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -408
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -103
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -106
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -74
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -366
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -37
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -363
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +0 -185
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -133
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -74
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +0 -13
  133. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  134. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
  135. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  136. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -118
  137. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
  138. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
  139. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
  140. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
  141. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
  142. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -217
  143. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +0 -94
  144. package/gradle/libs.versions.toml +0 -69
  145. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  146. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  147. package/gradle.properties +0 -26
  148. package/gradlew +0 -252
  149. package/gradlew.bat +0 -94
  150. package/ios-demo/README.md +0 -120
  151. package/settings.gradle.kts +0 -64
@@ -1,205 +0,0 @@
1
- package vn.momo.kits.navigation
2
-
3
- import androidx.compose.animation.core.tween
4
- import androidx.compose.animation.fadeIn
5
- import androidx.compose.animation.slideInVertically
6
- import androidx.compose.animation.slideOutVertically
7
- import androidx.compose.runtime.Composable
8
- import androidx.compose.runtime.CompositionLocalProvider
9
- import androidx.compose.runtime.DisposableEffect
10
- import androidx.compose.runtime.LaunchedEffect
11
- import androidx.compose.runtime.mutableStateOf
12
- import androidx.compose.runtime.remember
13
- import androidx.compose.runtime.saveable.rememberSaveable
14
- import androidx.compose.runtime.staticCompositionLocalOf
15
- import androidx.compose.ui.unit.Dp
16
- import androidx.navigation.compose.NavHost
17
- import androidx.navigation.compose.composable
18
- import androidx.navigation.compose.rememberNavController
19
- import androidx.navigation.toRoute
20
- import kotlinx.coroutines.delay
21
- import kotlinx.coroutines.flow.collectLatest
22
- import vn.momo.kits.application.DesignSystemConfig
23
- import vn.momo.kits.application.KitDesignSystemConfig
24
- import vn.momo.kits.application.LocalContext
25
- import vn.momo.kits.application.LocalDesignSystemConfig
26
- import vn.momo.kits.application.LocalLocalize
27
- import vn.momo.kits.application.Localize
28
- import vn.momo.kits.application.MiniAppContext
29
- import vn.momo.kits.const.AppNavigationBar
30
- import vn.momo.kits.const.AppStatusBar
31
- import vn.momo.kits.const.AppTheme
32
- import vn.momo.kits.const.Theme
33
- import vn.momo.kits.const.defaultTheme
34
- import vn.momo.kits.layout.LocalScreenLayout
35
- import vn.momo.kits.layout.calculateScreenLayout
36
- import vn.momo.kits.platform.ProvideNavigationEventDispatcherOwner
37
- import vn.momo.kits.platform.ProvideOsFontScale
38
- import vn.momo.kits.utils.getAppStatusBarHeight
39
- import vn.momo.kits.utils.getNavigationBarHeight
40
- import vn.momo.maxapi.IMaxApi
41
- import kotlin.time.Duration.Companion.milliseconds
42
-
43
- @Composable
44
- fun NavigationContainer(
45
- initialScreenName: String,
46
- initialScreen: @Composable () -> Unit,
47
- maxApi: IMaxApi,
48
- options: NavigationOptions? = null,
49
- initialTheme: Theme = defaultTheme,
50
- miniAppContext: MiniAppContext? = null,
51
- setNavigator: ((Navigator) -> Unit)? = null,
52
- statusBarHeight: Dp? = null,
53
- localize: Localize? = null,
54
- designSystemConfig: DesignSystemConfig? = null,
55
- ) {
56
- val navController = rememberNavController()
57
- val registry = remember { DynamicScreenRegistry() }
58
- val navigator = remember { Navigator(navController = navController, maxApi = maxApi, registry = registry) }
59
- val statusBarHeight = statusBarHeight ?: getAppStatusBarHeight()
60
- val navigationBarHeight = getNavigationBarHeight()
61
- val screenLayout = calculateScreenLayout(statusBarHeight, parent = LocalScreenLayout.current)
62
-
63
- val parentContext = LocalContext.current
64
- val mergedContext = MiniAppContext.merge(parentContext, miniAppContext)
65
-
66
- val stackTransition = remember { StackTransitionCoordinator() }
67
- val theme = remember { mutableStateOf(initialTheme) }
68
- val resolvedDesignSystemConfig =
69
- designSystemConfig ?: LocalDesignSystemConfig.current ?: KitDesignSystemConfig.config
70
- val headerBar = resolvedDesignSystemConfig?.headerBar
71
- // RN parity: the theme's own header image wins; config headerBar is only the fallback.
72
- val resolvedTheme = remember(theme.value, headerBar) {
73
- if (theme.value.isHeaderImage() || headerBar.isNullOrEmpty()) {
74
- theme.value
75
- } else {
76
- theme.value.copy(assets = theme.value.assets.copy(headerBackground = headerBar))
77
- }
78
- }
79
- val fallbackLocalize = remember { Localize() }
80
-
81
- val resolvedLocalize = localize ?: fallbackLocalize
82
-
83
- LaunchedEffect(maxApi, resolvedLocalize) {
84
- val api = maxApi ?: return@LaunchedEffect
85
- runCatching {
86
- api.getLanguage(callback = { data ->
87
- if (parseLanguage(data) == Localize.EN) {
88
- resolvedLocalize.changeLanguage(Localize.EN)
89
- }
90
- })
91
- }
92
- }
93
-
94
- val screenId = rememberSaveable { registry.nextId() }
95
- registry.bind(screenId, initialScreenName, initialScreen, options)
96
- val startDestination = remember(screenId) { DynamicScreenRoute(screenId) }
97
-
98
- ProvideOsFontScale {
99
- ProvideNavigationEventDispatcherOwner(navigator) {
100
- CompositionLocalProvider(
101
- LocalNavigator provides navigator,
102
- LocalDynamicScreenRegistry provides registry,
103
- LocalMaxApi provides maxApi,
104
- AppTheme provides resolvedTheme,
105
- AppStatusBar provides statusBarHeight,
106
- AppNavigationBar provides navigationBarHeight,
107
- LocalScreenLayout provides screenLayout,
108
- LocalContext provides mergedContext,
109
- LocalDesignSystemConfig provides resolvedDesignSystemConfig,
110
- LocalLocalize provides resolvedLocalize,
111
- LocalStackTransition provides stackTransition,
112
- ) {
113
- LaunchedEffect(Unit) {
114
- setNavigator?.invoke(navigator)
115
- }
116
-
117
- SwipeBackHaptic(maxApi)
118
-
119
- LaunchedEffect(navController, registry) {
120
- navController.currentBackStack.collectLatest { entries ->
121
- delay(STACK_TRANSITION_DURATION.milliseconds)
122
- val aliveIds = entries.mapNotNullTo(mutableSetOf()) { entry ->
123
- runCatching { entry.toRoute<DynamicScreenRoute>().id }.getOrNull()
124
- ?: runCatching { entry.toRoute<DynamicDialogRoute>().id }.getOrNull()
125
- }
126
- aliveIds.add(screenId)
127
- registry.retainOnly(aliveIds)
128
- }
129
- }
130
-
131
- NavHost(
132
- navController,
133
- startDestination = startDestination,
134
- enterTransition = { stackEnter() },
135
- exitTransition = { stackExit() },
136
- popEnterTransition = { stackPopEnter() },
137
- popExitTransition = { stackPopExit() },
138
- ) {
139
- composable<DynamicScreenRoute> { backStackEntry ->
140
- val route = backStackEntry.toRoute<DynamicScreenRoute>()
141
- val screen = registry.getScreen(route.id)
142
-
143
- if (screen != null) {
144
- StackTransitionDecor(id = route.id, isStackRoute = true) {
145
- StackScreen(
146
- id = route.id,
147
- name = screen.name,
148
- content = screen.content,
149
- navigationOptions = screen.options
150
- )
151
- }
152
- }
153
- }
154
-
155
- composable<DynamicDialogRoute>(
156
- enterTransition = {
157
- slideInVertically(
158
- animationSpec = tween(300),
159
- initialOffsetY = { it }
160
- )
161
- },
162
- exitTransition = null,
163
- popEnterTransition = { fadeIn(animationSpec = tween(0)) },
164
- popExitTransition = {
165
- slideOutVertically(
166
- animationSpec = tween(300),
167
- targetOffsetY = { it }
168
- )
169
- }
170
- ) { backStackEntry ->
171
- val route = backStackEntry.toRoute<DynamicDialogRoute>()
172
- val screen = registry.getScreen(route.id)
173
-
174
- if (screen != null) {
175
- StackTransitionDecor(id = route.id, isStackRoute = false) {
176
- StackScreen(
177
- id = route.id,
178
- name = screen.name,
179
- content = screen.content,
180
- navigationOptions = screen.options
181
- )
182
- }
183
- }
184
- }
185
- }
186
- }
187
- }
188
- }
189
-
190
- DisposableEffect(Unit) {
191
- onDispose {
192
- navigator.dispose()
193
- registry.unregisterScreen(screenId)
194
- }
195
- }
196
- }
197
-
198
- val LocalMaxApi = staticCompositionLocalOf<IMaxApi?> { null }
199
-
200
- private fun parseLanguage(raw: Map<String, Any?>?): String? {
201
- val code = (raw?.get("response") as? String)?.trim()?.lowercase()
202
- if (code.isNullOrEmpty()) return null
203
- return if (code.startsWith(Localize.EN)) Localize.EN else Localize.VI
204
- }
205
-
@@ -1,393 +0,0 @@
1
- package vn.momo.kits.navigation
2
-
3
- import androidx.compose.foundation.layout.Box
4
- import androidx.compose.foundation.layout.fillMaxSize
5
- import androidx.compose.runtime.Composable
6
- import androidx.compose.runtime.MutableState
7
- import androidx.compose.runtime.mutableStateOf
8
- import androidx.compose.runtime.staticCompositionLocalOf
9
- import androidx.compose.ui.Alignment
10
- import androidx.compose.ui.Modifier
11
- import androidx.navigation.NavController
12
- import androidx.navigation.toRoute
13
- import kotlinx.coroutines.CoroutineScope
14
- import kotlinx.coroutines.Dispatchers
15
- import kotlinx.coroutines.SupervisorJob
16
- import kotlinx.coroutines.cancel
17
- import kotlinx.coroutines.delay
18
- import kotlinx.coroutines.launch
19
- import kotlinx.serialization.Serializable
20
- import vn.momo.kits.components.PopupAction
21
- import vn.momo.kits.components.PopupNotify
22
- import vn.momo.kits.navigation.BottomHeader.*
23
- import vn.momo.kits.navigation.component.SnackBar
24
- import vn.momo.maxapi.IMaxApi
25
- import kotlin.time.Duration.Companion.milliseconds
26
-
27
- class Navigator(
28
- private val navController: NavController,
29
- private val maxApi: IMaxApi?,
30
- private val registry: DynamicScreenRegistry
31
- ) {
32
- private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
33
-
34
- // currentScreen() reads the root back stack, so it never sees the nested tab NavHost.
35
- internal var tabBackHandler: (() -> Unit)? = null
36
-
37
- private fun currentScreen(): DynamicScreen? {
38
- val entry = navController.currentBackStackEntry ?: return null
39
- val id = runCatching { entry.toRoute<DynamicScreenRoute>().id }.getOrNull()
40
- ?: runCatching { entry.toRoute<DynamicDialogRoute>().id }.getOrNull()
41
- ?: return null
42
- return registry.getScreen(id)
43
- }
44
-
45
- fun push(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
46
- val route = registry.register(screenName, content, options)
47
- navController.navigate(DynamicScreenRoute(route.id))
48
- }
49
-
50
- fun replace(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
51
- val replacedScreen = currentScreen()
52
- replacedScreen?.let { registry.unregisterScreen(it.id) }
53
- navController.popBackStack()
54
- push(screenName, content, options)
55
- }
56
-
57
- fun onBackSafe(callBack: (() -> Unit)? = null) {
58
- tabBackHandler?.let {
59
- it()
60
- return
61
- }
62
- val currentScreen = currentScreen()
63
- val options = currentScreen?.options
64
- if (options?.onBackHandler != null) {
65
- options.onBackHandler.invoke()
66
- return
67
- }
68
- val preventBack = options?.headerBackProps?.preventBack
69
- if (preventBack != null) {
70
- showModal(
71
- content = {
72
- PopupNotify(preventBack.copy(
73
- primary = PopupAction(
74
- title = preventBack.primary?.title ?: "",
75
- onPress = {
76
- preventBack.primary?.onPress?.invoke()
77
- pop(2, callBack) // close popup notify, then close the screen
78
- }
79
- )
80
- ))
81
- }
82
- )
83
- } else {
84
- pop(1, callBack)
85
- }
86
- }
87
-
88
- // The swipe-back opt-out predicate in StackScreen needs this: the root screen must keep custom
89
- // back handling so it still reaches maxApi.dismiss.
90
- // Public: the iOS host asks this to decide whether the kit owns the swipe on this screen.
91
- fun canPop(): Boolean = navController.previousBackStackEntry != null
92
-
93
- fun pop(count: Int = 1, callBack: (() -> Unit)? = null) {
94
- scope.launch {
95
- repeat(count) {
96
- if (OverplayComponentRegistry.getOverplayType() == OverplayComponentType.SNACK_BAR){
97
- dismissScreen()
98
- OverplayComponentRegistry.hardClearAfterDismiss()
99
- }
100
- else if (OverplayComponentRegistry.isOverplayShowing()){
101
- dismissOverplay()
102
- } else {
103
- dismissScreen()
104
- }
105
- }
106
- callBack?.invoke()
107
- }
108
- }
109
- private suspend fun dismissOverplay(isDelay: Boolean = true) {
110
- OverplayComponentRegistry.clear()
111
- if (isDelay) delay(300L.milliseconds)
112
- OverplayComponentRegistry.hardClearAfterDismiss()
113
- }
114
-
115
- private suspend fun dismissScreen() {
116
- if (navController.previousBackStackEntry != null){
117
- val dismissing = currentScreen()
118
- navController.popBackStack()
119
- delay(STACK_TRANSITION_DURATION.milliseconds)
120
- dismissing?.let { registry.unregisterScreen(it.id) }
121
- } else {
122
- maxApi?.dismiss { }
123
- }
124
- }
125
-
126
- fun present(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
127
- val route = registry.register(screenName, content, options)
128
- navController.navigate(DynamicDialogRoute(route.id))
129
- }
130
-
131
- fun reset(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
132
- registry.unregisterAll()
133
-
134
- val route = registry.register(screenName, content, options)
135
- navController.navigate(DynamicScreenRoute(route.id)) {
136
- popUpTo(0) { inclusive = true }
137
- }
138
- }
139
-
140
- fun showModal(
141
- content: @Composable () -> Unit,
142
- barrierDismissible: Boolean = true,
143
- onDismiss: (() -> Unit)? = null
144
- ){
145
- val id = currentScreen()?.id ?: -1
146
- OverplayComponentRegistry.registerOverplay(id, content, OverplayComponentType.MODAL, false, barrierDismissible, onDismiss)
147
- }
148
-
149
- fun showBottomSheet(
150
- content: @Composable () -> Unit,
151
- isSurface: Boolean = false,
152
- barrierDismissible: Boolean = true,
153
- onDismiss: (() -> Unit)? = null,
154
- bottomSheetHeader: BottomHeader? = null,
155
- draggable: Boolean = true,
156
- useBottomInset: Boolean = true,
157
- footerComponent: (@Composable () -> Unit)? = null
158
- ){
159
- val id = currentScreen()?.id ?: -1
160
- OverplayComponentRegistry.registerOverplay(id, content, OverplayComponentType.BOTTOM_SHEET, isSurface, barrierDismissible, onDismiss, bottomSheetHeader, draggable, useBottomInset, footerComponent)
161
- }
162
-
163
- fun showSnackBar(snackBar: SnackBar, onDismiss: (() -> Unit)? = null) {
164
- val id = currentScreen()?.id ?: -1
165
- scope.launch {
166
- OverplayComponentRegistry.registerOverplay(
167
- id = id,
168
- content = {
169
- SnackBar(snackBar, onDismiss)
170
- },
171
- type = OverplayComponentType.SNACK_BAR,
172
- onDismiss = onDismiss
173
- )
174
- }
175
- }
176
-
177
- fun hideSnackBar() {
178
- scope.launch {
179
- OverplayComponentRegistry.clear()
180
- delay(250L.milliseconds)
181
- OverplayComponentRegistry.hardClearAfterDismiss()
182
- }
183
- }
184
-
185
- fun dispose(){
186
- scope.cancel()
187
- }
188
- }
189
-
190
- val LocalNavigator = staticCompositionLocalOf<Navigator> {
191
- error("No NavigationStack provided")
192
- }
193
-
194
- @Serializable
195
- data class DynamicScreenRoute(val id: Int)
196
-
197
- @Serializable
198
- data class DynamicDialogRoute(val id: Int)
199
-
200
- data class DynamicScreen(
201
- val id: Int,
202
- val name: String,
203
- val content: @Composable () -> Unit,
204
- var options: NavigationOptions? = null
205
- )
206
-
207
- class DynamicScreenRegistry {
208
- private val screens = mutableMapOf<Int, DynamicScreen>()
209
-
210
- fun register(screenName: String, content: @Composable () -> Unit, options: NavigationOptions?): DynamicScreenRoute {
211
- val id = nextGlobalId()
212
- screens[id] = DynamicScreen(
213
- id = id,
214
- name = screenName,
215
- content = content,
216
- options = options
217
- )
218
- return DynamicScreenRoute(id)
219
- }
220
-
221
- fun nextId(): Int = nextGlobalId()
222
-
223
- fun bind(id: Int, screenName: String, content: @Composable () -> Unit, options: NavigationOptions?) {
224
- screens[id] = DynamicScreen(
225
- id = id,
226
- name = screenName,
227
- content = content,
228
- options = options
229
- )
230
- advanceGlobalIdPast(id) // keep counter ahead after process-death restore
231
- }
232
-
233
- fun unregisterScreen(id: Int) {
234
- screens.remove(id)
235
- }
236
-
237
- // Gesture pops go through composeNavigator.popBackStack() inside NavHost and never reach
238
- // Navigator.dismissScreen(), so screens would leak without a stack-driven prune.
239
- fun retainOnly(ids: Set<Int>) {
240
- val stale = screens.keys.filter { it !in ids }
241
- for (id in stale) {
242
- screens.remove(id)
243
- }
244
- }
245
-
246
- fun unregisterAll(){
247
- val ids = screens.keys.toList()
248
- for (id in ids) {
249
- unregisterScreen(id)
250
- }
251
- }
252
-
253
- fun getScreen(id: Int): DynamicScreen? = screens[id]
254
-
255
- fun setOptions(id: Int, options: NavigationOptions){
256
- screens[id]?.options = options
257
- }
258
-
259
- companion object {
260
- private var globalIdCounter = 1
261
-
262
- private fun nextGlobalId(): Int = globalIdCounter++
263
-
264
- private fun advanceGlobalIdPast(id: Int) {
265
- if (id >= globalIdCounter) globalIdCounter = id + 1
266
- }
267
- }
268
- }
269
-
270
- val LocalDynamicScreenRegistry = staticCompositionLocalOf<DynamicScreenRegistry?> { null }
271
-
272
-
273
- sealed class OverplayComponentParams {
274
- class Modal(
275
- val onDismiss: (() -> Unit)? = null,
276
- val barrierDismissible: Boolean = true
277
- ) : OverplayComponentParams()
278
-
279
- class BottomSheet(
280
- val isSurface: Boolean = false,
281
- val onDismiss: (() -> Unit)? = null,
282
- val barrierDismissible: Boolean = true,
283
- val bottomSheetHeader: BottomHeader? = null,
284
- val draggable: Boolean = true,
285
- val useBottomInset: Boolean = true,
286
- val footerComponent: (@Composable () -> Unit)? = null,
287
- ) : OverplayComponentParams()
288
-
289
- class SnackBar : OverplayComponentParams()
290
- }
291
-
292
- data class OverplayComponent(
293
- val id: Int,
294
- val type: OverplayComponentType? = null,
295
- val content: @Composable () -> Unit,
296
- val params: OverplayComponentParams? = null
297
- )
298
-
299
- enum class OverplayComponentType {
300
- MODAL, BOTTOM_SHEET, SNACK_BAR
301
- }
302
-
303
- object OverplayComponentRegistry {
304
- private var currentOverlayComponent : MutableState<OverplayComponent?> = mutableStateOf(null)
305
- private var requestClose: (() -> Unit)? = null
306
- internal fun bindClose(handler: (() -> Unit)?) {
307
- requestClose = handler
308
- }
309
-
310
- fun registerOverplay(
311
- id: Int,
312
- content: @Composable () -> Unit,
313
- type: OverplayComponentType,
314
- isSurface: Boolean = false,
315
- barrierDismissible: Boolean = true,
316
- onDismiss: (() -> Unit)?,
317
- bottomSheetHeader: BottomHeader? = null,
318
- draggable: Boolean = true,
319
- useBottomInset: Boolean = true,
320
- footerComponent: (@Composable () -> Unit)? = null,
321
- ){
322
- val params = when(type){
323
- OverplayComponentType.MODAL -> OverplayComponentParams.Modal(onDismiss, barrierDismissible)
324
- OverplayComponentType.BOTTOM_SHEET -> OverplayComponentParams.BottomSheet(isSurface, onDismiss, barrierDismissible, bottomSheetHeader, draggable, useBottomInset, footerComponent)
325
- OverplayComponentType.SNACK_BAR -> OverplayComponentParams.SnackBar()
326
- }
327
-
328
- currentOverlayComponent.value = OverplayComponent(
329
- id = id,
330
- type = type,
331
- content = content,
332
- params = params
333
- )
334
- }
335
-
336
- fun isOverplayShowing(): Boolean = currentOverlayComponent.value != null
337
-
338
- fun getOverplayType(): OverplayComponentType? = currentOverlayComponent.value?.type
339
-
340
- fun currentRootId(): Int? = currentOverlayComponent.value?.id
341
-
342
- fun clear(){
343
- if (requestClose != null) {
344
- requestClose?.invoke()
345
- } else {
346
- currentOverlayComponent.value = null
347
- }
348
- }
349
-
350
- internal fun hardClearAfterDismiss() {
351
- currentOverlayComponent.value = null
352
- requestClose = null
353
- }
354
-
355
- @Composable
356
- internal fun OverlayComponent(){
357
- val overplay = currentOverlayComponent.value ?: return
358
-
359
- when (val params = overplay.params) {
360
- is OverplayComponentParams.BottomSheet -> {
361
- BottomSheet(
362
- content = overplay.content,
363
- header = params.bottomSheetHeader ?: Title(),
364
- isSurface = params.isSurface,
365
- barrierDismissible = params.barrierDismissible,
366
- draggable = params.draggable,
367
- useBottomInset = params.useBottomInset,
368
- footerComponent = params.footerComponent,
369
- onDismiss = params.onDismiss
370
- )
371
- }
372
-
373
- is OverplayComponentParams.Modal -> {
374
- ModalScreen(
375
- content = overplay.content,
376
- barrierDismissible = params.barrierDismissible,
377
- onDismiss = params.onDismiss
378
- )
379
- }
380
-
381
- is OverplayComponentParams.SnackBar -> {
382
- Box(
383
- modifier = Modifier.fillMaxSize(),
384
- contentAlignment = Alignment.BottomCenter
385
- ) {
386
- overplay.content()
387
- }
388
- }
389
-
390
- null -> {}
391
- }
392
- }
393
- }
@@ -1,8 +0,0 @@
1
- package vn.momo.kits.navigation
2
-
3
- import androidx.compose.runtime.Composable
4
-
5
- @Composable
6
- internal expect fun RegisterScrollToTop(callback: (() -> Unit)?)
7
-
8
-