@momo-kits/native-kits 0.152.4-beta.9 → 0.152.4-scale.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.
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +2 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +246 -78
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +3 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +21 -19
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +12 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +22 -11
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +6 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +4 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +19 -24
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +24 -19
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +25 -18
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +3 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +42 -7
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +106 -36
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScaleSizeScope.kt +8 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +34 -10
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +11 -10
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +125 -0
- package/ios/Badge/Badge.swift +0 -6
- package/ios/Badge/BadgeRibbon.swift +77 -9
- package/ios/Button/Button.swift +7 -7
- package/local.properties +8 -0
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.width
|
|
|
14
14
|
import androidx.compose.foundation.shape.CircleShape
|
|
15
15
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
16
16
|
import androidx.compose.runtime.Composable
|
|
17
|
+
import androidx.compose.runtime.Stable
|
|
17
18
|
import androidx.compose.runtime.getValue
|
|
18
19
|
import androidx.compose.runtime.mutableStateOf
|
|
19
20
|
import androidx.compose.runtime.remember
|
|
@@ -32,6 +33,7 @@ import vn.momo.kits.components.Icon
|
|
|
32
33
|
import vn.momo.kits.const.AppTheme
|
|
33
34
|
import vn.momo.kits.const.Colors
|
|
34
35
|
|
|
36
|
+
@Stable
|
|
35
37
|
data class HeaderRightData(
|
|
36
38
|
val useShortcut: Boolean = false,
|
|
37
39
|
val useMore: Boolean = false,
|
|
@@ -85,7 +85,6 @@ import vn.momo.kits.modifier.shadow
|
|
|
85
85
|
import vn.momo.kits.utils.getAppStatusBarHeight
|
|
86
86
|
import kotlin.math.max
|
|
87
87
|
|
|
88
|
-
@Deprecated("Use NavigationContainer(StackScreen) instead", ReplaceWith("NavigationContainer(StackScreen)"))
|
|
89
88
|
@Composable
|
|
90
89
|
fun LiteScreen(
|
|
91
90
|
scrollable: Boolean = true,
|
|
@@ -352,7 +351,8 @@ private class LiteScreenHeaderPolicy(
|
|
|
352
351
|
val realConstraints = constraints.copy(
|
|
353
352
|
minWidth = 0,
|
|
354
353
|
minHeight = 0,
|
|
355
|
-
maxWidth = constraints.maxWidth - spacing12 * 2
|
|
354
|
+
maxWidth = (constraints.maxWidth - spacing12 * 2)
|
|
355
|
+
.coerceAtLeast(0),
|
|
356
356
|
)
|
|
357
357
|
val backIconPlaceable =
|
|
358
358
|
measurables.find { it.layoutId == HeaderId.BACK_ID }?.measure(realConstraints)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
package vn.momo.kits.application
|
|
2
2
|
|
|
3
|
+
import androidx.compose.animation.core.Animatable
|
|
3
4
|
import androidx.compose.animation.core.animateFloatAsState
|
|
5
|
+
import androidx.compose.animation.core.tween
|
|
4
6
|
import androidx.compose.foundation.ScrollState
|
|
5
7
|
import androidx.compose.foundation.background
|
|
6
8
|
import androidx.compose.foundation.gestures.detectTapGestures
|
|
@@ -13,14 +15,23 @@ import androidx.compose.foundation.layout.asPaddingValues
|
|
|
13
15
|
import androidx.compose.foundation.layout.aspectRatio
|
|
14
16
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
15
17
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
18
|
+
import androidx.compose.foundation.layout.height
|
|
16
19
|
import androidx.compose.foundation.layout.ime
|
|
17
20
|
import androidx.compose.foundation.layout.imePadding
|
|
21
|
+
import androidx.compose.foundation.layout.offset
|
|
18
22
|
import androidx.compose.foundation.layout.padding
|
|
19
23
|
import androidx.compose.foundation.layout.systemBars
|
|
20
24
|
import androidx.compose.foundation.rememberScrollState
|
|
21
25
|
import androidx.compose.foundation.verticalScroll
|
|
22
26
|
import androidx.compose.runtime.Composable
|
|
27
|
+
import androidx.compose.runtime.CompositionLocalProvider
|
|
28
|
+
import androidx.compose.runtime.DisposableEffect
|
|
29
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
23
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
|
|
24
35
|
import androidx.compose.ui.Alignment
|
|
25
36
|
import androidx.compose.ui.Modifier
|
|
26
37
|
import androidx.compose.ui.graphics.Color
|
|
@@ -30,15 +41,24 @@ import androidx.compose.ui.layout.onGloballyPositioned
|
|
|
30
41
|
import androidx.compose.ui.platform.LocalDensity
|
|
31
42
|
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
|
32
43
|
import androidx.compose.ui.unit.Dp
|
|
44
|
+
import androidx.compose.ui.unit.IntOffset
|
|
33
45
|
import androidx.compose.ui.unit.dp
|
|
34
46
|
import androidx.compose.ui.unit.min
|
|
35
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
|
|
36
54
|
import vn.momo.kits.components.InputSearchProps
|
|
55
|
+
import vn.momo.kits.const.AppNavigationBar
|
|
37
56
|
import vn.momo.kits.const.AppTheme
|
|
38
57
|
import vn.momo.kits.const.Colors
|
|
39
58
|
import vn.momo.kits.const.Spacing
|
|
40
59
|
import vn.momo.kits.modifier.conditional
|
|
41
60
|
import vn.momo.kits.modifier.shadow
|
|
61
|
+
import vn.momo.kits.navigation.component.SnackBar
|
|
42
62
|
import vn.momo.kits.platform.getAndroidBuildVersion
|
|
43
63
|
import vn.momo.kits.utils.getAppStatusBarHeight
|
|
44
64
|
|
|
@@ -102,97 +122,134 @@ fun Screen(
|
|
|
102
122
|
animatedHeader?.composable?.invoke(scrollState.value)
|
|
103
123
|
}
|
|
104
124
|
}
|
|
125
|
+
val helper = remember { ScreenHelper() }
|
|
105
126
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
}
|
|
127
|
+
DisposableEffect(Unit) {
|
|
128
|
+
onDispose { helper.dispose() }
|
|
129
|
+
}
|
|
121
130
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
})
|
|
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()
|
|
149
139
|
}
|
|
150
|
-
.zIndex(1f),
|
|
151
140
|
) {
|
|
141
|
+
val footerHeightPx = remember { mutableStateOf(0) }
|
|
152
142
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
+
})
|
|
168
183
|
}
|
|
184
|
+
.zIndex(1f),
|
|
185
|
+
) {
|
|
169
186
|
|
|
170
|
-
|
|
171
|
-
|
|
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
|
+
}
|
|
172
209
|
}
|
|
173
|
-
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
footer?.let {
|
|
213
|
+
val footerHeight = with(LocalDensity.current) { footerHeightPx.value.toDp() }
|
|
214
|
+
Spacer(Modifier.height(footerHeight))
|
|
174
215
|
}
|
|
175
216
|
}
|
|
176
217
|
}
|
|
177
218
|
|
|
178
|
-
|
|
179
|
-
|
|
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
|
+
}
|
|
180
227
|
}
|
|
181
|
-
}
|
|
182
228
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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(if (footer == null) 0 else footerHeightPx.value)
|
|
252
|
+
}
|
|
196
253
|
}
|
|
197
254
|
}
|
|
198
255
|
}
|
|
@@ -206,7 +263,11 @@ internal fun isKeyboardVisible(): Boolean {
|
|
|
206
263
|
}
|
|
207
264
|
|
|
208
265
|
@Composable
|
|
209
|
-
fun Footer(
|
|
266
|
+
fun Footer(
|
|
267
|
+
footer: @Composable (() -> Unit)? = null,
|
|
268
|
+
bottom: Dp = 0.dp,
|
|
269
|
+
onFooterMeasured: ((Int) -> Unit)? = null
|
|
270
|
+
) {
|
|
210
271
|
Box(
|
|
211
272
|
Modifier
|
|
212
273
|
.shadow(
|
|
@@ -216,6 +277,9 @@ fun Footer(footer: @Composable (() -> Unit)? = null, bottom: Dp = 0.dp) {
|
|
|
216
277
|
offsetY = (-4).dp
|
|
217
278
|
)
|
|
218
279
|
.background(AppTheme.current.colors.background.surface)
|
|
280
|
+
.onGloballyPositioned {
|
|
281
|
+
onFooterMeasured?.invoke(it.size.height)
|
|
282
|
+
}
|
|
219
283
|
) {
|
|
220
284
|
Box(
|
|
221
285
|
Modifier.fillMaxWidth()
|
|
@@ -228,6 +292,110 @@ fun Footer(footer: @Composable (() -> Unit)? = null, bottom: Dp = 0.dp) {
|
|
|
228
292
|
}
|
|
229
293
|
|
|
230
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
|
+
val navigationBar = AppNavigationBar.current
|
|
340
|
+
|
|
341
|
+
val footerHeight = if (footerHeightPx > 0) {
|
|
342
|
+
footerHeightPx
|
|
343
|
+
} else {
|
|
344
|
+
with(density) {
|
|
345
|
+
min(navigationBar, 21.dp).toPx()
|
|
346
|
+
}
|
|
347
|
+
}.toInt()
|
|
348
|
+
|
|
349
|
+
var startPosition by remember { mutableStateOf(Float.MAX_VALUE) }
|
|
350
|
+
val targetPosition = 0f
|
|
351
|
+
|
|
352
|
+
var offsetY by remember { mutableStateOf(Animatable(startPosition)) }
|
|
353
|
+
|
|
354
|
+
LaunchedEffect(startPosition) {
|
|
355
|
+
if (startPosition != Float.MAX_VALUE){
|
|
356
|
+
offsetY.snapTo(startPosition)
|
|
357
|
+
offsetY.animateTo(targetPosition, tween(350))
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
LaunchedEffect(helper.requestHide) {
|
|
362
|
+
if (helper.requestHide) {
|
|
363
|
+
offsetY.animateTo(startPosition, tween(200))
|
|
364
|
+
helper.removeSnackBarNow()
|
|
365
|
+
snackBarData.onDismiss?.invoke()
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
LaunchedEffect(snackBarData.type.duration) {
|
|
370
|
+
val duration = snackBarData.type.duration
|
|
371
|
+
if (duration != null) {
|
|
372
|
+
delay(duration)
|
|
373
|
+
helper.hideSnackBar()
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
DisposableEffect(Unit) {
|
|
378
|
+
onDispose { snackBarData.onDismiss?.invoke() }
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
Box(
|
|
382
|
+
modifier = Modifier
|
|
383
|
+
.offset { IntOffset(0, offsetY.value.toInt() - footerHeight) }
|
|
384
|
+
.onGloballyPositioned {
|
|
385
|
+
if (startPosition != it.size.height.toFloat()) {
|
|
386
|
+
startPosition = it.size.height.toFloat()
|
|
387
|
+
offsetY = Animatable(startPosition)
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
.fillMaxWidth()
|
|
391
|
+
) {
|
|
392
|
+
when (val type = snackBarData.type) {
|
|
393
|
+
is SnackBar.Custom -> type.content()
|
|
394
|
+
is SnackBar.Toast -> {}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
231
399
|
|
|
232
400
|
|
|
233
401
|
|
|
@@ -59,11 +59,12 @@ fun Badge(label: String = "Label", backgroundColor: Color? = null) {
|
|
|
59
59
|
if (backgroundColor != null && primaryColors.contains(backgroundColor)) {
|
|
60
60
|
badgeColor = backgroundColor
|
|
61
61
|
}
|
|
62
|
+
val scaleSize = scaleSize(16f)
|
|
62
63
|
|
|
63
64
|
Box(
|
|
64
65
|
modifier = Modifier
|
|
65
|
-
.height(scaleSize
|
|
66
|
-
.widthIn(min = scaleSize
|
|
66
|
+
.height(scaleSize.dp)
|
|
67
|
+
.widthIn(min = scaleSize.dp)
|
|
67
68
|
.background(color = badgeColor, shape = RoundedCornerShape(Radius.M))
|
|
68
69
|
.border(width = 1.dp, shape = RoundedCornerShape(Radius.M), color = Colors.black_01)
|
|
69
70
|
.padding(horizontal = Spacing.XS), contentAlignment = Alignment.Center
|
|
@@ -60,27 +60,29 @@ fun Chip(
|
|
|
60
60
|
val (height, horizontal, iconSize, iconSpacing) =
|
|
61
61
|
listOf(scaleSize(dims.height), scaleSize(dims.horizontal), scaleSize(dims.iconSize), scaleSize(dims.iconSpacing))
|
|
62
62
|
|
|
63
|
+
val radius = scaleSize(Radius.L)
|
|
64
|
+
|
|
63
65
|
Row(
|
|
64
66
|
modifier
|
|
65
67
|
.wrapContentWidth()
|
|
66
|
-
.height(height)
|
|
67
|
-
.clip(RoundedCornerShape(
|
|
68
|
+
.height(height.dp)
|
|
69
|
+
.clip(RoundedCornerShape(radius))
|
|
68
70
|
.background(bg)
|
|
69
71
|
.conditional(selected) {
|
|
70
|
-
Modifier.border(width = 2.dp, color = theme.colors.secondary, shape = RoundedCornerShape(
|
|
72
|
+
Modifier.border(width = 2.dp, color = theme.colors.secondary, shape = RoundedCornerShape(radius))
|
|
71
73
|
}
|
|
72
74
|
.activeOpacityClickable {
|
|
73
75
|
onClick()
|
|
74
76
|
}
|
|
75
|
-
.padding(horizontal = horizontal)
|
|
77
|
+
.padding(horizontal = horizontal.dp)
|
|
76
78
|
.conditional(accessibilityLabel != null) {
|
|
77
79
|
setAutomationId(accessibilityLabel.toString())
|
|
78
80
|
},
|
|
79
81
|
verticalAlignment = Alignment.CenterVertically,
|
|
80
|
-
horizontalArrangement = Arrangement.spacedBy(iconSpacing)
|
|
82
|
+
horizontalArrangement = Arrangement.spacedBy(iconSpacing.dp)
|
|
81
83
|
) {
|
|
82
84
|
if (iconLeft != null) {
|
|
83
|
-
Icon(source = iconLeft, size = dims.iconSize, color = leftTint)
|
|
85
|
+
Icon(source = iconLeft, size = dims.iconSize.dp, color = leftTint)
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
if (!label.isNullOrEmpty()) {
|
|
@@ -99,7 +101,7 @@ fun Chip(
|
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
if (iconRight != null) {
|
|
102
|
-
Icon(source = iconRight, size = iconSize, color = rightTint)
|
|
104
|
+
Icon(source = iconRight, size = iconSize.dp, color = rightTint)
|
|
103
105
|
}
|
|
104
106
|
}
|
|
105
107
|
}
|
|
@@ -109,23 +111,23 @@ enum class ChipSize { SMALL, LARGE }
|
|
|
109
111
|
object ChipDefaults {
|
|
110
112
|
@Immutable
|
|
111
113
|
data class Dimensions(
|
|
112
|
-
val height:
|
|
113
|
-
val horizontal:
|
|
114
|
-
val iconSize:
|
|
115
|
-
val iconSpacing:
|
|
114
|
+
val height: Float,
|
|
115
|
+
val horizontal: Float,
|
|
116
|
+
val iconSize: Float,
|
|
117
|
+
val iconSpacing: Float,
|
|
116
118
|
)
|
|
117
119
|
|
|
118
120
|
val Large = Dimensions(
|
|
119
|
-
height =
|
|
120
|
-
horizontal =
|
|
121
|
-
iconSize =
|
|
122
|
-
iconSpacing =
|
|
121
|
+
height = 32f,
|
|
122
|
+
horizontal = 12f,
|
|
123
|
+
iconSize = 20f,
|
|
124
|
+
iconSpacing = 4f,
|
|
123
125
|
)
|
|
124
126
|
|
|
125
127
|
val Small = Dimensions(
|
|
126
|
-
height =
|
|
127
|
-
horizontal =
|
|
128
|
-
iconSize =
|
|
129
|
-
iconSpacing =
|
|
128
|
+
height = 24f,
|
|
129
|
+
horizontal = 10f,
|
|
130
|
+
iconSize = 16f,
|
|
131
|
+
iconSpacing = 4f,
|
|
130
132
|
)
|
|
131
133
|
}
|
|
@@ -13,6 +13,8 @@ import androidx.compose.ui.semantics.semantics
|
|
|
13
13
|
import androidx.compose.ui.unit.Dp
|
|
14
14
|
import androidx.compose.ui.unit.dp
|
|
15
15
|
import coil3.compose.AsyncImage
|
|
16
|
+
import coil3.compose.LocalPlatformContext
|
|
17
|
+
import coil3.request.ImageRequest
|
|
16
18
|
import vn.momo.kits.const.AppTheme
|
|
17
19
|
import vn.momo.kits.utils.Icons
|
|
18
20
|
import vn.momo.kits.utils.noThemeIcons
|
|
@@ -24,6 +26,9 @@ fun Icon(
|
|
|
24
26
|
color: Color? = AppTheme.current.colors.text.default,
|
|
25
27
|
modifier: Modifier = Modifier,
|
|
26
28
|
) {
|
|
29
|
+
// decode image without downscaling it
|
|
30
|
+
val context = LocalPlatformContext.current
|
|
31
|
+
|
|
27
32
|
val iconUrl = remember(source) {
|
|
28
33
|
if (source.contains("https")) {
|
|
29
34
|
source
|
|
@@ -49,7 +54,13 @@ fun Icon(
|
|
|
49
54
|
) {
|
|
50
55
|
AsyncImage(
|
|
51
56
|
modifier = Modifier.matchParentSize(),
|
|
52
|
-
model =
|
|
57
|
+
model = ImageRequest.Builder(context)
|
|
58
|
+
.data(iconUrl)
|
|
59
|
+
.size(
|
|
60
|
+
coil3.size.Dimension.Undefined,
|
|
61
|
+
coil3.size.Dimension.Undefined
|
|
62
|
+
)
|
|
63
|
+
.build(),
|
|
53
64
|
contentDescription = null,
|
|
54
65
|
contentScale = ContentScale.Fit,
|
|
55
66
|
colorFilter = colorFilter,
|
|
@@ -34,6 +34,7 @@ import androidx.compose.ui.text.font.FontWeight
|
|
|
34
34
|
import androidx.compose.ui.text.input.KeyboardType
|
|
35
35
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
|
36
36
|
import androidx.compose.ui.text.input.VisualTransformation
|
|
37
|
+
import androidx.compose.ui.text.style.TextAlign
|
|
37
38
|
import androidx.compose.ui.unit.Dp
|
|
38
39
|
import androidx.compose.ui.unit.dp
|
|
39
40
|
import androidx.compose.ui.unit.sp
|
|
@@ -42,7 +43,9 @@ import vn.momo.kits.const.AppTheme
|
|
|
42
43
|
import vn.momo.kits.const.Radius
|
|
43
44
|
import vn.momo.kits.const.Spacing
|
|
44
45
|
import vn.momo.kits.const.Typography
|
|
46
|
+
import vn.momo.kits.const.scaleSize
|
|
45
47
|
import vn.momo.kits.modifier.setAutomationId
|
|
48
|
+
import vn.momo.kits.navigation.ScaleSizeScope
|
|
46
49
|
|
|
47
50
|
data class InputSizeDetail(
|
|
48
51
|
val borderWidth: Dp,
|
|
@@ -213,20 +216,24 @@ fun Input(
|
|
|
213
216
|
if (disabled) "input_${floatingValue}_disabled" else "input_$floatingValue"
|
|
214
217
|
}
|
|
215
218
|
|
|
219
|
+
val fontSize = scaleSize(16.sp)
|
|
220
|
+
val lineHeight = scaleSize(24.sp)
|
|
221
|
+
|
|
216
222
|
val textStyle = remember(textColor, fontWeight) {
|
|
217
223
|
TextStyle(
|
|
218
224
|
color = textColor,
|
|
219
|
-
fontSize =
|
|
220
|
-
lineHeight =
|
|
225
|
+
fontSize = fontSize,
|
|
226
|
+
lineHeight = lineHeight,
|
|
221
227
|
fontWeight = fontWeight.value
|
|
222
228
|
)
|
|
223
229
|
}
|
|
224
230
|
|
|
225
231
|
val placeholderStyle = remember(placeholderColor, fontWeight) {
|
|
226
232
|
TextStyle(
|
|
227
|
-
fontSize =
|
|
228
|
-
lineHeight =
|
|
229
|
-
fontWeight = fontWeight.value
|
|
233
|
+
fontSize = fontSize,
|
|
234
|
+
lineHeight = lineHeight,
|
|
235
|
+
fontWeight = fontWeight.value,
|
|
236
|
+
textAlign = TextAlign.Center
|
|
230
237
|
)
|
|
231
238
|
}
|
|
232
239
|
|
|
@@ -331,13 +338,17 @@ fun Input(
|
|
|
331
338
|
)
|
|
332
339
|
}
|
|
333
340
|
|
|
334
|
-
Box(Modifier.weight(1f)) {
|
|
341
|
+
Box(Modifier.weight(1f), contentAlignment = Alignment.CenterStart) {
|
|
335
342
|
if (text.value.isEmpty()) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
343
|
+
ScaleSizeScope(
|
|
344
|
+
disableScale = true
|
|
345
|
+
) {
|
|
346
|
+
Text(
|
|
347
|
+
text = placeholder,
|
|
348
|
+
style = placeholderStyle,
|
|
349
|
+
color = placeholderColor
|
|
350
|
+
)
|
|
351
|
+
}
|
|
341
352
|
}
|
|
342
353
|
innerTextField()
|
|
343
354
|
}
|
|
@@ -30,6 +30,7 @@ import androidx.compose.ui.zIndex
|
|
|
30
30
|
import vn.momo.kits.const.AppTheme
|
|
31
31
|
import vn.momo.kits.const.Spacing
|
|
32
32
|
import vn.momo.kits.const.Typography
|
|
33
|
+
import vn.momo.kits.const.scaleSize
|
|
33
34
|
|
|
34
35
|
@Composable
|
|
35
36
|
fun InputDropDown(
|
|
@@ -76,6 +77,9 @@ fun InputDropDown(
|
|
|
76
77
|
|
|
77
78
|
val testId = if (disabled) "input_${floatingValue}_disabled" else "input_$floatingValue"
|
|
78
79
|
|
|
80
|
+
val fontSize = scaleSize(16.sp)
|
|
81
|
+
val lineHeight = scaleSize(24.sp)
|
|
82
|
+
|
|
79
83
|
Column(modifier = Modifier.clickable(enabled = !disabled, onClick = onPress).semantics {
|
|
80
84
|
contentDescription = floatingValue; testTag = testId
|
|
81
85
|
}) {
|
|
@@ -142,8 +146,8 @@ fun InputDropDown(
|
|
|
142
146
|
Text(
|
|
143
147
|
text = value.value.ifEmpty { placeholder },
|
|
144
148
|
style = TextStyle(
|
|
145
|
-
fontSize =
|
|
146
|
-
lineHeight =
|
|
149
|
+
fontSize = fontSize,
|
|
150
|
+
lineHeight = lineHeight
|
|
147
151
|
),
|
|
148
152
|
color = if (value.value.isEmpty()) placeholderColor else textColor
|
|
149
153
|
)
|