@momo-kits/native-kits 0.114.2-pu.1 → 0.117.1-beta.2
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/HeaderTitle.kt +5 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +4 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +10 -22
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +4 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +6 -5
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +3 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +7 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +7 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/{PromotionPopup.kt → PopupPromotion.kt} +9 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -5
- package/ios/Application/Components.swift +35 -21
- package/ios/Application/Screen.swift +28 -15
- package/ios/Checkbox/Checkbox.swift +1 -1
- package/ios/Popup/PopupDisplay.swift +28 -23
- package/ios/Popup/PopupPromotion.swift +54 -40
- package/local.properties +2 -2
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
|
|
|
4
4
|
import androidx.compose.ui.Modifier
|
|
5
5
|
import androidx.compose.ui.graphics.Color
|
|
6
6
|
import androidx.compose.ui.text.style.TextAlign
|
|
7
|
+
import androidx.compose.ui.unit.sp
|
|
7
8
|
import androidx.compose.ui.zIndex
|
|
8
9
|
import vn.momo.kits.components.Text
|
|
9
10
|
import vn.momo.kits.const.Typography
|
|
@@ -19,7 +20,10 @@ fun HeaderTitle(
|
|
|
19
20
|
modifier = Modifier.then(modifier).zIndex(1f),
|
|
20
21
|
text = title,
|
|
21
22
|
textAlign = textAlign,
|
|
22
|
-
style = Typography.actionSBold
|
|
23
|
+
style = Typography.actionSBold.copy(
|
|
24
|
+
fontSize = 15.sp,
|
|
25
|
+
lineHeight = 22.sp,
|
|
26
|
+
),
|
|
23
27
|
color = color,
|
|
24
28
|
maxLines = 1
|
|
25
29
|
)
|
|
@@ -11,6 +11,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
11
11
|
import androidx.compose.runtime.Composable
|
|
12
12
|
import androidx.compose.ui.Alignment
|
|
13
13
|
import androidx.compose.ui.Modifier
|
|
14
|
+
import androidx.compose.ui.graphics.Color
|
|
14
15
|
import androidx.compose.ui.unit.dp
|
|
15
16
|
import vn.momo.kits.const.AppTheme
|
|
16
17
|
import vn.momo.kits.const.Colors
|
|
@@ -27,8 +28,8 @@ fun CheckBox(
|
|
|
27
28
|
title: String = "",
|
|
28
29
|
) {
|
|
29
30
|
var borderColor = AppTheme.current.colors.text.default
|
|
30
|
-
var backgroundColor =
|
|
31
|
-
val iconSource = if (indeterminate) "
|
|
31
|
+
var backgroundColor = Color.Transparent
|
|
32
|
+
val iconSource = if (indeterminate) "navigation_minus" else "ic_checked"
|
|
32
33
|
|
|
33
34
|
if (checked) {
|
|
34
35
|
borderColor = AppTheme.current.colors.primary
|
|
@@ -36,7 +37,7 @@ fun CheckBox(
|
|
|
36
37
|
}
|
|
37
38
|
if (disabled) {
|
|
38
39
|
borderColor = AppTheme.current.colors.border.disable
|
|
39
|
-
backgroundColor =
|
|
40
|
+
backgroundColor = Color.Transparent
|
|
40
41
|
if (checked) {
|
|
41
42
|
borderColor = AppTheme.current.colors.background.tonal
|
|
42
43
|
backgroundColor = AppTheme.current.colors.background.tonal
|
|
@@ -20,6 +20,7 @@ import androidx.compose.foundation.text.BasicTextField
|
|
|
20
20
|
import androidx.compose.foundation.text.KeyboardOptions
|
|
21
21
|
import androidx.compose.material3.CircularProgressIndicator
|
|
22
22
|
import androidx.compose.runtime.Composable
|
|
23
|
+
import androidx.compose.runtime.MutableState
|
|
23
24
|
import androidx.compose.runtime.getValue
|
|
24
25
|
import androidx.compose.runtime.mutableStateOf
|
|
25
26
|
import androidx.compose.runtime.remember
|
|
@@ -28,11 +29,13 @@ import androidx.compose.ui.Alignment
|
|
|
28
29
|
import androidx.compose.ui.Modifier
|
|
29
30
|
import androidx.compose.ui.focus.onFocusChanged
|
|
30
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
|
|
31
35
|
import androidx.compose.ui.text.TextStyle
|
|
32
36
|
import androidx.compose.ui.text.font.FontWeight
|
|
33
37
|
import androidx.compose.ui.text.input.KeyboardType
|
|
34
38
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
|
35
|
-
import androidx.compose.ui.text.input.TextFieldValue
|
|
36
39
|
import androidx.compose.ui.text.input.VisualTransformation
|
|
37
40
|
import androidx.compose.ui.unit.Dp
|
|
38
41
|
import androidx.compose.ui.unit.dp
|
|
@@ -151,7 +154,7 @@ fun ErrorView(errorMessage: String, errorSpacing: Boolean, hintText: String) {
|
|
|
151
154
|
|
|
152
155
|
@Composable
|
|
153
156
|
fun Input(
|
|
154
|
-
text: String = "",
|
|
157
|
+
text: MutableState<String> = remember { mutableStateOf("") },
|
|
155
158
|
floatingValue: String = "",
|
|
156
159
|
floatingValueColor: Color = AppTheme.current.colors.text.hint,
|
|
157
160
|
floatingIcon: String = "",
|
|
@@ -178,10 +181,6 @@ fun Input(
|
|
|
178
181
|
keyboardType: KeyboardType = KeyboardType.Text,
|
|
179
182
|
modifier: Modifier = Modifier,
|
|
180
183
|
) {
|
|
181
|
-
var textFieldValueState by remember { mutableStateOf(TextFieldValue(text = text)) }
|
|
182
|
-
val textFieldValue = textFieldValueState.copy(text = text)
|
|
183
|
-
var lastTextValue by remember(text) { mutableStateOf(text) }
|
|
184
|
-
|
|
185
184
|
var isFocused by remember { mutableStateOf(false) }
|
|
186
185
|
var passHidden by remember { mutableStateOf(false) }
|
|
187
186
|
var isBlurred = false
|
|
@@ -210,10 +209,10 @@ fun Input(
|
|
|
210
209
|
modifier = modifier.setAutomationId(testId)
|
|
211
210
|
) {
|
|
212
211
|
BasicTextField(
|
|
213
|
-
value = text,
|
|
214
212
|
enabled = !disabled,
|
|
215
213
|
readOnly = readOnly,
|
|
216
214
|
singleLine = true,
|
|
215
|
+
value = text.value,
|
|
217
216
|
textStyle = TextStyle(
|
|
218
217
|
color = textColor,
|
|
219
218
|
fontSize = 16.sp,
|
|
@@ -230,15 +229,7 @@ fun Input(
|
|
|
230
229
|
if (!it.isFocused && isBlurred) onBlur()
|
|
231
230
|
if (it.isFocused && !isBlurred) isBlurred = true
|
|
232
231
|
},
|
|
233
|
-
onValueChange =
|
|
234
|
-
textFieldValueState.copy(text = newValue)
|
|
235
|
-
val stringChangedSinceLastInvocation = lastTextValue != newValue
|
|
236
|
-
lastTextValue = newValue
|
|
237
|
-
|
|
238
|
-
if (stringChangedSinceLastInvocation) {
|
|
239
|
-
onChangeText(newValue)
|
|
240
|
-
}
|
|
241
|
-
},
|
|
232
|
+
onValueChange = onChangeText,
|
|
242
233
|
decorationBox = { innerTextField ->
|
|
243
234
|
// Floating Icon
|
|
244
235
|
if (floatingValue.isNotEmpty() || floatingIcon.isNotEmpty()) {
|
|
@@ -300,7 +291,7 @@ fun Input(
|
|
|
300
291
|
)
|
|
301
292
|
}
|
|
302
293
|
Box(Modifier.weight(1f)) {
|
|
303
|
-
if (
|
|
294
|
+
if (text.value.isEmpty()) {
|
|
304
295
|
Text(
|
|
305
296
|
text = placeholder,
|
|
306
297
|
style = TextStyle(
|
|
@@ -313,7 +304,7 @@ fun Input(
|
|
|
313
304
|
}
|
|
314
305
|
innerTextField()
|
|
315
306
|
}
|
|
316
|
-
if (isFocused &&
|
|
307
|
+
if (isFocused && text.value.isNotEmpty()) {
|
|
317
308
|
Row {
|
|
318
309
|
Spacer(Modifier.width(Spacing.XS))
|
|
319
310
|
Icon(
|
|
@@ -321,10 +312,7 @@ fun Input(
|
|
|
321
312
|
size = 16.dp,
|
|
322
313
|
color = AppTheme.current.colors.text.hint,
|
|
323
314
|
modifier = Modifier.clickable(
|
|
324
|
-
onClick = {
|
|
325
|
-
onChangeText("")
|
|
326
|
-
textFieldValueState = TextFieldValue(text = "")
|
|
327
|
-
},
|
|
315
|
+
onClick = { text.value = "" },
|
|
328
316
|
interactionSource = remember { MutableInteractionSource() },
|
|
329
317
|
indication = null
|
|
330
318
|
)
|
|
@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.padding
|
|
|
13
13
|
import androidx.compose.foundation.layout.wrapContentSize
|
|
14
14
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
15
15
|
import androidx.compose.runtime.Composable
|
|
16
|
+
import androidx.compose.runtime.MutableState
|
|
16
17
|
import androidx.compose.runtime.getValue
|
|
17
18
|
import androidx.compose.runtime.mutableStateOf
|
|
18
19
|
import androidx.compose.runtime.remember
|
|
@@ -32,7 +33,7 @@ import vn.momo.kits.const.Typography
|
|
|
32
33
|
|
|
33
34
|
@Composable
|
|
34
35
|
fun InputDropDown(
|
|
35
|
-
|
|
36
|
+
value: MutableState<String> = remember { mutableStateOf("") },
|
|
36
37
|
floatingValue: String = "",
|
|
37
38
|
floatingValueColor: Color = AppTheme.current.colors.text.hint,
|
|
38
39
|
floatingIcon: String = "",
|
|
@@ -139,12 +140,12 @@ fun InputDropDown(
|
|
|
139
140
|
}
|
|
140
141
|
Box(Modifier.weight(1f)) {
|
|
141
142
|
Text(
|
|
142
|
-
text =
|
|
143
|
+
text = value.value.ifEmpty { placeholder },
|
|
143
144
|
style = TextStyle(
|
|
144
145
|
fontSize = 16.sp,
|
|
145
146
|
lineHeight = 24.sp
|
|
146
147
|
),
|
|
147
|
-
color = if (
|
|
148
|
+
color = if (value.value.isEmpty()) placeholderColor else textColor
|
|
148
149
|
)
|
|
149
150
|
}
|
|
150
151
|
RenderRightIcon(
|
|
@@ -18,6 +18,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
18
18
|
import androidx.compose.foundation.text.BasicTextField
|
|
19
19
|
import androidx.compose.foundation.text.KeyboardOptions
|
|
20
20
|
import androidx.compose.runtime.Composable
|
|
21
|
+
import androidx.compose.runtime.MutableState
|
|
21
22
|
import androidx.compose.runtime.getValue
|
|
22
23
|
import androidx.compose.runtime.mutableStateOf
|
|
23
24
|
import androidx.compose.runtime.remember
|
|
@@ -62,7 +63,7 @@ class CustomConverter : VisualTransformation {
|
|
|
62
63
|
|
|
63
64
|
@Composable
|
|
64
65
|
fun InputMoney(
|
|
65
|
-
text: String = "0",
|
|
66
|
+
text: MutableState<String> = remember { mutableStateOf("0") },
|
|
66
67
|
floatingValue: String = "",
|
|
67
68
|
floatingValueColor: Color = AppTheme.current.colors.text.hint,
|
|
68
69
|
floatingIcon: String = "",
|
|
@@ -114,7 +115,7 @@ fun InputMoney(
|
|
|
114
115
|
BasicTextField(
|
|
115
116
|
enabled = !disabled,
|
|
116
117
|
singleLine = true,
|
|
117
|
-
value = text,
|
|
118
|
+
value = text.value,
|
|
118
119
|
textStyle = TextStyle(
|
|
119
120
|
color = textColor,
|
|
120
121
|
fontSize = 20.sp,
|
|
@@ -194,7 +195,7 @@ fun InputMoney(
|
|
|
194
195
|
)
|
|
195
196
|
}
|
|
196
197
|
Box(Modifier.weight(9f).padding(start = 0.dp)) {
|
|
197
|
-
if (text.isEmpty()) {
|
|
198
|
+
if (text.value.isEmpty()) {
|
|
198
199
|
Text(
|
|
199
200
|
text = placeholder,
|
|
200
201
|
style = TextStyle(
|
|
@@ -208,7 +209,7 @@ fun InputMoney(
|
|
|
208
209
|
innerTextField()
|
|
209
210
|
}
|
|
210
211
|
}
|
|
211
|
-
if (isFocused && text.isNotEmpty()) {
|
|
212
|
+
if (isFocused && text.value.isNotEmpty()) {
|
|
212
213
|
Row {
|
|
213
214
|
Spacer(Modifier.width(Spacing.XS))
|
|
214
215
|
Icon(
|
|
@@ -216,7 +217,7 @@ fun InputMoney(
|
|
|
216
217
|
size = 16.dp,
|
|
217
218
|
color = AppTheme.current.colors.text.hint,
|
|
218
219
|
modifier = Modifier.clickable(
|
|
219
|
-
onClick = {
|
|
220
|
+
onClick = { text.value = "" },
|
|
220
221
|
interactionSource = remember { MutableInteractionSource() },
|
|
221
222
|
indication = null
|
|
222
223
|
)
|
|
@@ -87,12 +87,12 @@ fun InputOTP(
|
|
|
87
87
|
dataType: String = "number",
|
|
88
88
|
modifier: Modifier = Modifier
|
|
89
89
|
) {
|
|
90
|
-
val
|
|
90
|
+
val maxLength = 10
|
|
91
91
|
var isFocused by remember { mutableStateOf(false) }
|
|
92
92
|
var isBlurred = false
|
|
93
93
|
|
|
94
94
|
val handleChangeText: (String) -> Unit = { text ->
|
|
95
|
-
if (text.length <=
|
|
95
|
+
if (text.length <= maxLength &&
|
|
96
96
|
(dataType != "number" || !text.any { !it.isDigit() }) &&
|
|
97
97
|
(text.length < value.length || value.length < text.length)
|
|
98
98
|
) {
|
|
@@ -115,7 +115,7 @@ fun InputOTP(
|
|
|
115
115
|
if (!it.isFocused && isBlurred) onBlur()
|
|
116
116
|
if (it.isFocused && !isBlurred) isBlurred = true
|
|
117
117
|
},
|
|
118
|
-
decorationBox = {
|
|
118
|
+
decorationBox = { _ ->
|
|
119
119
|
Box {
|
|
120
120
|
if (floatingValue.isNotEmpty()) {
|
|
121
121
|
Box(
|
|
@@ -19,6 +19,7 @@ import androidx.compose.foundation.text.KeyboardActions
|
|
|
19
19
|
import androidx.compose.foundation.text.KeyboardOptions
|
|
20
20
|
import androidx.compose.material3.CircularProgressIndicator
|
|
21
21
|
import androidx.compose.runtime.Composable
|
|
22
|
+
import androidx.compose.runtime.MutableState
|
|
22
23
|
import androidx.compose.runtime.getValue
|
|
23
24
|
import androidx.compose.runtime.mutableStateOf
|
|
24
25
|
import androidx.compose.runtime.remember
|
|
@@ -77,7 +78,7 @@ fun RenderRightIconSearch(
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
data class InputSearchProps(
|
|
80
|
-
val text: String
|
|
81
|
+
val text: MutableState<String>,
|
|
81
82
|
val buttonText: String = "",
|
|
82
83
|
val showButtonText: Boolean = false,
|
|
83
84
|
val placeholder: String = "",
|
|
@@ -105,7 +106,7 @@ data class InputSearchProps(
|
|
|
105
106
|
@Composable
|
|
106
107
|
fun InputSearch(
|
|
107
108
|
inputSearchProps: InputSearchProps = InputSearchProps(
|
|
108
|
-
text = "",
|
|
109
|
+
text = remember { mutableStateOf("") },
|
|
109
110
|
iconColor = AppTheme.current.colors.text.default
|
|
110
111
|
),
|
|
111
112
|
) {
|
|
@@ -126,7 +127,7 @@ fun InputSearch(
|
|
|
126
127
|
BasicTextField(
|
|
127
128
|
enabled = !inputSearchProps.disabled,
|
|
128
129
|
singleLine = true,
|
|
129
|
-
value = inputSearchProps.text,
|
|
130
|
+
value = inputSearchProps.text.value,
|
|
130
131
|
textStyle = TextStyle(
|
|
131
132
|
color = textColor,
|
|
132
133
|
fontSize = 14.sp,
|
|
@@ -174,7 +175,7 @@ fun InputSearch(
|
|
|
174
175
|
color = AppTheme.current.colors.text.hint
|
|
175
176
|
)
|
|
176
177
|
Box(Modifier.weight(1f)) {
|
|
177
|
-
if (inputSearchProps.text.isEmpty()) {
|
|
178
|
+
if (inputSearchProps.text.value.isEmpty()) {
|
|
178
179
|
Text(
|
|
179
180
|
text = inputSearchProps.placeholder,
|
|
180
181
|
style = TextStyle(
|
|
@@ -189,7 +190,7 @@ fun InputSearch(
|
|
|
189
190
|
}
|
|
190
191
|
innerTextField()
|
|
191
192
|
}
|
|
192
|
-
if (inputSearchProps.clearCondition?.invoke() == true || (isFocused && inputSearchProps.text.isNotEmpty())) {
|
|
193
|
+
if (inputSearchProps.clearCondition?.invoke() == true || (isFocused && inputSearchProps.text.value.isNotEmpty())) {
|
|
193
194
|
Row {
|
|
194
195
|
Spacer(Modifier.width(Spacing.XS))
|
|
195
196
|
Icon(
|
|
@@ -198,7 +199,7 @@ fun InputSearch(
|
|
|
198
199
|
color = AppTheme.current.colors.text.hint,
|
|
199
200
|
modifier = Modifier.clickable(
|
|
200
201
|
onClick = {
|
|
201
|
-
inputSearchProps.
|
|
202
|
+
inputSearchProps.text.value = ""
|
|
202
203
|
inputSearchProps.onClearPress.invoke()
|
|
203
204
|
},
|
|
204
205
|
interactionSource = remember { MutableInteractionSource() },
|
|
@@ -18,6 +18,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|
|
18
18
|
import androidx.compose.foundation.text.BasicTextField
|
|
19
19
|
import androidx.compose.foundation.text.KeyboardOptions
|
|
20
20
|
import androidx.compose.runtime.Composable
|
|
21
|
+
import androidx.compose.runtime.MutableState
|
|
21
22
|
import androidx.compose.runtime.getValue
|
|
22
23
|
import androidx.compose.runtime.mutableStateOf
|
|
23
24
|
import androidx.compose.runtime.remember
|
|
@@ -41,7 +42,7 @@ val DEFAULT_HEIGHT = 104.dp
|
|
|
41
42
|
|
|
42
43
|
@Composable
|
|
43
44
|
fun InputTextArea(
|
|
44
|
-
text: String = "",
|
|
45
|
+
text: MutableState<String> = remember { mutableStateOf("") },
|
|
45
46
|
maxLength: Int = MAX_LENGTH,
|
|
46
47
|
height: Dp = DEFAULT_HEIGHT,
|
|
47
48
|
floatingValue: String = "",
|
|
@@ -91,7 +92,7 @@ fun InputTextArea(
|
|
|
91
92
|
BasicTextField(
|
|
92
93
|
enabled = !disabled,
|
|
93
94
|
singleLine = false,
|
|
94
|
-
value = text,
|
|
95
|
+
value = text.value,
|
|
95
96
|
textStyle = TextStyle(
|
|
96
97
|
color = textColor,
|
|
97
98
|
fontSize = 16.sp,
|
|
@@ -172,7 +173,7 @@ fun InputTextArea(
|
|
|
172
173
|
verticalAlignment = Alignment.Top
|
|
173
174
|
) {
|
|
174
175
|
Box(Modifier.weight(1f)) {
|
|
175
|
-
if (text.isEmpty()) {
|
|
176
|
+
if (text.value.isEmpty()) {
|
|
176
177
|
Text(
|
|
177
178
|
text = placeholder,
|
|
178
179
|
style = TextStyle(
|
|
@@ -185,7 +186,7 @@ fun InputTextArea(
|
|
|
185
186
|
}
|
|
186
187
|
innerTextField()
|
|
187
188
|
}
|
|
188
|
-
if (isFocused && text.isNotEmpty()) {
|
|
189
|
+
if (isFocused && text.value.isNotEmpty()) {
|
|
189
190
|
Row {
|
|
190
191
|
Spacer(Modifier.width(Spacing.XS))
|
|
191
192
|
Icon(
|
|
@@ -193,7 +194,7 @@ fun InputTextArea(
|
|
|
193
194
|
size = 16.dp,
|
|
194
195
|
color = AppTheme.current.colors.text.hint,
|
|
195
196
|
modifier = Modifier.clickable(
|
|
196
|
-
onClick = {
|
|
197
|
+
onClick = { text.value = "" },
|
|
197
198
|
interactionSource = remember { MutableInteractionSource() },
|
|
198
199
|
indication = null
|
|
199
200
|
)
|
|
@@ -211,7 +212,7 @@ fun InputTextArea(
|
|
|
211
212
|
contentAlignment = Alignment.CenterEnd
|
|
212
213
|
) {
|
|
213
214
|
Text(
|
|
214
|
-
"${text.length}/$maxLength",
|
|
215
|
+
"${text.value.length}/$maxLength",
|
|
215
216
|
style = Typography.descriptionXsRegular,
|
|
216
217
|
color = AppTheme.current.colors.text.hint
|
|
217
218
|
)
|
|
@@ -25,15 +25,22 @@ import vn.momo.kits.const.Radius
|
|
|
25
25
|
import vn.momo.kits.const.Spacing
|
|
26
26
|
|
|
27
27
|
@Composable
|
|
28
|
-
fun
|
|
28
|
+
fun PopupPromotion(
|
|
29
29
|
source: String = "",
|
|
30
|
+
onPress: (() -> Unit) = {},
|
|
30
31
|
onClose: (() -> Unit) = {},
|
|
31
32
|
) {
|
|
32
33
|
Column(Modifier.semantics { testTag = "popup_notify" }) {
|
|
33
34
|
if (source.isNotEmpty()) {
|
|
34
35
|
Image(
|
|
35
36
|
source = source,
|
|
36
|
-
modifier = Modifier.fillMaxWidth()
|
|
37
|
+
modifier = Modifier.fillMaxWidth()
|
|
38
|
+
.aspectRatio(0.72f)
|
|
39
|
+
.clickable(
|
|
40
|
+
interactionSource = remember { MutableInteractionSource() },
|
|
41
|
+
indication = null,
|
|
42
|
+
onClick = onPress
|
|
43
|
+
),
|
|
37
44
|
)
|
|
38
45
|
}
|
|
39
46
|
Box(
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
package vn.momo.kits.modifier
|
|
2
2
|
|
|
3
|
-
import androidx.compose.foundation.clickable
|
|
4
|
-
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
5
|
-
import androidx.compose.runtime.remember
|
|
6
3
|
import androidx.compose.ui.Modifier
|
|
7
|
-
import androidx.compose.ui.composed
|
|
8
|
-
import androidx.compose.ui.semantics.Role
|
|
9
4
|
import androidx.compose.ui.semantics.contentDescription
|
|
10
5
|
import androidx.compose.ui.semantics.semantics
|
|
11
6
|
import androidx.compose.ui.semantics.testTag
|
|
@@ -45,13 +45,24 @@ func safeAreaTopInset() -> CGFloat {
|
|
|
45
45
|
public struct HeaderBackground: View {
|
|
46
46
|
var headerType: HeaderType = .default
|
|
47
47
|
var scrollState: CGFloat
|
|
48
|
+
var isTransparent: Bool = false
|
|
49
|
+
|
|
50
|
+
public init(
|
|
51
|
+
headerType: HeaderType = .default,
|
|
52
|
+
scrollState: CGFloat = 0,
|
|
53
|
+
isTransparent: Bool = false
|
|
54
|
+
) {
|
|
55
|
+
self.headerType = headerType
|
|
56
|
+
self.scrollState = scrollState
|
|
57
|
+
self.isTransparent = isTransparent
|
|
58
|
+
}
|
|
48
59
|
|
|
49
60
|
public var body: some View {
|
|
50
61
|
|
|
51
62
|
let statusBarHeight = safeAreaTopInset()
|
|
52
63
|
|
|
53
64
|
let opacity = 1 - CGFloat(scrollState) / 200
|
|
54
|
-
let backgroundColor =
|
|
65
|
+
let backgroundColor = isTransparent ? Color.clear : Colors.black01
|
|
55
66
|
|
|
56
67
|
Group {
|
|
57
68
|
if headerType == .default {
|
|
@@ -62,7 +73,9 @@ public struct HeaderBackground: View {
|
|
|
62
73
|
.fill(backgroundColor)
|
|
63
74
|
.frame(height: height)
|
|
64
75
|
.shadow(color: Colors.black20.opacity(0.2), radius: 10, x: 0, y: -2)
|
|
65
|
-
.overlay(
|
|
76
|
+
.overlay(
|
|
77
|
+
isTransparent ? nil :
|
|
78
|
+
Rectangle()
|
|
66
79
|
.fill(LinearGradient(
|
|
67
80
|
gradient: Gradient(colors: [
|
|
68
81
|
Color(red: 1, green: 0.8, blue: 0.87),
|
|
@@ -111,6 +124,7 @@ public struct Header: View {
|
|
|
111
124
|
var animatedHeader: AnimatedHeader? = nil
|
|
112
125
|
var scrollState: CGFloat = 0
|
|
113
126
|
var inputSearchProps: InputSearchProps? = nil
|
|
127
|
+
var tintColor: Color? = nil
|
|
114
128
|
|
|
115
129
|
@State private var colorFraction: CGFloat = 0
|
|
116
130
|
|
|
@@ -123,7 +137,8 @@ public struct Header: View {
|
|
|
123
137
|
opacity: CGFloat? = nil,
|
|
124
138
|
animatedHeader: AnimatedHeader? = nil,
|
|
125
139
|
scrollState: CGFloat = 0,
|
|
126
|
-
inputSearchProps: InputSearchProps? = nil
|
|
140
|
+
inputSearchProps: InputSearchProps? = nil,
|
|
141
|
+
tintColor: Color? = nil
|
|
127
142
|
) {
|
|
128
143
|
self.headerType = headerType
|
|
129
144
|
self.titlePosition = titlePosition
|
|
@@ -134,27 +149,27 @@ public struct Header: View {
|
|
|
134
149
|
self.animatedHeader = animatedHeader
|
|
135
150
|
self.scrollState = scrollState
|
|
136
151
|
self.inputSearchProps = inputSearchProps
|
|
152
|
+
self.tintColor = tintColor
|
|
137
153
|
}
|
|
138
154
|
|
|
139
155
|
public var body: some View {
|
|
140
156
|
|
|
141
|
-
let
|
|
142
|
-
let
|
|
143
|
-
let
|
|
157
|
+
// let tintIconColor = Colors.black17
|
|
158
|
+
let backgroundButton = tintColor == Colors.black01 ? Color.white.opacity(0.2) : Colors.black01.opacity(0.6)
|
|
159
|
+
let borderColor: Color = tintColor == Colors.black01 ? Color.black.opacity(0.6) : Color.black.opacity(0.2)
|
|
144
160
|
|
|
145
161
|
if headerType != .none {
|
|
146
|
-
|
|
162
|
+
VStack(spacing: 0) {
|
|
147
163
|
ZStack {
|
|
148
164
|
HStack {
|
|
149
165
|
if let goBack = goBack {
|
|
150
166
|
SwiftUI.Button(action: goBack) {
|
|
151
167
|
Circle()
|
|
152
|
-
.stroke(
|
|
168
|
+
.stroke(borderColor, lineWidth: 0.2)
|
|
153
169
|
.background(Circle().fill(backgroundButton))
|
|
154
170
|
.frame(width: 28, height: 28)
|
|
155
171
|
.overlay(
|
|
156
|
-
|
|
157
|
-
.foregroundColor(.black)
|
|
172
|
+
Icon(source: "arrow-back", size: 20, color: tintColor)
|
|
158
173
|
)
|
|
159
174
|
}
|
|
160
175
|
|
|
@@ -167,14 +182,11 @@ public struct Header: View {
|
|
|
167
182
|
}
|
|
168
183
|
|
|
169
184
|
}
|
|
170
|
-
.
|
|
171
|
-
.padding(.horizontal)
|
|
172
|
-
|
|
173
|
-
|
|
185
|
+
.padding(.horizontal, 12)
|
|
174
186
|
|
|
175
187
|
HStack {
|
|
176
188
|
if titlePosition == .left, goBack != nil {
|
|
177
|
-
Spacer().frame(width:
|
|
189
|
+
Spacer().frame(width: 38)
|
|
178
190
|
}
|
|
179
191
|
|
|
180
192
|
if inputSearchProps != nil {
|
|
@@ -201,20 +213,22 @@ public struct Header: View {
|
|
|
201
213
|
}
|
|
202
214
|
} else {
|
|
203
215
|
Text(title)
|
|
204
|
-
.font(.
|
|
205
|
-
.foregroundColor(
|
|
206
|
-
.frame(maxWidth: titlePosition == .center ? .
|
|
216
|
+
.font(Font.system(size: 17).weight(.bold)) .lineSpacing(22)
|
|
217
|
+
.foregroundColor(Colors.black17)
|
|
218
|
+
.frame(maxWidth: titlePosition == .center ? UIScreen.main.bounds.width - 252 : nil)
|
|
219
|
+
.frame(maxWidth: titlePosition == .center ? .infinity : UIScreen.main.bounds.width - 172, alignment: titlePosition == .center ? .center : .leading)
|
|
220
|
+
.lineLimit(1)
|
|
221
|
+
|
|
207
222
|
}
|
|
208
223
|
Spacer()
|
|
209
224
|
}
|
|
210
|
-
.frame(height: 52)
|
|
211
225
|
.padding(.horizontal)
|
|
212
226
|
}
|
|
213
227
|
.background(Color.clear)
|
|
214
228
|
}
|
|
215
|
-
|
|
229
|
+
.frame(height: 52)
|
|
216
230
|
}
|
|
217
|
-
|
|
231
|
+
}
|
|
218
232
|
}
|
|
219
233
|
|
|
220
234
|
|
|
@@ -9,6 +9,8 @@ import SwiftUI
|
|
|
9
9
|
|
|
10
10
|
public struct Screen<Content: View>: View {
|
|
11
11
|
var backgroundColor: Color?
|
|
12
|
+
var headerTransparent: Bool = false
|
|
13
|
+
var tintColor: Color? = Colors.black17
|
|
12
14
|
var isBack: Bool
|
|
13
15
|
var headerType: HeaderType
|
|
14
16
|
var verticalAlignment: VerticalAlignment
|
|
@@ -29,12 +31,14 @@ public struct Screen<Content: View>: View {
|
|
|
29
31
|
|
|
30
32
|
public init(
|
|
31
33
|
backgroundColor: Color? = nil,
|
|
34
|
+
headerTransparent: Bool = false,
|
|
35
|
+
tintColor: Color = Colors.black17,
|
|
32
36
|
isBack: Bool = true,
|
|
33
37
|
headerType: HeaderType = .default,
|
|
34
38
|
verticalAlignment: VerticalAlignment = .top,
|
|
35
39
|
horizontalAlignment: HorizontalAlignment = .leading,
|
|
36
40
|
title: String = "Stack",
|
|
37
|
-
titlePosition: TitlePosition = .
|
|
41
|
+
titlePosition: TitlePosition = .left,
|
|
38
42
|
goBack: (() -> Void)? = nil,
|
|
39
43
|
scrollable: Bool = true,
|
|
40
44
|
onContentLayout: ((CGRect) -> Void)? = nil,
|
|
@@ -48,6 +52,8 @@ public struct Screen<Content: View>: View {
|
|
|
48
52
|
@ViewBuilder content: @escaping () -> Content
|
|
49
53
|
) {
|
|
50
54
|
self.backgroundColor = backgroundColor
|
|
55
|
+
self.headerTransparent = headerTransparent
|
|
56
|
+
self.tintColor = tintColor
|
|
51
57
|
self.isBack = isBack
|
|
52
58
|
self.headerType = headerType
|
|
53
59
|
self.verticalAlignment = verticalAlignment
|
|
@@ -71,23 +77,25 @@ public struct Screen<Content: View>: View {
|
|
|
71
77
|
|
|
72
78
|
public var body: some View {
|
|
73
79
|
GeometryReader { geometry in
|
|
74
|
-
let
|
|
75
|
-
let statusBarHeight = safeAreaInsets.top
|
|
80
|
+
let topInset = geometry.safeAreaInsets.top
|
|
76
81
|
let keyboardHeight: CGFloat = 0
|
|
77
82
|
let keyboardSize: CGFloat = useAvoidKeyboard ? max(keyboardHeight, 0) : 0
|
|
83
|
+
let height = geometry.size.height
|
|
84
|
+
let bottomInset = geometry.safeAreaInsets.bottom
|
|
85
|
+
let screenHeight = height + topInset + bottomInset
|
|
78
86
|
|
|
79
87
|
ZStack {
|
|
80
88
|
(backgroundColor ?? Color.white).edgesIgnoringSafeArea(.all)
|
|
81
89
|
|
|
82
90
|
VStack(spacing: 0) {
|
|
83
|
-
ZStack {
|
|
84
|
-
if animatedHeader == nil {
|
|
85
|
-
HeaderBackground(headerType: headerType, scrollState: scrollOffset)
|
|
86
|
-
} else {
|
|
87
|
-
Color.white.opacity(Double(min(scrollOffset / 114, 1)))
|
|
88
|
-
.overlay(HeaderBackground(headerType: headerType, scrollState: scrollOffset))
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
+
ZStack(alignment: .top) {
|
|
92
|
+
// if animatedHeader == nil {
|
|
93
|
+
// HeaderBackground(headerType: headerType, scrollState: scrollOffset)
|
|
94
|
+
// } else {
|
|
95
|
+
// Color.white.opacity(Double(min(scrollOffset / 114, 1)))
|
|
96
|
+
// .overlay(HeaderBackground(headerType: headerType, scrollState: scrollOffset))
|
|
97
|
+
//
|
|
98
|
+
// }
|
|
91
99
|
|
|
92
100
|
Header(
|
|
93
101
|
headerType: headerType,
|
|
@@ -98,14 +106,19 @@ public struct Screen<Content: View>: View {
|
|
|
98
106
|
opacity: min(scrollOffset / 114, 1),
|
|
99
107
|
animatedHeader: animatedHeader,
|
|
100
108
|
scrollState: scrollOffset,
|
|
101
|
-
inputSearchProps: inputSearchProps
|
|
102
|
-
|
|
103
|
-
|
|
109
|
+
inputSearchProps: inputSearchProps,
|
|
110
|
+
tintColor: tintColor
|
|
111
|
+
)
|
|
112
|
+
.background(HeaderBackground(headerType: headerType, scrollState: scrollOffset, isTransparent: headerTransparent).edgesIgnoringSafeArea(.top))
|
|
113
|
+
.offset(y: topInset)
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
.offset(y: -topInset)
|
|
104
117
|
|
|
105
118
|
|
|
106
119
|
VStack(alignment: horizontalAlignment, spacing: 0) {
|
|
107
120
|
if animatedHeader != nil {
|
|
108
|
-
Spacer().frame(height:
|
|
121
|
+
Spacer().frame(height: topInset + 52 + layoutOffset)
|
|
109
122
|
}
|
|
110
123
|
|
|
111
124
|
if scrollable {
|
|
@@ -20,7 +20,7 @@ public enum PopupButtonType {
|
|
|
20
20
|
public struct PopupDisplay: View {
|
|
21
21
|
// MARK: Lifecycle
|
|
22
22
|
|
|
23
|
-
public init(isPresented: Binding<Bool>, title: String = "", description: String = "", url: String = "", buttonDirection: PopupButtonDirection = .column, buttonType: PopupButtonType = .button, actionButtonTitle: String = "", closeButtonTitle: String = "", onPressAction: @escaping () -> Void = {}, onPressCloseButton: @escaping () -> Void = {}, onClose: @escaping () -> Void = {}) {
|
|
23
|
+
public init(isPresented: Binding<Bool>, title: String = "", description: String = "", url: String = "", buttonDirection: PopupButtonDirection = .column, buttonType: PopupButtonType = .button, actionButtonTitle: String = "", closeButtonTitle: String = "", onPressAction: @escaping () -> Void = {}, onPressCloseButton: @escaping () -> Void = {}, onClose: @escaping () -> Void = {}, errorCode: String = "") {
|
|
24
24
|
self._isPresented = isPresented
|
|
25
25
|
self.title = title
|
|
26
26
|
self.description = description
|
|
@@ -32,6 +32,7 @@ public struct PopupDisplay: View {
|
|
|
32
32
|
self.onClose = onClose
|
|
33
33
|
self.closeButtonTitle = closeButtonTitle
|
|
34
34
|
self.actionButtonTitle = actionButtonTitle
|
|
35
|
+
self.errorCode = errorCode
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
// MARK: Public
|
|
@@ -39,7 +40,7 @@ public struct PopupDisplay: View {
|
|
|
39
40
|
public var body: some View {
|
|
40
41
|
VStack(spacing: 12) {
|
|
41
42
|
ZStack(alignment: .topTrailing) {
|
|
42
|
-
SwiftUI.Button(action:
|
|
43
|
+
SwiftUI.Button(action: onClose) {
|
|
43
44
|
Image(systemName: "xmark.circle.fill")
|
|
44
45
|
.resizable()
|
|
45
46
|
.frame(width: 22, height: 22)
|
|
@@ -51,20 +52,20 @@ public struct PopupDisplay: View {
|
|
|
51
52
|
.zIndex(1)
|
|
52
53
|
.accessibility(identifier: "ic_popup_close")
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
VStack {
|
|
56
|
+
if(!url.isEmpty) {
|
|
57
|
+
WebImage(url: URL(string: url), isAnimating: .constant(true))
|
|
58
|
+
.resizable()
|
|
59
|
+
.placeholder {
|
|
60
|
+
Rectangle()
|
|
61
|
+
.fill(Color.gray.opacity(0.3))
|
|
62
|
+
.frame(maxWidth: .infinity, maxHeight: 184)
|
|
63
|
+
}
|
|
64
|
+
.scaledToFill()
|
|
65
|
+
.frame(maxWidth: .infinity)
|
|
66
|
+
.clipShape(RoundedCorner(radius: 15, corners: [.topLeft, .topRight]))
|
|
67
|
+
.aspectRatio(2, contentMode: .fit)
|
|
68
|
+
}
|
|
68
69
|
VStack(alignment: .leading) {
|
|
69
70
|
Text(title)
|
|
70
71
|
.foregroundColor(.black)
|
|
@@ -79,10 +80,18 @@ public struct PopupDisplay: View {
|
|
|
79
80
|
.font(.paragraph)
|
|
80
81
|
.opacity(0.6)
|
|
81
82
|
.multilineTextAlignment(.leading)
|
|
82
|
-
.padding(.bottom,
|
|
83
|
+
.padding(.bottom, 8)
|
|
84
|
+
|
|
85
|
+
if(!errorCode.isEmpty) {
|
|
86
|
+
Text(errorCode)
|
|
87
|
+
.foregroundColor(Colors.black12)
|
|
88
|
+
.font(.description_xs_regular)
|
|
89
|
+
.lineLimit(1)
|
|
90
|
+
}
|
|
83
91
|
}
|
|
84
92
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
85
93
|
.padding(.horizontal, 24)
|
|
94
|
+
.padding(.bottom, 24)
|
|
86
95
|
|
|
87
96
|
if buttonDirection == .row {
|
|
88
97
|
if buttonType == .text {
|
|
@@ -120,7 +129,8 @@ public struct PopupDisplay: View {
|
|
|
120
129
|
var onClose: () -> Void
|
|
121
130
|
var actionButtonTitle: String
|
|
122
131
|
var closeButtonTitle: String
|
|
123
|
-
|
|
132
|
+
var errorCode: String
|
|
133
|
+
|
|
124
134
|
var RowTextButtons: some View {
|
|
125
135
|
HStack {
|
|
126
136
|
SwiftUI.Button(action: onPressCloseButton) {
|
|
@@ -181,9 +191,4 @@ public struct PopupDisplay: View {
|
|
|
181
191
|
.padding(.bottom, 24)
|
|
182
192
|
}
|
|
183
193
|
|
|
184
|
-
|
|
185
|
-
func onPressClose(){
|
|
186
|
-
isPresented = false
|
|
187
|
-
onClose()
|
|
188
|
-
}
|
|
189
194
|
}
|
|
@@ -1,52 +1,66 @@
|
|
|
1
|
-
import SDWebImageSwiftUI
|
|
2
1
|
import SwiftUI
|
|
2
|
+
import SDWebImageSwiftUI
|
|
3
3
|
|
|
4
4
|
public struct PopupPromotion: View {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
self._isPresented = isPresented
|
|
9
|
-
self.onPressAction = onPressAction
|
|
10
|
-
self.buttonTitle = buttonTitle
|
|
11
|
-
self.onClose = onClose
|
|
12
|
-
self.url = url
|
|
13
|
-
}
|
|
5
|
+
var imageUrl: String
|
|
6
|
+
var onIconClose: (() -> Void)?
|
|
7
|
+
var onAction: (() -> Void)?
|
|
14
8
|
|
|
15
|
-
|
|
9
|
+
|
|
10
|
+
public init(
|
|
11
|
+
imageUrl: String,
|
|
12
|
+
onIconClose: (() -> Void)? = nil,
|
|
13
|
+
onAction: (() -> Void)? = nil
|
|
14
|
+
) {
|
|
15
|
+
self.imageUrl = imageUrl
|
|
16
|
+
self.onIconClose = onIconClose
|
|
17
|
+
self.onAction = onAction
|
|
18
|
+
}
|
|
16
19
|
|
|
17
20
|
public var body: some View {
|
|
18
|
-
VStack(spacing:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
VStack(spacing: 8) {
|
|
22
|
+
WebImage(url: URL(string: imageUrl)!)
|
|
23
|
+
.resizable()
|
|
24
|
+
.placeholder {
|
|
25
|
+
Color.gray
|
|
26
|
+
.aspectRatio(0.72, contentMode: .fit)
|
|
27
|
+
.frame(maxWidth: UIScreen.main.bounds.width - Spacing.XL * 2)
|
|
28
|
+
.clipped()
|
|
29
|
+
}
|
|
30
|
+
.aspectRatio(0.72, contentMode: .fit)
|
|
31
|
+
.frame(maxWidth: UIScreen.main.bounds.width - Spacing.XL * 2)
|
|
32
|
+
.clipped()
|
|
33
|
+
.onTapGesture {
|
|
34
|
+
onAction?()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
buildCloseIcon()
|
|
33
38
|
}
|
|
34
|
-
.
|
|
35
|
-
.shadow(color: .black.opacity(0.08), radius: 2, x: 0, y: 0)
|
|
36
|
-
.shadow(color: .black.opacity(0.16), radius: 24, x: 0, y: 0)
|
|
37
|
-
.padding(.horizontal, 40)
|
|
39
|
+
.accessibility(identifier: "popup_promotion")
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
@ViewBuilder
|
|
43
|
+
private func buildCloseIcon() -> some View {
|
|
44
|
+
HStack {
|
|
45
|
+
Spacer()
|
|
46
|
+
SwiftUI.Button(action: {
|
|
47
|
+
onIconClose?()
|
|
48
|
+
}) {
|
|
49
|
+
ZStack {
|
|
50
|
+
Circle()
|
|
51
|
+
.strokeBorder(Colors.black01, lineWidth: 2)
|
|
52
|
+
.background(Circle().fill(Colors.black17))
|
|
53
|
+
.frame(width: 20, height: 20)
|
|
41
54
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
func onPressClose(){
|
|
49
|
-
isPresented = false
|
|
50
|
-
onClose()
|
|
55
|
+
Icon(source: "navigation_close", size: 14, color: Colors.black01)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
.padding(8)
|
|
59
|
+
Spacer()
|
|
60
|
+
}
|
|
51
61
|
}
|
|
62
|
+
|
|
52
63
|
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
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
|
+
#Wed Aug 21 14:20:12 ICT 2024
|
|
8
|
+
sdk.dir=/Users/huynhdung/Library/Android/sdk
|