@momo-kits/native-kits 0.152.4-beta.2 → 0.152.4-beta.3

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