@momo-kits/native-kits 0.89.30 → 0.89.31-beta.22
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/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +10 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Components.kt +127 -71
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +30 -20
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +10 -10
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +8 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +1 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +8 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +8 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +7 -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 +11 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +3 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +33 -22
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +4 -1
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +6 -0
- package/local.properties +2 -2
- package/package.json +1 -1
|
@@ -3,9 +3,12 @@ package vn.momo.kits.platform
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.res.Resources
|
|
5
5
|
import android.graphics.BlurMaskFilter
|
|
6
|
+
import androidx.compose.foundation.layout.WindowInsets
|
|
7
|
+
import androidx.compose.foundation.layout.navigationBars
|
|
6
8
|
import androidx.compose.runtime.Composable
|
|
7
9
|
import androidx.compose.ui.graphics.NativePaint
|
|
8
10
|
import androidx.compose.ui.platform.LocalConfiguration
|
|
11
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
9
12
|
import androidx.compose.ui.unit.Dp
|
|
10
13
|
import androidx.compose.ui.unit.dp
|
|
11
14
|
|
|
@@ -34,4 +37,11 @@ actual fun getStatusBarHeight(): Dp {
|
|
|
34
37
|
"android"
|
|
35
38
|
)
|
|
36
39
|
return if(resourceId > 0) Resources.getSystem().getDimensionPixelSize(resourceId).dp else 0.dp
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@Composable
|
|
43
|
+
actual fun getNavigationBarHeight(): Dp {
|
|
44
|
+
val density = LocalDensity.current
|
|
45
|
+
val navigationBarHeight = WindowInsets.navigationBars.getBottom(density)
|
|
46
|
+
return navigationBarHeight.dp
|
|
37
47
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
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
|
|
7
|
-
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
8
8
|
import androidx.compose.foundation.layout.Arrangement
|
|
9
9
|
import androidx.compose.foundation.layout.Box
|
|
10
10
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
|
@@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.padding
|
|
|
16
16
|
import androidx.compose.foundation.layout.size
|
|
17
17
|
import androidx.compose.foundation.layout.width
|
|
18
18
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
19
|
-
import androidx.compose.material.ripple.rememberRipple
|
|
20
19
|
import androidx.compose.runtime.Composable
|
|
21
20
|
import androidx.compose.runtime.LaunchedEffect
|
|
22
21
|
import androidx.compose.runtime.getValue
|
|
@@ -26,9 +25,13 @@ import androidx.compose.runtime.setValue
|
|
|
26
25
|
import androidx.compose.runtime.snapshotFlow
|
|
27
26
|
import androidx.compose.ui.Alignment
|
|
28
27
|
import androidx.compose.ui.Modifier
|
|
28
|
+
import androidx.compose.ui.draw.alpha
|
|
29
|
+
import androidx.compose.ui.geometry.Offset
|
|
30
|
+
import androidx.compose.ui.graphics.Brush
|
|
29
31
|
import androidx.compose.ui.graphics.Color
|
|
30
32
|
import androidx.compose.ui.graphics.graphicsLayer
|
|
31
33
|
import androidx.compose.ui.layout.ContentScale
|
|
34
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
32
35
|
import androidx.compose.ui.semantics.contentDescription
|
|
33
36
|
import androidx.compose.ui.semantics.semantics
|
|
34
37
|
import androidx.compose.ui.semantics.testTag
|
|
@@ -39,6 +42,8 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
|
|
39
42
|
import kotlinx.coroutines.flow.map
|
|
40
43
|
import vn.momo.kits.components.Icon
|
|
41
44
|
import vn.momo.kits.components.Image
|
|
45
|
+
import vn.momo.kits.components.InputSearch
|
|
46
|
+
import vn.momo.kits.components.InputSearchProps
|
|
42
47
|
import vn.momo.kits.components.Options
|
|
43
48
|
import vn.momo.kits.components.Text
|
|
44
49
|
import vn.momo.kits.const.AppStatusBar
|
|
@@ -46,6 +51,7 @@ import vn.momo.kits.const.AppTheme
|
|
|
46
51
|
import vn.momo.kits.const.Colors
|
|
47
52
|
import vn.momo.kits.const.Spacing
|
|
48
53
|
import vn.momo.kits.const.Typography
|
|
54
|
+
import vn.momo.kits.modifier.shadow
|
|
49
55
|
import vn.momo.kits.platform.getStatusBarHeight
|
|
50
56
|
import vn.momo.kits.utils.bottomBorder
|
|
51
57
|
|
|
@@ -60,41 +66,88 @@ data class AnimatedHeader(
|
|
|
60
66
|
)
|
|
61
67
|
|
|
62
68
|
@Composable
|
|
63
|
-
fun
|
|
69
|
+
fun HeaderBackground(
|
|
64
70
|
headerType: HeaderType = HeaderType.DEFAULT,
|
|
65
|
-
|
|
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
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
Box(
|
|
83
|
+
modifier = Modifier.fillMaxWidth().height(height)
|
|
84
|
+
.bottomBorder(
|
|
85
|
+
strokeWidth = 1.dp,
|
|
86
|
+
color = AppTheme.current.colors.border.default
|
|
87
|
+
)
|
|
88
|
+
) {
|
|
89
|
+
Box(
|
|
90
|
+
modifier = Modifier
|
|
91
|
+
.height(height)
|
|
92
|
+
.fillMaxWidth()
|
|
93
|
+
.background(
|
|
94
|
+
Brush.linearGradient(
|
|
95
|
+
colors = listOf(
|
|
96
|
+
Color(0xFFFDCACE),
|
|
97
|
+
Color(0x00FDCACE)
|
|
98
|
+
),
|
|
99
|
+
start = Offset(0f, 0f),
|
|
100
|
+
end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
|
|
101
|
+
)
|
|
102
|
+
)
|
|
76
103
|
)
|
|
77
|
-
|
|
78
|
-
|
|
104
|
+
if (AppTheme.current.assets.headerBackground != null) {
|
|
105
|
+
Image(
|
|
106
|
+
source = AppTheme.current.assets.headerBackground!!,
|
|
107
|
+
modifier = Modifier.fillMaxWidth().height(height),
|
|
108
|
+
options = Options(
|
|
109
|
+
contentScale = ContentScale.FillWidth
|
|
110
|
+
)
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
79
114
|
|
|
80
|
-
HeaderType.EXTENDED -> {
|
|
81
|
-
Image(
|
|
82
|
-
source = headerBackground ?: "",
|
|
83
|
-
modifier = Modifier.fillMaxWidth(),
|
|
84
|
-
options = Options(
|
|
85
|
-
contentScale = ContentScale.FillWidth
|
|
86
|
-
)
|
|
87
|
-
)
|
|
88
115
|
}
|
|
89
116
|
|
|
90
|
-
HeaderType.
|
|
91
|
-
val height = statusBarHeight + 52.dp
|
|
117
|
+
HeaderType.EXTENDED -> {
|
|
92
118
|
Box(
|
|
93
|
-
modifier = Modifier.fillMaxWidth().height(
|
|
94
|
-
.
|
|
95
|
-
.
|
|
96
|
-
|
|
97
|
-
|
|
119
|
+
modifier = Modifier.fillMaxWidth().height(154.dp)
|
|
120
|
+
.alpha(opacityAni)
|
|
121
|
+
.background(
|
|
122
|
+
Brush.linearGradient(
|
|
123
|
+
colors = listOf(
|
|
124
|
+
Color(0xFFFDCACE),
|
|
125
|
+
Color(0x00FDCACE)
|
|
126
|
+
),
|
|
127
|
+
start = Offset(0f, 0f),
|
|
128
|
+
end = Offset(0f, with(LocalDensity.current) { 154.dp.toPx() })
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
) {
|
|
132
|
+
if (AppTheme.current.assets.headerBackground != null) {
|
|
133
|
+
Image(
|
|
134
|
+
source = AppTheme.current.assets.headerBackground!!,
|
|
135
|
+
modifier = Modifier.fillMaxWidth().height(154.dp),
|
|
136
|
+
options = Options(
|
|
137
|
+
contentScale = ContentScale.FillWidth
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
}
|
|
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
|
+
)
|
|
98
151
|
)
|
|
99
152
|
)
|
|
100
153
|
}
|
|
@@ -115,25 +168,21 @@ fun Header(
|
|
|
115
168
|
goBack: (() -> Unit) = { },
|
|
116
169
|
opacity: Float? = null,
|
|
117
170
|
animatedHeader: AnimatedHeader? = null,
|
|
118
|
-
|
|
171
|
+
useSearchInput: Boolean? = false,
|
|
172
|
+
scrollState: Int = 0,
|
|
173
|
+
inputSearchProps: InputSearchProps?
|
|
119
174
|
) {
|
|
120
175
|
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (headerType == HeaderType.SURFACE) {
|
|
124
|
-
tintIconColor = AppTheme.current.colors.text.default
|
|
125
|
-
backgroundButton = Color.Transparent
|
|
126
|
-
}
|
|
176
|
+
val tintIconColor = AppTheme.current.colors.text.default
|
|
177
|
+
val backgroundButton = Colors.black_01.copy(alpha = 0.2f)
|
|
127
178
|
|
|
128
179
|
var colorFraction by remember { mutableStateOf(0f) }
|
|
129
180
|
|
|
130
181
|
LaunchedEffect(scrollState) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
.collect { fraction -> colorFraction = fraction }
|
|
136
|
-
}
|
|
182
|
+
snapshotFlow { scrollState }
|
|
183
|
+
.map { (it / 50f).coerceIn(0f, 1f) }
|
|
184
|
+
.distinctUntilChanged()
|
|
185
|
+
.collect { fraction -> colorFraction = fraction }
|
|
137
186
|
}
|
|
138
187
|
|
|
139
188
|
val tintIconColorAnim by animateColorAsState(
|
|
@@ -144,6 +193,14 @@ fun Header(
|
|
|
144
193
|
)
|
|
145
194
|
)
|
|
146
195
|
|
|
196
|
+
val backgroundSearch by animateColorAsState(
|
|
197
|
+
targetValue = animateColor(
|
|
198
|
+
Colors.black_01,
|
|
199
|
+
AppTheme.current.colors.background.default,
|
|
200
|
+
colorFraction
|
|
201
|
+
)
|
|
202
|
+
)
|
|
203
|
+
|
|
147
204
|
if (headerType != HeaderType.NONE) {
|
|
148
205
|
BoxWithConstraints(
|
|
149
206
|
Modifier.height(statusBarHeight + 52.dp)
|
|
@@ -164,15 +221,11 @@ fun Header(
|
|
|
164
221
|
modifier = Modifier
|
|
165
222
|
.size(28.dp)
|
|
166
223
|
.then(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
173
|
-
} else {
|
|
174
|
-
Modifier
|
|
175
|
-
}
|
|
224
|
+
Modifier.border(
|
|
225
|
+
0.5.dp,
|
|
226
|
+
Colors.black_20.copy(alpha = 0.4f),
|
|
227
|
+
RoundedCornerShape(100)
|
|
228
|
+
)
|
|
176
229
|
)
|
|
177
230
|
.background(
|
|
178
231
|
backgroundButton,
|
|
@@ -183,23 +236,24 @@ fun Header(
|
|
|
183
236
|
)
|
|
184
237
|
.padding(Spacing.XS)
|
|
185
238
|
.semantics {
|
|
186
|
-
|
|
187
|
-
"btn_navigation_back"
|
|
239
|
+
testTag = "btn_navigation_back"
|
|
188
240
|
},
|
|
189
241
|
contentAlignment = Alignment.Center
|
|
190
242
|
) {
|
|
191
243
|
Icon(
|
|
192
244
|
source = "ic_back_ios",
|
|
193
|
-
color = if (
|
|
245
|
+
color = if (animatedHeader !== null) tintIconColorAnim else tintIconColor,
|
|
194
246
|
size = 20.dp,
|
|
195
247
|
)
|
|
196
248
|
}
|
|
197
249
|
}
|
|
198
250
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
251
|
+
if (useSearchInput == false) {
|
|
252
|
+
Box(Modifier.graphicsLayer {
|
|
253
|
+
alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
254
|
+
}) {
|
|
255
|
+
headerRight?.invoke()
|
|
256
|
+
}
|
|
203
257
|
}
|
|
204
258
|
}
|
|
205
259
|
|
|
@@ -213,23 +267,25 @@ fun Header(
|
|
|
213
267
|
if (isBack) {
|
|
214
268
|
Spacer(Modifier.width(40.dp))
|
|
215
269
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
219
|
-
},
|
|
220
|
-
contentAlignment = if (titlePosition == TitlePosition.LEFT) Alignment.TopStart else Alignment.Center
|
|
221
|
-
) {
|
|
222
|
-
HeaderTitle(
|
|
223
|
-
title = title,
|
|
224
|
-
color = if (headerType == HeaderType.SURFACE && animatedHeader !== null) tintIconColorAnim else tintIconColor,
|
|
225
|
-
modifier = Modifier.semantics {
|
|
226
|
-
contentDescription = "title_navigation_header"
|
|
227
|
-
testTag = "title_navigation_header"
|
|
228
|
-
}
|
|
229
|
-
)
|
|
270
|
+
if (useSearchInput == true && inputSearchProps != null) {
|
|
271
|
+
InputSearch(inputSearchProps = inputSearchProps.copy(backgroundColor = backgroundSearch))
|
|
230
272
|
}
|
|
231
|
-
|
|
232
|
-
|
|
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
|
+
}
|
|
233
289
|
}
|
|
234
290
|
}
|
|
235
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,21 +25,24 @@ 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
|
|
|
39
44
|
enum class HeaderType {
|
|
40
45
|
DEFAULT,
|
|
41
|
-
SURFACE,
|
|
42
46
|
EXTENDED,
|
|
43
47
|
NONE
|
|
44
48
|
}
|
|
@@ -46,7 +50,6 @@ enum class HeaderType {
|
|
|
46
50
|
@Composable
|
|
47
51
|
fun Screen(
|
|
48
52
|
backgroundColor: Color? = null,
|
|
49
|
-
headerBackground: String? = null,
|
|
50
53
|
isBack: Boolean = true,
|
|
51
54
|
headerType: HeaderType = HeaderType.DEFAULT,
|
|
52
55
|
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
|
|
@@ -55,12 +58,17 @@ fun Screen(
|
|
|
55
58
|
titlePosition: TitlePosition = TitlePosition.LEFT,
|
|
56
59
|
goBack: (() -> Unit) = { },
|
|
57
60
|
scrollable: Boolean = true,
|
|
61
|
+
scrollState: ScrollState = rememberScrollState(),
|
|
62
|
+
onContentLayout: ((LayoutCoordinates) -> Unit)? = null,
|
|
58
63
|
useAvoidKeyboard: Boolean = true,
|
|
59
64
|
footer: @Composable (() -> Unit)? = null,
|
|
60
65
|
headerRight: @Composable (() -> Unit)? = null,
|
|
61
66
|
fabProps: FabProps? = null,
|
|
62
67
|
animatedHeader: AnimatedHeader? = null,
|
|
63
68
|
layoutOffset: Dp = 56.dp,
|
|
69
|
+
useShadow: Boolean? = true,
|
|
70
|
+
useSearchInput: Boolean? = false,
|
|
71
|
+
inputSearchProps: InputSearchProps? = null,
|
|
64
72
|
content: @Composable () -> Unit,
|
|
65
73
|
) {
|
|
66
74
|
val statusBarHeight = AppStatusBar.current ?: getStatusBarHeight()
|
|
@@ -75,7 +83,6 @@ fun Screen(
|
|
|
75
83
|
|
|
76
84
|
val indicator = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
|
|
77
85
|
val bottomPadding = min(indicator, 21.dp)
|
|
78
|
-
val scrollState = rememberScrollState()
|
|
79
86
|
|
|
80
87
|
val opacity by animateFloatAsState(
|
|
81
88
|
targetValue = ((scrollState.value / 114f)).coerceIn(0f, 1f)
|
|
@@ -90,17 +97,17 @@ fun Screen(
|
|
|
90
97
|
) {
|
|
91
98
|
|
|
92
99
|
if (animatedHeader === null) {
|
|
93
|
-
|
|
94
|
-
headerType,
|
|
95
|
-
headerBackground ?: AppTheme.current.assets.headerBackground
|
|
96
|
-
)
|
|
100
|
+
HeaderBackground(headerType = headerType, scrollState = scrollState.value)
|
|
97
101
|
} else {
|
|
98
102
|
Box(
|
|
99
|
-
Modifier.zIndex(5f)
|
|
100
|
-
.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
Modifier.zIndex(5f)
|
|
104
|
+
.background(Color.White.copy(alpha = opacity))
|
|
105
|
+
.graphicsLayer { alpha = opacity }
|
|
106
|
+
) {
|
|
107
|
+
HeaderBackground(
|
|
108
|
+
headerType = headerType,
|
|
109
|
+
useShadow = useShadow,
|
|
110
|
+
scrollState = scrollState.value
|
|
104
111
|
)
|
|
105
112
|
}
|
|
106
113
|
}
|
|
@@ -114,6 +121,8 @@ fun Screen(
|
|
|
114
121
|
goBack = goBack,
|
|
115
122
|
opacity = opacity,
|
|
116
123
|
animatedHeader = animatedHeader,
|
|
124
|
+
useSearchInput = useSearchInput,
|
|
125
|
+
inputSearchProps = inputSearchProps,
|
|
117
126
|
scrollState = scrollState.value
|
|
118
127
|
)
|
|
119
128
|
|
|
@@ -129,9 +138,13 @@ fun Screen(
|
|
|
129
138
|
) {
|
|
130
139
|
|
|
131
140
|
Column(
|
|
132
|
-
modifier =
|
|
133
|
-
.
|
|
134
|
-
|
|
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) },
|
|
135
148
|
verticalArrangement = verticalArrangement,
|
|
136
149
|
horizontalAlignment = horizontalAlignment
|
|
137
150
|
) {
|
|
@@ -186,11 +199,8 @@ fun Footer(footer: @Composable (() -> Unit)? = null, keyboardSize: Dp = 0.dp, bo
|
|
|
186
199
|
.background(AppTheme.current.colors.background.surface)
|
|
187
200
|
) {
|
|
188
201
|
Box(
|
|
189
|
-
Modifier
|
|
190
|
-
|
|
191
|
-
.padding(vertical = Spacing.S, horizontal = Spacing.M)
|
|
192
|
-
)
|
|
193
|
-
{
|
|
202
|
+
Modifier.fillMaxWidth().padding(vertical = Spacing.S, horizontal = Spacing.M)
|
|
203
|
+
) {
|
|
194
204
|
footer?.invoke()
|
|
195
205
|
}
|
|
196
206
|
}
|
|
@@ -3,7 +3,6 @@ package vn.momo.kits.components
|
|
|
3
3
|
import androidx.compose.foundation.background
|
|
4
4
|
import androidx.compose.foundation.border
|
|
5
5
|
import androidx.compose.foundation.clickable
|
|
6
|
-
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
7
6
|
import androidx.compose.foundation.layout.Arrangement
|
|
8
7
|
import androidx.compose.foundation.layout.Box
|
|
9
8
|
import androidx.compose.foundation.layout.Row
|
|
@@ -13,14 +12,15 @@ import androidx.compose.foundation.layout.height
|
|
|
13
12
|
import androidx.compose.foundation.layout.padding
|
|
14
13
|
import androidx.compose.foundation.layout.size
|
|
15
14
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
16
|
-
import androidx.compose.material.ripple.rememberRipple
|
|
17
15
|
import androidx.compose.material3.CircularProgressIndicator
|
|
18
16
|
import androidx.compose.runtime.Composable
|
|
19
|
-
import androidx.compose.runtime.remember
|
|
20
17
|
import androidx.compose.ui.Alignment
|
|
21
18
|
import androidx.compose.ui.Modifier
|
|
22
19
|
import androidx.compose.ui.draw.clip
|
|
23
20
|
import androidx.compose.ui.graphics.Color
|
|
21
|
+
import androidx.compose.ui.semantics.contentDescription
|
|
22
|
+
import androidx.compose.ui.semantics.semantics
|
|
23
|
+
import androidx.compose.ui.semantics.testTag
|
|
24
24
|
import androidx.compose.ui.text.TextStyle
|
|
25
25
|
import androidx.compose.ui.text.style.TextOverflow
|
|
26
26
|
import androidx.compose.ui.unit.Dp
|
|
@@ -221,9 +221,6 @@ fun getTypeStyle(
|
|
|
221
221
|
* @param iconLeft [String] the icon at the left of title
|
|
222
222
|
* @param title [String] title of button
|
|
223
223
|
* @param loading [Boolean] used when you want to use loading animation
|
|
224
|
-
* @param enabled controls the enabled state of this button. When `false`,
|
|
225
|
-
* this component will not respond to user input, and it will appear
|
|
226
|
-
* visually disabled and disabled to accessibility services.
|
|
227
224
|
* @param useTintColor [Boolean] controls color of the icon.
|
|
228
225
|
*/
|
|
229
226
|
@Composable
|
|
@@ -235,23 +232,23 @@ fun Button(
|
|
|
235
232
|
iconLeft: String = "",
|
|
236
233
|
title: String = "Button",
|
|
237
234
|
loading: Boolean = false,
|
|
238
|
-
enabled: Boolean = true,
|
|
239
235
|
useTintColor: Boolean = true,
|
|
240
236
|
isFull: Boolean = true,
|
|
241
237
|
modifier: Modifier = Modifier,
|
|
242
238
|
) {
|
|
239
|
+
val testId = "btn_${type.toString().lowercase()}_$title"
|
|
243
240
|
val customModifier = if (isFull) {
|
|
244
241
|
modifier
|
|
245
242
|
.fillMaxWidth()
|
|
246
243
|
.clip(RoundedCornerShape(size.value.radius)).clickable(
|
|
247
|
-
enabled =
|
|
244
|
+
enabled = type != ButtonType.DISABLED,
|
|
248
245
|
onClick = onClick
|
|
249
246
|
)
|
|
250
247
|
|
|
251
248
|
} else {
|
|
252
249
|
modifier
|
|
253
250
|
.clip(RoundedCornerShape(size.value.radius)).clickable(
|
|
254
|
-
enabled =
|
|
251
|
+
enabled = type != ButtonType.DISABLED,
|
|
255
252
|
onClick = onClick
|
|
256
253
|
)
|
|
257
254
|
}
|
|
@@ -261,7 +258,10 @@ fun Button(
|
|
|
261
258
|
.padding(horizontal = size.value.padding)
|
|
262
259
|
.defaultMinSize(
|
|
263
260
|
minWidth = size.value.width
|
|
264
|
-
).height(size.value.height)
|
|
261
|
+
).height(size.value.height)
|
|
262
|
+
.semantics {
|
|
263
|
+
contentDescription = title; testTag = testId
|
|
264
|
+
},
|
|
265
265
|
horizontalArrangement = Arrangement.Center,
|
|
266
266
|
verticalAlignment = Alignment.CenterVertically,
|
|
267
267
|
) {
|
|
@@ -33,7 +33,6 @@ fun CheckBox(
|
|
|
33
33
|
var backgroundColor = AppTheme.current.colors.background.surface
|
|
34
34
|
val iconSource = if (indeterminate) "minus" else "ic_checked"
|
|
35
35
|
|
|
36
|
-
|
|
37
36
|
if (checked) {
|
|
38
37
|
borderColor = AppTheme.current.colors.primary
|
|
39
38
|
backgroundColor = AppTheme.current.colors.primary
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
package vn.momo.kits.components
|
|
2
2
|
|
|
3
|
-
import androidx.compose.foundation.layout.Box
|
|
4
|
-
import androidx.compose.foundation.layout.fillMaxSize
|
|
5
3
|
import androidx.compose.foundation.layout.size
|
|
6
4
|
import androidx.compose.runtime.Composable
|
|
7
|
-
import androidx.compose.ui.Alignment
|
|
8
5
|
import androidx.compose.ui.Modifier
|
|
9
6
|
import androidx.compose.ui.graphics.Color
|
|
10
7
|
import androidx.compose.ui.graphics.ColorFilter
|
|
11
8
|
import androidx.compose.ui.layout.ContentScale
|
|
12
9
|
import androidx.compose.ui.unit.Dp
|
|
13
10
|
import androidx.compose.ui.unit.dp
|
|
14
|
-
import coil3.compose.AsyncImage
|
|
15
11
|
import vn.momo.kits.const.AppTheme
|
|
16
12
|
import vn.momo.kits.utils.Icons
|
|
17
13
|
|
|
@@ -25,16 +21,16 @@ fun Icon(
|
|
|
25
21
|
val icon = if (source.contains("https")) {
|
|
26
22
|
source
|
|
27
23
|
} else {
|
|
28
|
-
Icons[source]
|
|
24
|
+
Icons[source] ?: ""
|
|
29
25
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
Image(
|
|
27
|
+
modifier = modifier.size(size),
|
|
28
|
+
source = icon,
|
|
29
|
+
loading = false,
|
|
30
|
+
options = Options(
|
|
35
31
|
contentScale = ContentScale.Fit,
|
|
36
32
|
colorFilter = color?.let { ColorFilter.tint(it) }
|
|
37
|
-
)
|
|
38
|
-
|
|
33
|
+
),
|
|
34
|
+
)
|
|
39
35
|
}
|
|
40
36
|
|
|
@@ -110,7 +110,7 @@ fun IconButton(
|
|
|
110
110
|
.then(getIconStyle(type))
|
|
111
111
|
.clip(RoundedCornerShape(size.value.radius))
|
|
112
112
|
.clickable(
|
|
113
|
-
enabled = type
|
|
113
|
+
enabled = type != ButtonType.DISABLED,
|
|
114
114
|
onClick = onClick
|
|
115
115
|
),
|
|
116
116
|
contentAlignment = Alignment.Center
|
|
@@ -15,7 +15,6 @@ import androidx.compose.ui.layout.ContentScale
|
|
|
15
15
|
import androidx.compose.ui.semantics.contentDescription
|
|
16
16
|
import androidx.compose.ui.semantics.semantics
|
|
17
17
|
import androidx.compose.ui.semantics.testTag
|
|
18
|
-
import androidx.compose.ui.unit.dp
|
|
19
18
|
import coil3.compose.AsyncImage
|
|
20
19
|
import vn.momo.kits.const.AppTheme
|
|
21
20
|
|
|
@@ -37,7 +36,6 @@ fun Image(
|
|
|
37
36
|
options: Options? = null,
|
|
38
37
|
loading: Boolean = true,
|
|
39
38
|
) {
|
|
40
|
-
modifier.semantics {contentDescription = "img|$source"; testTag = "img|$source"}
|
|
41
39
|
var imageOptions = Options()
|
|
42
40
|
var imageState by remember { mutableStateOf(ImageState.Loading) }
|
|
43
41
|
|
|
@@ -52,7 +50,7 @@ fun Image(
|
|
|
52
50
|
|
|
53
51
|
Box(modifier = modifier) {
|
|
54
52
|
AsyncImage(
|
|
55
|
-
modifier =
|
|
53
|
+
modifier = Modifier.matchParentSize().semantics {contentDescription = "img|$source"; testTag = "img|$source"},
|
|
56
54
|
model = source,
|
|
57
55
|
contentDescription = null,
|
|
58
56
|
contentScale = imageOptions.contentScale,
|
|
@@ -29,6 +29,9 @@ import androidx.compose.ui.Alignment
|
|
|
29
29
|
import androidx.compose.ui.Modifier
|
|
30
30
|
import androidx.compose.ui.focus.onFocusChanged
|
|
31
31
|
import androidx.compose.ui.graphics.Color
|
|
32
|
+
import androidx.compose.ui.semantics.contentDescription
|
|
33
|
+
import androidx.compose.ui.semantics.semantics
|
|
34
|
+
import androidx.compose.ui.semantics.testTag
|
|
32
35
|
import androidx.compose.ui.text.TextStyle
|
|
33
36
|
import androidx.compose.ui.text.font.FontWeight
|
|
34
37
|
import androidx.compose.ui.text.input.KeyboardType
|
|
@@ -198,7 +201,11 @@ fun Input(
|
|
|
198
201
|
iconTintColor = disabledColor
|
|
199
202
|
}
|
|
200
203
|
|
|
201
|
-
|
|
204
|
+
val testId = if (disabled) "input_${floatingValue}_disabled" else "input_$floatingValue"
|
|
205
|
+
|
|
206
|
+
Column(modifier = Modifier.semantics {
|
|
207
|
+
contentDescription = floatingValue; testTag = testId
|
|
208
|
+
}) {
|
|
202
209
|
BasicTextField(
|
|
203
210
|
enabled = !disabled,
|
|
204
211
|
readOnly = readOnly,
|
|
@@ -17,10 +17,12 @@ 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
|
|
23
|
+
import androidx.compose.ui.semantics.contentDescription
|
|
24
|
+
import androidx.compose.ui.semantics.semantics
|
|
25
|
+
import androidx.compose.ui.semantics.testTag
|
|
24
26
|
import androidx.compose.ui.text.TextStyle
|
|
25
27
|
import androidx.compose.ui.unit.dp
|
|
26
28
|
import androidx.compose.ui.unit.sp
|
|
@@ -51,7 +53,7 @@ fun InputDropDown(
|
|
|
51
53
|
loading: Boolean = false,
|
|
52
54
|
required: Boolean = false,
|
|
53
55
|
) {
|
|
54
|
-
|
|
56
|
+
val isFocused by remember { mutableStateOf(false) }
|
|
55
57
|
|
|
56
58
|
val disabledColor = AppTheme.current.colors.text.disable
|
|
57
59
|
var textColor = AppTheme.current.colors.text.default
|
|
@@ -72,8 +74,11 @@ fun InputDropDown(
|
|
|
72
74
|
iconTintColor = disabledColor
|
|
73
75
|
}
|
|
74
76
|
|
|
77
|
+
val testId = if (disabled) "input_${floatingValue}_disabled" else "input_$floatingValue"
|
|
75
78
|
|
|
76
|
-
Column(modifier = Modifier.clickable(enabled = !disabled, onClick = onPress)
|
|
79
|
+
Column(modifier = Modifier.clickable(enabled = !disabled, onClick = onPress).semantics {
|
|
80
|
+
contentDescription = floatingValue; testTag = testId
|
|
81
|
+
}) {
|
|
77
82
|
Box {
|
|
78
83
|
if (floatingValue.isNotEmpty() || floatingIcon.isNotEmpty()) {
|
|
79
84
|
Box(
|
|
@@ -27,6 +27,9 @@ import androidx.compose.ui.Alignment
|
|
|
27
27
|
import androidx.compose.ui.Modifier
|
|
28
28
|
import androidx.compose.ui.focus.onFocusChanged
|
|
29
29
|
import androidx.compose.ui.graphics.Color
|
|
30
|
+
import androidx.compose.ui.semantics.contentDescription
|
|
31
|
+
import androidx.compose.ui.semantics.semantics
|
|
32
|
+
import androidx.compose.ui.semantics.testTag
|
|
30
33
|
import androidx.compose.ui.text.AnnotatedString
|
|
31
34
|
import androidx.compose.ui.text.TextStyle
|
|
32
35
|
import androidx.compose.ui.text.input.KeyboardType
|
|
@@ -104,8 +107,11 @@ fun InputMoney(
|
|
|
104
107
|
iconTintColor = disabledColor
|
|
105
108
|
}
|
|
106
109
|
|
|
110
|
+
val testId = if (disabled) "input_${floatingValue}_disabled" else "input_$floatingValue"
|
|
107
111
|
|
|
108
|
-
Column {
|
|
112
|
+
Column(modifier = Modifier.semantics {
|
|
113
|
+
contentDescription = floatingValue; testTag = testId
|
|
114
|
+
}) {
|
|
109
115
|
BasicTextField(
|
|
110
116
|
enabled = !disabled,
|
|
111
117
|
singleLine = true,
|
|
@@ -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
|
}
|
|
@@ -123,7 +123,10 @@ fun TrustBanner(
|
|
|
123
123
|
modifier = Modifier
|
|
124
124
|
.width(64.dp)
|
|
125
125
|
.height(64.dp)
|
|
126
|
-
.padding(end = 8.dp)
|
|
126
|
+
.padding(end = 8.dp),
|
|
127
|
+
options = Options(
|
|
128
|
+
contentScale = ContentScale.Fit,
|
|
129
|
+
)
|
|
127
130
|
)
|
|
128
131
|
Column {
|
|
129
132
|
Text(
|
|
@@ -141,11 +144,17 @@ fun TrustBanner(
|
|
|
141
144
|
.padding(end = 4.dp)
|
|
142
145
|
.width(52.dp)
|
|
143
146
|
.height(20.dp)
|
|
147
|
+
,options = Options(
|
|
148
|
+
contentScale = ContentScale.Fit,
|
|
149
|
+
)
|
|
144
150
|
)
|
|
145
151
|
Image(
|
|
146
152
|
source = trustBanner.sslImage, modifier = Modifier
|
|
147
153
|
.width(52.dp)
|
|
148
|
-
.height(20.dp)
|
|
154
|
+
.height(20.dp),
|
|
155
|
+
options = Options(
|
|
156
|
+
contentScale = ContentScale.Fit,
|
|
157
|
+
)
|
|
149
158
|
)
|
|
150
159
|
}
|
|
151
160
|
Row(
|
|
@@ -106,7 +106,7 @@ val defaultTheme = Theme(
|
|
|
106
106
|
),
|
|
107
107
|
font = "SFProText",
|
|
108
108
|
assets = ThemeAssets(
|
|
109
|
-
headerBackground =
|
|
109
|
+
headerBackground = null
|
|
110
110
|
)
|
|
111
111
|
)
|
|
112
112
|
|
|
@@ -168,6 +168,5 @@ val darkTheme = Theme(
|
|
|
168
168
|
|
|
169
169
|
|
|
170
170
|
val AppTheme = staticCompositionLocalOf { defaultTheme }
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
171
|
+
|
|
172
|
+
val AppStatusBar = staticCompositionLocalOf<Dp?> { null }
|
|
@@ -27,10 +27,10 @@ fun scaleSize(size: Float): Float {
|
|
|
27
27
|
|
|
28
28
|
@OptIn(InternalResourceApi::class)
|
|
29
29
|
@Composable
|
|
30
|
-
fun getFont(font: String
|
|
30
|
+
fun getFont(font: String): FontFamily {
|
|
31
31
|
val fontResource = FontResource(
|
|
32
|
-
"font:${font}",
|
|
33
|
-
setOf(ResourceItem(setOf(), "font/${font}.${
|
|
32
|
+
"font:${font.substringBeforeLast(".")}",
|
|
33
|
+
setOf(ResourceItem(setOf(), "font/${font.substringBeforeLast(".")}.${font.substringAfterLast(".")}", -1, -1))
|
|
34
34
|
)
|
|
35
35
|
return FontFamily(Font(fontResource))
|
|
36
36
|
}
|
|
@@ -39,27 +39,38 @@ fun getFont(font: String, ext: String = "ttf"): FontFamily {
|
|
|
39
39
|
fun getFontFamily(fontFamily: String, fontWeight: FontWeight? = FontWeight.Normal): FontFamily {
|
|
40
40
|
val key = "$fontFamily-${fontWeight?.weight}"
|
|
41
41
|
val fontMap = mapOf(
|
|
42
|
-
"SFProText-100" to
|
|
43
|
-
"SFProText-200" to
|
|
44
|
-
"SFProText-300" to
|
|
45
|
-
"SFProText-400" to
|
|
46
|
-
"SFProText-500" to
|
|
47
|
-
"SFProText-600" to
|
|
48
|
-
"SFProText-700" to
|
|
49
|
-
"SFProText-800" to
|
|
50
|
-
"SFProText-900" to
|
|
42
|
+
"SFProText-100" to "sfprotext_thin.ttf",
|
|
43
|
+
"SFProText-200" to "sfprotext_ultralight.ttf",
|
|
44
|
+
"SFProText-300" to "sfprotext_light.ttf",
|
|
45
|
+
"SFProText-400" to "sfprotext_regular.ttf",
|
|
46
|
+
"SFProText-500" to "sfprotext_medium.ttf",
|
|
47
|
+
"SFProText-600" to "sfprotext_medium.ttf",
|
|
48
|
+
"SFProText-700" to "sfprotext_semibold.ttf",
|
|
49
|
+
"SFProText-800" to "sfprotext_bold.ttf",
|
|
50
|
+
"SFProText-900" to "sfprotext_heavy.ttf",
|
|
51
51
|
|
|
52
|
-
"MoMoSignature-100" to
|
|
53
|
-
"MoMoSignature-200" to
|
|
54
|
-
"MoMoSignature-300" to
|
|
55
|
-
"MoMoSignature-400" to
|
|
56
|
-
"MoMoSignature-500" to
|
|
57
|
-
"MoMoSignature-600" to
|
|
58
|
-
"MoMoSignature-700" to
|
|
59
|
-
"MoMoSignature-800" to
|
|
60
|
-
"MoMoSignature-900" to
|
|
52
|
+
"MoMoSignature-100" to "momosignature.otf",
|
|
53
|
+
"MoMoSignature-200" to "momosignature.otf",
|
|
54
|
+
"MoMoSignature-300" to "momosignature.otf",
|
|
55
|
+
"MoMoSignature-400" to "momosignature.otf",
|
|
56
|
+
"MoMoSignature-500" to "momosignature.otf",
|
|
57
|
+
"MoMoSignature-600" to "momosignature.otf",
|
|
58
|
+
"MoMoSignature-700" to "momosignature.otf",
|
|
59
|
+
"MoMoSignature-800" to "momosignature.otf",
|
|
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"
|
|
73
|
+
return getFont(font)
|
|
63
74
|
}
|
|
64
75
|
|
|
65
76
|
@Immutable
|
|
@@ -19,4 +19,7 @@ expect fun getScreenDimensions(): ScreenDimension
|
|
|
19
19
|
expect fun NativePaint.setMaskFilter(blurRadius: Float)
|
|
20
20
|
|
|
21
21
|
@Composable
|
|
22
|
-
expect fun getStatusBarHeight(): Dp
|
|
22
|
+
expect fun getStatusBarHeight(): Dp
|
|
23
|
+
|
|
24
|
+
@Composable
|
|
25
|
+
expect fun getNavigationBarHeight(): Dp
|
|
@@ -4,6 +4,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
|
|
4
4
|
import androidx.compose.foundation.gestures.optOutOfCupertinoOverscroll
|
|
5
5
|
import androidx.compose.foundation.layout.WindowInsets
|
|
6
6
|
import androidx.compose.foundation.layout.asPaddingValues
|
|
7
|
+
import androidx.compose.foundation.layout.navigationBars
|
|
7
8
|
import androidx.compose.foundation.layout.systemBars
|
|
8
9
|
import androidx.compose.runtime.Composable
|
|
9
10
|
import androidx.compose.ui.graphics.NativePaint
|
|
@@ -42,4 +43,9 @@ actual fun NativePaint.setMaskFilter(blurRadius: Float) {
|
|
|
42
43
|
@Composable
|
|
43
44
|
actual fun getStatusBarHeight(): Dp {
|
|
44
45
|
return WindowInsets.systemBars.asPaddingValues().calculateTopPadding()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Composable
|
|
49
|
+
actual fun getNavigationBarHeight(): Dp {
|
|
50
|
+
return WindowInsets.navigationBars.asPaddingValues().calculateTopPadding()
|
|
45
51
|
}
|
package/local.properties
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
# Location of the SDK. This is only used by Gradle.
|
|
5
5
|
# For customization when using a Version Control System, please read the
|
|
6
6
|
# header note.
|
|
7
|
-
#
|
|
8
|
-
sdk.dir=/Users/
|
|
7
|
+
#Tue Apr 23 16:40:15 ICT 2024
|
|
8
|
+
sdk.dir=/Users/hung.dao1/Library/Android/sdk
|