@momo-kits/native-kits 0.162.6-debug → 0.163.1-beta.1-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 +78 -0
- package/compose/build.gradle.kts +8 -11
- package/compose/build.gradle.kts.backup +7 -10
- package/compose/compose.podspec +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +7 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +5 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +24 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +19 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +10 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +2 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +16 -5
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +101 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +269 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +15 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +33 -8
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +25 -22
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +29 -27
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +26 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +30 -27
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +13 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +5 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +11 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +18 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +11 -11
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +11 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +5 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +59 -84
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +71 -13
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +51 -10
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +1 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +21 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +75 -16
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +26 -5
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +11 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +36 -15
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +9 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +28 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +13 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +17 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +10 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +28 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +47 -8
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +25 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +11 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +17 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +6 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +111 -50
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +5 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +8 -7
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +12 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +96 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +12 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +21 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +2 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +14 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +11 -8
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +40 -24
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +5 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +4 -94
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +5 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +15 -5
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +14 -65
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +33 -48
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +55 -56
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +9 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +31 -13
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +24 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +6 -11
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +1 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +3 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +13 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +2 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +40 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +8 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +17 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +3 -3
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +3 -2
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +2 -0
- package/example/ios/Example.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
- package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcworkspace/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/Pods-Example.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImage.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/SkeletonUI.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/huynhdung.xcuserdatad/xcschemes/xcschememanagement.plist +46 -0
- package/gradle.properties +1 -1
- package/ios/Application/ApplicationEnvironment.swift +0 -1
- package/ios/Application/Components.swift +0 -1
- package/ios/Application/FloatingButton.swift +0 -1
- package/ios/Badge/Badge.swift +0 -1
- package/ios/Badge/BadgeRibbon.swift +0 -2
- package/ios/Button/Button.swift +1 -1
- package/ios/Checkbox/Checkbox.swift +0 -1
- package/ios/Input/Input.swift +0 -1
- package/ios/Input/InputPhoneNumber.swift +0 -1
- package/ios/Input/InputSearch.swift +0 -3
- package/ios/Input/InputTextArea.swift +0 -1
- package/ios/OTPKeyboard/KeyboardButton.swift +1 -1
- package/ios/Popup/PopupDisplay.swift +0 -6
- package/ios/Popup/PopupInput.swift +0 -2
- package/ios/Template/TrustBanner/TrustBanner.swift +0 -2
- package/ios/Typography/Text.swift +7 -13
- package/ios/Typography/Typography.swift +8 -22
- package/local.properties +8 -0
- package/package.json +1 -1
- package/ios/Application/FontScaleStore.swift +0 -59
- package/ios/Information/Information.swift +0 -151
|
@@ -9,7 +9,6 @@ import androidx.compose.runtime.staticCompositionLocalOf
|
|
|
9
9
|
import androidx.compose.ui.Alignment
|
|
10
10
|
import androidx.compose.ui.Modifier
|
|
11
11
|
import androidx.navigation.NavController
|
|
12
|
-
import androidx.navigation.toRoute
|
|
13
12
|
import kotlinx.coroutines.CoroutineScope
|
|
14
13
|
import kotlinx.coroutines.Dispatchers
|
|
15
14
|
import kotlinx.coroutines.SupervisorJob
|
|
@@ -22,38 +21,30 @@ import vn.momo.kits.components.PopupNotify
|
|
|
22
21
|
import vn.momo.kits.navigation.BottomHeader.*
|
|
23
22
|
import vn.momo.kits.navigation.component.SnackBar
|
|
24
23
|
import vn.momo.maxapi.IMaxApi
|
|
25
|
-
import kotlin.time.Duration.Companion.milliseconds
|
|
26
24
|
|
|
27
25
|
class Navigator(
|
|
28
26
|
private val navController: NavController,
|
|
29
|
-
private val maxApi: IMaxApi
|
|
30
|
-
private val registry: DynamicScreenRegistry
|
|
27
|
+
private val maxApi: IMaxApi?
|
|
31
28
|
) {
|
|
32
29
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
|
33
30
|
|
|
34
|
-
private fun currentScreen(): DynamicScreen? {
|
|
35
|
-
val entry = navController.currentBackStackEntry ?: return null
|
|
36
|
-
val id = runCatching { entry.toRoute<DynamicScreenRoute>().id }.getOrNull()
|
|
37
|
-
?: runCatching { entry.toRoute<DynamicDialogRoute>().id }.getOrNull()
|
|
38
|
-
?: return null
|
|
39
|
-
return registry.getScreen(id)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
31
|
fun push(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
|
|
43
|
-
val route =
|
|
32
|
+
val route = DynamicScreenRegistry.register(screenName, content, options)
|
|
44
33
|
navController.navigate(DynamicScreenRoute(route.id))
|
|
45
34
|
}
|
|
46
35
|
|
|
47
36
|
fun replace(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
if (navController.previousBackStackEntry != null){
|
|
38
|
+
val latestScreen = DynamicScreenRegistry.getLatestScreen()
|
|
39
|
+
latestScreen?.let { DynamicScreenRegistry.unregisterScreen(it.id) }
|
|
40
|
+
navController.popBackStack()
|
|
41
|
+
push(screenName, content, options)
|
|
42
|
+
}
|
|
52
43
|
}
|
|
53
44
|
|
|
54
45
|
fun onBackSafe(callBack: (() -> Unit)? = null) {
|
|
55
|
-
val
|
|
56
|
-
val options =
|
|
46
|
+
val latestScreen = DynamicScreenRegistry.getLatestScreen()
|
|
47
|
+
val options = latestScreen?.options
|
|
57
48
|
if (options?.onBackHandler != null) {
|
|
58
49
|
options.onBackHandler.invoke()
|
|
59
50
|
return
|
|
@@ -96,30 +87,31 @@ class Navigator(
|
|
|
96
87
|
}
|
|
97
88
|
private suspend fun dismissOverplay(isDelay: Boolean = true) {
|
|
98
89
|
OverplayComponentRegistry.clear()
|
|
99
|
-
if (isDelay) delay(300L
|
|
90
|
+
if (isDelay) delay(300L)
|
|
100
91
|
OverplayComponentRegistry.hardClearAfterDismiss()
|
|
101
92
|
}
|
|
102
93
|
|
|
103
94
|
private suspend fun dismissScreen() {
|
|
104
95
|
if (navController.previousBackStackEntry != null){
|
|
105
|
-
val dismissing = currentScreen()
|
|
106
96
|
navController.popBackStack()
|
|
107
|
-
delay(300L
|
|
108
|
-
|
|
97
|
+
delay(300L)
|
|
98
|
+
DynamicScreenRegistry.getLatestScreen()?.let { it1 ->
|
|
99
|
+
DynamicScreenRegistry.unregisterScreen(it1.id)
|
|
100
|
+
}
|
|
109
101
|
} else {
|
|
110
102
|
maxApi?.dismiss { }
|
|
111
103
|
}
|
|
112
104
|
}
|
|
113
105
|
|
|
114
106
|
fun present(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
|
|
115
|
-
val route =
|
|
107
|
+
val route = DynamicScreenRegistry.register(screenName, content, options)
|
|
116
108
|
navController.navigate(DynamicDialogRoute(route.id))
|
|
117
109
|
}
|
|
118
110
|
|
|
119
111
|
fun reset(screenName: String, content: @Composable () -> Unit, options: NavigationOptions? = null) {
|
|
120
|
-
|
|
112
|
+
DynamicScreenRegistry.unregisterAll()
|
|
121
113
|
|
|
122
|
-
val route =
|
|
114
|
+
val route = DynamicScreenRegistry.register(screenName, content, options)
|
|
123
115
|
navController.navigate(DynamicScreenRoute(route.id)) {
|
|
124
116
|
popUpTo(0) { inclusive = true }
|
|
125
117
|
}
|
|
@@ -130,7 +122,7 @@ class Navigator(
|
|
|
130
122
|
barrierDismissible: Boolean = true,
|
|
131
123
|
onDismiss: (() -> Unit)? = null
|
|
132
124
|
){
|
|
133
|
-
val id =
|
|
125
|
+
val id = DynamicScreenRegistry.getLatestScreen()?.id ?: -1
|
|
134
126
|
OverplayComponentRegistry.registerOverplay(id, content, OverplayComponentType.MODAL, false, barrierDismissible, onDismiss)
|
|
135
127
|
}
|
|
136
128
|
|
|
@@ -141,12 +133,12 @@ class Navigator(
|
|
|
141
133
|
onDismiss: (() -> Unit)? = null,
|
|
142
134
|
bottomSheetHeader: BottomHeader? = null
|
|
143
135
|
){
|
|
144
|
-
val id =
|
|
136
|
+
val id = DynamicScreenRegistry.getLatestScreen()?.id ?: -1
|
|
145
137
|
OverplayComponentRegistry.registerOverplay(id, content, OverplayComponentType.BOTTOM_SHEET, isSurface, barrierDismissible, onDismiss, bottomSheetHeader)
|
|
146
138
|
}
|
|
147
139
|
|
|
148
140
|
fun showSnackBar(snackBar: SnackBar, onDismiss: (() -> Unit)? = null) {
|
|
149
|
-
val id =
|
|
141
|
+
val id = DynamicScreenRegistry.getLatestScreen()?.id ?: -1
|
|
150
142
|
scope.launch {
|
|
151
143
|
OverplayComponentRegistry.registerOverplay(
|
|
152
144
|
id = id,
|
|
@@ -162,7 +154,7 @@ class Navigator(
|
|
|
162
154
|
fun hideSnackBar() {
|
|
163
155
|
scope.launch {
|
|
164
156
|
OverplayComponentRegistry.clear()
|
|
165
|
-
delay(250L
|
|
157
|
+
delay(250L)
|
|
166
158
|
OverplayComponentRegistry.hardClearAfterDismiss()
|
|
167
159
|
}
|
|
168
160
|
}
|
|
@@ -189,11 +181,12 @@ data class DynamicScreen(
|
|
|
189
181
|
var options: NavigationOptions? = null
|
|
190
182
|
)
|
|
191
183
|
|
|
192
|
-
|
|
184
|
+
object DynamicScreenRegistry {
|
|
193
185
|
private val screens = mutableMapOf<Int, DynamicScreen>()
|
|
186
|
+
private var idCounter = 1
|
|
194
187
|
|
|
195
188
|
fun register(screenName: String, content: @Composable () -> Unit, options: NavigationOptions?): DynamicScreenRoute {
|
|
196
|
-
val id =
|
|
189
|
+
val id = idCounter++
|
|
197
190
|
screens[id] = DynamicScreen(
|
|
198
191
|
id = id,
|
|
199
192
|
name = screenName,
|
|
@@ -203,7 +196,7 @@ class DynamicScreenRegistry {
|
|
|
203
196
|
return DynamicScreenRoute(id)
|
|
204
197
|
}
|
|
205
198
|
|
|
206
|
-
fun nextId(): Int =
|
|
199
|
+
fun nextId(): Int = idCounter++
|
|
207
200
|
|
|
208
201
|
fun bind(id: Int, screenName: String, content: @Composable () -> Unit, options: NavigationOptions?) {
|
|
209
202
|
screens[id] = DynamicScreen(
|
|
@@ -212,13 +205,17 @@ class DynamicScreenRegistry {
|
|
|
212
205
|
content = content,
|
|
213
206
|
options = options
|
|
214
207
|
)
|
|
215
|
-
|
|
208
|
+
if (id >= idCounter) idCounter = id + 1 // keep counter ahead after process-death restore
|
|
216
209
|
}
|
|
217
210
|
|
|
218
211
|
fun unregisterScreen(id: Int) {
|
|
219
212
|
screens.remove(id)
|
|
220
213
|
}
|
|
221
214
|
|
|
215
|
+
fun getLatestScreen(): DynamicScreen?{
|
|
216
|
+
return screens.entries.lastOrNull()?.value
|
|
217
|
+
}
|
|
218
|
+
|
|
222
219
|
fun unregisterAll(){
|
|
223
220
|
val ids = screens.keys.toList()
|
|
224
221
|
for (id in ids) {
|
|
@@ -231,20 +228,8 @@ class DynamicScreenRegistry {
|
|
|
231
228
|
fun setOptions(id: Int, options: NavigationOptions){
|
|
232
229
|
screens[id]?.options = options
|
|
233
230
|
}
|
|
234
|
-
|
|
235
|
-
companion object {
|
|
236
|
-
private var globalIdCounter = 1
|
|
237
|
-
|
|
238
|
-
private fun nextGlobalId(): Int = globalIdCounter++
|
|
239
|
-
|
|
240
|
-
private fun advanceGlobalIdPast(id: Int) {
|
|
241
|
-
if (id >= globalIdCounter) globalIdCounter = id + 1
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
231
|
}
|
|
245
232
|
|
|
246
|
-
val LocalDynamicScreenRegistry = staticCompositionLocalOf<DynamicScreenRegistry?> { null }
|
|
247
|
-
|
|
248
233
|
|
|
249
234
|
sealed class OverplayComponentParams {
|
|
250
235
|
class Modal(
|
|
@@ -259,7 +244,7 @@ sealed class OverplayComponentParams {
|
|
|
259
244
|
val bottomSheetHeader: BottomHeader? = null,
|
|
260
245
|
) : OverplayComponentParams()
|
|
261
246
|
|
|
262
|
-
class SnackBar : OverplayComponentParams()
|
|
247
|
+
class SnackBar() : OverplayComponentParams()
|
|
263
248
|
}
|
|
264
249
|
|
|
265
250
|
data class OverplayComponent(
|
|
@@ -323,7 +308,7 @@ object OverplayComponentRegistry {
|
|
|
323
308
|
}
|
|
324
309
|
|
|
325
310
|
@Composable
|
|
326
|
-
|
|
311
|
+
fun OverlayComponent(){
|
|
327
312
|
val overplay = currentOverlayComponent.value ?: return
|
|
328
313
|
|
|
329
314
|
when (val params = overplay.params) {
|
|
@@ -45,8 +45,8 @@ import androidx.compose.ui.layout.onGloballyPositioned
|
|
|
45
45
|
import androidx.compose.ui.platform.LocalDensity
|
|
46
46
|
import androidx.compose.ui.unit.Dp
|
|
47
47
|
import androidx.compose.ui.unit.dp
|
|
48
|
+
import androidx.compose.ui.unit.min
|
|
48
49
|
import androidx.compose.ui.zIndex
|
|
49
|
-
import kotlinx.coroutines.flow.Flow
|
|
50
50
|
import vn.momo.kits.components.InputSearch
|
|
51
51
|
import vn.momo.kits.const.AppNavigationBar
|
|
52
52
|
import vn.momo.kits.const.AppStatusBar
|
|
@@ -71,7 +71,6 @@ import vn.momo.kits.navigation.tracking.ScreenTrackingState
|
|
|
71
71
|
import kotlinx.coroutines.delay
|
|
72
72
|
import vn.momo.kits.application.ApplicationContext
|
|
73
73
|
import kotlin.time.Clock
|
|
74
|
-
import kotlin.time.Duration.Companion.milliseconds
|
|
75
74
|
import kotlin.time.ExperimentalTime
|
|
76
75
|
|
|
77
76
|
internal val LocalFooterHeightPx = staticCompositionLocalOf { mutableIntStateOf(0) }
|
|
@@ -92,15 +91,14 @@ internal fun StackScreen(
|
|
|
92
91
|
val context = ApplicationContext.current
|
|
93
92
|
val statusBar = AppStatusBar.current
|
|
94
93
|
val density = LocalDensity.current
|
|
95
|
-
val
|
|
96
|
-
val navigation = remember { Navigation(id = id, bottomTabIndex = bottomTabIndex, initOptions = navigationOptions, registry = screenRegistry) }
|
|
94
|
+
val navigation = remember { Navigation(id = id, bottomTabIndex = bottomTabIndex, initOptions = navigationOptions) }
|
|
97
95
|
|
|
98
96
|
val options by navigation.currentOptions
|
|
99
97
|
|
|
100
98
|
// Auto tracking state
|
|
101
99
|
val trackingState = remember {
|
|
102
100
|
ScreenTrackingState().apply {
|
|
103
|
-
|
|
101
|
+
startTime = Clock.System.now().toEpochMilliseconds()
|
|
104
102
|
}
|
|
105
103
|
}
|
|
106
104
|
|
|
@@ -121,8 +119,8 @@ internal fun StackScreen(
|
|
|
121
119
|
)
|
|
122
120
|
|
|
123
121
|
// Track screen displayed after 2 seconds (debounce)
|
|
124
|
-
delay(2000
|
|
125
|
-
val loadTime = Clock.System.now().toEpochMilliseconds() - trackingState.
|
|
122
|
+
delay(2000)
|
|
123
|
+
val loadTime = Clock.System.now().toEpochMilliseconds() - trackingState.startTime
|
|
126
124
|
ScreenTracker.trackScreenDisplayed(
|
|
127
125
|
maxApi = maxApi,
|
|
128
126
|
context = context,
|
|
@@ -132,7 +130,7 @@ internal fun StackScreen(
|
|
|
132
130
|
)
|
|
133
131
|
|
|
134
132
|
// Track screen interacted after displayed
|
|
135
|
-
val interactionTime = Clock.System.now().toEpochMilliseconds() - trackingState.
|
|
133
|
+
val interactionTime = Clock.System.now().toEpochMilliseconds() - trackingState.startTime
|
|
136
134
|
ScreenTracker.trackScreenInteracted(
|
|
137
135
|
maxApi = maxApi,
|
|
138
136
|
context = context,
|
|
@@ -206,9 +204,8 @@ internal fun StackScreen(
|
|
|
206
204
|
}
|
|
207
205
|
}
|
|
208
206
|
|
|
209
|
-
@Suppress("FrequentlyChangingValue")
|
|
210
207
|
@Composable
|
|
211
|
-
|
|
208
|
+
fun FloatingContent() {
|
|
212
209
|
val options = LocalOptions.current
|
|
213
210
|
val density = LocalDensity.current
|
|
214
211
|
val footerHeightPx = LocalFooterHeightPx.current
|
|
@@ -232,7 +229,7 @@ internal fun FloatingContent() {
|
|
|
232
229
|
}
|
|
233
230
|
|
|
234
231
|
@Composable
|
|
235
|
-
|
|
232
|
+
fun ColumnScope.MainContent(content: @Composable () -> Unit) {
|
|
236
233
|
val options = LocalOptions.current
|
|
237
234
|
val inputSearchType = getInputSearchType(options)
|
|
238
235
|
val density = LocalDensity.current
|
|
@@ -267,7 +264,7 @@ internal fun ColumnScope.MainContent(content: @Composable () -> Unit) {
|
|
|
267
264
|
}
|
|
268
265
|
|
|
269
266
|
@Composable
|
|
270
|
-
|
|
267
|
+
fun ScreenContent(content: @Composable () -> Unit) {
|
|
271
268
|
val scrollState = LocalScrollState.current
|
|
272
269
|
val options = LocalOptions.current
|
|
273
270
|
|
|
@@ -287,7 +284,7 @@ internal fun ScreenContent(content: @Composable () -> Unit) {
|
|
|
287
284
|
}
|
|
288
285
|
|
|
289
286
|
@Composable
|
|
290
|
-
|
|
287
|
+
fun FooterContent() {
|
|
291
288
|
val options = LocalOptions.current
|
|
292
289
|
if (options.footerComponent != null) {
|
|
293
290
|
val keyboardSize = keyboardSizeState()
|
|
@@ -297,13 +294,13 @@ internal fun FooterContent() {
|
|
|
297
294
|
}
|
|
298
295
|
|
|
299
296
|
@Composable
|
|
300
|
-
|
|
297
|
+
fun keyboardSizeState(): State<Dp> {
|
|
301
298
|
val bottom = WindowInsets.ime.asPaddingValues()
|
|
302
299
|
return rememberUpdatedState(bottom.calculateBottomPadding())
|
|
303
300
|
}
|
|
304
301
|
|
|
305
302
|
@Composable
|
|
306
|
-
|
|
303
|
+
fun OverplayView(bottomTabIndex: Int, id: Int) {
|
|
307
304
|
val overplayType = OverplayComponentRegistry.getOverplayType()
|
|
308
305
|
|
|
309
306
|
if (overplayType != null) {
|
|
@@ -358,9 +355,8 @@ data class InputSearchLayoutParams(
|
|
|
358
355
|
val endPadding: Dp
|
|
359
356
|
)
|
|
360
357
|
|
|
361
|
-
@Suppress("FrequentlyChangingValue")
|
|
362
358
|
@Composable
|
|
363
|
-
|
|
359
|
+
fun SearchAnimated(
|
|
364
360
|
isScrollInProgress: Boolean
|
|
365
361
|
) {
|
|
366
362
|
val scrollState = LocalScrollState.current
|
|
@@ -473,61 +469,64 @@ private fun quantize(value: Int, stepPx: Int): Int {
|
|
|
473
469
|
}
|
|
474
470
|
|
|
475
471
|
@Composable
|
|
476
|
-
|
|
472
|
+
fun LazyListState.proxyScrollState(
|
|
477
473
|
thresholdPx: Int = 200,
|
|
478
474
|
stepPx: Int = 4
|
|
479
|
-
): Pair<ScrollState, Boolean>
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
)
|
|
475
|
+
): Pair<ScrollState, Boolean> {
|
|
476
|
+
val scrollState = rememberScrollState()
|
|
477
|
+
val locked = remember { mutableStateOf(false) }
|
|
478
|
+
|
|
479
|
+
LaunchedEffect(this, scrollState, thresholdPx, stepPx) {
|
|
480
|
+
snapshotFlow { firstVisibleItemIndex to firstVisibleItemScrollOffset }
|
|
481
|
+
.collect { (index, offset) ->
|
|
482
|
+
val rawTarget = if (index == 0) offset else SCROLLED_PAST_FIRST_ITEM_THRESHOLD
|
|
483
|
+
val shouldLock = rawTarget > thresholdPx
|
|
484
|
+
if (locked.value != shouldLock) locked.value = shouldLock
|
|
485
|
+
|
|
486
|
+
val desired = if (shouldLock) thresholdPx else quantize(rawTarget, stepPx)
|
|
487
|
+
|
|
488
|
+
if (scrollState.value != desired) {
|
|
489
|
+
scrollState.scrollTo(desired.coerceAtLeast(0))
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
val inProgress = remember { mutableStateOf(false) }
|
|
495
|
+
LaunchedEffect(this, thresholdPx) {
|
|
496
|
+
snapshotFlow { isScrollInProgress }
|
|
497
|
+
.collect { progressing ->
|
|
498
|
+
inProgress.value = if (locked.value) false else progressing
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return scrollState to inProgress.value
|
|
503
|
+
}
|
|
491
504
|
|
|
492
505
|
@Composable
|
|
493
|
-
|
|
506
|
+
fun ScrollState.proxyLimitedScrollState(
|
|
494
507
|
thresholdPx: Int = 200,
|
|
495
508
|
stepPx: Int = 4
|
|
496
|
-
): Pair<ScrollState, Boolean> = proxyScroll(
|
|
497
|
-
source = this,
|
|
498
|
-
thresholdPx = thresholdPx,
|
|
499
|
-
stepPx = stepPx,
|
|
500
|
-
isScrollInProgress = { isScrollInProgress },
|
|
501
|
-
rawTargetFlow = { snapshotFlow { value } },
|
|
502
|
-
)
|
|
503
|
-
|
|
504
|
-
@Composable
|
|
505
|
-
private fun proxyScroll(
|
|
506
|
-
source: Any,
|
|
507
|
-
thresholdPx: Int,
|
|
508
|
-
stepPx: Int,
|
|
509
|
-
isScrollInProgress: () -> Boolean,
|
|
510
|
-
rawTargetFlow: () -> Flow<Int>,
|
|
511
509
|
): Pair<ScrollState, Boolean> {
|
|
512
510
|
val proxy = rememberScrollState()
|
|
513
511
|
val locked = remember { mutableStateOf(false) }
|
|
514
512
|
|
|
515
|
-
LaunchedEffect(
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
513
|
+
LaunchedEffect(this, proxy, thresholdPx, stepPx) {
|
|
514
|
+
snapshotFlow { value }
|
|
515
|
+
.collect { rawTarget ->
|
|
516
|
+
val shouldLock = rawTarget > thresholdPx
|
|
517
|
+
if (locked.value != shouldLock) locked.value = shouldLock
|
|
519
518
|
|
|
520
|
-
|
|
519
|
+
val desired = if (shouldLock) thresholdPx else quantize(rawTarget, stepPx)
|
|
521
520
|
|
|
522
|
-
|
|
523
|
-
|
|
521
|
+
if (proxy.value != desired) {
|
|
522
|
+
proxy.scrollTo(desired.coerceAtLeast(0))
|
|
523
|
+
}
|
|
524
524
|
}
|
|
525
|
-
}
|
|
526
525
|
}
|
|
527
526
|
|
|
528
527
|
val inProgress = remember { mutableStateOf(false) }
|
|
529
|
-
LaunchedEffect(
|
|
530
|
-
snapshotFlow { isScrollInProgress
|
|
528
|
+
LaunchedEffect(this, thresholdPx) {
|
|
529
|
+
snapshotFlow { isScrollInProgress }
|
|
531
530
|
.collect { progressing ->
|
|
532
531
|
inProgress.value = if (locked.value) false else progressing
|
|
533
532
|
}
|
|
@@ -6,7 +6,13 @@ import androidx.compose.animation.fadeOut
|
|
|
6
6
|
import androidx.compose.animation.scaleIn
|
|
7
7
|
import androidx.compose.animation.scaleOut
|
|
8
8
|
import androidx.compose.foundation.background
|
|
9
|
-
import androidx.compose.foundation.layout
|
|
9
|
+
import androidx.compose.foundation.layout.Box
|
|
10
|
+
import androidx.compose.foundation.layout.Column
|
|
11
|
+
import androidx.compose.foundation.layout.Spacer
|
|
12
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
13
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
14
|
+
import androidx.compose.foundation.layout.height
|
|
15
|
+
import androidx.compose.foundation.layout.padding
|
|
10
16
|
import androidx.compose.runtime.Composable
|
|
11
17
|
import androidx.compose.runtime.LaunchedEffect
|
|
12
18
|
import androidx.compose.ui.Alignment
|
|
@@ -26,12 +32,12 @@ import vn.momo.kits.navigation.component.HeaderType
|
|
|
26
32
|
import vn.momo.kits.platform.getScreenHeight
|
|
27
33
|
|
|
28
34
|
private var bottomTabOptionItems : MutableList<NavigationOptions?> = mutableListOf()
|
|
29
|
-
|
|
35
|
+
fun setBottomTabOption(index: Int, options: NavigationOptions){
|
|
30
36
|
if (index in bottomTabOptionItems.indices) {
|
|
31
37
|
bottomTabOptionItems[index] = options
|
|
32
38
|
}
|
|
33
39
|
}
|
|
34
|
-
|
|
40
|
+
fun getBottomTabOption(index: Int): NavigationOptions? {
|
|
35
41
|
return if (index in bottomTabOptionItems.indices) {
|
|
36
42
|
bottomTabOptionItems[index]
|
|
37
43
|
} else null
|
|
@@ -5,7 +5,19 @@ import androidx.compose.animation.core.animateDpAsState
|
|
|
5
5
|
import androidx.compose.animation.core.tween
|
|
6
6
|
import androidx.compose.foundation.background
|
|
7
7
|
import androidx.compose.foundation.border
|
|
8
|
-
import androidx.compose.foundation.layout
|
|
8
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
9
|
+
import androidx.compose.foundation.layout.Box
|
|
10
|
+
import androidx.compose.foundation.layout.Column
|
|
11
|
+
import androidx.compose.foundation.layout.Row
|
|
12
|
+
import androidx.compose.foundation.layout.RowScope
|
|
13
|
+
import androidx.compose.foundation.layout.Spacer
|
|
14
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
15
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
16
|
+
import androidx.compose.foundation.layout.height
|
|
17
|
+
import androidx.compose.foundation.layout.offset
|
|
18
|
+
import androidx.compose.foundation.layout.padding
|
|
19
|
+
import androidx.compose.foundation.layout.size
|
|
20
|
+
import androidx.compose.foundation.layout.width
|
|
9
21
|
import androidx.compose.foundation.shape.CircleShape
|
|
10
22
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
11
23
|
import androidx.compose.runtime.Composable
|
|
@@ -20,20 +32,26 @@ import androidx.compose.ui.text.style.TextOverflow
|
|
|
20
32
|
import androidx.compose.ui.unit.dp
|
|
21
33
|
import androidx.navigation.NavController
|
|
22
34
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
|
35
|
+
import vn.momo.kits.components.Badge
|
|
36
|
+
import vn.momo.kits.components.Icon
|
|
37
|
+
import vn.momo.kits.components.Text
|
|
38
|
+
import vn.momo.kits.const.AppTheme
|
|
39
|
+
import vn.momo.kits.const.Colors
|
|
40
|
+
import vn.momo.kits.const.Radius
|
|
41
|
+
import vn.momo.kits.const.Spacing
|
|
23
42
|
import vn.momo.kits.application.IsShowBaseLineDebug
|
|
24
|
-
import vn.momo.kits.components
|
|
25
|
-
import vn.momo.kits.
|
|
26
|
-
import vn.momo.kits.
|
|
43
|
+
import vn.momo.kits.components.BadgeDot
|
|
44
|
+
import vn.momo.kits.components.DotSize
|
|
45
|
+
import vn.momo.kits.const.Typography
|
|
27
46
|
import vn.momo.kits.modifier.conditional
|
|
28
47
|
import vn.momo.kits.modifier.noFeedbackClickable
|
|
29
48
|
import vn.momo.kits.platform.getScreenDimensions
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
@InternalApi
|
|
50
|
+
val floatingButtonWidth = 75.dp
|
|
33
51
|
const val BOTTOM_TAB_BAR_HEIGHT = 64
|
|
34
52
|
|
|
35
53
|
@Composable
|
|
36
|
-
|
|
54
|
+
fun BottomTabBar(
|
|
37
55
|
items: List<BottomTabItem>,
|
|
38
56
|
floatingButton: BottomTabFloatingButton? = null,
|
|
39
57
|
navController: NavController,
|
|
@@ -73,11 +91,11 @@ internal fun BottomTabBar(
|
|
|
73
91
|
horizontalArrangement = Arrangement.SpaceAround,
|
|
74
92
|
) {
|
|
75
93
|
if (floatingButton == null) {
|
|
76
|
-
|
|
94
|
+
renderTabBarItem(items, 0, items.size, selectedIndex, onTabSelected)
|
|
77
95
|
} else {
|
|
78
|
-
|
|
96
|
+
renderTabBarItem(items, 0, mid, selectedIndex, onTabSelected)
|
|
79
97
|
Spacer(modifier = Modifier.width(floatingButtonWidth).padding(horizontal = Spacing.XXS))
|
|
80
|
-
|
|
98
|
+
renderTabBarItem(items, mid, items.size, selectedIndex, onTabSelected)
|
|
81
99
|
}
|
|
82
100
|
}
|
|
83
101
|
|
|
@@ -106,7 +124,7 @@ internal fun BottomTabBar(
|
|
|
106
124
|
}
|
|
107
125
|
|
|
108
126
|
@Composable
|
|
109
|
-
|
|
127
|
+
fun RowScope.renderTabBarItem(
|
|
110
128
|
items: List<BottomTabItem>,
|
|
111
129
|
fromIndex: Int,
|
|
112
130
|
toIndex: Int,
|
|
@@ -125,7 +143,7 @@ internal fun RowScope.RenderTabBarItem(
|
|
|
125
143
|
}
|
|
126
144
|
|
|
127
145
|
@Composable
|
|
128
|
-
|
|
146
|
+
fun TabBarItem(item: BottomTabItem, selected: Boolean, onClick: () -> Unit) {
|
|
129
147
|
fun isNumber(label: String): Boolean {
|
|
130
148
|
val numberRegex = "^\\d+$".toRegex()
|
|
131
149
|
return numberRegex.matches(label)
|
|
@@ -185,7 +203,7 @@ internal fun TabBarItem(item: BottomTabItem, selected: Boolean, onClick: () -> U
|
|
|
185
203
|
}
|
|
186
204
|
|
|
187
205
|
@Composable
|
|
188
|
-
|
|
206
|
+
fun FloatingButton(data: BottomTabFloatingButton) {
|
|
189
207
|
Column(
|
|
190
208
|
modifier = Modifier
|
|
191
209
|
.width(floatingButtonWidth)
|
|
@@ -1,21 +1,40 @@
|
|
|
1
1
|
package vn.momo.kits.navigation.component
|
|
2
2
|
|
|
3
|
-
import androidx.compose.animation
|
|
3
|
+
import androidx.compose.animation.AnimatedVisibility
|
|
4
4
|
import androidx.compose.animation.core.CubicBezierEasing
|
|
5
5
|
import androidx.compose.animation.core.LinearEasing
|
|
6
6
|
import androidx.compose.animation.core.animateDpAsState
|
|
7
7
|
import androidx.compose.animation.core.tween
|
|
8
|
+
import androidx.compose.animation.expandHorizontally
|
|
9
|
+
import androidx.compose.animation.fadeIn
|
|
10
|
+
import androidx.compose.animation.fadeOut
|
|
11
|
+
import androidx.compose.animation.shrinkHorizontally
|
|
8
12
|
import androidx.compose.foundation.ScrollState
|
|
9
13
|
import androidx.compose.foundation.background
|
|
10
14
|
import androidx.compose.foundation.border
|
|
11
15
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
12
|
-
import androidx.compose.foundation.layout
|
|
16
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
17
|
+
import androidx.compose.foundation.layout.Box
|
|
18
|
+
import androidx.compose.foundation.layout.Row
|
|
19
|
+
import androidx.compose.foundation.layout.Spacer
|
|
20
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
21
|
+
import androidx.compose.foundation.layout.height
|
|
22
|
+
import androidx.compose.foundation.layout.offset
|
|
23
|
+
import androidx.compose.foundation.layout.padding
|
|
24
|
+
import androidx.compose.foundation.layout.sizeIn
|
|
25
|
+
import androidx.compose.foundation.layout.width
|
|
13
26
|
import androidx.compose.material3.AlertDialogDefaults
|
|
14
27
|
import androidx.compose.material3.FloatingActionButton
|
|
15
28
|
import androidx.compose.material3.FloatingActionButtonDefaults
|
|
16
29
|
import androidx.compose.material3.FloatingActionButtonElevation
|
|
17
|
-
import androidx.compose.runtime
|
|
30
|
+
import androidx.compose.runtime.Composable
|
|
31
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
32
|
+
import androidx.compose.runtime.getValue
|
|
33
|
+
import androidx.compose.runtime.mutableStateOf
|
|
34
|
+
import androidx.compose.runtime.remember
|
|
35
|
+
import androidx.compose.runtime.rememberCoroutineScope
|
|
18
36
|
import androidx.compose.runtime.saveable.rememberSaveable
|
|
37
|
+
import androidx.compose.runtime.setValue
|
|
19
38
|
import androidx.compose.ui.Alignment
|
|
20
39
|
import androidx.compose.ui.Modifier
|
|
21
40
|
import androidx.compose.ui.graphics.Color
|
|
@@ -31,7 +50,6 @@ import vn.momo.kits.components.Text
|
|
|
31
50
|
import vn.momo.kits.const.Colors
|
|
32
51
|
import vn.momo.kits.const.Typography
|
|
33
52
|
import vn.momo.kits.modifier.conditional
|
|
34
|
-
import kotlin.time.Duration.Companion.milliseconds
|
|
35
53
|
|
|
36
54
|
enum class FABSize { SMALL, DEFAULT }
|
|
37
55
|
enum class FABPosition { END, CENTER }
|
|
@@ -55,7 +73,7 @@ private val FabIconSizeDefault = 24.dp
|
|
|
55
73
|
private val FabPaddingHorizontal = 12.dp
|
|
56
74
|
|
|
57
75
|
@Composable
|
|
58
|
-
|
|
76
|
+
fun FloatingButton(
|
|
59
77
|
scrollPosition: Int,
|
|
60
78
|
bottom: Dp,
|
|
61
79
|
onClick: () -> Unit,
|
|
@@ -88,7 +106,7 @@ internal fun FloatingButton(
|
|
|
88
106
|
coroutineScope.launch {
|
|
89
107
|
scrollStateFlow.collectLatest { newScroll ->
|
|
90
108
|
isExpanded = newScroll <= lastScrollPosition
|
|
91
|
-
delay(100
|
|
109
|
+
delay(100)
|
|
92
110
|
lastScrollPosition = newScroll
|
|
93
111
|
}
|
|
94
112
|
}
|