@momo-kits/native-kits 0.156.6-beta.4 → 0.156.6-dialog.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.
Files changed (128) hide show
  1. package/build.gradle.kts +11 -0
  2. package/compose/MoMoComposeKits.podspec +54 -0
  3. package/compose/build.gradle.kts +183 -0
  4. package/compose/build.gradle.kts.backup +183 -0
  5. package/compose/compose.podspec +48 -0
  6. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +270 -0
  7. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  8. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  9. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  10. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  11. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  12. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +57 -0
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +95 -0
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +305 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +720 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +121 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +405 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +83 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +32 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +340 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +348 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +94 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +136 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +63 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +148 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +185 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +116 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +447 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +172 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +255 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +231 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +234 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +254 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +241 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +56 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +41 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +92 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +40 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +352 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +103 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +70 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +17 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +96 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +96 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +92 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +130 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +214 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +177 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +205 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +239 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +13 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +189 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +285 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +59 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +14 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +50 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +238 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +118 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +98 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +209 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +227 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +484 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +162 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +226 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +187 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +277 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +31 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +370 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +129 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +63 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +62 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +88 -0
  107. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +325 -0
  108. package/gradle/libs.versions.toml +57 -0
  109. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  110. package/gradle/wrapper/gradle-wrapper.properties +8 -0
  111. package/gradle.properties +26 -0
  112. package/gradlew +252 -0
  113. package/gradlew.bat +94 -0
  114. package/ios/Image/Image.swift +1 -5
  115. package/local.properties +8 -0
  116. package/package.json +1 -1
  117. package/settings.gradle.kts +52 -0
  118. package/example/ios/Example.xcodeproj/xcuserdata/sophia.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  119. package/example/ios/Example.xcworkspace/xcuserdata/sophia.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  120. package/example/ios/Example.xcworkspace/xcuserdata/sophia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
  121. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sophia.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
  122. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sophia.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
  123. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sophia.xcuserdatad/xcschemes/SDWebImage.xcscheme +0 -58
  124. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sophia.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +0 -58
  125. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sophia.xcuserdatad/xcschemes/SkeletonUI.xcscheme +0 -58
  126. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sophia.xcuserdatad/xcschemes/lottie-ios-LottiePrivacyInfo.xcscheme +0 -58
  127. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sophia.xcuserdatad/xcschemes/lottie-ios.xcscheme +0 -58
  128. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sophia.xcuserdatad/xcschemes/xcschememanagement.plist +0 -46
