@momo-kits/native-kits 0.89.30-beta.7 → 0.89.30-nav.11
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/Components.kt +71 -37
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +31 -7
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +1 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +58 -47
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +6 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PromotionPopup.kt +2 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +30 -56
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +10 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1 -3
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package vn.momo.kits.application
|
|
2
2
|
|
|
3
3
|
import androidx.compose.animation.animateColorAsState
|
|
4
|
+
import androidx.compose.animation.core.animateFloatAsState
|
|
4
5
|
import androidx.compose.foundation.background
|
|
5
6
|
import androidx.compose.foundation.border
|
|
6
7
|
import androidx.compose.foundation.clickable
|
|
@@ -24,6 +25,7 @@ import androidx.compose.runtime.setValue
|
|
|
24
25
|
import androidx.compose.runtime.snapshotFlow
|
|
25
26
|
import androidx.compose.ui.Alignment
|
|
26
27
|
import androidx.compose.ui.Modifier
|
|
28
|
+
import androidx.compose.ui.draw.alpha
|
|
27
29
|
import androidx.compose.ui.geometry.Offset
|
|
28
30
|
import androidx.compose.ui.graphics.Brush
|
|
29
31
|
import androidx.compose.ui.graphics.Color
|
|
@@ -40,6 +42,8 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
|
|
40
42
|
import kotlinx.coroutines.flow.map
|
|
41
43
|
import vn.momo.kits.components.Icon
|
|
42
44
|
import vn.momo.kits.components.Image
|
|
45
|
+
import vn.momo.kits.components.InputSearch
|
|
46
|
+
import vn.momo.kits.components.InputSearchProps
|
|
43
47
|
import vn.momo.kits.components.Options
|
|
44
48
|
import vn.momo.kits.components.Text
|
|
45
49
|
import vn.momo.kits.const.AppStatusBar
|
|
@@ -47,6 +51,7 @@ import vn.momo.kits.const.AppTheme
|
|
|
47
51
|
import vn.momo.kits.const.Colors
|
|
48
52
|
import vn.momo.kits.const.Spacing
|
|
49
53
|
import vn.momo.kits.const.Typography
|
|
54
|
+
import vn.momo.kits.modifier.shadow
|
|
50
55
|
import vn.momo.kits.platform.getStatusBarHeight
|
|
51
56
|
import vn.momo.kits.utils.bottomBorder
|
|
52
57
|
|
|
@@ -62,9 +67,15 @@ data class AnimatedHeader(
|
|
|
62
67
|
|
|
63
68
|
@Composable
|
|
64
69
|
fun HeaderBackground(
|
|
65
|
-
headerType: HeaderType = HeaderType.DEFAULT
|
|
70
|
+
headerType: HeaderType = HeaderType.DEFAULT,
|
|
71
|
+
useShadow: Boolean? = true,
|
|
72
|
+
scrollState: Int
|
|
66
73
|
) {
|
|
67
74
|
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
75
|
+
val opacityAni by animateFloatAsState(
|
|
76
|
+
targetValue = (1 - (scrollState / 200f)).coerceIn(0f, 1f),
|
|
77
|
+
)
|
|
78
|
+
|
|
68
79
|
when (headerType) {
|
|
69
80
|
HeaderType.DEFAULT -> {
|
|
70
81
|
val height = statusBarHeight + 52.dp
|
|
@@ -106,6 +117,7 @@ fun HeaderBackground(
|
|
|
106
117
|
HeaderType.EXTENDED -> {
|
|
107
118
|
Box(
|
|
108
119
|
modifier = Modifier.fillMaxWidth().height(154.dp)
|
|
120
|
+
.alpha(opacityAni)
|
|
109
121
|
.background(
|
|
110
122
|
Brush.linearGradient(
|
|
111
123
|
colors = listOf(
|
|
@@ -116,10 +128,6 @@ fun HeaderBackground(
|
|
|
116
128
|
end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
|
|
117
129
|
)
|
|
118
130
|
)
|
|
119
|
-
.bottomBorder(
|
|
120
|
-
strokeWidth = 1.dp,
|
|
121
|
-
color = AppTheme.current.colors.border.default
|
|
122
|
-
)
|
|
123
131
|
) {
|
|
124
132
|
if (AppTheme.current.assets.headerBackground != null) {
|
|
125
133
|
Image(
|
|
@@ -131,6 +139,17 @@ fun HeaderBackground(
|
|
|
131
139
|
)
|
|
132
140
|
}
|
|
133
141
|
}
|
|
142
|
+
Box(
|
|
143
|
+
modifier = Modifier.fillMaxWidth().height(statusBarHeight + 52.dp)
|
|
144
|
+
.alpha(1 - opacityAni)
|
|
145
|
+
.background(Colors.black_01)
|
|
146
|
+
.then(
|
|
147
|
+
if (useShadow == true) Modifier.shadow() else Modifier.bottomBorder(
|
|
148
|
+
1.dp,
|
|
149
|
+
Colors.black_04
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
)
|
|
134
153
|
}
|
|
135
154
|
|
|
136
155
|
else -> {
|
|
@@ -144,14 +163,18 @@ fun Header(
|
|
|
144
163
|
headerType: HeaderType = HeaderType.DEFAULT,
|
|
145
164
|
titlePosition: TitlePosition,
|
|
146
165
|
title: String,
|
|
166
|
+
isBack: Boolean,
|
|
147
167
|
headerRight: @Composable (() -> Unit)? = null,
|
|
148
|
-
goBack: (() -> Unit)
|
|
168
|
+
goBack: (() -> Unit) = { },
|
|
149
169
|
opacity: Float? = null,
|
|
150
170
|
animatedHeader: AnimatedHeader? = null,
|
|
151
|
-
|
|
171
|
+
useSearchInput: Boolean? = false,
|
|
172
|
+
scrollState: Int = 0,
|
|
173
|
+
inputSearchProps: InputSearchProps?
|
|
152
174
|
) {
|
|
153
175
|
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
154
176
|
val tintIconColor = AppTheme.current.colors.text.default
|
|
177
|
+
val backgroundButton = Colors.black_01.copy(alpha = 0.2f)
|
|
155
178
|
|
|
156
179
|
var colorFraction by remember { mutableStateOf(0f) }
|
|
157
180
|
|
|
@@ -170,7 +193,15 @@ fun Header(
|
|
|
170
193
|
)
|
|
171
194
|
)
|
|
172
195
|
|
|
173
|
-
|
|
196
|
+
val backgroundSearch by animateColorAsState(
|
|
197
|
+
targetValue = animateColor(
|
|
198
|
+
Colors.black_01,
|
|
199
|
+
AppTheme.current.colors.background.default,
|
|
200
|
+
colorFraction
|
|
201
|
+
)
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
if (headerType != HeaderType.NONE) {
|
|
174
205
|
BoxWithConstraints(
|
|
175
206
|
Modifier.height(statusBarHeight + 52.dp)
|
|
176
207
|
.fillMaxWidth()
|
|
@@ -185,19 +216,19 @@ fun Header(
|
|
|
185
216
|
horizontalArrangement = Arrangement.SpaceBetween
|
|
186
217
|
) {
|
|
187
218
|
Box {
|
|
188
|
-
if (
|
|
219
|
+
if (isBack) {
|
|
189
220
|
Box(
|
|
190
221
|
modifier = Modifier
|
|
191
222
|
.size(28.dp)
|
|
192
223
|
.then(
|
|
193
224
|
Modifier.border(
|
|
194
|
-
0.
|
|
195
|
-
Colors.black_20.copy(alpha = 0.
|
|
196
|
-
RoundedCornerShape(
|
|
225
|
+
0.5.dp,
|
|
226
|
+
Colors.black_20.copy(alpha = 0.4f),
|
|
227
|
+
RoundedCornerShape(100)
|
|
197
228
|
)
|
|
198
229
|
)
|
|
199
230
|
.background(
|
|
200
|
-
|
|
231
|
+
backgroundButton,
|
|
201
232
|
RoundedCornerShape(100)
|
|
202
233
|
)
|
|
203
234
|
.clickable(
|
|
@@ -205,23 +236,24 @@ fun Header(
|
|
|
205
236
|
)
|
|
206
237
|
.padding(Spacing.XS)
|
|
207
238
|
.semantics {
|
|
208
|
-
|
|
209
|
-
"btn_navigation_back"
|
|
239
|
+
testTag = "btn_navigation_back"
|
|
210
240
|
},
|
|
211
241
|
contentAlignment = Alignment.Center
|
|
212
242
|
) {
|
|
213
243
|
Icon(
|
|
214
|
-
source = "
|
|
244
|
+
source = "ic_back_ios",
|
|
215
245
|
color = if (animatedHeader !== null) tintIconColorAnim else tintIconColor,
|
|
216
246
|
size = 20.dp,
|
|
217
247
|
)
|
|
218
248
|
}
|
|
219
249
|
}
|
|
220
250
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
251
|
+
if (useSearchInput == false) {
|
|
252
|
+
Box(Modifier.graphicsLayer {
|
|
253
|
+
alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
254
|
+
}) {
|
|
255
|
+
headerRight?.invoke()
|
|
256
|
+
}
|
|
225
257
|
}
|
|
226
258
|
}
|
|
227
259
|
|
|
@@ -232,26 +264,28 @@ fun Header(
|
|
|
232
264
|
.padding(horizontal = Spacing.M),
|
|
233
265
|
verticalAlignment = Alignment.CenterVertically,
|
|
234
266
|
) {
|
|
235
|
-
if (
|
|
267
|
+
if (isBack) {
|
|
236
268
|
Spacer(Modifier.width(40.dp))
|
|
237
269
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
241
|
-
},
|
|
242
|
-
contentAlignment = if (titlePosition == TitlePosition.LEFT) Alignment.TopStart else Alignment.Center
|
|
243
|
-
) {
|
|
244
|
-
HeaderTitle(
|
|
245
|
-
title = title,
|
|
246
|
-
color = if (animatedHeader !== null) tintIconColorAnim else tintIconColor,
|
|
247
|
-
modifier = Modifier.semantics {
|
|
248
|
-
contentDescription = "title_navigation_header"
|
|
249
|
-
testTag = "title_navigation_header"
|
|
250
|
-
}
|
|
251
|
-
)
|
|
270
|
+
if (useSearchInput == true && inputSearchProps != null) {
|
|
271
|
+
InputSearch(inputSearchProps = inputSearchProps.copy(backgroundColor = backgroundSearch))
|
|
252
272
|
}
|
|
253
|
-
|
|
254
|
-
|
|
273
|
+
else{
|
|
274
|
+
Box(
|
|
275
|
+
Modifier.weight(1f).graphicsLayer {
|
|
276
|
+
alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
277
|
+
},
|
|
278
|
+
contentAlignment = if (titlePosition == TitlePosition.LEFT) Alignment.TopStart else Alignment.Center
|
|
279
|
+
) {
|
|
280
|
+
HeaderTitle(
|
|
281
|
+
title = title,
|
|
282
|
+
color = if (animatedHeader !== null) tintIconColorAnim else tintIconColor,
|
|
283
|
+
modifier = Modifier.semantics {
|
|
284
|
+
contentDescription = title
|
|
285
|
+
testTag = "title_navigation_header"
|
|
286
|
+
}
|
|
287
|
+
)
|
|
288
|
+
}
|
|
255
289
|
}
|
|
256
290
|
}
|
|
257
291
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package vn.momo.kits.application
|
|
2
2
|
|
|
3
3
|
import androidx.compose.animation.core.animateFloatAsState
|
|
4
|
+
import androidx.compose.foundation.ScrollState
|
|
4
5
|
import androidx.compose.foundation.background
|
|
5
6
|
import androidx.compose.foundation.gestures.detectTapGestures
|
|
6
7
|
import androidx.compose.foundation.layout.Arrangement
|
|
@@ -24,15 +25,19 @@ import androidx.compose.ui.Modifier
|
|
|
24
25
|
import androidx.compose.ui.graphics.Color
|
|
25
26
|
import androidx.compose.ui.graphics.graphicsLayer
|
|
26
27
|
import androidx.compose.ui.input.pointer.pointerInput
|
|
28
|
+
import androidx.compose.ui.layout.LayoutCoordinates
|
|
29
|
+
import androidx.compose.ui.layout.onGloballyPositioned
|
|
27
30
|
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
|
28
31
|
import androidx.compose.ui.unit.Dp
|
|
29
32
|
import androidx.compose.ui.unit.dp
|
|
30
33
|
import androidx.compose.ui.unit.min
|
|
31
34
|
import androidx.compose.ui.zIndex
|
|
35
|
+
import vn.momo.kits.components.InputSearchProps
|
|
32
36
|
import vn.momo.kits.const.AppStatusBar
|
|
33
37
|
import vn.momo.kits.const.AppTheme
|
|
34
38
|
import vn.momo.kits.const.Colors
|
|
35
39
|
import vn.momo.kits.const.Spacing
|
|
40
|
+
import vn.momo.kits.modifier.conditional
|
|
36
41
|
import vn.momo.kits.modifier.shadow
|
|
37
42
|
import vn.momo.kits.platform.getStatusBarHeight
|
|
38
43
|
|
|
@@ -45,19 +50,25 @@ enum class HeaderType {
|
|
|
45
50
|
@Composable
|
|
46
51
|
fun Screen(
|
|
47
52
|
backgroundColor: Color? = null,
|
|
48
|
-
isBack: Boolean = true,
|
|
53
|
+
isBack: Boolean = true,
|
|
54
|
+
headerType: HeaderType = HeaderType.DEFAULT,
|
|
49
55
|
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
|
|
50
56
|
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
|
|
51
57
|
title: String = "Stack",
|
|
52
58
|
titlePosition: TitlePosition = TitlePosition.LEFT,
|
|
53
|
-
goBack: (() -> Unit)
|
|
59
|
+
goBack: (() -> Unit) = { },
|
|
54
60
|
scrollable: Boolean = true,
|
|
61
|
+
scrollState: ScrollState = rememberScrollState(),
|
|
62
|
+
onContentLayout: ((LayoutCoordinates) -> Unit)? = null,
|
|
55
63
|
useAvoidKeyboard: Boolean = true,
|
|
56
64
|
footer: @Composable (() -> Unit)? = null,
|
|
57
65
|
headerRight: @Composable (() -> Unit)? = null,
|
|
58
66
|
fabProps: FabProps? = null,
|
|
59
67
|
animatedHeader: AnimatedHeader? = null,
|
|
60
68
|
layoutOffset: Dp = 56.dp,
|
|
69
|
+
useShadow: Boolean? = true,
|
|
70
|
+
useSearchInput: Boolean? = false,
|
|
71
|
+
inputSearchProps: InputSearchProps? = null,
|
|
61
72
|
content: @Composable () -> Unit,
|
|
62
73
|
) {
|
|
63
74
|
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
@@ -72,7 +83,6 @@ fun Screen(
|
|
|
72
83
|
|
|
73
84
|
val indicator = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
|
|
74
85
|
val bottomPadding = min(indicator, 21.dp)
|
|
75
|
-
val scrollState = rememberScrollState()
|
|
76
86
|
|
|
77
87
|
val opacity by animateFloatAsState(
|
|
78
88
|
targetValue = ((scrollState.value / 114f)).coerceIn(0f, 1f)
|
|
@@ -87,14 +97,18 @@ fun Screen(
|
|
|
87
97
|
) {
|
|
88
98
|
|
|
89
99
|
if (animatedHeader === null) {
|
|
90
|
-
HeaderBackground(headerType)
|
|
100
|
+
HeaderBackground(headerType = headerType, scrollState = scrollState.value)
|
|
91
101
|
} else {
|
|
92
102
|
Box(
|
|
93
103
|
Modifier.zIndex(5f)
|
|
94
104
|
.background(Color.White.copy(alpha = opacity))
|
|
95
105
|
.graphicsLayer { alpha = opacity }
|
|
96
106
|
) {
|
|
97
|
-
HeaderBackground(
|
|
107
|
+
HeaderBackground(
|
|
108
|
+
headerType = headerType,
|
|
109
|
+
useShadow = useShadow,
|
|
110
|
+
scrollState = scrollState.value
|
|
111
|
+
)
|
|
98
112
|
}
|
|
99
113
|
}
|
|
100
114
|
|
|
@@ -103,9 +117,12 @@ fun Screen(
|
|
|
103
117
|
title = title,
|
|
104
118
|
titlePosition = titlePosition,
|
|
105
119
|
headerRight = headerRight,
|
|
120
|
+
isBack = isBack,
|
|
106
121
|
goBack = goBack,
|
|
107
122
|
opacity = opacity,
|
|
108
123
|
animatedHeader = animatedHeader,
|
|
124
|
+
useSearchInput = useSearchInput,
|
|
125
|
+
inputSearchProps = inputSearchProps,
|
|
109
126
|
scrollState = scrollState.value
|
|
110
127
|
)
|
|
111
128
|
|
|
@@ -121,7 +138,13 @@ fun Screen(
|
|
|
121
138
|
) {
|
|
122
139
|
|
|
123
140
|
Column(
|
|
124
|
-
modifier =
|
|
141
|
+
modifier = Modifier
|
|
142
|
+
.conditional(scrollable) { weight(1f) }
|
|
143
|
+
.padding(bottom = keyboardSize)
|
|
144
|
+
.conditional(onContentLayout != null) {
|
|
145
|
+
onGloballyPositioned(onContentLayout ?: {})
|
|
146
|
+
}
|
|
147
|
+
.conditional(scrollable) { verticalScroll(scrollState) },
|
|
125
148
|
verticalArrangement = verticalArrangement,
|
|
126
149
|
horizontalAlignment = horizontalAlignment
|
|
127
150
|
) {
|
|
@@ -146,7 +169,8 @@ fun Screen(
|
|
|
146
169
|
scrollPosition = fabProps.scrollState?.value ?: scrollState.value,
|
|
147
170
|
onClick = fabProps.onClick,
|
|
148
171
|
containerColor = AppTheme.current.colors.primary,
|
|
149
|
-
bottom = fabProps.bottom
|
|
172
|
+
bottom = fabProps.bottom
|
|
173
|
+
?: if (footer != null) bottomPadding + 76.dp else bottomPadding + 12.dp,
|
|
150
174
|
icon = fabProps.icon,
|
|
151
175
|
iconColor = fabProps.iconColor,
|
|
152
176
|
text = fabProps.label,
|
|
@@ -260,7 +260,7 @@ fun Button(
|
|
|
260
260
|
minWidth = size.value.width
|
|
261
261
|
).height(size.value.height)
|
|
262
262
|
.semantics {
|
|
263
|
-
contentDescription =
|
|
263
|
+
contentDescription = title; testTag = testId
|
|
264
264
|
},
|
|
265
265
|
horizontalArrangement = Arrangement.Center,
|
|
266
266
|
verticalAlignment = Alignment.CenterVertically,
|
|
@@ -204,7 +204,7 @@ fun Input(
|
|
|
204
204
|
val testId = if (disabled) "input_${floatingValue}_disabled" else "input_$floatingValue"
|
|
205
205
|
|
|
206
206
|
Column(modifier = Modifier.semantics {
|
|
207
|
-
contentDescription =
|
|
207
|
+
contentDescription = floatingValue; testTag = testId
|
|
208
208
|
}) {
|
|
209
209
|
BasicTextField(
|
|
210
210
|
enabled = !disabled,
|
|
@@ -17,7 +17,6 @@ import androidx.compose.runtime.MutableState
|
|
|
17
17
|
import androidx.compose.runtime.getValue
|
|
18
18
|
import androidx.compose.runtime.mutableStateOf
|
|
19
19
|
import androidx.compose.runtime.remember
|
|
20
|
-
import androidx.compose.runtime.setValue
|
|
21
20
|
import androidx.compose.ui.Alignment
|
|
22
21
|
import androidx.compose.ui.Modifier
|
|
23
22
|
import androidx.compose.ui.graphics.Color
|
|
@@ -78,7 +77,7 @@ fun InputDropDown(
|
|
|
78
77
|
val testId = if (disabled) "input_${floatingValue}_disabled" else "input_$floatingValue"
|
|
79
78
|
|
|
80
79
|
Column(modifier = Modifier.clickable(enabled = !disabled, onClick = onPress).semantics {
|
|
81
|
-
contentDescription =
|
|
80
|
+
contentDescription = floatingValue; testTag = testId
|
|
82
81
|
}) {
|
|
83
82
|
Box {
|
|
84
83
|
if (floatingValue.isNotEmpty() || floatingIcon.isNotEmpty()) {
|
|
@@ -110,7 +110,7 @@ fun InputMoney(
|
|
|
110
110
|
val testId = if (disabled) "input_${floatingValue}_disabled" else "input_$floatingValue"
|
|
111
111
|
|
|
112
112
|
Column(modifier = Modifier.semantics {
|
|
113
|
-
contentDescription =
|
|
113
|
+
contentDescription = floatingValue; testTag = testId
|
|
114
114
|
}) {
|
|
115
115
|
BasicTextField(
|
|
116
116
|
enabled = !disabled,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
package vn.momo.kits.components
|
|
2
2
|
|
|
3
3
|
import androidx.compose.foundation.background
|
|
4
|
-
import androidx.compose.foundation.border
|
|
5
4
|
import androidx.compose.foundation.clickable
|
|
6
5
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
7
6
|
import androidx.compose.foundation.layout.Arrangement
|
|
@@ -33,13 +32,19 @@ import androidx.compose.ui.text.input.KeyboardType
|
|
|
33
32
|
import androidx.compose.ui.unit.dp
|
|
34
33
|
import androidx.compose.ui.unit.sp
|
|
35
34
|
import vn.momo.kits.const.AppTheme
|
|
35
|
+
import vn.momo.kits.const.Colors
|
|
36
36
|
import vn.momo.kits.const.Radius
|
|
37
37
|
import vn.momo.kits.const.Spacing
|
|
38
38
|
import vn.momo.kits.const.Typography
|
|
39
39
|
import vn.momo.kits.utils.ifTrue
|
|
40
40
|
|
|
41
41
|
@Composable
|
|
42
|
-
fun RenderRightIconSearch(
|
|
42
|
+
fun RenderRightIconSearch(
|
|
43
|
+
loading: Boolean,
|
|
44
|
+
icon: String,
|
|
45
|
+
color: Color,
|
|
46
|
+
onClick: () -> Unit,
|
|
47
|
+
) {
|
|
43
48
|
if (loading) {
|
|
44
49
|
Box(Modifier.padding(horizontal = Spacing.S)) {
|
|
45
50
|
CircularProgressIndicator(
|
|
@@ -68,34 +73,41 @@ fun RenderRightIconSearch(loading: Boolean, icon: String, color: Color, onClick:
|
|
|
68
73
|
}
|
|
69
74
|
}
|
|
70
75
|
|
|
76
|
+
data class InputSearchProps(
|
|
77
|
+
val text: MutableState<String>,
|
|
78
|
+
val buttonText: String = "",
|
|
79
|
+
val showButtonText: Boolean = false,
|
|
80
|
+
val placeholder: String = "",
|
|
81
|
+
val onChangeText: (String) -> Unit = {},
|
|
82
|
+
val onPressButtonText: () -> Unit = {},
|
|
83
|
+
val disabled: Boolean = false,
|
|
84
|
+
val icon: String = "",
|
|
85
|
+
val iconColor: Color = Color(0xff),
|
|
86
|
+
val onRightIconPressed: () -> Unit = {},
|
|
87
|
+
val onFocus: () -> Unit = {},
|
|
88
|
+
val onBlur: () -> Unit = {},
|
|
89
|
+
val loading: Boolean = false,
|
|
90
|
+
val fontWeight: InputFontWeight = InputFontWeight.REGULAR,
|
|
91
|
+
val keyboardType: KeyboardType = KeyboardType.Text,
|
|
92
|
+
val backgroundColor: Color = Colors.black_01,
|
|
93
|
+
)
|
|
94
|
+
|
|
71
95
|
@Composable
|
|
72
96
|
fun InputSearch(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
onChangeText: (String) -> Unit = {},
|
|
79
|
-
onPressButtonText: () -> Unit = {},
|
|
80
|
-
error: String = "",
|
|
81
|
-
disabled: Boolean = false,
|
|
82
|
-
icon: String = "",
|
|
83
|
-
iconColor: Color = AppTheme.current.colors.text.default,
|
|
84
|
-
onRightIconPressed: () -> Unit = {},
|
|
85
|
-
onFocus: () -> Unit = {},
|
|
86
|
-
onBlur: () -> Unit = {},
|
|
87
|
-
loading: Boolean = false,
|
|
88
|
-
fontWeight: InputFontWeight = InputFontWeight.REGULAR,
|
|
89
|
-
keyboardType: KeyboardType = KeyboardType.Text,
|
|
97
|
+
inputSearchProps: InputSearchProps = InputSearchProps(
|
|
98
|
+
text = remember { mutableStateOf("") },
|
|
99
|
+
iconColor = AppTheme.current.colors.text.default
|
|
100
|
+
),
|
|
101
|
+
|
|
90
102
|
) {
|
|
91
103
|
var isFocused by remember { mutableStateOf(false) }
|
|
92
104
|
var isBlurred = false
|
|
93
105
|
val disabledColor = AppTheme.current.colors.text.disable
|
|
94
106
|
var textColor = AppTheme.current.colors.text.default
|
|
95
107
|
var placeholderColor = AppTheme.current.colors.text.hint
|
|
96
|
-
var iconTintColor = iconColor
|
|
108
|
+
var iconTintColor = inputSearchProps.iconColor
|
|
97
109
|
|
|
98
|
-
if (disabled) {
|
|
110
|
+
if (inputSearchProps.disabled) {
|
|
99
111
|
textColor = disabledColor
|
|
100
112
|
placeholderColor = disabledColor
|
|
101
113
|
iconTintColor = disabledColor
|
|
@@ -103,37 +115,31 @@ fun InputSearch(
|
|
|
103
115
|
|
|
104
116
|
Column {
|
|
105
117
|
BasicTextField(
|
|
106
|
-
enabled = !disabled,
|
|
118
|
+
enabled = !inputSearchProps.disabled,
|
|
107
119
|
singleLine = true,
|
|
108
|
-
value = text.value,
|
|
120
|
+
value = inputSearchProps.text.value,
|
|
109
121
|
textStyle = TextStyle(
|
|
110
122
|
color = textColor,
|
|
111
|
-
fontSize =
|
|
112
|
-
lineHeight =
|
|
113
|
-
fontWeight = fontWeight.value
|
|
123
|
+
fontSize = 14.sp,
|
|
124
|
+
lineHeight = 20.sp,
|
|
125
|
+
fontWeight = inputSearchProps.fontWeight.value
|
|
114
126
|
),
|
|
115
|
-
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = keyboardType),
|
|
127
|
+
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = inputSearchProps.keyboardType),
|
|
116
128
|
modifier = Modifier.height(36.dp).onFocusChanged {
|
|
117
129
|
isFocused = it.isFocused
|
|
118
130
|
if (it.isFocused) {
|
|
119
|
-
onFocus()
|
|
131
|
+
inputSearchProps.onFocus()
|
|
120
132
|
}
|
|
121
|
-
if (!it.isFocused && isBlurred) onBlur()
|
|
133
|
+
if (!it.isFocused && isBlurred) inputSearchProps.onBlur()
|
|
122
134
|
if (it.isFocused && !isBlurred) isBlurred = true
|
|
123
135
|
},
|
|
124
|
-
onValueChange = onChangeText,
|
|
136
|
+
onValueChange = inputSearchProps.onChangeText,
|
|
125
137
|
decorationBox = { innerTextField ->
|
|
126
|
-
//input box wrapper
|
|
127
138
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
128
139
|
Row(
|
|
129
|
-
modifier = Modifier.weight(showButtonText.ifTrue(8f, 1f))
|
|
140
|
+
modifier = Modifier.weight(inputSearchProps.showButtonText.ifTrue(8f, 1f))
|
|
130
141
|
.background(
|
|
131
|
-
|
|
132
|
-
RoundedCornerShape(Radius.XL)
|
|
133
|
-
)
|
|
134
|
-
.border(
|
|
135
|
-
showBorder.ifTrue(1.dp, 0.dp),
|
|
136
|
-
getBorderColor(isFocused, error, disabled),
|
|
142
|
+
inputSearchProps.backgroundColor,
|
|
137
143
|
RoundedCornerShape(Radius.XL)
|
|
138
144
|
),
|
|
139
145
|
horizontalArrangement = Arrangement.Start,
|
|
@@ -154,20 +160,20 @@ fun InputSearch(
|
|
|
154
160
|
color = AppTheme.current.colors.text.hint
|
|
155
161
|
)
|
|
156
162
|
Box(Modifier.weight(1f)) {
|
|
157
|
-
if (text.value.isEmpty()) {
|
|
163
|
+
if (inputSearchProps.text.value.isEmpty()) {
|
|
158
164
|
Text(
|
|
159
|
-
text = placeholder,
|
|
165
|
+
text = inputSearchProps.placeholder,
|
|
160
166
|
style = TextStyle(
|
|
161
167
|
fontSize = 16.sp,
|
|
162
168
|
lineHeight = 24.sp,
|
|
163
|
-
fontWeight = fontWeight.value
|
|
169
|
+
fontWeight = inputSearchProps.fontWeight.value
|
|
164
170
|
),
|
|
165
171
|
color = placeholderColor
|
|
166
172
|
)
|
|
167
173
|
}
|
|
168
174
|
innerTextField()
|
|
169
175
|
}
|
|
170
|
-
if (isFocused && text.value.isNotEmpty()) {
|
|
176
|
+
if (isFocused && inputSearchProps.text.value.isNotEmpty()) {
|
|
171
177
|
Row {
|
|
172
178
|
Spacer(Modifier.width(Spacing.XS))
|
|
173
179
|
Icon(
|
|
@@ -175,25 +181,30 @@ fun InputSearch(
|
|
|
175
181
|
size = 16.dp,
|
|
176
182
|
color = AppTheme.current.colors.text.hint,
|
|
177
183
|
modifier = Modifier.clickable(
|
|
178
|
-
onClick = { text.value = "" },
|
|
184
|
+
onClick = { inputSearchProps.text.value = "" },
|
|
179
185
|
interactionSource = remember { MutableInteractionSource() },
|
|
180
186
|
indication = null
|
|
181
187
|
)
|
|
182
188
|
)
|
|
183
189
|
}
|
|
184
190
|
}
|
|
185
|
-
RenderRightIconSearch(
|
|
191
|
+
RenderRightIconSearch(
|
|
192
|
+
inputSearchProps.loading,
|
|
193
|
+
inputSearchProps.icon,
|
|
194
|
+
iconTintColor,
|
|
195
|
+
inputSearchProps.onRightIconPressed
|
|
196
|
+
)
|
|
186
197
|
}
|
|
187
198
|
}
|
|
188
|
-
if (showButtonText) {
|
|
199
|
+
if (inputSearchProps.showButtonText) {
|
|
189
200
|
Text(
|
|
190
|
-
text = buttonText,
|
|
201
|
+
text = inputSearchProps.buttonText,
|
|
191
202
|
style = Typography.actionDefault,
|
|
192
203
|
color = AppTheme.current.colors.text.default,
|
|
193
204
|
modifier = Modifier.padding(start = Spacing.L).clickable(
|
|
194
205
|
interactionSource = remember { MutableInteractionSource() },
|
|
195
206
|
indication = null,
|
|
196
|
-
onClick = onPressButtonText
|
|
207
|
+
onClick = inputSearchProps.onPressButtonText
|
|
197
208
|
)
|
|
198
209
|
)
|
|
199
210
|
}
|
|
@@ -97,7 +97,7 @@ fun PopupNotify(
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
Box(Modifier.semantics {
|
|
100
|
-
contentDescription =
|
|
100
|
+
contentDescription = title; testTag = "popup_notify"
|
|
101
101
|
}, contentAlignment = Alignment.TopEnd) {
|
|
102
102
|
Column(
|
|
103
103
|
modifier = Modifier
|
|
@@ -166,7 +166,7 @@ fun PopupNotify(
|
|
|
166
166
|
color = AppTheme.current.colors.background.surface,
|
|
167
167
|
size = 14.dp,
|
|
168
168
|
modifier = Modifier.semantics {
|
|
169
|
-
|
|
169
|
+
testTag = "ic_popup_close"
|
|
170
170
|
}
|
|
171
171
|
)
|
|
172
172
|
}
|
|
@@ -235,7 +235,7 @@ fun renderRow(
|
|
|
235
235
|
title = it.title,
|
|
236
236
|
type = ButtonType.TEXT,
|
|
237
237
|
modifier = Modifier.semantics {
|
|
238
|
-
contentDescription =
|
|
238
|
+
contentDescription = it.title; testTag = "btn_popup_cancel"
|
|
239
239
|
}
|
|
240
240
|
)
|
|
241
241
|
}
|
|
@@ -250,7 +250,7 @@ fun renderRow(
|
|
|
250
250
|
},
|
|
251
251
|
title = primary?.title ?: "",
|
|
252
252
|
modifier = Modifier.semantics {
|
|
253
|
-
contentDescription = "
|
|
253
|
+
contentDescription = primary?.title ?: ""; testTag = "btn_popup_allow"
|
|
254
254
|
}
|
|
255
255
|
)
|
|
256
256
|
}
|
|
@@ -273,7 +273,7 @@ fun renderColumn(
|
|
|
273
273
|
},
|
|
274
274
|
title = primary?.title ?: "",
|
|
275
275
|
modifier = Modifier.semantics {
|
|
276
|
-
contentDescription = "
|
|
276
|
+
contentDescription = primary?.title ?: ""; testTag = "btn_popup_allow"
|
|
277
277
|
}
|
|
278
278
|
)
|
|
279
279
|
secondary?.let {
|
|
@@ -288,7 +288,7 @@ fun renderColumn(
|
|
|
288
288
|
title = it.title,
|
|
289
289
|
type = ButtonType.TEXT,
|
|
290
290
|
modifier = Modifier.semantics {
|
|
291
|
-
contentDescription =
|
|
291
|
+
contentDescription = it.title; testTag = "btn_popup_cancel"
|
|
292
292
|
}
|
|
293
293
|
)
|
|
294
294
|
}
|
|
@@ -17,7 +17,6 @@ import androidx.compose.runtime.remember
|
|
|
17
17
|
import androidx.compose.ui.Alignment
|
|
18
18
|
import androidx.compose.ui.Modifier
|
|
19
19
|
import androidx.compose.ui.draw.clip
|
|
20
|
-
import androidx.compose.ui.semantics.contentDescription
|
|
21
20
|
import androidx.compose.ui.semantics.semantics
|
|
22
21
|
import androidx.compose.ui.semantics.testTag
|
|
23
22
|
import androidx.compose.ui.unit.dp
|
|
@@ -30,7 +29,7 @@ fun PromotionPopup(
|
|
|
30
29
|
source: String = "",
|
|
31
30
|
onClose: (() -> Unit) = {},
|
|
32
31
|
) {
|
|
33
|
-
Column(Modifier.semantics {
|
|
32
|
+
Column(Modifier.semantics { testTag = "popup_notify" }) {
|
|
34
33
|
if (source.isNotEmpty()) {
|
|
35
34
|
Image(
|
|
36
35
|
source = source,
|
|
@@ -69,7 +68,7 @@ fun PromotionPopup(
|
|
|
69
68
|
color = AppTheme.current.colors.background.surface,
|
|
70
69
|
size = 14.dp,
|
|
71
70
|
modifier = Modifier.semantics {
|
|
72
|
-
|
|
71
|
+
testTag = "ic_popup_close"
|
|
73
72
|
}
|
|
74
73
|
)
|
|
75
74
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
package vn.momo.kits.components
|
|
2
2
|
|
|
3
3
|
import androidx.compose.foundation.background
|
|
4
|
-
import androidx.compose.foundation.border
|
|
5
4
|
import androidx.compose.foundation.clickable
|
|
6
5
|
import androidx.compose.foundation.layout.Arrangement
|
|
7
6
|
import androidx.compose.foundation.layout.Column
|
|
@@ -9,9 +8,7 @@ import androidx.compose.foundation.layout.Row
|
|
|
9
8
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
10
9
|
import androidx.compose.foundation.layout.height
|
|
11
10
|
import androidx.compose.foundation.layout.padding
|
|
12
|
-
import androidx.compose.foundation.layout.size
|
|
13
11
|
import androidx.compose.foundation.layout.width
|
|
14
|
-
import androidx.compose.foundation.shape.CircleShape
|
|
15
12
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
16
13
|
import androidx.compose.material.Text
|
|
17
14
|
import androidx.compose.runtime.Composable
|
|
@@ -29,7 +26,11 @@ val defaultBanner = TrustBannerData(
|
|
|
29
26
|
"vi" to "Bảo mật thông tin & An toàn tài sản của bạn là ưu tiên hàng đầu của MoMo.",
|
|
30
27
|
"en" to "Your data security and money safety are MoMo's top priorities."
|
|
31
28
|
),
|
|
32
|
-
|
|
29
|
+
subContent = mapOf(
|
|
30
|
+
"vi" to "Tìm hiểu thêm",
|
|
31
|
+
"en" to "Learn more"
|
|
32
|
+
),
|
|
33
|
+
pciImage = "https://static.momocdn.net/app/img/kits/trustBanner/pci_dss.png",
|
|
33
34
|
sslImage = "https://static.momocdn.net/app/img/kits/trustBanner/ssl.png",
|
|
34
35
|
urlConfig = "login_and_security",
|
|
35
36
|
icons = listOf(
|
|
@@ -38,40 +39,23 @@ val defaultBanner = TrustBannerData(
|
|
|
38
39
|
"https://static.momocdn.net/app/img/kits/trustBanner/ic_vietcombank.png",
|
|
39
40
|
"https://static.momocdn.net/app/img/kits/trustBanner/ic_bidv.png"
|
|
40
41
|
),
|
|
41
|
-
momoImage = "https://static.momocdn.net/app/img/kits/trustBanner/
|
|
42
|
+
momoImage = "https://static.momocdn.net/app/img/kits/trustBanner/ic_secu.png"
|
|
42
43
|
)
|
|
43
44
|
|
|
44
|
-
const val borderColor = 0xFFE8E8E8
|
|
45
|
-
const val tonalColor = 0xFFFDEAF4
|
|
46
45
|
const val backgroundBlue = 0xFFF2F8FF
|
|
47
46
|
const val contentColor = 0xFF484848
|
|
48
|
-
const val
|
|
49
|
-
|
|
50
|
-
data class TrustBannerClass(
|
|
51
|
-
val trustBanner: TrustBannerData
|
|
52
|
-
)
|
|
47
|
+
const val subContentColor = 0xFFEB2F96
|
|
53
48
|
|
|
54
49
|
data class TrustBannerData(
|
|
55
50
|
val content: Map<String, String>,
|
|
51
|
+
val subContent: Map<String, String>,
|
|
56
52
|
val pciImage: String,
|
|
53
|
+
val momoImage: String,
|
|
57
54
|
val sslImage: String,
|
|
58
55
|
val icons: List<String>,
|
|
59
|
-
val momoImage: String,
|
|
60
56
|
val urlConfig: String
|
|
61
57
|
)
|
|
62
58
|
|
|
63
|
-
@Composable
|
|
64
|
-
fun Avatar(iconURL: String) {
|
|
65
|
-
Image(
|
|
66
|
-
source = iconURL,
|
|
67
|
-
modifier = Modifier
|
|
68
|
-
.size(24.dp)
|
|
69
|
-
.background(Color.White, CircleShape)
|
|
70
|
-
.border(width = 1.dp, color = Color(borderColor), CircleShape),
|
|
71
|
-
options = Options(contentScale = ContentScale.Fit)
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
59
|
@Composable
|
|
76
60
|
fun TrustBanner(
|
|
77
61
|
trustBanner: TrustBannerData = defaultBanner,
|
|
@@ -80,6 +64,7 @@ fun TrustBanner(
|
|
|
80
64
|
onPress: ((Map<String, String>) -> Unit)? = null,
|
|
81
65
|
trackEvent: ((String, Map<String, String>) -> Unit)? = null,
|
|
82
66
|
language: String = "vi"
|
|
67
|
+
|
|
83
68
|
) {
|
|
84
69
|
val trackParams = mapOf(
|
|
85
70
|
"service_name" to serviceName,
|
|
@@ -123,12 +108,11 @@ fun TrustBanner(
|
|
|
123
108
|
modifier = Modifier
|
|
124
109
|
.width(64.dp)
|
|
125
110
|
.height(64.dp)
|
|
126
|
-
.padding(end = 8.dp),
|
|
127
|
-
options = Options(
|
|
128
|
-
contentScale = ContentScale.Fit,
|
|
129
|
-
)
|
|
130
111
|
)
|
|
131
|
-
Column
|
|
112
|
+
Column (
|
|
113
|
+
modifier = Modifier
|
|
114
|
+
.padding(start = 10.dp)
|
|
115
|
+
) {
|
|
132
116
|
Text(
|
|
133
117
|
text = trustBanner.content[language] ?: "",
|
|
134
118
|
modifier = Modifier.padding(bottom = 8.dp),
|
|
@@ -138,11 +122,26 @@ fun TrustBanner(
|
|
|
138
122
|
maxLines = 2
|
|
139
123
|
)
|
|
140
124
|
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
|
125
|
+
Row (
|
|
126
|
+
verticalAlignment = Alignment.CenterVertically,
|
|
127
|
+
) {
|
|
128
|
+
Text(
|
|
129
|
+
text = trustBanner.subContent[language] ?: "",
|
|
130
|
+
lineHeight = 16.sp,
|
|
131
|
+
fontSize = 12.sp,
|
|
132
|
+
color = Color(subContentColor),
|
|
133
|
+
maxLines = 2
|
|
134
|
+
)
|
|
135
|
+
Icon(
|
|
136
|
+
source = "https://img.mservice.io/momo_app_v2/new_version/img/appx_icon/16_arrow_chevron_right_small.png",
|
|
137
|
+
color = Color(subContentColor),
|
|
138
|
+
)
|
|
139
|
+
}
|
|
141
140
|
Row {
|
|
142
141
|
Image(
|
|
143
142
|
source = trustBanner.pciImage, modifier = Modifier
|
|
144
143
|
.padding(end = 4.dp)
|
|
145
|
-
.width(
|
|
144
|
+
.width(27.dp)
|
|
146
145
|
.height(20.dp)
|
|
147
146
|
,options = Options(
|
|
148
147
|
contentScale = ContentScale.Fit,
|
|
@@ -157,31 +156,6 @@ fun TrustBanner(
|
|
|
157
156
|
)
|
|
158
157
|
)
|
|
159
158
|
}
|
|
160
|
-
Row(
|
|
161
|
-
modifier = Modifier
|
|
162
|
-
.width(96.dp)
|
|
163
|
-
.height(24.dp),
|
|
164
|
-
horizontalArrangement = Arrangement.spacedBy((-6).dp)
|
|
165
|
-
) {
|
|
166
|
-
trustBanner.icons.forEach { iconURL ->
|
|
167
|
-
Avatar(iconURL = iconURL)
|
|
168
|
-
}
|
|
169
|
-
Row(
|
|
170
|
-
modifier = Modifier
|
|
171
|
-
.size(24.dp)
|
|
172
|
-
.background(color = Color(tonalColor), CircleShape)
|
|
173
|
-
.border(width = 1.dp, color = Color(borderColor), CircleShape),
|
|
174
|
-
verticalAlignment = Alignment.CenterVertically,
|
|
175
|
-
horizontalArrangement = Arrangement.Center
|
|
176
|
-
) {
|
|
177
|
-
Text(
|
|
178
|
-
text = "36+",
|
|
179
|
-
color = Color(primaryColor),
|
|
180
|
-
lineHeight = 14.sp,
|
|
181
|
-
fontSize = 10.sp
|
|
182
|
-
)
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
159
|
}
|
|
186
160
|
}
|
|
187
161
|
}
|
|
@@ -58,6 +58,16 @@ fun getFontFamily(fontFamily: String, fontWeight: FontWeight? = FontWeight.Norma
|
|
|
58
58
|
"MoMoSignature-700" to "momosignature.otf",
|
|
59
59
|
"MoMoSignature-800" to "momosignature.otf",
|
|
60
60
|
"MoMoSignature-900" to "momosignature.otf",
|
|
61
|
+
|
|
62
|
+
"MoMoTrustDisplay-100" to "momotrustdisplay.otf",
|
|
63
|
+
"MoMoTrustDisplay-200" to "momotrustdisplay.otf",
|
|
64
|
+
"MoMoTrustDisplay-300" to "momotrustdisplay.otf",
|
|
65
|
+
"MoMoTrustDisplay-400" to "momotrustdisplay.otf",
|
|
66
|
+
"MoMoTrustDisplay-500" to "momotrustdisplay.otf",
|
|
67
|
+
"MoMoTrustDisplay-600" to "momotrustdisplay.otf",
|
|
68
|
+
"MoMoTrustDisplay-700" to "momotrustdisplay.otf",
|
|
69
|
+
"MoMoTrustDisplay-800" to "momotrustdisplay.otf",
|
|
70
|
+
"MoMoTrustDisplay-900" to "momotrustdisplay.otf",
|
|
61
71
|
)
|
|
62
72
|
val font = fontMap[key] ?: "sfprotext_regular.ttf"
|
|
63
73
|
return getFont(font)
|
|
@@ -1317,7 +1317,5 @@ val Icons = mapOf(
|
|
|
1317
1317
|
"ic_checked" to "https://img.mservice.com.vn/app/img/kits/checked_ic.png",
|
|
1318
1318
|
"ic_minus" to "https://img.mservice.com.vn/app/img/kits/minus.png",
|
|
1319
1319
|
"ic_navigation" to "https://static.momocdn.net/app/img/kits/ic_navigation.png",
|
|
1320
|
-
"ic_money_bag" to "https://static.momocdn.net/app/img/kits/ic_money_bag.png"
|
|
1321
|
-
"help_center" to "https://static.momocdn.net/app/img/kits/ic_money_bag_2.png",
|
|
1322
|
-
"arrow_back" to "https://static.momocdn.net/app/img/kits/arrow-back.png",
|
|
1320
|
+
"ic_money_bag" to "https://static.momocdn.net/app/img/kits/ic_money_bag.png"
|
|
1323
1321
|
)
|