@momo-kits/native-kits 0.157.1-skill.1-debug → 0.157.1-skill.3-debug
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/.claude/momo-native-kits-skill/SKILL.md +51 -0
- package/.claude/momo-native-kits-skill/evals/evals.json +95 -0
- package/.claude/momo-native-kits-skill/references/badge.md +52 -0
- package/.claude/momo-native-kits-skill/references/button.md +182 -0
- package/.claude/momo-native-kits-skill/references/card.md +48 -0
- package/.claude/momo-native-kits-skill/references/checkbox.md +51 -0
- package/.claude/momo-native-kits-skill/references/chip.md +48 -0
- package/.claude/momo-native-kits-skill/references/constants.md +260 -0
- package/.claude/momo-native-kits-skill/references/divider.md +26 -0
- package/.claude/momo-native-kits-skill/references/input.md +408 -0
- package/.claude/momo-native-kits-skill/references/navigation.md +475 -0
- package/.claude/momo-native-kits-skill/references/popup.md +97 -0
- package/.claude/momo-native-kits-skill/references/radio.md +60 -0
- package/.claude/momo-native-kits-skill/references/skeleton.md +40 -0
- package/.claude/momo-native-kits-skill/references/snackbar.md +54 -0
- package/.claude/momo-native-kits-skill/references/switch.md +62 -0
- package/.claude/momo-native-kits-skill/references/text.md +195 -0
- package/.claude/momo-native-kits-skill/references/tooltip.md +34 -0
- package/.claude/momo-native-kits-skill/references/trustbanner.md +61 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/benchmark.json +20 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/benchmark.md +13 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-0-button/eval_metadata.json +6 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-0-button/with_skill/outputs/ButtonExample.kt +55 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-0-button/without_skill/outputs/ButtonExample.kt +45 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-1-input/eval_metadata.json +6 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-1-input/with_skill/outputs/InputPhoneExample.kt +40 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-1-input/without_skill/outputs/InputPhoneExample.kt +42 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-2-bottomtab/eval_metadata.json +6 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-2-bottomtab/with_skill/outputs/BottomTabExample.kt +236 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-2-bottomtab/without_skill/outputs/BottomTabExample.kt +152 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-3-checkbox/eval_metadata.json +6 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-3-checkbox/with_skill/outputs/CheckBoxExample.kt +49 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-3-checkbox/without_skill/outputs/CheckBoxExample.kt +123 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-4-datetimepicker/eval_metadata.json +6 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-4-datetimepicker/with_skill/outputs/DateTimePickerExample.kt +318 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-4-datetimepicker/without_skill/outputs/DateTimePickerExample.kt +330 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-card/with_skill/outputs/CardExample.kt +124 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-card/without_skill/outputs/CardExample.kt +71 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-loginform/with_skill/outputs/LoginFormExample.kt +134 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-loginform/without_skill/outputs/LoginFormExample.kt +199 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-navcontainer/with_skill/outputs/NavigationContainerExample.kt +224 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-navcontainer/without_skill/outputs/NavigationContainerExample.kt +225 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-popup/with_skill/outputs/PopupExample.kt +79 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-popup/without_skill/outputs/PopupExample.kt +169 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-setoptions/eval_metadata.json +6 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-setoptions/with_skill/outputs/SetOptionsExample.kt +255 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-setoptions/without_skill/outputs/SetOptionsExample.kt +212 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-skeleton/with_skill/outputs/SkeletonExample.kt +199 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-skeleton/without_skill/outputs/SkeletonExample.kt +229 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/benchmark.json +20 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/benchmark.md +13 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/eval_metadata.json +22 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/with_skill/outputs/PrimaryButtonExample.kt +38 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/with_skill/timing.json +5 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/without_skill/outputs/PrimaryButtonExample.kt +83 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/without_skill/timing.json +5 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/eval_metadata.json +22 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/with_skill/outputs/NavigationContainerExample.kt +547 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/with_skill/timing.json +5 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/without_skill/outputs/MoMoNavigationContainer.kt +519 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/without_skill/timing.json +5 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/eval_metadata.json +27 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/with_skill/outputs/SetOptionsExample.kt +429 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/with_skill/timing.json +5 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/without_skill/outputs/SetOptionsExample.kt +353 -0
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/without_skill/timing.json +5 -0
- package/.claude/settings.local.json +35 -7
- package/compose/build.gradle.kts +1 -1
- package/gradle.properties +1 -1
- package/ios/Input/Input.swift +112 -50
- package/local.properties +1 -1
- package/package.json +1 -1
- package/.claude/momo-native-kits/SKILL.md +0 -87
- package/.claude/momo-native-kits/references/Badge.md +0 -39
- package/.claude/momo-native-kits/references/BadgeDot.md +0 -37
- package/.claude/momo-native-kits/references/BottomSheet.md +0 -51
- package/.claude/momo-native-kits/references/BottomTab.md +0 -65
- package/.claude/momo-native-kits/references/Button.md +0 -197
- package/.claude/momo-native-kits/references/CheckBox.md +0 -51
- package/.claude/momo-native-kits/references/Chip.md +0 -47
- package/.claude/momo-native-kits/references/Divider.md +0 -29
- package/.claude/momo-native-kits/references/HeaderTitle.md +0 -45
- package/.claude/momo-native-kits/references/HeaderType.md +0 -47
- package/.claude/momo-native-kits/references/Icon.md +0 -32
- package/.claude/momo-native-kits/references/Image.md +0 -38
- package/.claude/momo-native-kits/references/Information.md +0 -36
- package/.claude/momo-native-kits/references/Input.md +0 -334
- package/.claude/momo-native-kits/references/InputDropDown.md +0 -47
- package/.claude/momo-native-kits/references/InputMoney.md +0 -241
- package/.claude/momo-native-kits/references/InputOTP.md +0 -52
- package/.claude/momo-native-kits/references/InputPhoneNumber.md +0 -175
- package/.claude/momo-native-kits/references/InputSearch.md +0 -57
- package/.claude/momo-native-kits/references/InputTextArea.md +0 -46
- package/.claude/momo-native-kits/references/NavigationContainer.md +0 -51
- package/.claude/momo-native-kits/references/Navigator.md +0 -287
- package/.claude/momo-native-kits/references/PaginationDot.md +0 -28
- package/.claude/momo-native-kits/references/PaginationNumber.md +0 -28
- package/.claude/momo-native-kits/references/PopupNotify.md +0 -47
- package/.claude/momo-native-kits/references/Radio.md +0 -44
- package/.claude/momo-native-kits/references/Skeleton.md +0 -32
- package/.claude/momo-native-kits/references/Switch.md +0 -36
- package/.claude/momo-native-kits/references/Tag.md +0 -40
- package/.claude/momo-native-kits/references/Text.md +0 -37
- package/.claude/momo-native-kits/references/Title.md +0 -43
- package/.claude/momo-native-kits/references/Tooltip.md +0 -30
- package/building-skill-for-claude.md +0 -1190
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
package com.example
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Column
|
|
4
|
+
import androidx.compose.foundation.layout.Row
|
|
5
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
6
|
+
import androidx.compose.foundation.layout.padding
|
|
7
|
+
import androidx.compose.foundation.layout.size
|
|
8
|
+
import androidx.compose.runtime.Composable
|
|
9
|
+
import androidx.compose.ui.Modifier
|
|
10
|
+
import androidx.compose.ui.unit.dp
|
|
11
|
+
import vn.momo.kits.components.Card
|
|
12
|
+
import vn.momo.kits.components.Image
|
|
13
|
+
import vn.momo.kits.components.Text
|
|
14
|
+
import vn.momo.kits.components.Title
|
|
15
|
+
import vn.momo.kits.components.TitleType
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Example: Card component to display a list item with image and title
|
|
19
|
+
*
|
|
20
|
+
* This demonstrates how to create a card in MoMo Native Kits that displays
|
|
21
|
+
* a list item with an image on the left and a title on the right.
|
|
22
|
+
*/
|
|
23
|
+
@Composable
|
|
24
|
+
fun ListItemCardExample() {
|
|
25
|
+
Card(
|
|
26
|
+
onClick = {
|
|
27
|
+
// Handle item click
|
|
28
|
+
},
|
|
29
|
+
modifier = Modifier
|
|
30
|
+
.fillMaxWidth()
|
|
31
|
+
.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
32
|
+
) {
|
|
33
|
+
Row(
|
|
34
|
+
modifier = Modifier.padding(12.dp)
|
|
35
|
+
) {
|
|
36
|
+
// Image on the left
|
|
37
|
+
Image(
|
|
38
|
+
source = "https://example.com/image.jpg",
|
|
39
|
+
modifier = Modifier.size(48.dp)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
// Title on the right
|
|
43
|
+
Column(
|
|
44
|
+
modifier = Modifier.padding(start = 12.dp)
|
|
45
|
+
) {
|
|
46
|
+
Title(
|
|
47
|
+
text = "Item Title",
|
|
48
|
+
type = TitleType.TITLE_4
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Alternative example: Card with image and title with description
|
|
57
|
+
*/
|
|
58
|
+
@Composable
|
|
59
|
+
fun ListItemCardWithDescriptionExample() {
|
|
60
|
+
Card(
|
|
61
|
+
onClick = {
|
|
62
|
+
// Handle item click
|
|
63
|
+
},
|
|
64
|
+
modifier = Modifier
|
|
65
|
+
.fillMaxWidth()
|
|
66
|
+
.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
67
|
+
) {
|
|
68
|
+
Row(
|
|
69
|
+
modifier = Modifier.padding(12.dp)
|
|
70
|
+
) {
|
|
71
|
+
// Image on the left
|
|
72
|
+
Image(
|
|
73
|
+
source = "https://example.com/avatar.jpg",
|
|
74
|
+
modifier = Modifier.size(56.dp)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
// Title and description on the right
|
|
78
|
+
Column(
|
|
79
|
+
modifier = Modifier.padding(start = 12.dp)
|
|
80
|
+
) {
|
|
81
|
+
Title(
|
|
82
|
+
text = "User Profile",
|
|
83
|
+
type = TitleType.TITLE_4
|
|
84
|
+
)
|
|
85
|
+
Text(
|
|
86
|
+
text = "View and edit your profile information",
|
|
87
|
+
modifier = Modifier.padding(top = 4.dp)
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Example: Static card with image and title (non-clickable)
|
|
96
|
+
*/
|
|
97
|
+
@Composable
|
|
98
|
+
fun StaticListItemCardExample() {
|
|
99
|
+
Card(
|
|
100
|
+
modifier = Modifier
|
|
101
|
+
.fillMaxWidth()
|
|
102
|
+
.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
103
|
+
) {
|
|
104
|
+
Row(
|
|
105
|
+
modifier = Modifier.padding(12.dp)
|
|
106
|
+
) {
|
|
107
|
+
// Image on the left
|
|
108
|
+
Image(
|
|
109
|
+
source = "https://example.com/icon.png",
|
|
110
|
+
modifier = Modifier.size(40.dp)
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
// Title on the right
|
|
114
|
+
Column(
|
|
115
|
+
modifier = Modifier.padding(start = 12.dp)
|
|
116
|
+
) {
|
|
117
|
+
Title(
|
|
118
|
+
text = "Settings",
|
|
119
|
+
type = TitleType.TITLE_4
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
package com.example.card
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Row
|
|
4
|
+
import androidx.compose.foundation.layout.Spacer
|
|
5
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
6
|
+
import androidx.compose.foundation.layout.padding
|
|
7
|
+
import androidx.compose.foundation.layout.size
|
|
8
|
+
import androidx.compose.foundation.layout.width
|
|
9
|
+
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
10
|
+
import androidx.compose.material3.Card
|
|
11
|
+
import androidx.compose.material3.CardDefaults
|
|
12
|
+
import androidx.compose.material3.Text
|
|
13
|
+
import androidx.compose.runtime.Composable
|
|
14
|
+
import androidx.compose.ui.Alignment
|
|
15
|
+
import androidx.compose.ui.Modifier
|
|
16
|
+
import androidx.compose.ui.draw.clip
|
|
17
|
+
import androidx.compose.ui.layout.ContentScale
|
|
18
|
+
import androidx.compose.ui.unit.dp
|
|
19
|
+
import coil.compose.AsyncImage
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A card component to display a list item with image and title
|
|
23
|
+
*/
|
|
24
|
+
@Composable
|
|
25
|
+
fun ListItemCard(
|
|
26
|
+
imageUrl: String,
|
|
27
|
+
title: String,
|
|
28
|
+
modifier: Modifier = Modifier
|
|
29
|
+
) {
|
|
30
|
+
Card(
|
|
31
|
+
modifier = modifier
|
|
32
|
+
.fillMaxWidth()
|
|
33
|
+
.padding(8.dp),
|
|
34
|
+
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
|
|
35
|
+
shape = RoundedCornerShape(12.dp)
|
|
36
|
+
) {
|
|
37
|
+
Row(
|
|
38
|
+
modifier = Modifier
|
|
39
|
+
.fillMaxWidth()
|
|
40
|
+
.padding(12.dp),
|
|
41
|
+
verticalAlignment = Alignment.CenterVertically
|
|
42
|
+
) {
|
|
43
|
+
// Image
|
|
44
|
+
AsyncImage(
|
|
45
|
+
model = imageUrl,
|
|
46
|
+
contentDescription = title,
|
|
47
|
+
modifier = Modifier
|
|
48
|
+
.size(60.dp)
|
|
49
|
+
.clip(RoundedCornerShape(8.dp)),
|
|
50
|
+
contentScale = ContentScale.Crop
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
Spacer(modifier = Modifier.width(16.dp))
|
|
54
|
+
|
|
55
|
+
// Title
|
|
56
|
+
Text(
|
|
57
|
+
text = title,
|
|
58
|
+
modifier = Modifier.weight(1f)
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Example usage
|
|
65
|
+
@Composable
|
|
66
|
+
fun CardExample() {
|
|
67
|
+
ListItemCard(
|
|
68
|
+
imageUrl = "https://example.com/image.jpg",
|
|
69
|
+
title = "Sample Item Title"
|
|
70
|
+
)
|
|
71
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
package vn.momo.kits.screens
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
4
|
+
import androidx.compose.foundation.layout.Column
|
|
5
|
+
import androidx.compose.foundation.layout.Spacer
|
|
6
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
7
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
8
|
+
import androidx.compose.foundation.layout.height
|
|
9
|
+
import androidx.compose.foundation.layout.padding
|
|
10
|
+
import androidx.compose.foundation.rememberScrollState
|
|
11
|
+
import androidx.compose.foundation.verticalScroll
|
|
12
|
+
import androidx.compose.runtime.Composable
|
|
13
|
+
import androidx.compose.runtime.MutableState
|
|
14
|
+
import androidx.compose.runtime.getValue
|
|
15
|
+
import androidx.compose.runtime.mutableStateOf
|
|
16
|
+
import androidx.compose.runtime.remember
|
|
17
|
+
import androidx.compose.runtime.setValue
|
|
18
|
+
import androidx.compose.ui.Alignment
|
|
19
|
+
import androidx.compose.ui.Modifier
|
|
20
|
+
import androidx.compose.ui.text.input.KeyboardType
|
|
21
|
+
import androidx.compose.ui.unit.dp
|
|
22
|
+
import vn.momo.kits.components.Button
|
|
23
|
+
import vn.momo.kits.components.ButtonType
|
|
24
|
+
import vn.momo.kits.components.Input
|
|
25
|
+
import vn.momo.kits.components.InputPhoneNumber
|
|
26
|
+
import vn.momo.kits.components.Size
|
|
27
|
+
|
|
28
|
+
@Composable
|
|
29
|
+
fun LoginFormExample() {
|
|
30
|
+
val phoneNumber: MutableState<String> = remember { mutableStateOf("") }
|
|
31
|
+
val password: MutableState<String> = remember { mutableStateOf("") }
|
|
32
|
+
var isLoading by remember { mutableStateOf(false) }
|
|
33
|
+
var phoneError by remember { mutableStateOf("") }
|
|
34
|
+
var passwordError by remember { mutableStateOf("") }
|
|
35
|
+
|
|
36
|
+
Column(
|
|
37
|
+
modifier = Modifier
|
|
38
|
+
.fillMaxSize()
|
|
39
|
+
.padding(horizontal = 16.dp)
|
|
40
|
+
.verticalScroll(rememberScrollState()),
|
|
41
|
+
horizontalAlignment = Alignment.CenterHorizontally,
|
|
42
|
+
verticalArrangement = Arrangement.spacedBy(16.dp)
|
|
43
|
+
) {
|
|
44
|
+
Spacer(modifier = Modifier.height(48.dp))
|
|
45
|
+
|
|
46
|
+
// Phone number input
|
|
47
|
+
InputPhoneNumber(
|
|
48
|
+
text = phoneNumber,
|
|
49
|
+
onChangeText = {
|
|
50
|
+
phoneNumber.value = it
|
|
51
|
+
phoneError = "" // Clear error on typing
|
|
52
|
+
},
|
|
53
|
+
floatingValue = "Số điện thoại",
|
|
54
|
+
placeholder = "Nhập số điện thoại",
|
|
55
|
+
error = phoneError,
|
|
56
|
+
countryCode = "+84",
|
|
57
|
+
modifier = Modifier.fillMaxWidth()
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
// Password input
|
|
61
|
+
Input(
|
|
62
|
+
text = password,
|
|
63
|
+
onChangeText = {
|
|
64
|
+
password.value = it
|
|
65
|
+
passwordError = "" // Clear error on typing
|
|
66
|
+
},
|
|
67
|
+
floatingValue = "Mật khẩu",
|
|
68
|
+
placeholder = "Nhập mật khẩu",
|
|
69
|
+
password = true,
|
|
70
|
+
keyboardType = KeyboardType.Password,
|
|
71
|
+
error = passwordError,
|
|
72
|
+
modifier = Modifier.fillMaxWidth()
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
76
|
+
|
|
77
|
+
// Forgot password button
|
|
78
|
+
Button(
|
|
79
|
+
onClick = { /* Navigate to forgot password */ },
|
|
80
|
+
title = "Quên mật khẩu?",
|
|
81
|
+
type = ButtonType.TEXT
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
Spacer(modifier = Modifier.height(16.dp))
|
|
85
|
+
|
|
86
|
+
// Login button
|
|
87
|
+
Button(
|
|
88
|
+
onClick = {
|
|
89
|
+
// Validate inputs
|
|
90
|
+
var hasError = false
|
|
91
|
+
|
|
92
|
+
if (phoneNumber.value.isEmpty()) {
|
|
93
|
+
phoneError = "Vui lòng nhập số điện thoại"
|
|
94
|
+
hasError = true
|
|
95
|
+
} else if (phoneNumber.value.length < 10) {
|
|
96
|
+
phoneError = "Số điện thoại không hợp lệ"
|
|
97
|
+
hasError = true
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (password.value.isEmpty()) {
|
|
101
|
+
passwordError = "Vui lòng nhập mật khẩu"
|
|
102
|
+
hasError = true
|
|
103
|
+
} else if (password.value.length < 6) {
|
|
104
|
+
passwordError = "Mật khẩu phải có ít nhất 6 ký tự"
|
|
105
|
+
hasError = true
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!hasError) {
|
|
109
|
+
isLoading = true
|
|
110
|
+
// Perform login logic here
|
|
111
|
+
// login(phoneNumber.value, password.value)
|
|
112
|
+
isLoading = false
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
title = "Đăng nhập",
|
|
116
|
+
type = ButtonType.PRIMARY,
|
|
117
|
+
size = Size.LARGE,
|
|
118
|
+
isFull = true,
|
|
119
|
+
loading = isLoading,
|
|
120
|
+
modifier = Modifier.fillMaxWidth()
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
Spacer(modifier = Modifier.height(16.dp))
|
|
124
|
+
|
|
125
|
+
// Register link
|
|
126
|
+
Button(
|
|
127
|
+
onClick = { /* Navigate to register */ },
|
|
128
|
+
title = "Chưa có tài khoản? Đăng ký ngay",
|
|
129
|
+
type = ButtonType.TEXT
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
Spacer(modifier = Modifier.height(48.dp))
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
package vn.momo.kits.components
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.background
|
|
4
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
5
|
+
import androidx.compose.foundation.layout.Column
|
|
6
|
+
import androidx.compose.foundation.layout.Spacer
|
|
7
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
8
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
9
|
+
import androidx.compose.foundation.layout.height
|
|
10
|
+
import androidx.compose.foundation.layout.padding
|
|
11
|
+
import androidx.compose.foundation.rememberScrollState
|
|
12
|
+
import androidx.compose.foundation.verticalScroll
|
|
13
|
+
import androidx.compose.runtime.Composable
|
|
14
|
+
import androidx.compose.runtime.MutableState
|
|
15
|
+
import androidx.compose.runtime.mutableStateOf
|
|
16
|
+
import androidx.compose.runtime.remember
|
|
17
|
+
import androidx.compose.ui.Alignment
|
|
18
|
+
import androidx.compose.ui.Modifier
|
|
19
|
+
import androidx.compose.ui.unit.dp
|
|
20
|
+
import vn.momo.kits.const.AppTheme
|
|
21
|
+
import vn.momo.kits.const.Colors
|
|
22
|
+
import vn.momo.kits.const.Spacing
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Login Form Example for MoMo Native Kits
|
|
26
|
+
*
|
|
27
|
+
* This example demonstrates how to create a login form with:
|
|
28
|
+
* - Phone number input with country code (+84 for Vietnam)
|
|
29
|
+
* - Password input with visibility toggle
|
|
30
|
+
* - Login button
|
|
31
|
+
*
|
|
32
|
+
* Usage:
|
|
33
|
+
* ```kotlin
|
|
34
|
+
* LoginFormExample()
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
@Composable
|
|
38
|
+
fun LoginFormExample(
|
|
39
|
+
modifier: Modifier = Modifier
|
|
40
|
+
) {
|
|
41
|
+
// State management for form fields
|
|
42
|
+
val phoneNumber: MutableState<String> = remember { mutableStateOf("") }
|
|
43
|
+
val password: MutableState<String> = remember { mutableStateOf("") }
|
|
44
|
+
|
|
45
|
+
// Error states
|
|
46
|
+
val phoneError: MutableState<String> = remember { mutableStateOf("") }
|
|
47
|
+
val passwordError: MutableState<String> = remember { mutableStateOf("") }
|
|
48
|
+
|
|
49
|
+
// Loading state
|
|
50
|
+
val isLoading: MutableState<Boolean> = remember { mutableStateOf(false) }
|
|
51
|
+
|
|
52
|
+
// Theme
|
|
53
|
+
val theme = AppTheme.current
|
|
54
|
+
|
|
55
|
+
// Form validation
|
|
56
|
+
fun validateForm(): Boolean {
|
|
57
|
+
var isValid = true
|
|
58
|
+
|
|
59
|
+
// Validate phone number
|
|
60
|
+
if (phoneNumber.value.isEmpty()) {
|
|
61
|
+
phoneError.value = "Vui lòng nhập số điện thoại"
|
|
62
|
+
isValid = false
|
|
63
|
+
} else if (phoneNumber.value.length < 10) {
|
|
64
|
+
phoneError.value = "Số điện thoại không hợp lệ"
|
|
65
|
+
isValid = false
|
|
66
|
+
} else {
|
|
67
|
+
phoneError.value = ""
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Validate password
|
|
71
|
+
if (password.value.isEmpty()) {
|
|
72
|
+
passwordError.value = "Vui lòng nhập mật khẩu"
|
|
73
|
+
isValid = false
|
|
74
|
+
} else if (password.value.length < 6) {
|
|
75
|
+
passwordError.value = "Mật khẩu phải có ít nhất 6 ký tự"
|
|
76
|
+
isValid = false
|
|
77
|
+
} else {
|
|
78
|
+
passwordError.value = ""
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return isValid
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Login handler
|
|
85
|
+
fun handleLogin() {
|
|
86
|
+
if (validateForm()) {
|
|
87
|
+
isLoading.value = true
|
|
88
|
+
// Perform login API call here
|
|
89
|
+
// For demo purposes, we'll just simulate a delay
|
|
90
|
+
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
|
|
91
|
+
isLoading.value = false
|
|
92
|
+
}, 2000)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Clear errors on text change
|
|
97
|
+
fun onPhoneNumberChange(value: String) {
|
|
98
|
+
phoneNumber.value = value
|
|
99
|
+
if (phoneError.value.isNotEmpty()) {
|
|
100
|
+
phoneError.value = ""
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fun onPasswordChange(value: String) {
|
|
105
|
+
password.value = value
|
|
106
|
+
if (passwordError.value.isNotEmpty()) {
|
|
107
|
+
passwordError.value = ""
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Main layout
|
|
112
|
+
Column(
|
|
113
|
+
modifier = modifier
|
|
114
|
+
.fillMaxSize()
|
|
115
|
+
.background(theme.colors.background.page)
|
|
116
|
+
.verticalScroll(rememberScrollState())
|
|
117
|
+
.padding(horizontal = Spacing.L)
|
|
118
|
+
.padding(top = Spacing.XXL),
|
|
119
|
+
horizontalAlignment = Alignment.CenterHorizontally,
|
|
120
|
+
verticalArrangement = Arrangement.Top
|
|
121
|
+
) {
|
|
122
|
+
// App Logo / Title
|
|
123
|
+
Title(
|
|
124
|
+
text = "Đăng nhập",
|
|
125
|
+
style = vn.momo.kits.const.Typography.headerL
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
Spacer(modifier = Modifier.height(Spacing.XL))
|
|
129
|
+
|
|
130
|
+
// Phone Number Input
|
|
131
|
+
InputPhoneNumber(
|
|
132
|
+
text = phoneNumber,
|
|
133
|
+
placeholder = "Nhập số điện thoại",
|
|
134
|
+
size = InputPhoneNumberSize.LARGE,
|
|
135
|
+
onChangeText = ::onPhoneNumberChange,
|
|
136
|
+
error = phoneError.value,
|
|
137
|
+
errorSpacing = true,
|
|
138
|
+
modifier = Modifier.fillMaxWidth()
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
Spacer(modifier = Modifier.height(Spacing.L))
|
|
142
|
+
|
|
143
|
+
// Password Input
|
|
144
|
+
Input(
|
|
145
|
+
text = password,
|
|
146
|
+
placeholder = "Nhập mật khẩu",
|
|
147
|
+
size = InputSize.LARGE,
|
|
148
|
+
onChangeText = ::onPasswordChange,
|
|
149
|
+
error = passwordError.value,
|
|
150
|
+
errorSpacing = true,
|
|
151
|
+
secureTextEntry = true,
|
|
152
|
+
leadingIcon = "24_security_lock",
|
|
153
|
+
modifier = Modifier.fillMaxWidth()
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
Spacer(modifier = Modifier.height(Spacing.XL))
|
|
157
|
+
|
|
158
|
+
// Login Button
|
|
159
|
+
Button(
|
|
160
|
+
onClick = ::handleLogin,
|
|
161
|
+
title = "Đăng nhập",
|
|
162
|
+
type = ButtonType.PRIMARY,
|
|
163
|
+
size = Size.LARGE,
|
|
164
|
+
loading = isLoading.value,
|
|
165
|
+
modifier = Modifier.fillMaxWidth()
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
Spacer(modifier = Modifier.height(Spacing.L))
|
|
169
|
+
|
|
170
|
+
// Forgot Password Link
|
|
171
|
+
Column(
|
|
172
|
+
horizontalAlignment = Alignment.CenterHorizontally
|
|
173
|
+
) {
|
|
174
|
+
vn.momo.kits.components.Text(
|
|
175
|
+
text = "Quên mật khẩu?",
|
|
176
|
+
style = vn.momo.kits.const.Typography.actionDefaultMedium,
|
|
177
|
+
color = theme.colors.primary
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
Spacer(modifier = Modifier.height(Spacing.XXL))
|
|
182
|
+
|
|
183
|
+
// Register Link
|
|
184
|
+
Column(
|
|
185
|
+
horizontalAlignment = Alignment.CenterHorizontally
|
|
186
|
+
) {
|
|
187
|
+
vn.momo.kits.components.Text(
|
|
188
|
+
text = "Chưa có tài khoản? ",
|
|
189
|
+
style = vn.momo.kits.const.Typography.bodyDefaultRegular,
|
|
190
|
+
color = theme.colors.text.secondary
|
|
191
|
+
)
|
|
192
|
+
vn.momo.kits.components.Text(
|
|
193
|
+
text = "Đăng ký ngay",
|
|
194
|
+
style = vn.momo.kits.const.Typography.bodyDefaultRegular,
|
|
195
|
+
color = theme.colors.primary
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|