@momo-kits/native-kits 0.152.4-beta.6 → 0.152.4-maxapi

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 +58 -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,214 @@
1
+ package vn.momo.kits.application
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import androidx.compose.runtime.CompositionLocalProvider
5
+ import androidx.compose.runtime.Immutable
6
+ import androidx.compose.runtime.LaunchedEffect
7
+ import androidx.compose.runtime.getValue
8
+ import androidx.compose.runtime.mutableStateOf
9
+ import androidx.compose.runtime.remember
10
+ import androidx.compose.runtime.setValue
11
+ import androidx.compose.runtime.staticCompositionLocalOf
12
+ import androidx.compose.ui.unit.Dp
13
+ import vn.momo.kits.components.TrustBannerData
14
+ import vn.momo.kits.const.AppStatusBar
15
+ import vn.momo.kits.const.AppTheme
16
+ import vn.momo.kits.const.Theme
17
+ import vn.momo.kits.const.ThemeAssets
18
+ import vn.momo.kits.const.defaultTheme
19
+ import vn.momo.kits.platform.getStatusBarHeight
20
+
21
+ @Deprecated("Use IMaxApi instead", ReplaceWith("IMaxApi"))
22
+ interface ComposeApi {
23
+ fun request(funcName: String, params: Any?): String
24
+ fun request(funcName: String, params: Any?, onResponse: ((String) -> Unit)?): String
25
+ fun requestCallback(funcName: String, params: Any?, onResponse: ((String) -> Unit)?)
26
+ fun removeCallback(id: String)
27
+ }
28
+
29
+ class Navigator {
30
+ fun push(content: @Composable () -> Unit) {
31
+ //implement
32
+ }
33
+
34
+ fun present(content: @Composable () -> Unit) {
35
+ //implement
36
+ }
37
+
38
+ fun reset(content: @Composable () -> Unit) {
39
+ //implement
40
+ }
41
+
42
+ fun pop() {
43
+ //implement
44
+ }
45
+
46
+ fun replace(content: @Composable () -> Unit) {
47
+ //implement
48
+ }
49
+
50
+ fun popToTop() {
51
+ //implement
52
+ }
53
+
54
+ fun showModal(
55
+ onClose: () -> Unit = {},
56
+ canBackgroundClose: Boolean = true,
57
+ content: @Composable () -> Unit,
58
+ ) {
59
+ //implement
60
+ }
61
+
62
+ fun showBottomSheet(content: @Composable () -> Unit) {
63
+ //implement
64
+ }
65
+ }
66
+
67
+ @Immutable
68
+ data class MiniAppContext(
69
+ val appIcon: String = "",
70
+ val appName: Any? = null,
71
+ val appId: String = "",
72
+ val appCode: String = "",
73
+ val description: Any? = null,
74
+ val support: Map<String, Any?> = emptyMap(),
75
+ val toolkitConfig: Map<String, Any?> = emptyMap(),
76
+ val providerId: String = "",
77
+ val permissions: List<Map<String, Any>>? = emptyList()
78
+ ) {
79
+ companion object {
80
+ private const val KEY_ICON = "icon"
81
+ private const val KEY_NAME = "name"
82
+ private const val KEY_APP_ID = "appId"
83
+ private const val KEY_CODE = "code"
84
+ private const val KEY_DESCRIPTION = "description"
85
+ private const val KEY_SUPPORT = "support"
86
+ private const val KEY_TOOLKIT_CFG = "toolkitConfig"
87
+ private const val KEY_PERMISSIONS = "permissions"
88
+ private const val KEY_ORIGIN_APP = "originAppId"
89
+
90
+ fun toMap(context: MiniAppContext?): Map<String, Any?> = mapOf(
91
+ "icon" to (context?.appIcon ?: ""),
92
+ "name" to context?.appName,
93
+ "appId" to (context?.appId ?: ""),
94
+ "code" to (context?.appCode ?: ""),
95
+ "description" to (context?.description ?: ""),
96
+ "support" to (context?.support ?: emptyMap<String, Any?>()),
97
+ "toolkitConfig" to (context?.toolkitConfig ?: emptyMap<String, Any?>()),
98
+ "providerId" to (context?.providerId ?: ""),
99
+ "permissions" to (context?.permissions ?: emptyList<Map<String, Any>>())
100
+ )
101
+
102
+ fun fromMap(data: Map<String, Any?>?): MiniAppContext = MiniAppContext(
103
+ appIcon = data.string(KEY_ICON) ?: "",
104
+ appName = data?.get(KEY_NAME),
105
+ appId = data.string(KEY_APP_ID) ?: "",
106
+ appCode = data.string(KEY_CODE) ?: "",
107
+ description = data?.get(KEY_DESCRIPTION),
108
+ support = data.mapStringAny(KEY_SUPPORT),
109
+ toolkitConfig = data.mapStringAny(KEY_TOOLKIT_CFG),
110
+ providerId = computeProviderId(
111
+ originAppId = data.string(KEY_ORIGIN_APP),
112
+ appId = data.string(KEY_APP_ID)
113
+ ),
114
+ permissions = data.listOfMapStringAny(KEY_PERMISSIONS)
115
+ )
116
+
117
+ private fun computeProviderId(originAppId: String?, appId: String?): String {
118
+ val id = when {
119
+ !originAppId.isNullOrBlank() -> originAppId
120
+ !appId.isNullOrBlank() -> appId
121
+ else -> null
122
+ } ?: return "unknown"
123
+
124
+ val parts = id.split('.')
125
+ return parts.getOrNull(1) ?: "unknown"
126
+ }
127
+ }
128
+ }
129
+
130
+ private fun Map<String, Any?>?.string(key: String): String? =
131
+ (this?.get(key) as? String)
132
+
133
+ @Suppress("UNCHECKED_CAST")
134
+ private fun Map<String, Any?>?.mapStringAny(key: String): Map<String, Any?> =
135
+ (this?.get(key) as? Map<String, Any?>) ?: emptyMap()
136
+
137
+ @Suppress("UNCHECKED_CAST")
138
+ private fun Map<String, Any?>?.listOfMapStringAny(key: String): List<Map<String, Any>> =
139
+ (this?.get(key) as? List<Map<String, Any>>) ?: emptyList()
140
+
141
+ @Deprecated("Use LocalApi instead", ReplaceWith("LocalApi"))
142
+ val PlatformApi = staticCompositionLocalOf<Any?> { null }
143
+
144
+ @Deprecated("Use LocalNavigator instead", ReplaceWith("LocalNavigator"))
145
+ val AppNavigator = staticCompositionLocalOf<Navigator?> {
146
+ null
147
+ }
148
+
149
+ val ApplicationContext = staticCompositionLocalOf<MiniAppContext?> {
150
+ null
151
+ }
152
+
153
+ val AppConfig = staticCompositionLocalOf<KitConfig?> {
154
+ null
155
+ }
156
+
157
+ val AppLanguage = staticCompositionLocalOf<String?> {
158
+ null
159
+ }
160
+
161
+ @Immutable
162
+ data class KitConfig(
163
+ val trustBanner: TrustBannerData? = null,
164
+ val headerBar: String? = null,
165
+ val headerGradient: String? = null,
166
+ )
167
+
168
+ internal var DesignSystemWhiteList: Boolean? = null
169
+
170
+ @Deprecated("Use NavigationContainer instead", ReplaceWith("NavigationContainer"))
171
+ @Composable
172
+ fun ApplicationContainer(
173
+ theme: Theme = defaultTheme,
174
+ composeApi: ComposeApi? = null,
175
+ statusBarHeight: Dp? = AppStatusBar.current,
176
+ applicationContext: MiniAppContext? = null,
177
+ config: KitConfig? = null,
178
+ language: String? = null,
179
+ isWhiteList: Boolean = false,
180
+ content: @Composable () -> Unit,
181
+ ) {
182
+ var appTheme by remember { mutableStateOf(theme) }
183
+
184
+ LaunchedEffect(Unit) {
185
+ DesignSystemWhiteList = isWhiteList
186
+ try {
187
+ val headerBar = config?.headerBar
188
+ if (headerBar != null && appTheme.assets.headerBackground == null) {
189
+ appTheme = appTheme.copy(
190
+ assets = ThemeAssets(
191
+ headerBackground = headerBar
192
+ )
193
+ )
194
+ }
195
+ } catch (e: Exception) {
196
+ print("@@ == NavigationContainer get config error $e")
197
+ }
198
+ }
199
+
200
+ val appStatusBarHeight = statusBarHeight ?: getStatusBarHeight()
201
+
202
+ CompositionLocalProvider(
203
+ AppTheme provides appTheme,
204
+ PlatformApi provides composeApi,
205
+ AppNavigator provides Navigator(),
206
+ AppStatusBar provides appStatusBarHeight,
207
+ ApplicationContext provides applicationContext,
208
+ AppConfig provides config,
209
+ AppLanguage provides language,
210
+ ) {
211
+ content()
212
+ }
213
+
214
+ }
@@ -0,0 +1,236 @@
1
+ package vn.momo.kits.application
2
+
3
+ import androidx.compose.animation.core.animateFloatAsState
4
+ import androidx.compose.foundation.ScrollState
5
+ import androidx.compose.foundation.background
6
+ import androidx.compose.foundation.gestures.detectTapGestures
7
+ import androidx.compose.foundation.layout.Arrangement
8
+ import androidx.compose.foundation.layout.Box
9
+ import androidx.compose.foundation.layout.Column
10
+ import androidx.compose.foundation.layout.Spacer
11
+ import androidx.compose.foundation.layout.WindowInsets
12
+ import androidx.compose.foundation.layout.asPaddingValues
13
+ import androidx.compose.foundation.layout.aspectRatio
14
+ import androidx.compose.foundation.layout.fillMaxSize
15
+ import androidx.compose.foundation.layout.fillMaxWidth
16
+ import androidx.compose.foundation.layout.ime
17
+ import androidx.compose.foundation.layout.imePadding
18
+ import androidx.compose.foundation.layout.padding
19
+ import androidx.compose.foundation.layout.systemBars
20
+ import androidx.compose.foundation.rememberScrollState
21
+ import androidx.compose.foundation.verticalScroll
22
+ import androidx.compose.runtime.Composable
23
+ import androidx.compose.runtime.getValue
24
+ import androidx.compose.ui.Alignment
25
+ import androidx.compose.ui.Modifier
26
+ import androidx.compose.ui.graphics.Color
27
+ import androidx.compose.ui.input.pointer.pointerInput
28
+ import androidx.compose.ui.layout.LayoutCoordinates
29
+ import androidx.compose.ui.layout.onGloballyPositioned
30
+ import androidx.compose.ui.platform.LocalDensity
31
+ import androidx.compose.ui.platform.LocalSoftwareKeyboardController
32
+ import androidx.compose.ui.unit.Dp
33
+ import androidx.compose.ui.unit.dp
34
+ import androidx.compose.ui.unit.min
35
+ import androidx.compose.ui.zIndex
36
+ import vn.momo.kits.components.InputSearchProps
37
+ import vn.momo.kits.const.AppTheme
38
+ import vn.momo.kits.const.Colors
39
+ import vn.momo.kits.const.Spacing
40
+ import vn.momo.kits.modifier.conditional
41
+ import vn.momo.kits.modifier.shadow
42
+ import vn.momo.kits.platform.getAndroidBuildVersion
43
+ import vn.momo.kits.utils.getAppStatusBarHeight
44
+
45
+ enum class HeaderType {
46
+ DEFAULT,
47
+ EXTENDED,
48
+ NONE
49
+ }
50
+
51
+ const val HEADER_HEIGHT = 52
52
+
53
+ @Deprecated("Use NavigationContainer(StackScreen) instead", ReplaceWith("NavigationContainer(StackScreen)"))
54
+ @Composable
55
+ fun Screen(
56
+ backgroundColor: Color? = null,
57
+ tintColor: Color? = null,
58
+ headerTransparent: Boolean = false,
59
+ fullScreenContent: Boolean = false,
60
+ isBack: Boolean = true,
61
+ headerType: HeaderType = HeaderType.DEFAULT,
62
+ verticalArrangement: Arrangement.Vertical = Arrangement.Top,
63
+ horizontalAlignment: Alignment.Horizontal = Alignment.Start,
64
+ title: String = "Stack",
65
+ titlePosition: TitlePosition = TitlePosition.LEFT,
66
+ goBack: (() -> Unit)? = null,
67
+ scrollable: Boolean = true,
68
+ scrollState: ScrollState = rememberScrollState(),
69
+ onContentLayout: ((LayoutCoordinates) -> Unit)? = null,
70
+ useAvoidKeyboard: Boolean = true,
71
+ footer: @Composable (() -> Unit)? = null,
72
+ headerRight: @Composable (() -> Unit)? = null,
73
+ fabProps: FabProps? = null,
74
+ animatedHeader: AnimatedHeader? = null,
75
+ layoutOffset: Dp = 56.dp,
76
+ inputSearchProps: InputSearchProps? = null,
77
+ useAnimationSearch: Boolean = false,
78
+ headerRightWidth: Dp = 0.dp,
79
+ content: @Composable () -> Unit,
80
+ ) {
81
+ val statusBarHeight = getAppStatusBarHeight()
82
+ val keyboardController = LocalSoftwareKeyboardController.current
83
+
84
+ val isKeyboardVisible = isKeyboardVisible()
85
+ val indicator = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
86
+ val bottomPadding = min(indicator, if (isKeyboardVisible) 0.dp else 21.dp)
87
+
88
+ val headerHeight = if (animatedHeader !== null)
89
+ with(LocalDensity.current) { layoutOffset.roundToPx() }
90
+ else HEADER_HEIGHT
91
+ val opacity by animateFloatAsState(
92
+ targetValue = ((scrollState.value.toFloat() / headerHeight)).coerceIn(0f, 1f),
93
+ )
94
+
95
+ val headerAnimated =
96
+ @Composable {
97
+ Box(
98
+ modifier = Modifier
99
+ .fillMaxWidth()
100
+ .aspectRatio(animatedHeader?.aspectRatio?.value ?: AnimatedHeaderRatio.RATIO_16_9.value)
101
+ ) {
102
+ animatedHeader?.composable?.invoke(scrollState.value)
103
+ }
104
+ }
105
+
106
+ Box(
107
+ Modifier.fillMaxSize()
108
+ .background(backgroundColor ?: AppTheme.current.colors.background.default)
109
+ .conditional(useAvoidKeyboard && getAndroidBuildVersion() > 29) {
110
+ imePadding()
111
+ }
112
+ ) {
113
+
114
+ if (animatedHeader === null) {
115
+ HeaderBackground(
116
+ headerType = headerType,
117
+ scrollState = scrollState.value,
118
+ headerTransparent = headerTransparent
119
+ )
120
+ }
121
+
122
+ Header(
123
+ headerType = headerType,
124
+ title = title,
125
+ titlePosition = titlePosition,
126
+ headerRight = headerRight,
127
+ headerRightWidth = headerRightWidth,
128
+ goBack = goBack,
129
+ opacity = opacity,
130
+ animatedHeader = animatedHeader,
131
+ inputSearchProps = inputSearchProps,
132
+ scrollState = scrollState.value,
133
+ useAnimationSearch = useAnimationSearch,
134
+ tintColor = tintColor
135
+ )
136
+
137
+ Column(
138
+ modifier = Modifier.fillMaxSize()
139
+ .padding( top = when {
140
+ animatedHeader != null -> 0.dp
141
+ headerType == HeaderType.NONE -> 0.dp
142
+ fullScreenContent -> 0.dp
143
+ else -> statusBarHeight + HEADER_HEIGHT.dp
144
+ })
145
+ .pointerInput(Unit) {
146
+ detectTapGestures(onTap = {
147
+ keyboardController?.hide()
148
+ })
149
+ }
150
+ .zIndex(1f),
151
+ ) {
152
+
153
+ Column(
154
+ modifier = Modifier
155
+ .conditional(scrollable) { weight(1f) }
156
+ .conditional(onContentLayout != null) {
157
+ onGloballyPositioned(onContentLayout ?: {})
158
+ }
159
+ .conditional(scrollable) { verticalScroll(scrollState) },
160
+ verticalArrangement = verticalArrangement,
161
+ horizontalAlignment = horizontalAlignment
162
+ ) {
163
+ Box {
164
+ if (animatedHeader !== null) headerAnimated()
165
+ Column {
166
+ if (animatedHeader !== null) {
167
+ Spacer(modifier = Modifier.padding(top = statusBarHeight + HEADER_HEIGHT.dp + layoutOffset))
168
+ }
169
+
170
+ if (useAnimationSearch && inputSearchProps != null && headerType == HeaderType.EXTENDED) {
171
+ Spacer(modifier = Modifier.padding(top = (HEADER_HEIGHT.dp + Spacing.S)))
172
+ }
173
+ content()
174
+ }
175
+ }
176
+ }
177
+
178
+ footer?.let {
179
+ Footer(footer, bottomPadding)
180
+ }
181
+ }
182
+
183
+ if (fabProps != null) {
184
+ FloatingButton(
185
+ scrollPosition = fabProps.scrollState?.value ?: scrollState.value,
186
+ onClick = fabProps.onClick,
187
+ containerColor = AppTheme.current.colors.primary,
188
+ bottom = fabProps.bottom
189
+ ?: if (footer != null) bottomPadding + 76.dp else bottomPadding + 12.dp,
190
+ icon = fabProps.icon,
191
+ iconColor = fabProps.iconColor,
192
+ text = fabProps.label,
193
+ size = fabProps.size,
194
+ position = fabProps.position ?: FABPosition.END,
195
+ )
196
+ }
197
+ }
198
+ }
199
+
200
+ @Composable
201
+ internal fun isKeyboardVisible(): Boolean {
202
+ val ime = WindowInsets.ime
203
+ val density = LocalDensity.current
204
+ val bottom = ime.getBottom(density)
205
+ return bottom > 0
206
+ }
207
+
208
+ @Composable
209
+ fun Footer(footer: @Composable (() -> Unit)? = null, bottom: Dp = 0.dp) {
210
+ Box(
211
+ Modifier
212
+ .shadow(
213
+ color = Colors.black_20.copy(alpha = 0.05f),
214
+ blurRadius = 24f,
215
+ offsetX = 0.dp,
216
+ offsetY = (-4).dp
217
+ )
218
+ .background(AppTheme.current.colors.background.surface)
219
+ ) {
220
+ Box(
221
+ Modifier.fillMaxWidth()
222
+ .padding(bottom = bottom)
223
+ .padding(vertical = Spacing.S, horizontal = Spacing.M)
224
+ ) {
225
+ footer?.invoke()
226
+ }
227
+ }
228
+ }
229
+
230
+
231
+
232
+
233
+
234
+
235
+
236
+
@@ -0,0 +1,69 @@
1
+ package vn.momo.kits.application
2
+
3
+ import androidx.compose.animation.animateColorAsState
4
+ import androidx.compose.animation.core.animateFloatAsState
5
+ import androidx.compose.runtime.Composable
6
+ import androidx.compose.runtime.getValue
7
+ import androidx.compose.ui.graphics.Color
8
+ import androidx.compose.ui.unit.Dp
9
+ import androidx.compose.ui.unit.dp
10
+ import vn.momo.kits.const.AppTheme
11
+ import vn.momo.kits.const.Colors
12
+ import vn.momo.kits.platform.getScreenDimensions
13
+
14
+ data class HeaderAnimations(
15
+ val opacity: Float,
16
+ val backgroundSearch: Color,
17
+ val translateX: Float,
18
+ val width: Float,
19
+ val translateY: Float
20
+ )
21
+
22
+ private const val SCREEN_PADDING = 12
23
+ private const val BACK_WIDTH = 28
24
+
25
+ @Deprecated("Use vn.momo.kits.navigation.component.Header instead", ReplaceWith("vn.momo.kits.navigation.component.Header"))
26
+ @Composable
27
+ fun useHeaderSearchAnimation(
28
+ opacityAni: Float,
29
+ scrollState: Int,
30
+ headerRightWidth: Dp,
31
+ isBack: Boolean
32
+ ): HeaderAnimations {
33
+ val screenWidth = getScreenDimensions().width
34
+ val leftPosition = if (isBack) (BACK_WIDTH + 20).dp else 12.dp
35
+ val searchWidth = screenWidth - (SCREEN_PADDING * 2)
36
+
37
+ val backgroundSearch by animateColorAsState(
38
+ targetValue = animateColor(
39
+ Colors.black_01,
40
+ AppTheme.current.colors.background.default,
41
+ opacityAni
42
+ ),
43
+ )
44
+
45
+ val animatedTranslateX by animateFloatAsState(
46
+ targetValue = (scrollState / HEADER_HEIGHT * 1f).coerceIn(
47
+ 0f,
48
+ 1f
49
+ ) * (leftPosition.value - 12) + 12,
50
+ )
51
+
52
+ val animatedWidth by animateFloatAsState(
53
+ targetValue = (scrollState / HEADER_HEIGHT * 1f).coerceIn(
54
+ 0f,
55
+ 1f
56
+ ) * ((searchWidth - leftPosition.value - headerRightWidth.value + 12) - searchWidth) + searchWidth,
57
+ )
58
+
59
+ val animatedTranslateY by animateFloatAsState(
60
+ targetValue = (1 - (scrollState / HEADER_HEIGHT * 1f).coerceIn(0f, 1f)) * HEADER_HEIGHT
61
+ )
62
+ return HeaderAnimations(
63
+ opacity = opacityAni,
64
+ backgroundSearch = backgroundSearch,
65
+ translateX = animatedTranslateX,
66
+ width = animatedWidth,
67
+ translateY = animatedTranslateY
68
+ )
69
+ }
@@ -0,0 +1,77 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.border
5
+ import androidx.compose.foundation.layout.Box
6
+ import androidx.compose.foundation.layout.height
7
+ import androidx.compose.foundation.layout.padding
8
+ import androidx.compose.foundation.layout.widthIn
9
+ import androidx.compose.foundation.shape.RoundedCornerShape
10
+ import androidx.compose.runtime.Composable
11
+ import androidx.compose.ui.Alignment
12
+ import androidx.compose.ui.Modifier
13
+ import androidx.compose.ui.graphics.Color
14
+ import androidx.compose.ui.unit.dp
15
+ import vn.momo.kits.const.AppTheme
16
+ import vn.momo.kits.const.Colors
17
+ import vn.momo.kits.const.Radius
18
+ import vn.momo.kits.const.Spacing
19
+ import vn.momo.kits.const.Typography
20
+ import vn.momo.kits.const.scaleSize
21
+
22
+
23
+ @Composable
24
+ fun Badge(label: String = "Label", backgroundColor: Color? = null) {
25
+ val primaryColors = listOf(
26
+ Color(0xFFF0F0F0),
27
+ Color(0xFFEB2F96),
28
+ Color(0xFF962AF0),
29
+ Color(0xFF4E4BFF),
30
+ Color(0xFF007AFF),
31
+ Color(0xFF13C2C2),
32
+ Color(0xFF34C759),
33
+ Color(0xFFA0D911),
34
+ Color(0xFFFFCC00),
35
+ Color(0xFFFA8C16),
36
+ Color(0xFFFA541C),
37
+ Color(0xFFF5222D)
38
+ )
39
+
40
+ fun isNumber(label: String): Boolean {
41
+ val numberRegex = "^\\d+$".toRegex()
42
+ return numberRegex.matches(label)
43
+ }
44
+
45
+ fun formatTitle(label: String): String {
46
+ if (isNumber(label) && label.toInt() > 99) {
47
+ return "99+"
48
+ }
49
+ return label
50
+ }
51
+
52
+ var badgeColor =
53
+ if (isNumber(label)) {
54
+ AppTheme.current.colors.error.primary
55
+ } else {
56
+ AppTheme.current.colors.warning.primary
57
+ }
58
+
59
+ if (backgroundColor != null && primaryColors.contains(backgroundColor)) {
60
+ badgeColor = backgroundColor
61
+ }
62
+
63
+ Box(
64
+ modifier = Modifier
65
+ .height(scaleSize(16.toFloat()).dp)
66
+ .widthIn(min = scaleSize(16.toFloat()).dp)
67
+ .background(color = badgeColor, shape = RoundedCornerShape(Radius.M))
68
+ .border(width = 1.dp, shape = RoundedCornerShape(Radius.M), color = Colors.black_01)
69
+ .padding(horizontal = Spacing.XS), contentAlignment = Alignment.Center
70
+ ) {
71
+ Text(
72
+ text = formatTitle(label),
73
+ color = Colors.black_01,
74
+ style = Typography.actionXxsBold
75
+ )
76
+ }
77
+ }
@@ -0,0 +1,27 @@
1
+ package vn.momo.kits.components
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.border
5
+ import androidx.compose.foundation.layout.Box
6
+ import androidx.compose.foundation.layout.size
7
+ import androidx.compose.foundation.shape.RoundedCornerShape
8
+ import androidx.compose.runtime.Composable
9
+ import androidx.compose.ui.Modifier
10
+ import androidx.compose.ui.unit.dp
11
+ import vn.momo.kits.const.Colors
12
+ import vn.momo.kits.const.Radius
13
+
14
+ enum class DotSize(val size: Int) {
15
+ Small(10),
16
+ Large(16)
17
+ }
18
+
19
+ @Composable
20
+ fun BadgeDot(size: DotSize = DotSize.Large, modifier: Modifier = Modifier) {
21
+ Box(
22
+ modifier = modifier
23
+ .size(size.size.dp)
24
+ .border(width = 1.dp, color = Colors.black_01, shape = RoundedCornerShape(Radius.S))
25
+ .background(color = Colors.red_03, shape = RoundedCornerShape(Radius.S))
26
+ )
27
+ }