@momo-kits/native-kits 0.151.2-test.15 → 0.151.2-test.16
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/components/Chip.kt +1 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +8 -7
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +3 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +385 -0
- package/package.json +1 -1
|
@@ -128,14 +128,16 @@ fun RowScope.HeaderContent(headerTitle: HeaderTitle, tintIconColor: Color){
|
|
|
128
128
|
is HeaderTitle.Default -> {
|
|
129
129
|
HeaderTitle(
|
|
130
130
|
title = headerTitle.title,
|
|
131
|
-
color = tintIconColor
|
|
132
|
-
modifier = Modifier.fillMaxWidth(),
|
|
133
|
-
textAlign = TextAlign.Start
|
|
131
|
+
color = tintIconColor
|
|
134
132
|
)
|
|
135
133
|
}
|
|
136
134
|
is HeaderTitle.Journey -> {}
|
|
137
135
|
is HeaderTitle.Location -> {}
|
|
138
|
-
is HeaderTitle.User -> {
|
|
136
|
+
is HeaderTitle.User -> {
|
|
137
|
+
HeaderUser(
|
|
138
|
+
data = headerTitle
|
|
139
|
+
)
|
|
140
|
+
}
|
|
139
141
|
}
|
|
140
142
|
}
|
|
141
143
|
}
|
|
@@ -163,9 +165,8 @@ sealed class HeaderTitle {
|
|
|
163
165
|
val title: String,
|
|
164
166
|
val subTitle: String? = null,
|
|
165
167
|
val image: List<String>? = null,
|
|
166
|
-
val dotColor:
|
|
167
|
-
val
|
|
168
|
-
val tintColor: String? = null,
|
|
168
|
+
val dotColor: Color? = null,
|
|
169
|
+
val tintColor: Color? = null,
|
|
169
170
|
val onPress: (() -> Unit)? = null,
|
|
170
171
|
val icons: List<String> = emptyList(),
|
|
171
172
|
val isLoading: Boolean = false
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package vn.momo.kits.navigation.component
|
|
2
2
|
|
|
3
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
3
4
|
import androidx.compose.runtime.Composable
|
|
4
5
|
import androidx.compose.ui.Modifier
|
|
5
6
|
import androidx.compose.ui.graphics.Color
|
|
@@ -13,14 +14,12 @@ import vn.momo.kits.const.Typography
|
|
|
13
14
|
@Composable
|
|
14
15
|
fun HeaderTitle(
|
|
15
16
|
title: String = "",
|
|
16
|
-
modifier: Modifier = Modifier,
|
|
17
|
-
textAlign: TextAlign = TextAlign.Start,
|
|
18
17
|
color: Color? = null,
|
|
19
18
|
) {
|
|
20
19
|
Text(
|
|
21
|
-
modifier = Modifier.
|
|
20
|
+
modifier = Modifier.fillMaxWidth().zIndex(1f),
|
|
22
21
|
text = title,
|
|
23
|
-
textAlign =
|
|
22
|
+
textAlign = TextAlign.Start,
|
|
24
23
|
style = Typography.actionSBold.copy(
|
|
25
24
|
fontSize = 15.sp,
|
|
26
25
|
lineHeight = 22.sp,
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
package vn.momo.kits.navigation.component
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.background
|
|
4
|
+
import androidx.compose.foundation.border
|
|
5
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
6
|
+
import androidx.compose.foundation.layout.Box
|
|
7
|
+
import androidx.compose.foundation.layout.Column
|
|
8
|
+
import androidx.compose.foundation.layout.Row
|
|
9
|
+
import androidx.compose.foundation.layout.Spacer
|
|
10
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
11
|
+
import androidx.compose.foundation.layout.height
|
|
12
|
+
import androidx.compose.foundation.layout.padding
|
|
13
|
+
import androidx.compose.foundation.layout.size
|
|
14
|
+
import androidx.compose.foundation.layout.width
|
|
15
|
+
import androidx.compose.foundation.layout.widthIn
|
|
16
|
+
import androidx.compose.foundation.shape.CircleShape
|
|
17
|
+
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
18
|
+
import androidx.compose.runtime.Composable
|
|
19
|
+
import androidx.compose.runtime.Immutable
|
|
20
|
+
import androidx.compose.runtime.remember
|
|
21
|
+
import androidx.compose.ui.Alignment
|
|
22
|
+
import androidx.compose.ui.Modifier
|
|
23
|
+
import androidx.compose.ui.draw.clip
|
|
24
|
+
import androidx.compose.ui.draw.clipToBounds
|
|
25
|
+
import androidx.compose.ui.layout.ContentScale
|
|
26
|
+
import androidx.compose.ui.text.style.TextOverflow
|
|
27
|
+
import androidx.compose.ui.unit.Dp
|
|
28
|
+
import androidx.compose.ui.unit.dp
|
|
29
|
+
import androidx.compose.ui.unit.sp
|
|
30
|
+
import vn.momo.kits.components.Image
|
|
31
|
+
import vn.momo.kits.components.Options
|
|
32
|
+
import vn.momo.kits.components.Skeleton
|
|
33
|
+
import vn.momo.kits.components.Text
|
|
34
|
+
import vn.momo.kits.const.AppTheme
|
|
35
|
+
import vn.momo.kits.const.Colors
|
|
36
|
+
import vn.momo.kits.const.Spacing
|
|
37
|
+
import vn.momo.kits.const.Typography
|
|
38
|
+
import vn.momo.kits.const.scaleSize
|
|
39
|
+
import vn.momo.kits.modifier.activeOpacityClickable
|
|
40
|
+
import vn.momo.kits.navigation.component.HeaderTitle.User
|
|
41
|
+
import vn.momo.kits.platform.getScreenDimensions
|
|
42
|
+
|
|
43
|
+
@Composable
|
|
44
|
+
fun HeaderUser(
|
|
45
|
+
data: HeaderTitle
|
|
46
|
+
) {
|
|
47
|
+
if (data !is User) return
|
|
48
|
+
|
|
49
|
+
if (data.isLoading) {
|
|
50
|
+
return TitleUserShimmer()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
val maxWidth = getScreenDimensions().width.dp - scaleSize(172.dp)- (data.icons.size * 16).dp
|
|
54
|
+
|
|
55
|
+
Row(
|
|
56
|
+
modifier = Modifier
|
|
57
|
+
.fillMaxWidth()
|
|
58
|
+
.padding(vertical = Spacing.XS)
|
|
59
|
+
.activeOpacityClickable(enabled = data.onPress != null, onClick = { data.onPress?.invoke() }),
|
|
60
|
+
horizontalArrangement = Arrangement.SpaceBetween,
|
|
61
|
+
verticalAlignment = Alignment.CenterVertically
|
|
62
|
+
) {
|
|
63
|
+
Row(
|
|
64
|
+
modifier = Modifier.widthIn(max = maxWidth),
|
|
65
|
+
verticalAlignment = Alignment.CenterVertically
|
|
66
|
+
) {
|
|
67
|
+
Box(modifier = Modifier.size(Spacing.XXL)) {
|
|
68
|
+
AvatarGroup(urls = AvatarUrls(data.image ?: listOf()), title = data.title)
|
|
69
|
+
if (data.dotColor != null) {
|
|
70
|
+
Box(
|
|
71
|
+
modifier = Modifier
|
|
72
|
+
.align(Alignment.BottomEnd)
|
|
73
|
+
.size(10.dp)
|
|
74
|
+
.clip(CircleShape)
|
|
75
|
+
.background(data.dotColor)
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
Spacer(Modifier.width(6.dp))
|
|
81
|
+
|
|
82
|
+
Column(modifier = Modifier.weight(1f, fill = false)) {
|
|
83
|
+
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
84
|
+
Text(
|
|
85
|
+
text = data.title,
|
|
86
|
+
color = data.tintColor,
|
|
87
|
+
style = Typography.actionXsBold,
|
|
88
|
+
maxLines = 1,
|
|
89
|
+
overflow = TextOverflow.Ellipsis
|
|
90
|
+
)
|
|
91
|
+
if (data.icons.isNotEmpty()) {
|
|
92
|
+
Spacer(Modifier.width(6.dp))
|
|
93
|
+
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
94
|
+
data.icons.forEach { icon ->
|
|
95
|
+
RemoteIcon16(url = icon)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!data.subTitle.isNullOrEmpty()) {
|
|
102
|
+
Spacer(Modifier.height(2.dp))
|
|
103
|
+
Text(
|
|
104
|
+
text = data.subTitle,
|
|
105
|
+
color = data.tintColor,
|
|
106
|
+
style = Typography.descriptionXsRegular,
|
|
107
|
+
maxLines = 1,
|
|
108
|
+
overflow = TextOverflow.Ellipsis
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@Composable
|
|
117
|
+
private fun TitleUserShimmer() {
|
|
118
|
+
val theme = AppTheme.current
|
|
119
|
+
Row(
|
|
120
|
+
modifier = Modifier
|
|
121
|
+
.fillMaxWidth()
|
|
122
|
+
.padding(vertical = Spacing.XS),
|
|
123
|
+
verticalAlignment = Alignment.CenterVertically
|
|
124
|
+
) {
|
|
125
|
+
Box(
|
|
126
|
+
modifier = Modifier
|
|
127
|
+
.size(Spacing.XXL)
|
|
128
|
+
.clip(CircleShape)
|
|
129
|
+
.background(theme.colors.border.default)
|
|
130
|
+
) {
|
|
131
|
+
Skeleton()
|
|
132
|
+
}
|
|
133
|
+
Spacer(Modifier.width(Spacing.M / 2))
|
|
134
|
+
Column(modifier = Modifier.fillMaxWidth()) {
|
|
135
|
+
Box(
|
|
136
|
+
modifier = Modifier
|
|
137
|
+
.height(18.dp)
|
|
138
|
+
.width(120.dp)
|
|
139
|
+
.clip(RoundedCornerShape(8.dp))
|
|
140
|
+
) { Skeleton() }
|
|
141
|
+
Spacer(Modifier.height(Spacing.XXS))
|
|
142
|
+
Box(
|
|
143
|
+
modifier = Modifier
|
|
144
|
+
.height(12.dp)
|
|
145
|
+
.width(120.dp)
|
|
146
|
+
.clip(RoundedCornerShape(8.dp))
|
|
147
|
+
) { Skeleton() }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@Composable
|
|
153
|
+
private fun AvatarGroup(
|
|
154
|
+
urls: AvatarUrls?,
|
|
155
|
+
title: String? = null,
|
|
156
|
+
size: Dp = Spacing.XXL
|
|
157
|
+
) {
|
|
158
|
+
val theme = AppTheme.current
|
|
159
|
+
val modifierBorder = remember {
|
|
160
|
+
Modifier.clip(CircleShape).border(width = (0.5).dp, color = theme.colors.border.default, shape = CircleShape)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
when (urls?.items?.size) {
|
|
164
|
+
0 -> InitialsAvatar(
|
|
165
|
+
modifier = modifierBorder,
|
|
166
|
+
name = title ?: "",
|
|
167
|
+
fallbackInitials = null,
|
|
168
|
+
size = size
|
|
169
|
+
)
|
|
170
|
+
1 -> SingleAvatar(modifier = modifierBorder, urls.items[0], size)
|
|
171
|
+
2 -> TwoAvatar(modifier = modifierBorder, urls, size)
|
|
172
|
+
3 -> ThreeAvatar(modifier = modifierBorder, urls, size)
|
|
173
|
+
4 -> FourAvatar(modifier = modifierBorder, urls, size)
|
|
174
|
+
else -> ManyAvatar(modifier = modifierBorder, urls!!, size)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@Composable
|
|
179
|
+
private fun SingleAvatar(modifier: Modifier = Modifier, url: String, size: Dp) {
|
|
180
|
+
Image(
|
|
181
|
+
source = url,
|
|
182
|
+
options = Options(
|
|
183
|
+
contentScale = ContentScale.Crop
|
|
184
|
+
),
|
|
185
|
+
modifier = modifier
|
|
186
|
+
.size(size)
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@Composable
|
|
191
|
+
private fun TwoAvatar(modifier: Modifier = Modifier, urls: AvatarUrls, size: Dp) {
|
|
192
|
+
val child = 24.dp
|
|
193
|
+
Box(modifier = Modifier.size(size)) {
|
|
194
|
+
Image(
|
|
195
|
+
source = urls.items[0],
|
|
196
|
+
options = Options(
|
|
197
|
+
contentScale = ContentScale.Crop
|
|
198
|
+
),
|
|
199
|
+
modifier = modifier
|
|
200
|
+
.size(child)
|
|
201
|
+
.align(Alignment.TopEnd)
|
|
202
|
+
)
|
|
203
|
+
Image(
|
|
204
|
+
source = urls.items[1],
|
|
205
|
+
options = Options(
|
|
206
|
+
contentScale = ContentScale.Crop
|
|
207
|
+
),
|
|
208
|
+
modifier = modifier
|
|
209
|
+
.size(child)
|
|
210
|
+
.align(Alignment.BottomStart)
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@Composable
|
|
216
|
+
private fun ThreeAvatar(modifier: Modifier = Modifier, urls: AvatarUrls, size: Dp) {
|
|
217
|
+
val child = 16.dp
|
|
218
|
+
Box(modifier = Modifier.size(size).padding(2.dp)) {
|
|
219
|
+
Image(
|
|
220
|
+
source = urls.items[0],
|
|
221
|
+
options = Options(
|
|
222
|
+
contentScale = ContentScale.Crop
|
|
223
|
+
),
|
|
224
|
+
modifier = modifier
|
|
225
|
+
.size(child)
|
|
226
|
+
.align(Alignment.BottomEnd)
|
|
227
|
+
)
|
|
228
|
+
Image(
|
|
229
|
+
source = urls.items[1],
|
|
230
|
+
options = Options(
|
|
231
|
+
contentScale = ContentScale.Crop
|
|
232
|
+
),
|
|
233
|
+
modifier = modifier
|
|
234
|
+
.size(child)
|
|
235
|
+
.align(Alignment.TopCenter)
|
|
236
|
+
)
|
|
237
|
+
Image(
|
|
238
|
+
source = urls.items[2],
|
|
239
|
+
options = Options(
|
|
240
|
+
contentScale = ContentScale.Crop
|
|
241
|
+
),
|
|
242
|
+
modifier = modifier
|
|
243
|
+
.size(child)
|
|
244
|
+
.align(Alignment.BottomStart)
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
@Composable
|
|
250
|
+
private fun FourAvatar(modifier: Modifier = Modifier, urls: AvatarUrls, size: Dp) {
|
|
251
|
+
val child = 16.dp
|
|
252
|
+
Box(modifier = Modifier.size(size).padding(1.dp)) {
|
|
253
|
+
Image(
|
|
254
|
+
source = urls.items[0],
|
|
255
|
+
options = Options(
|
|
256
|
+
contentScale = ContentScale.Crop
|
|
257
|
+
),
|
|
258
|
+
modifier = modifier
|
|
259
|
+
.size(child)
|
|
260
|
+
.align(Alignment.BottomStart)
|
|
261
|
+
)
|
|
262
|
+
Image(
|
|
263
|
+
source = urls.items[1],
|
|
264
|
+
options = Options(
|
|
265
|
+
contentScale = ContentScale.Crop
|
|
266
|
+
),
|
|
267
|
+
modifier = modifier
|
|
268
|
+
.size(child)
|
|
269
|
+
.align(Alignment.BottomEnd)
|
|
270
|
+
)
|
|
271
|
+
Image(
|
|
272
|
+
source = urls.items[2],
|
|
273
|
+
options = Options(
|
|
274
|
+
contentScale = ContentScale.Crop
|
|
275
|
+
),
|
|
276
|
+
modifier = modifier
|
|
277
|
+
.size(child)
|
|
278
|
+
.align(Alignment.TopEnd)
|
|
279
|
+
)
|
|
280
|
+
Image(
|
|
281
|
+
source = urls.items[3],
|
|
282
|
+
options = Options(
|
|
283
|
+
contentScale = ContentScale.Crop
|
|
284
|
+
),
|
|
285
|
+
modifier = modifier
|
|
286
|
+
.size(child)
|
|
287
|
+
.align(Alignment.TopStart)
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
@Composable
|
|
293
|
+
private fun ManyAvatar(modifier: Modifier = Modifier, urls: AvatarUrls, size: Dp) {
|
|
294
|
+
val child = 16.dp
|
|
295
|
+
val more = urls.items.size - 3
|
|
296
|
+
Box(modifier = Modifier.size(size).padding(1.dp)) {
|
|
297
|
+
Image(
|
|
298
|
+
source = urls.items[0],
|
|
299
|
+
options = Options(
|
|
300
|
+
contentScale = ContentScale.Crop
|
|
301
|
+
),
|
|
302
|
+
modifier = modifier
|
|
303
|
+
.size(child)
|
|
304
|
+
.align(Alignment.BottomStart)
|
|
305
|
+
)
|
|
306
|
+
Image(
|
|
307
|
+
source = urls.items[1],
|
|
308
|
+
options = Options(
|
|
309
|
+
contentScale = ContentScale.Crop
|
|
310
|
+
),
|
|
311
|
+
modifier = modifier
|
|
312
|
+
.size(child)
|
|
313
|
+
.align(Alignment.TopEnd)
|
|
314
|
+
)
|
|
315
|
+
Image(
|
|
316
|
+
source = urls.items[2],
|
|
317
|
+
options = Options(
|
|
318
|
+
contentScale = ContentScale.Crop
|
|
319
|
+
),
|
|
320
|
+
modifier = modifier
|
|
321
|
+
.size(child)
|
|
322
|
+
.align(Alignment.TopStart)
|
|
323
|
+
)
|
|
324
|
+
Box(
|
|
325
|
+
modifier = modifier
|
|
326
|
+
.size(child)
|
|
327
|
+
.align(Alignment.BottomEnd)
|
|
328
|
+
.background(Colors.pink_09)
|
|
329
|
+
.padding(1.dp)
|
|
330
|
+
.clipToBounds(),
|
|
331
|
+
contentAlignment = Alignment.Center
|
|
332
|
+
) {
|
|
333
|
+
Text(
|
|
334
|
+
text = "+$more",
|
|
335
|
+
color = Colors.pink_03,
|
|
336
|
+
style = Typography.descriptionXsRegular.copy(fontSize = 8.sp),
|
|
337
|
+
maxLines = 1,
|
|
338
|
+
overflow = TextOverflow.Visible
|
|
339
|
+
)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
@Composable
|
|
345
|
+
private fun InitialsAvatar(
|
|
346
|
+
modifier: Modifier = Modifier,
|
|
347
|
+
name: String,
|
|
348
|
+
fallbackInitials: String? = null,
|
|
349
|
+
size: Dp = Spacing.XXL
|
|
350
|
+
) {
|
|
351
|
+
val initials = remember(name, fallbackInitials) {
|
|
352
|
+
fallbackInitials ?: run {
|
|
353
|
+
val words = name.trim().split(Regex("\\s+")).takeLast(2)
|
|
354
|
+
words.joinToString("") { it.firstOrNull()?.uppercase() ?: "" }
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
Box(
|
|
358
|
+
modifier = modifier
|
|
359
|
+
.size(size)
|
|
360
|
+
.background(Colors.pink_09),
|
|
361
|
+
contentAlignment = Alignment.Center
|
|
362
|
+
) {
|
|
363
|
+
Text(
|
|
364
|
+
text = initials,
|
|
365
|
+
color = Colors.pink_03,
|
|
366
|
+
style = Typography.descriptionXsRegular
|
|
367
|
+
)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
@Composable
|
|
372
|
+
private fun RemoteIcon16(url: String) {
|
|
373
|
+
Image(
|
|
374
|
+
source = url,
|
|
375
|
+
options = Options(
|
|
376
|
+
contentScale = ContentScale.Crop
|
|
377
|
+
),
|
|
378
|
+
modifier = Modifier
|
|
379
|
+
.size(16.dp)
|
|
380
|
+
.clip(RoundedCornerShape(4.dp)),
|
|
381
|
+
)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
@Immutable
|
|
385
|
+
data class AvatarUrls(val items: List<String>)
|