@momo-kits/native-kits 0.164.1-beta.6-debug → 0.164.1-beta.6

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