@momo-kits/native-kits 0.152.4-beta.6 → 0.152.4-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CODE_OF_CONDUCT.md +133 -0
- package/CONTRIBUTING.md +114 -0
- package/LICENSE +20 -0
- package/README.md +7 -0
- package/build.gradle.kts +32 -0
- package/compose/MoMoComposeKits.podspec +54 -0
- package/compose/build.gradle.kts +149 -0
- package/compose/src/androidMain/AndroidManifest.xml +2 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +105 -0
- package/compose/src/commonMain/composeResources/files/lottie_circle_loader.json +1 -0
- package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
- package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
- package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +57 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +715 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +214 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +396 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +77 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +27 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +334 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +345 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +90 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +131 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +58 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +143 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +179 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +111 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +384 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +160 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +234 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +223 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +232 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +236 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +228 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +50 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +34 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +85 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +33 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +338 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +95 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +64 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +89 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +91 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +84 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +208 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +172 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +199 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +237 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +13 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +191 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +258 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +59 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +49 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +232 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +111 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +94 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +159 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +302 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScaleSizeScope.kt +17 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +484 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +169 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +216 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +180 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +251 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +31 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +385 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +117 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +38 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +62 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +88 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +144 -0
- package/gradle.properties +19 -0
- package/gradlew +240 -0
- package/gradlew.bat +91 -0
- package/ios/Application/ApplicationEnvironment.swift +50 -0
- package/ios/Application/Components.swift +263 -0
- package/ios/Application/ComposeApi.swift +22 -0
- package/ios/Application/FloatingButton.swift +172 -0
- package/ios/Application/HeaderRight.swift +271 -0
- package/ios/Application/Screen.swift +249 -0
- package/ios/Badge/BadgeDot.swift +31 -0
- package/ios/Button/Button.swift +211 -0
- package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
- package/ios/Checkbox/Checkbox.swift +81 -0
- package/ios/Chip/Chip.swift +96 -0
- package/ios/Colors+Radius+Spacing/Colors.swift +172 -0
- package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
- package/ios/Colors+Radius+Spacing/Spacing.swift +12 -0
- package/ios/Extensions/Color++.swift +25 -0
- package/ios/Icon/Icon.swift +51 -0
- package/ios/Image/Image.swift +70 -0
- package/ios/Input/Input.swift +207 -0
- package/ios/Input/InputPhoneNumber.swift +176 -0
- package/ios/Input/InputSearch.swift +238 -0
- package/ios/Input/InputTextArea.swift +242 -0
- package/ios/Lottie/LottieView.swift +86 -0
- package/ios/OTPKeyboard/KeyboardButton.swift +41 -0
- package/ios/OTPKeyboard/OTPKeyboard.swift +145 -0
- package/ios/Popup/PopupDisplay.swift +284 -0
- package/ios/Popup/PopupInput.swift +96 -0
- package/ios/Popup/PopupPromotion.swift +73 -0
- package/ios/PopupView/FullscreenPopup.swift +251 -0
- package/ios/PopupView/Modifiers.swift +158 -0
- package/ios/PopupView/PopupView.swift +289 -0
- package/ios/PopupView/Utils++.swift +281 -0
- package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
- package/ios/Swipeable/SwipeCell.swift +278 -0
- package/ios/Swipeable/SwipeCellModel.swift +86 -0
- package/ios/Switch/Switch.swift +44 -0
- package/ios/Template/Logo/Logo.swift +75 -0
- package/ios/Template/TrustBanner/TrustBanner.swift +120 -0
- package/ios/Theme.md +18 -0
- package/ios/Typography/Text.swift +140 -0
- package/ios/Typography/Typography.swift +95 -0
- package/ios/native-kits.podspec +18 -0
- package/package.json +6 -7
- package/settings.gradle.kts +25 -0
- 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,396 @@
|
|
|
1
|
+
package vn.momo.kits.application
|
|
2
|
+
|
|
3
|
+
import androidx.compose.animation.core.Animatable
|
|
4
|
+
import androidx.compose.animation.core.animateFloatAsState
|
|
5
|
+
import androidx.compose.animation.core.tween
|
|
6
|
+
import androidx.compose.foundation.ScrollState
|
|
7
|
+
import androidx.compose.foundation.background
|
|
8
|
+
import androidx.compose.foundation.gestures.detectTapGestures
|
|
9
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
10
|
+
import androidx.compose.foundation.layout.Box
|
|
11
|
+
import androidx.compose.foundation.layout.Column
|
|
12
|
+
import androidx.compose.foundation.layout.Spacer
|
|
13
|
+
import androidx.compose.foundation.layout.WindowInsets
|
|
14
|
+
import androidx.compose.foundation.layout.asPaddingValues
|
|
15
|
+
import androidx.compose.foundation.layout.aspectRatio
|
|
16
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
17
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
18
|
+
import androidx.compose.foundation.layout.height
|
|
19
|
+
import androidx.compose.foundation.layout.ime
|
|
20
|
+
import androidx.compose.foundation.layout.imePadding
|
|
21
|
+
import androidx.compose.foundation.layout.offset
|
|
22
|
+
import androidx.compose.foundation.layout.padding
|
|
23
|
+
import androidx.compose.foundation.layout.systemBars
|
|
24
|
+
import androidx.compose.foundation.rememberScrollState
|
|
25
|
+
import androidx.compose.foundation.verticalScroll
|
|
26
|
+
import androidx.compose.runtime.Composable
|
|
27
|
+
import androidx.compose.runtime.CompositionLocalProvider
|
|
28
|
+
import androidx.compose.runtime.DisposableEffect
|
|
29
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
30
|
+
import androidx.compose.runtime.getValue
|
|
31
|
+
import androidx.compose.runtime.mutableStateOf
|
|
32
|
+
import androidx.compose.runtime.remember
|
|
33
|
+
import androidx.compose.runtime.setValue
|
|
34
|
+
import androidx.compose.runtime.staticCompositionLocalOf
|
|
35
|
+
import androidx.compose.ui.Alignment
|
|
36
|
+
import androidx.compose.ui.Modifier
|
|
37
|
+
import androidx.compose.ui.graphics.Color
|
|
38
|
+
import androidx.compose.ui.input.pointer.pointerInput
|
|
39
|
+
import androidx.compose.ui.layout.LayoutCoordinates
|
|
40
|
+
import androidx.compose.ui.layout.onGloballyPositioned
|
|
41
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
42
|
+
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
|
43
|
+
import androidx.compose.ui.unit.Dp
|
|
44
|
+
import androidx.compose.ui.unit.IntOffset
|
|
45
|
+
import androidx.compose.ui.unit.dp
|
|
46
|
+
import androidx.compose.ui.unit.min
|
|
47
|
+
import androidx.compose.ui.zIndex
|
|
48
|
+
import kotlinx.coroutines.CoroutineScope
|
|
49
|
+
import kotlinx.coroutines.Dispatchers
|
|
50
|
+
import kotlinx.coroutines.SupervisorJob
|
|
51
|
+
import kotlinx.coroutines.cancel
|
|
52
|
+
import kotlinx.coroutines.delay
|
|
53
|
+
import kotlinx.coroutines.launch
|
|
54
|
+
import vn.momo.kits.components.InputSearchProps
|
|
55
|
+
import vn.momo.kits.const.AppNavigationBar
|
|
56
|
+
import vn.momo.kits.const.AppTheme
|
|
57
|
+
import vn.momo.kits.const.Colors
|
|
58
|
+
import vn.momo.kits.const.Spacing
|
|
59
|
+
import vn.momo.kits.modifier.conditional
|
|
60
|
+
import vn.momo.kits.modifier.shadow
|
|
61
|
+
import vn.momo.kits.navigation.component.SnackBar
|
|
62
|
+
import vn.momo.kits.platform.getAndroidBuildVersion
|
|
63
|
+
import vn.momo.kits.utils.getAppStatusBarHeight
|
|
64
|
+
|
|
65
|
+
enum class HeaderType {
|
|
66
|
+
DEFAULT,
|
|
67
|
+
EXTENDED,
|
|
68
|
+
NONE
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const val HEADER_HEIGHT = 52
|
|
72
|
+
|
|
73
|
+
@Deprecated("Use NavigationContainer(StackScreen) instead", ReplaceWith("NavigationContainer(StackScreen)"))
|
|
74
|
+
@Composable
|
|
75
|
+
fun Screen(
|
|
76
|
+
backgroundColor: Color? = null,
|
|
77
|
+
tintColor: Color? = null,
|
|
78
|
+
headerTransparent: Boolean = false,
|
|
79
|
+
fullScreenContent: Boolean = false,
|
|
80
|
+
isBack: Boolean = true,
|
|
81
|
+
headerType: HeaderType = HeaderType.DEFAULT,
|
|
82
|
+
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
|
|
83
|
+
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
|
|
84
|
+
title: String = "Stack",
|
|
85
|
+
titlePosition: TitlePosition = TitlePosition.LEFT,
|
|
86
|
+
goBack: (() -> Unit)? = null,
|
|
87
|
+
scrollable: Boolean = true,
|
|
88
|
+
scrollState: ScrollState = rememberScrollState(),
|
|
89
|
+
onContentLayout: ((LayoutCoordinates) -> Unit)? = null,
|
|
90
|
+
useAvoidKeyboard: Boolean = true,
|
|
91
|
+
footer: @Composable (() -> Unit)? = null,
|
|
92
|
+
headerRight: @Composable (() -> Unit)? = null,
|
|
93
|
+
fabProps: FabProps? = null,
|
|
94
|
+
animatedHeader: AnimatedHeader? = null,
|
|
95
|
+
layoutOffset: Dp = 56.dp,
|
|
96
|
+
inputSearchProps: InputSearchProps? = null,
|
|
97
|
+
useAnimationSearch: Boolean = false,
|
|
98
|
+
headerRightWidth: Dp = 0.dp,
|
|
99
|
+
content: @Composable () -> Unit,
|
|
100
|
+
) {
|
|
101
|
+
val statusBarHeight = getAppStatusBarHeight()
|
|
102
|
+
val keyboardController = LocalSoftwareKeyboardController.current
|
|
103
|
+
|
|
104
|
+
val isKeyboardVisible = isKeyboardVisible()
|
|
105
|
+
val indicator = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
|
|
106
|
+
val bottomPadding = min(indicator, if (isKeyboardVisible) 0.dp else 21.dp)
|
|
107
|
+
|
|
108
|
+
val headerHeight = if (animatedHeader !== null)
|
|
109
|
+
with(LocalDensity.current) { layoutOffset.roundToPx() }
|
|
110
|
+
else HEADER_HEIGHT
|
|
111
|
+
val opacity by animateFloatAsState(
|
|
112
|
+
targetValue = ((scrollState.value.toFloat() / headerHeight)).coerceIn(0f, 1f),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
val headerAnimated =
|
|
116
|
+
@Composable {
|
|
117
|
+
Box(
|
|
118
|
+
modifier = Modifier
|
|
119
|
+
.fillMaxWidth()
|
|
120
|
+
.aspectRatio(animatedHeader?.aspectRatio?.value ?: AnimatedHeaderRatio.RATIO_16_9.value)
|
|
121
|
+
) {
|
|
122
|
+
animatedHeader?.composable?.invoke(scrollState.value)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
val helper = remember { ScreenHelper() }
|
|
126
|
+
|
|
127
|
+
DisposableEffect(Unit) {
|
|
128
|
+
onDispose { helper.dispose() }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
CompositionLocalProvider(
|
|
132
|
+
LocalScreenHelper provides helper
|
|
133
|
+
) {
|
|
134
|
+
Box(
|
|
135
|
+
Modifier.fillMaxSize()
|
|
136
|
+
.background(backgroundColor ?: AppTheme.current.colors.background.default)
|
|
137
|
+
.conditional(useAvoidKeyboard && getAndroidBuildVersion() > 29) {
|
|
138
|
+
imePadding()
|
|
139
|
+
}
|
|
140
|
+
) {
|
|
141
|
+
val footerHeightPx = remember { mutableStateOf(0) }
|
|
142
|
+
|
|
143
|
+
Box(Modifier.zIndex(1f)) {
|
|
144
|
+
if (animatedHeader === null) {
|
|
145
|
+
HeaderBackground(
|
|
146
|
+
headerType = headerType,
|
|
147
|
+
scrollState = scrollState.value,
|
|
148
|
+
headerTransparent = headerTransparent
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
Box(Modifier.zIndex(5f)) {
|
|
154
|
+
Header(
|
|
155
|
+
headerType = headerType,
|
|
156
|
+
title = title,
|
|
157
|
+
titlePosition = titlePosition,
|
|
158
|
+
headerRight = headerRight,
|
|
159
|
+
headerRightWidth = headerRightWidth,
|
|
160
|
+
goBack = goBack,
|
|
161
|
+
opacity = opacity,
|
|
162
|
+
animatedHeader = animatedHeader,
|
|
163
|
+
inputSearchProps = inputSearchProps,
|
|
164
|
+
scrollState = scrollState.value,
|
|
165
|
+
useAnimationSearch = useAnimationSearch,
|
|
166
|
+
tintColor = tintColor
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
Box(Modifier.zIndex(2f).fillMaxSize()){
|
|
171
|
+
Column(
|
|
172
|
+
modifier = Modifier.fillMaxSize()
|
|
173
|
+
.padding( top = when {
|
|
174
|
+
animatedHeader != null -> 0.dp
|
|
175
|
+
headerType == HeaderType.NONE -> 0.dp
|
|
176
|
+
fullScreenContent -> 0.dp
|
|
177
|
+
else -> statusBarHeight + HEADER_HEIGHT.dp
|
|
178
|
+
})
|
|
179
|
+
.pointerInput(Unit) {
|
|
180
|
+
detectTapGestures(onTap = {
|
|
181
|
+
keyboardController?.hide()
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
.zIndex(1f),
|
|
185
|
+
) {
|
|
186
|
+
|
|
187
|
+
Column(
|
|
188
|
+
modifier = Modifier
|
|
189
|
+
.conditional(scrollable) { weight(1f) }
|
|
190
|
+
.conditional(onContentLayout != null) {
|
|
191
|
+
onGloballyPositioned(onContentLayout ?: {})
|
|
192
|
+
}
|
|
193
|
+
.conditional(scrollable) { verticalScroll(scrollState) },
|
|
194
|
+
verticalArrangement = verticalArrangement,
|
|
195
|
+
horizontalAlignment = horizontalAlignment
|
|
196
|
+
) {
|
|
197
|
+
Box {
|
|
198
|
+
if (animatedHeader !== null) headerAnimated()
|
|
199
|
+
Column {
|
|
200
|
+
if (animatedHeader !== null) {
|
|
201
|
+
Spacer(modifier = Modifier.padding(top = statusBarHeight + HEADER_HEIGHT.dp + layoutOffset))
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (useAnimationSearch && inputSearchProps != null && headerType == HeaderType.EXTENDED) {
|
|
205
|
+
Spacer(modifier = Modifier.padding(top = (HEADER_HEIGHT.dp + Spacing.S)))
|
|
206
|
+
}
|
|
207
|
+
content()
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
footer?.let {
|
|
213
|
+
val footerHeight = with(LocalDensity.current) { footerHeightPx.value.toDp() }
|
|
214
|
+
Spacer(Modifier.height(footerHeight))
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
Box(Modifier.zIndex(4f).align(Alignment.BottomCenter)) {
|
|
220
|
+
footer?.let {
|
|
221
|
+
Footer(
|
|
222
|
+
footer = footer,
|
|
223
|
+
bottom = bottomPadding,
|
|
224
|
+
onFooterMeasured = { footerHeightPx.value = it }
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
Column (Modifier.zIndex(6f)) {
|
|
230
|
+
if (fabProps != null) {
|
|
231
|
+
FloatingButton(
|
|
232
|
+
scrollPosition = fabProps.scrollState?.value ?: scrollState.value,
|
|
233
|
+
onClick = fabProps.onClick,
|
|
234
|
+
containerColor = AppTheme.current.colors.primary,
|
|
235
|
+
bottom = fabProps.bottom
|
|
236
|
+
?: if (footer != null) bottomPadding + 76.dp else bottomPadding + 12.dp,
|
|
237
|
+
icon = fabProps.icon,
|
|
238
|
+
iconColor = fabProps.iconColor,
|
|
239
|
+
text = fabProps.label,
|
|
240
|
+
size = fabProps.size,
|
|
241
|
+
position = fabProps.position ?: FABPosition.END,
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
Box(
|
|
247
|
+
modifier = Modifier
|
|
248
|
+
.align(Alignment.BottomCenter)
|
|
249
|
+
.zIndex(3f)
|
|
250
|
+
) {
|
|
251
|
+
ScreenSnackBarHost(footerHeightPx.value)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
@Composable
|
|
258
|
+
internal fun isKeyboardVisible(): Boolean {
|
|
259
|
+
val ime = WindowInsets.ime
|
|
260
|
+
val density = LocalDensity.current
|
|
261
|
+
val bottom = ime.getBottom(density)
|
|
262
|
+
return bottom > 0
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@Composable
|
|
266
|
+
fun Footer(
|
|
267
|
+
footer: @Composable (() -> Unit)? = null,
|
|
268
|
+
bottom: Dp = 0.dp,
|
|
269
|
+
onFooterMeasured: ((Int) -> Unit)? = null
|
|
270
|
+
) {
|
|
271
|
+
Box(
|
|
272
|
+
Modifier
|
|
273
|
+
.shadow(
|
|
274
|
+
color = Colors.black_20.copy(alpha = 0.05f),
|
|
275
|
+
blurRadius = 24f,
|
|
276
|
+
offsetX = 0.dp,
|
|
277
|
+
offsetY = (-4).dp
|
|
278
|
+
)
|
|
279
|
+
.background(AppTheme.current.colors.background.surface)
|
|
280
|
+
.onGloballyPositioned {
|
|
281
|
+
onFooterMeasured?.invoke(it.size.height)
|
|
282
|
+
}
|
|
283
|
+
) {
|
|
284
|
+
Box(
|
|
285
|
+
Modifier.fillMaxWidth()
|
|
286
|
+
.padding(bottom = bottom)
|
|
287
|
+
.padding(vertical = Spacing.S, horizontal = Spacing.M)
|
|
288
|
+
) {
|
|
289
|
+
footer?.invoke()
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
class ScreenHelper {
|
|
296
|
+
|
|
297
|
+
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
|
298
|
+
|
|
299
|
+
internal var snackBarState by mutableStateOf<SnackBarData?>(null)
|
|
300
|
+
|
|
301
|
+
internal var requestHide by mutableStateOf(false)
|
|
302
|
+
|
|
303
|
+
fun showSnackBar(snackBar: SnackBar, onDismiss: (() -> Unit)? = null) {
|
|
304
|
+
scope.launch {
|
|
305
|
+
requestHide = false
|
|
306
|
+
snackBarState = SnackBarData(snackBar, onDismiss)
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
fun hideSnackBar() {
|
|
311
|
+
scope.launch {
|
|
312
|
+
requestHide = true
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
internal fun removeSnackBarNow() {
|
|
317
|
+
snackBarState = null
|
|
318
|
+
requestHide = false
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
fun dispose() {
|
|
322
|
+
scope.cancel()
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
data class SnackBarData(
|
|
326
|
+
val type: SnackBar,
|
|
327
|
+
val onDismiss: (() -> Unit)?
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
val LocalScreenHelper = staticCompositionLocalOf<ScreenHelper> {
|
|
331
|
+
error("No Screen helper provided")
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
@Composable
|
|
335
|
+
fun ScreenSnackBarHost(footerHeightPx: Int) {
|
|
336
|
+
val helper = LocalScreenHelper.current
|
|
337
|
+
val snackBarData = helper.snackBarState ?: return
|
|
338
|
+
val density = LocalDensity.current
|
|
339
|
+
|
|
340
|
+
val footerHeight = if (footerHeightPx > 0) {
|
|
341
|
+
with(LocalDensity.current) {
|
|
342
|
+
footerHeightPx.toDp()
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
min(AppNavigationBar.current, 21.dp)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
val startPosition = with(density) {200.dp.toPx()}
|
|
349
|
+
val targetPosition = 0f
|
|
350
|
+
|
|
351
|
+
val offsetY = remember { Animatable(startPosition) }
|
|
352
|
+
|
|
353
|
+
LaunchedEffect(snackBarData, footerHeightPx) {
|
|
354
|
+
offsetY.snapTo(startPosition)
|
|
355
|
+
offsetY.animateTo(targetPosition, tween(350))
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
LaunchedEffect(helper.requestHide) {
|
|
359
|
+
if (helper.requestHide) {
|
|
360
|
+
offsetY.animateTo(startPosition, tween(200))
|
|
361
|
+
helper.removeSnackBarNow()
|
|
362
|
+
snackBarData.onDismiss?.invoke()
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
LaunchedEffect(snackBarData.type.duration) {
|
|
367
|
+
val duration = snackBarData.type.duration
|
|
368
|
+
if (duration != null) {
|
|
369
|
+
delay(duration)
|
|
370
|
+
helper.hideSnackBar()
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
DisposableEffect(Unit) {
|
|
375
|
+
onDispose { snackBarData.onDismiss?.invoke() }
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
Box(
|
|
379
|
+
modifier = Modifier
|
|
380
|
+
.offset { IntOffset(0, offsetY.value.toInt()) }
|
|
381
|
+
.padding(bottom = footerHeight)
|
|
382
|
+
.fillMaxWidth()
|
|
383
|
+
) {
|
|
384
|
+
when (val type = snackBarData.type) {
|
|
385
|
+
is SnackBar.Custom -> type.content()
|
|
386
|
+
is SnackBar.Toast -> {}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
|
|
@@ -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
|
+
}
|