@@ -0,0 +1,238 @@
1
+ package vn.momo.kits.navigation
2
+
3
+ import androidx.compose.animation.core.Animatable
4
+ import androidx.compose.animation.core.CubicBezierEasing
5
+ import androidx.compose.animation.core.tween
6
+ import androidx.compose.foundation.background
7
+ import androidx.compose.foundation.border
8
+ import androidx.compose.foundation.gestures.detectDragGestures
9
+ import androidx.compose.foundation.layout.Box
10
+ import androidx.compose.foundation.layout.BoxWithConstraints
11
+ import androidx.compose.foundation.layout.Column
12
+ import androidx.compose.foundation.layout.Row
13
+ import androidx.compose.foundation.layout.Spacer
14
+ import androidx.compose.foundation.layout.fillMaxHeight
15
+ import androidx.compose.foundation.layout.fillMaxSize
16
+ import androidx.compose.foundation.layout.fillMaxWidth
17
+ import androidx.compose.foundation.layout.height
18
+ import androidx.compose.foundation.layout.heightIn
19
+ import androidx.compose.foundation.layout.offset
20
+ import androidx.compose.foundation.layout.padding
21
+ import androidx.compose.foundation.layout.size
22
+ import androidx.compose.foundation.layout.width
23
+ import androidx.compose.foundation.shape.RoundedCornerShape
24
+ import androidx.compose.runtime.Composable
25
+ import androidx.compose.runtime.DisposableEffect
26
+ import androidx.compose.runtime.LaunchedEffect
27
+ import androidx.compose.runtime.remember
28
+ import androidx.compose.runtime.rememberCoroutineScope
29
+ import androidx.compose.ui.Alignment
30
+ import androidx.compose.ui.Modifier
31
+ import androidx.compose.ui.graphics.Color
32
+ import androidx.compose.ui.input.pointer.pointerInput
33
+ import androidx.compose.ui.platform.LocalDensity
34
+ import androidx.compose.ui.unit.IntOffset
35
+ import androidx.compose.ui.unit.dp
36
+ import kotlinx.coroutines.launch
37
+ import vn.momo.kits.components.Divider
38
+ import vn.momo.kits.components.Icon
39
+ import vn.momo.kits.components.Text
40
+ import vn.momo.kits.const.AppTheme
41
+ import vn.momo.kits.const.Colors
42
+ import vn.momo.kits.const.Radius
43
+ import vn.momo.kits.const.Spacing
44
+ import vn.momo.kits.application.IsShowBaseLineDebug
45
+ import vn.momo.kits.const.Typography
46
+ import vn.momo.kits.modifier.conditional
47
+ import vn.momo.kits.modifier.noFeedbackClickable
48
+ import vn.momo.kits.platform.BackHandler
49
+ import vn.momo.kits.platform.getScreenHeight
50
+
51
+ @Composable
52
+ internal fun BottomSheet(
53
+ content: @Composable () -> Unit,
54
+ header: BottomHeader,
55
+ isSurface: Boolean = false,
56
+ barrierDismissible: Boolean = true,
57
+ onDismiss: (() -> Unit)?
58
+ ) {
59
+ val navigator = LocalNavigator.current
60
+
61
+ val screenHeightDp = getScreenHeight()
62
+ val screenHeightPx = with(LocalDensity.current) { screenHeightDp.toPx() }
63
+ val sheetOffset = remember { Animatable(screenHeightPx) }
64
+
65
+ val backgroundAlpha = remember { Animatable(0f) }
66
+ val dynamicAlpha = ((1f - (sheetOffset.value / screenHeightPx)).coerceIn(0f, 1f)) * 0.3f
67
+ val alpha = backgroundAlpha.value + dynamicAlpha
68
+
69
+ val sheetCloseOffset = with(LocalDensity.current) { 100.dp.toPx() }
70
+
71
+ val coroutineScope = rememberCoroutineScope()
72
+
73
+ suspend fun openEvent(){
74
+ backgroundAlpha.animateTo(
75
+ targetValue = 0.3f,
76
+ animationSpec = tween(
77
+ durationMillis = 100,
78
+ easing = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f)
79
+ )
80
+ )
81
+ sheetOffset.animateTo(
82
+ targetValue = 0f,
83
+ animationSpec = tween(
84
+ durationMillis = 350,
85
+ easing = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f)
86
+ )
87
+ )
88
+ }
89
+
90
+ fun closeEvent(){
91
+ coroutineScope.launch {
92
+ sheetOffset.animateTo(
93
+ targetValue = screenHeightPx,
94
+ animationSpec = tween(
95
+ durationMillis = 200,
96
+ easing = CubicBezierEasing(0.3f, 0.0f, 0.8f, 0.15f)
97
+ )
98
+ )
99
+ backgroundAlpha.animateTo(
100
+ targetValue = 0f,
101
+ animationSpec = tween(
102
+ durationMillis = 100,
103
+ easing = CubicBezierEasing(0.3f, 0.0f, 0.8f, 0.15f)
104
+ )
105
+ )
106
+ navigator.pop()
107
+ }
108
+ }
109
+
110
+ LaunchedEffect(Unit) {
111
+ openEvent()
112
+ }
113
+
114
+ DisposableEffect(Unit) {
115
+ onDispose {
116
+ onDismiss?.invoke()
117
+ }
118
+ }
119
+
120
+ BackHandler(true){
121
+ closeEvent()
122
+ }
123
+
124
+ BoxWithConstraints(
125
+ modifier = Modifier
126
+ .fillMaxSize()
127
+ .background(Color.Black.copy(alpha = alpha))
128
+ .noFeedbackClickable {
129
+ if(barrierDismissible) closeEvent()
130
+ }
131
+ ) {
132
+ val parentHeight = with(LocalDensity.current) { constraints.maxHeight.toDp() }
133
+
134
+ Box(
135
+ modifier = Modifier
136
+ .align(Alignment.BottomCenter)
137
+ .offset { IntOffset(x = 0, y = sheetOffset.value.toInt()) }
138
+ .fillMaxWidth()
139
+ .heightIn(max = parentHeight - 90.dp)
140
+ .background(
141
+ color = if (isSurface) AppTheme.current.colors.background.surface else AppTheme.current.colors.background.default,
142
+ shape = RoundedCornerShape(topStart = Radius.M, topEnd = Radius.M)
143
+ )
144
+ .conditional(IsShowBaseLineDebug) {
145
+ border(1.dp, Colors.blue_03)
146
+ }
147
+ .noFeedbackClickable { },
148
+ contentAlignment = Alignment.BottomCenter
149
+ ) {
150
+ Column {
151
+ Box(
152
+ modifier = Modifier
153
+ .height(72.dp)
154
+ .fillMaxWidth()
155
+ .pointerInput(Unit) {
156
+ detectDragGestures(
157
+ onDrag = { change, dragAmount ->
158
+ change.consume()
159
+ coroutineScope.launch {
160
+ val newOffset = (sheetOffset.value + dragAmount.y).coerceAtLeast(0f)
161
+ sheetOffset.snapTo(newOffset)
162
+ }
163
+ },
164
+ onDragEnd = {
165
+ coroutineScope.launch {
166
+ if (sheetOffset.value > sheetCloseOffset) {
167
+ closeEvent()
168
+ } else {
169
+ sheetOffset.animateTo(0f)
170
+ }
171
+ }
172
+ }
173
+ )
174
+ }
175
+ ) {
176
+ Column(
177
+ modifier = Modifier
178
+ .fillMaxSize()
179
+ .padding(horizontal = Spacing.M),
180
+ horizontalAlignment = Alignment.CenterHorizontally
181
+ ) {
182
+ Spacer(Modifier.height(8.dp))
183
+ Box(
184
+ modifier = Modifier
185
+ .height(4.dp)
186
+ .width(40.dp)
187
+ .background(
188
+ color = Colors.black_06,
189
+ shape = RoundedCornerShape(Radius.S)
190
+ )
191
+ )
192
+ Spacer(Modifier.height(4.dp))
193
+ Box(Modifier.fillMaxWidth().height(56.dp), contentAlignment = Alignment.Center){
194
+ when (header) {
195
+ is BottomHeader.Title -> {
196
+ Row(modifier = Modifier.fillMaxSize(), verticalAlignment = Alignment.CenterVertically) {
197
+ Box(Modifier.size(24.dp))
198
+ Box(Modifier.fillMaxHeight().weight(1f), contentAlignment = Alignment.Center){
199
+ Text(
200
+ text = header.data,
201
+ color = Colors.black_17,
202
+ style = Typography.headerDefaultBold
203
+ )
204
+ }
205
+ Box(Modifier
206
+ .size(24.dp)
207
+ .noFeedbackClickable {
208
+ closeEvent()
209
+ },
210
+ contentAlignment = Alignment.Center
211
+ ){
212
+ Icon(source = "navigation_close")
213
+ }
214
+ }
215
+ }
216
+ is BottomHeader.Custom -> {
217
+ header.content()
218
+ }
219
+ }
220
+ }
221
+ }
222
+ }
223
+ Divider()
224
+ content()
225
+ }
226
+ }
227
+ }
228
+ }
229
+
230
+ sealed class BottomHeader {
231
+ data class Title(
232
+ val data: String = "Bottom Sheet Title",
233
+ ) : BottomHeader()
234
+
235
+ data class Custom(
236
+ val content: @Composable () -> Unit
237
+ ) : BottomHeader()
238
+ }
@@ -0,0 +1,118 @@
1
+ package vn.momo.kits.navigation
2
+
3
+ import androidx.compose.animation.core.Animatable
4
+ import androidx.compose.animation.core.CubicBezierEasing
5
+ import androidx.compose.animation.core.tween
6
+ import androidx.compose.foundation.background
7
+ import androidx.compose.foundation.border
8
+ import androidx.compose.foundation.clickable
9
+ import androidx.compose.foundation.interaction.MutableInteractionSource
10
+ import androidx.compose.foundation.layout.Box
11
+ import androidx.compose.foundation.layout.fillMaxSize
12
+ import androidx.compose.foundation.layout.wrapContentSize
13
+ import androidx.compose.runtime.Composable
14
+ import androidx.compose.runtime.DisposableEffect
15
+ import androidx.compose.runtime.LaunchedEffect
16
+ import androidx.compose.runtime.remember
17
+ import androidx.compose.runtime.rememberCoroutineScope
18
+ import androidx.compose.ui.Alignment
19
+ import androidx.compose.ui.Modifier
20
+ import androidx.compose.ui.draw.alpha
21
+ import androidx.compose.ui.draw.scale
22
+ import androidx.compose.ui.graphics.Color
23
+ import androidx.compose.ui.unit.dp
24
+ import kotlinx.coroutines.launch
25
+ import vn.momo.kits.application.IsShowBaseLineDebug
26
+ import vn.momo.kits.const.Colors
27
+ import vn.momo.kits.modifier.conditional
28
+ import vn.momo.kits.modifier.noFeedbackClickable
29
+ import vn.momo.kits.platform.BackHandler
30
+
31
+ @Composable
32
+ internal fun ModalScreen(
33
+ content: @Composable () -> Unit,
34
+ barrierDismissible: Boolean = true,
35
+ onDismiss: (() -> Unit)? = null
36
+ ) {
37
+ val navigator = LocalNavigator.current
38
+
39
+ val alpha = remember { Animatable(0f) }
40
+ val scale = remember { Animatable(0.8f) }
41
+
42
+ val coroutineScope = rememberCoroutineScope()
43
+
44
+ fun openEvent() {
45
+ coroutineScope.launch {
46
+ launch {
47
+ alpha.animateTo(
48
+ targetValue = 1f,
49
+ animationSpec = tween(durationMillis = 250)
50
+ )
51
+ }
52
+ launch {
53
+ scale.animateTo(
54
+ targetValue = 1f,
55
+ animationSpec = tween(
56
+ durationMillis = 250,
57
+ easing = CubicBezierEasing(0.2f, 0.0f, 0f, 1f)
58
+ )
59
+ )
60
+ }
61
+ }
62
+ }
63
+
64
+ fun closeEvent() {
65
+ coroutineScope.launch {
66
+ alpha.animateTo(
67
+ targetValue = 0f,
68
+ animationSpec = tween(durationMillis = 200)
69
+ )
70
+ scale.animateTo(
71
+ targetValue = 0.8f,
72
+ animationSpec = tween(durationMillis = 200)
73
+ )
74
+ navigator.pop()
75
+ }
76
+ }
77
+
78
+ LaunchedEffect(Unit) {
79
+ openEvent()
80
+ }
81
+
82
+ DisposableEffect(Unit) {
83
+ onDispose {
84
+ onDismiss?.invoke()
85
+ }
86
+ }
87
+
88
+ BackHandler(enabled = true) {
89
+ closeEvent()
90
+ }
91
+
92
+ Box(
93
+ modifier = Modifier
94
+ .fillMaxSize()
95
+ .background(Color.Black.copy(alpha = 0.6f * alpha.value))
96
+ .noFeedbackClickable {
97
+ if(barrierDismissible) closeEvent()
98
+ },
99
+ contentAlignment = Alignment.Center
100
+ ) {
101
+ Box(
102
+ modifier = Modifier
103
+ .scale(scale.value)
104
+ .alpha(alpha.value)
105
+ .wrapContentSize()
106
+ .conditional(IsShowBaseLineDebug) {
107
+ border(1.dp, Colors.blue_03)
108
+ }
109
+ .clickable(
110
+ indication = null,
111
+ interactionSource = remember { MutableInteractionSource() }
112
+ ) {},
113
+ contentAlignment = Alignment.Center
114
+ ) {
115
+ content()
116
+ }
117
+ }
118
+ }
@@ -0,0 +1,98 @@
1
+ package vn.momo.kits.navigation
2
+
3
+ import androidx.compose.foundation.gestures.ScrollableState
4
+ import androidx.compose.runtime.Composable
5
+ import androidx.compose.runtime.Stable
6
+ import androidx.compose.runtime.State
7
+ import androidx.compose.runtime.mutableStateOf
8
+ import androidx.compose.runtime.staticCompositionLocalOf
9
+ import androidx.compose.ui.graphics.Color
10
+ import vn.momo.kits.navigation.bottomtab.setBottomTabOption
11
+ import vn.momo.kits.navigation.component.FloatingButtonProps
12
+ import vn.momo.kits.navigation.component.HeaderBackProps
13
+ import vn.momo.kits.navigation.component.HeaderRight
14
+ import vn.momo.kits.navigation.component.HeaderTitle
15
+ import vn.momo.kits.navigation.component.HeaderType
16
+
17
+ class Navigation(
18
+ val id: Int = -1,
19
+ val bottomTabIndex: Int = -1,
20
+ val initOptions: NavigationOptions? = null
21
+ ) {
22
+ private val _options = mutableStateOf(initOptions ?: NavigationOptions())
23
+ val currentOptions: State<NavigationOptions> get() = _options
24
+ val options: NavigationOptions get() = _options.value
25
+
26
+ fun setOptions(
27
+ onBackHandler: (() -> Unit)? = null,
28
+ hiddenBack: Boolean? = null,
29
+ headerBackProps: HeaderBackProps? = null,
30
+ headerTitle: HeaderTitle? = null,
31
+ headerRight: HeaderRight? = null,
32
+ headerType: HeaderType? = null,
33
+ scrollData: ScrollData? = null,
34
+ backgroundColor: Color? = null,
35
+ tintColor: Color? = null,
36
+ footerComponent: (@Composable () -> Unit)? = null,
37
+ floatingButtonProps: FloatingButtonProps? = null,
38
+ keyboardOptions: KeyboardOptions? = null
39
+ ) {
40
+ updateOptions(
41
+ options.copy(
42
+ onBackHandler = onBackHandler ?: options.onBackHandler,
43
+ hiddenBack = hiddenBack ?: options.hiddenBack,
44
+ headerBackProps = headerBackProps ?: options.headerBackProps,
45
+ headerTitle = headerTitle ?: options.headerTitle,
46
+ headerRight = headerRight ?: options.headerRight,
47
+ headerType = headerType ?: options.headerType,
48
+ scrollData = scrollData ?: options.scrollData,
49
+ backgroundColor = backgroundColor ?: options.backgroundColor,
50
+ tintColor = tintColor ?: options.tintColor,
51
+ footerComponent = footerComponent ?: options.footerComponent,
52
+ floatingButtonProps = floatingButtonProps ?: options.floatingButtonProps,
53
+ keyboardOptions = keyboardOptions ?: options.keyboardOptions,
54
+ )
55
+ )
56
+ }
57
+
58
+ fun setOptions(newOptions: NavigationOptions) {
59
+ updateOptions(newOptions)
60
+ }
61
+
62
+ private fun updateOptions(updated: NavigationOptions) {
63
+ _options.value = updated
64
+ if (bottomTabIndex != -1) setBottomTabOption(bottomTabIndex, updated)
65
+ if (id != -1) DynamicScreenRegistry.setOptions(id, updated)
66
+ }
67
+ }
68
+
69
+ val LocalNavigation = staticCompositionLocalOf<Navigation> {
70
+ error("No NavigationStack provided")
71
+ }
72
+
73
+ @Stable
74
+ data class NavigationOptions(
75
+ val onBackHandler: (() -> Unit)? = null,
76
+ val hiddenBack: Boolean = false,
77
+ val headerBackProps: HeaderBackProps = HeaderBackProps(),
78
+ val headerTitle: HeaderTitle = HeaderTitle.Default("Stack"),
79
+ val headerRight: HeaderRight = HeaderRight.Toolkit(),
80
+ val headerType: HeaderType = HeaderType.Default(),
81
+ val scrollData: ScrollData = ScrollData(),
82
+ val backgroundColor: Color? = null,
83
+ val tintColor: Color? = null,
84
+ val footerComponent: @Composable (() -> Unit)? = null,
85
+ val floatingButtonProps: FloatingButtonProps? = null,
86
+ val keyboardOptions: KeyboardOptions = KeyboardOptions()
87
+ )
88
+
89
+ data class KeyboardOptions(
90
+ val keyboardShouldPersistTaps: Boolean = false,
91
+ val useAvoidKeyboard: Boolean = true
92
+ )
93
+
94
+
95
+ data class ScrollData(
96
+ val scrollable: Boolean = true,
97
+ val scrollState: ScrollableState? = null,
98
+ )
@@ -0,0 +1,209 @@
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.slideInHorizontally
6
+ import androidx.compose.animation.slideInVertically
7
+ import androidx.compose.animation.slideOutHorizontally
8
+ import androidx.compose.animation.slideOutVertically
9
+ import androidx.compose.foundation.layout.WindowInsets
10
+ import androidx.compose.foundation.layout.asPaddingValues
11
+ import androidx.compose.foundation.layout.systemBars
12
+ import androidx.compose.runtime.Composable
13
+ import androidx.compose.runtime.CompositionLocalProvider
14
+ import androidx.compose.runtime.DisposableEffect
15
+ import androidx.compose.runtime.LaunchedEffect
16
+ import androidx.compose.runtime.mutableStateOf
17
+ import androidx.compose.runtime.remember
18
+ import androidx.compose.runtime.staticCompositionLocalOf
19
+ import androidx.compose.ui.unit.Dp
20
+ import androidx.compose.ui.unit.dp
21
+ import androidx.compose.ui.window.DialogProperties
22
+ import androidx.navigation.compose.NavHost
23
+ import androidx.navigation.compose.composable
24
+ import androidx.navigation.compose.dialog
25
+ import androidx.navigation.compose.rememberNavController
26
+ import androidx.navigation.toRoute
27
+ import vn.momo.kits.application.AppConfig
28
+ import vn.momo.kits.application.AppLanguage
29
+ import vn.momo.kits.application.ApplicationContext
30
+ import vn.momo.kits.application.KitConfig
31
+ import vn.momo.kits.application.MiniAppContext
32
+ import vn.momo.kits.const.AppNavigationBar
33
+ import vn.momo.kits.const.AppStatusBar
34
+ import vn.momo.kits.const.AppTheme
35
+ import vn.momo.kits.const.AppThemeController
36
+ import vn.momo.kits.const.Theme
37
+ import vn.momo.kits.const.ThemeAssets
38
+ import vn.momo.kits.const.defaultTheme
39
+ import vn.momo.kits.platform.ConfigureDialogWindow
40
+ import vn.momo.kits.utils.getAppStatusBarHeight
41
+ import vn.momo.maxapi.IMaxApi
42
+
43
+ @Composable
44
+ fun NavigationContainer(
45
+ initialScreen: @Composable () -> Unit,
46
+ options: NavigationOptions? = null,
47
+ initialTheme: Theme = defaultTheme,
48
+ applicationContext: MiniAppContext? = null,
49
+ maxApi: IMaxApi? = null,
50
+ setNavigator: ((Navigator) -> Unit)? = null,
51
+ statusBarHeight: Dp? = null,
52
+ config: KitConfig? = null,
53
+ language: String? = null
54
+ ){
55
+ val navController = rememberNavController()
56
+ val navigator = remember { Navigator(navController = navController, maxApi = maxApi) }
57
+ val statusBarHeight = statusBarHeight ?: getAppStatusBarHeight()
58
+ val navigationBarHeight = if (AppNavigationBar.current == 0.dp) {
59
+ WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
60
+ } else {
61
+ AppNavigationBar.current
62
+ }
63
+
64
+ val parentContext = ApplicationContext.current
65
+ val mergedContext = MiniAppContext.merge(parentContext, applicationContext)
66
+
67
+ val theme = remember { mutableStateOf(initialTheme) }
68
+
69
+ LaunchedEffect(Unit) {
70
+ val headerBar = config?.headerBar
71
+ if (headerBar != null && theme.value.assets.headerBackground == null) {
72
+ theme.value = theme.value.copy(
73
+ assets = ThemeAssets(
74
+ headerBackground = headerBar
75
+ )
76
+ )
77
+ }
78
+ }
79
+
80
+ val startDestination = DynamicScreenRegistry.register(initialScreen, options)
81
+
82
+ CompositionLocalProvider(
83
+ LocalNavigator provides navigator,
84
+ LocalMaxApi provides maxApi,
85
+ AppTheme provides theme.value,
86
+ AppThemeController provides { theme.value = it },
87
+ AppStatusBar provides statusBarHeight,
88
+ AppNavigationBar provides navigationBarHeight,
89
+ ApplicationContext provides mergedContext,
90
+ AppConfig provides config,
91
+ AppLanguage provides language,
92
+ ) {
93
+ LaunchedEffect(Unit) {
94
+ setNavigator?.invoke(navigator)
95
+ }
96
+
97
+ NavHost(navController, startDestination = startDestination) {
98
+ // ── Stack screens (push/replace/reset) ──────────────────────────
99
+ composable<DynamicScreenRoute>(
100
+ enterTransition = {
101
+ slideInHorizontally(
102
+ animationSpec = tween(300),
103
+ initialOffsetX = { it }
104
+ )
105
+ },
106
+ exitTransition = null,
107
+ popEnterTransition = { fadeIn(animationSpec = tween(0)) },
108
+ popExitTransition = {
109
+ slideOutHorizontally(
110
+ animationSpec = tween(300),
111
+ targetOffsetX = { it }
112
+ )
113
+ }
114
+ ) { backStackEntry ->
115
+ val route = backStackEntry.toRoute<DynamicScreenRoute>()
116
+ val screen = DynamicScreenRegistry.getScreen(route.id)
117
+
118
+ if (screen != null){
119
+ StackScreen(
120
+ id = route.id,
121
+ content = screen.content,
122
+ navigationOptions = screen.options
123
+ )
124
+ }
125
+ }
126
+
127
+ // ── Present screens (vertical slide dialog) ──────────────────────
128
+ composable<DynamicDialogRoute>(
129
+ enterTransition = {
130
+ slideInVertically (
131
+ animationSpec = tween(300),
132
+ initialOffsetY = { it }
133
+ )
134
+ },
135
+ exitTransition = null,
136
+ popEnterTransition = { fadeIn(animationSpec = tween(0)) },
137
+ popExitTransition = {
138
+ slideOutVertically (
139
+ animationSpec = tween(300),
140
+ targetOffsetY = { it }
141
+ )
142
+ }
143
+ ) { backStackEntry ->
144
+ val route = backStackEntry.toRoute<DynamicDialogRoute>()
145
+ val screen = DynamicScreenRegistry.getScreen(route.id)
146
+
147
+ if (screen != null){
148
+ StackScreen(
149
+ id = route.id,
150
+ content = screen.content,
151
+ navigationOptions = screen.options
152
+ )
153
+ }
154
+ }
155
+
156
+ // ── Bottom Sheet dialog ──────────────────────────────────────────
157
+ dialog<DynamicBottomSheetRoute>(
158
+ dialogProperties = DialogProperties(
159
+ dismissOnBackPress = false,
160
+ dismissOnClickOutside = false,
161
+ usePlatformDefaultWidth = false
162
+ )
163
+ ) { backStackEntry ->
164
+ val route = backStackEntry.toRoute<DynamicBottomSheetRoute>()
165
+ val screen = DynamicScreenRegistry.getScreen(route.id)
166
+ ConfigureDialogWindow()
167
+ screen?.content?.invoke()
168
+ }
169
+
170
+ // ── Modal dialog ─────────────────────────────────────────────────
171
+ dialog<DynamicModalRoute>(
172
+ dialogProperties = DialogProperties(
173
+ dismissOnBackPress = false,
174
+ dismissOnClickOutside = false,
175
+ usePlatformDefaultWidth = false,
176
+ )
177
+ ) { backStackEntry ->
178
+ val route = backStackEntry.toRoute<DynamicModalRoute>()
179
+ val screen = DynamicScreenRegistry.getScreen(route.id)
180
+ ConfigureDialogWindow()
181
+ screen?.content?.invoke()
182
+ }
183
+
184
+ // ── Snack Bar dialog ─────────────────────────────────────────────
185
+ dialog<DynamicSnackBarRoute>(
186
+ dialogProperties = DialogProperties(
187
+ dismissOnBackPress = false,
188
+ dismissOnClickOutside = false,
189
+ usePlatformDefaultWidth = false
190
+ )
191
+ ) { backStackEntry ->
192
+ val route = backStackEntry.toRoute<DynamicSnackBarRoute>()
193
+ val screen = DynamicScreenRegistry.getScreen(route.id)
194
+ ConfigureDialogWindow()
195
+ screen?.content?.invoke()
196
+ }
197
+ }
198
+ }
199
+
200
+ DisposableEffect(Unit) {
201
+ onDispose {
202
+ navigator.dispose()
203
+ }
204
+ }
205
+ }
206
+
207
+ val LocalMaxApi = staticCompositionLocalOf<IMaxApi?> {
208
+ error("No MaxApi provided")
209
+ }