@momo-kits/native-kits 0.157.1-skill.3-debug → 0.157.1-skill.6-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/skills/momo-native-kits-skills/README.md +52 -0
- package/.claude/skills/momo-native-kits-skills/SKILL.md +32 -0
- package/.claude/skills/momo-native-kits-skills/data-display/SKILL.md +42 -0
- package/.claude/skills/momo-native-kits-skills/feedback/SKILL.md +43 -0
- package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/feedback}/references/popup.md +3 -10
- package/.claude/skills/momo-native-kits-skills/form-controls/SKILL.md +42 -0
- package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/form-controls}/references/button.md +2 -3
- package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/form-controls}/references/input.md +3 -7
- package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/form-controls}/references/radio.md +9 -9
- package/.claude/skills/momo-native-kits-skills/layout/SKILL.md +39 -0
- package/.claude/skills/momo-native-kits-skills/navigation/SKILL.md +38 -0
- package/.claude/skills/momo-native-kits-skills/output/test-report.json +12 -0
- package/.claude/skills/momo-native-kits-skills/output/validation-result.json +108 -0
- package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills}/references/constants.md +81 -6
- package/.claude/skills/momo-native-kits-skills/references/design-guidelines.md +130 -0
- package/.claude/skills/momo-native-kits-skills/references/developer/android-compose.md +29 -0
- package/.claude/skills/momo-native-kits-skills/references/developer/code-convention.md +118 -0
- package/.claude/skills/momo-native-kits-skills/references/developer/compose-multiplatform.md +29 -0
- package/.claude/skills/momo-native-kits-skills/scripts/logger.js +63 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/badge.js +32 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/bottomtab.js +19 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/button.js +32 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/card.js +32 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/checkbox.js +32 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/chip.js +59 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/divider.js +19 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/global.js +61 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/index.js +54 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/input.js +32 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/navigation.js +48 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/popup.js +45 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/radio.js +105 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/skeleton.js +20 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/snackbar.js +32 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/state.js +21 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/switch.js +45 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/text.js +19 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/tooltip.js +45 -0
- package/.claude/skills/momo-native-kits-skills/scripts/rules/trustbanner.js +22 -0
- package/.claude/skills/momo-native-kits-skills/scripts/test-on-device.sh +117 -0
- package/.claude/skills/momo-native-kits-skills/scripts/test-runner.js +167 -0
- package/.claude/skills/momo-native-kits-skills/scripts/validate-kits.js +131 -0
- package/.momo-agent.json +13 -0
- package/compose/build.gradle.kts +1 -1
- package/gradle.properties +1 -1
- package/package.json +1 -1
- package/.claude/momo-native-kits-skill/SKILL.md +0 -51
- package/.claude/momo-native-kits-skill/evals/evals.json +0 -95
- package/.claude/momo-native-kits-skill/workspace/iteration-1/benchmark.json +0 -20
- package/.claude/momo-native-kits-skill/workspace/iteration-1/benchmark.md +0 -13
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-0-button/eval_metadata.json +0 -6
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-0-button/with_skill/outputs/ButtonExample.kt +0 -55
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-0-button/without_skill/outputs/ButtonExample.kt +0 -45
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-1-input/eval_metadata.json +0 -6
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-1-input/with_skill/outputs/InputPhoneExample.kt +0 -40
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-1-input/without_skill/outputs/InputPhoneExample.kt +0 -42
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-2-bottomtab/eval_metadata.json +0 -6
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-2-bottomtab/with_skill/outputs/BottomTabExample.kt +0 -236
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-2-bottomtab/without_skill/outputs/BottomTabExample.kt +0 -152
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-3-checkbox/eval_metadata.json +0 -6
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-3-checkbox/with_skill/outputs/CheckBoxExample.kt +0 -49
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-3-checkbox/without_skill/outputs/CheckBoxExample.kt +0 -123
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-4-datetimepicker/eval_metadata.json +0 -6
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-4-datetimepicker/with_skill/outputs/DateTimePickerExample.kt +0 -318
- package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-4-datetimepicker/without_skill/outputs/DateTimePickerExample.kt +0 -330
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-card/with_skill/outputs/CardExample.kt +0 -124
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-card/without_skill/outputs/CardExample.kt +0 -71
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-loginform/with_skill/outputs/LoginFormExample.kt +0 -134
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-loginform/without_skill/outputs/LoginFormExample.kt +0 -199
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-navcontainer/with_skill/outputs/NavigationContainerExample.kt +0 -224
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-navcontainer/without_skill/outputs/NavigationContainerExample.kt +0 -225
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-popup/with_skill/outputs/PopupExample.kt +0 -79
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-popup/without_skill/outputs/PopupExample.kt +0 -169
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-setoptions/eval_metadata.json +0 -6
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-setoptions/with_skill/outputs/SetOptionsExample.kt +0 -255
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-setoptions/without_skill/outputs/SetOptionsExample.kt +0 -212
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-skeleton/with_skill/outputs/SkeletonExample.kt +0 -199
- package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-skeleton/without_skill/outputs/SkeletonExample.kt +0 -229
- package/.claude/momo-native-kits-skill/workspace/iteration-3/benchmark.json +0 -20
- package/.claude/momo-native-kits-skill/workspace/iteration-3/benchmark.md +0 -13
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/eval_metadata.json +0 -22
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/with_skill/outputs/PrimaryButtonExample.kt +0 -38
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/with_skill/timing.json +0 -5
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/without_skill/outputs/PrimaryButtonExample.kt +0 -83
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/without_skill/timing.json +0 -5
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/eval_metadata.json +0 -22
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/with_skill/outputs/NavigationContainerExample.kt +0 -547
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/with_skill/timing.json +0 -5
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/without_skill/outputs/MoMoNavigationContainer.kt +0 -519
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/without_skill/timing.json +0 -5
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/eval_metadata.json +0 -27
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/with_skill/outputs/SetOptionsExample.kt +0 -429
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/with_skill/timing.json +0 -5
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/without_skill/outputs/SetOptionsExample.kt +0 -353
- package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/without_skill/timing.json +0 -5
- package/.claude/settings.local.json +0 -41
- package/local.properties +0 -8
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/data-display}/references/badge.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/data-display}/references/chip.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/data-display}/references/skeleton.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/data-display}/references/text.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/feedback}/references/snackbar.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/feedback}/references/tooltip.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/feedback}/references/trustbanner.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/form-controls}/references/checkbox.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/form-controls}/references/switch.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/layout}/references/card.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/layout}/references/divider.md +0 -0
- /package/.claude/{momo-native-kits-skill → skills/momo-native-kits-skills/navigation}/references/navigation.md +0 -0
|
@@ -1,199 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
package vn.momo.kits.examples
|
|
2
|
-
|
|
3
|
-
import androidx.compose.foundation.layout.Box
|
|
4
|
-
import androidx.compose.foundation.layout.fillMaxSize
|
|
5
|
-
import androidx.compose.foundation.layout.padding
|
|
6
|
-
import androidx.compose.foundation.rememberScrollState
|
|
7
|
-
import androidx.compose.foundation.verticalScroll
|
|
8
|
-
import androidx.compose.material3.Text
|
|
9
|
-
import androidx.compose.runtime.Composable
|
|
10
|
-
import androidx.compose.runtime.LaunchedEffect
|
|
11
|
-
import androidx.compose.runtime.getValue
|
|
12
|
-
import androidx.compose.runtime.mutableStateOf
|
|
13
|
-
import androidx.compose.runtime.remember
|
|
14
|
-
import androidx.compose.runtime.setValue
|
|
15
|
-
import androidx.compose.ui.Modifier
|
|
16
|
-
import androidx.compose.ui.unit.dp
|
|
17
|
-
import vn.momo.kits.navigation.LocalNavigation
|
|
18
|
-
import vn.momo.kits.navigation.LocalNavigator
|
|
19
|
-
import vn.momo.kits.navigation.NavigationContainer
|
|
20
|
-
import vn.momo.kits.navigation.NavigationOptions
|
|
21
|
-
import vn.momo.kits.navigation.component.HeaderTitle
|
|
22
|
-
import vn.momo.kits.navigation.component.HeaderType
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* NavigationContainer Example for MoMo App
|
|
26
|
-
*
|
|
27
|
-
* Key Points:
|
|
28
|
-
* - ONE NavigationContainer per Fragment/Activity
|
|
29
|
-
* - Use setOptions in LaunchedEffect(Unit) for dynamic configuration
|
|
30
|
-
* - Use LocalNavigation.current for setOptions
|
|
31
|
-
* - Use LocalNavigator.current for push/pop/present
|
|
32
|
-
*/
|
|
33
|
-
@Composable
|
|
34
|
-
fun NavigationContainerExample() {
|
|
35
|
-
// Single NavigationContainer - root of the app/fragment
|
|
36
|
-
NavigationContainer(
|
|
37
|
-
initialScreen = {
|
|
38
|
-
HomeScreen()
|
|
39
|
-
},
|
|
40
|
-
options = NavigationOptions(
|
|
41
|
-
headerTitle = HeaderTitle.Default("MoMo App"),
|
|
42
|
-
headerType = HeaderType.DEFAULT
|
|
43
|
-
)
|
|
44
|
-
) {
|
|
45
|
-
// All screens are pushed within this container
|
|
46
|
-
// No need to add anything here as initialScreen handles the first screen
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Home Screen - Initial screen in NavigationContainer
|
|
52
|
-
*/
|
|
53
|
-
@Composable
|
|
54
|
-
fun HomeScreen() {
|
|
55
|
-
val navigator = LocalNavigator.current
|
|
56
|
-
val navigation = LocalNavigation.current
|
|
57
|
-
|
|
58
|
-
// Use LaunchedEffect(Unit) for setOptions - NOT in composable root
|
|
59
|
-
LaunchedEffect(Unit) {
|
|
60
|
-
navigation.setOptions(
|
|
61
|
-
headerTitle = HeaderTitle.Default("Trang chủ"),
|
|
62
|
-
headerType = HeaderType.DEFAULT
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Example: Connect scroll state for header animation
|
|
67
|
-
val scrollState = rememberScrollState()
|
|
68
|
-
LaunchedEffect(Unit) {
|
|
69
|
-
navigation.setOptions(
|
|
70
|
-
scrollData = vn.momo.kits.navigation.ScrollData(
|
|
71
|
-
scrollState = scrollState
|
|
72
|
-
)
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
Box(
|
|
77
|
-
modifier = Modifier
|
|
78
|
-
.fillMaxSize()
|
|
79
|
-
.padding(16.dp)
|
|
80
|
-
.verticalScroll(scrollState)
|
|
81
|
-
) {
|
|
82
|
-
// Screen content
|
|
83
|
-
Text("Home Screen Content")
|
|
84
|
-
|
|
85
|
-
// Example: Navigate to another screen
|
|
86
|
-
// val navigator = LocalNavigator.current
|
|
87
|
-
// navigator.push({ DetailScreen() })
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Detail Screen - Pushed from HomeScreen
|
|
93
|
-
*/
|
|
94
|
-
@Composable
|
|
95
|
-
fun DetailScreen() {
|
|
96
|
-
val navigation = LocalNavigation.current
|
|
97
|
-
|
|
98
|
-
LaunchedEffect(Unit) {
|
|
99
|
-
navigation.setOptions(
|
|
100
|
-
headerTitle = HeaderTitle.Default("Chi tiết"),
|
|
101
|
-
headerType = HeaderType.DEFAULT
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
Box(
|
|
106
|
-
modifier = Modifier
|
|
107
|
-
.fillMaxSize()
|
|
108
|
-
.padding(16.dp)
|
|
109
|
-
) {
|
|
110
|
-
Text("Detail Screen Content")
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Example: Using NavigationOptions with push
|
|
116
|
-
*/
|
|
117
|
-
@Composable
|
|
118
|
-
fun PushWithOptionsExample() {
|
|
119
|
-
val navigator = LocalNavigator.current
|
|
120
|
-
|
|
121
|
-
// Push screen with custom options
|
|
122
|
-
navigator.push(
|
|
123
|
-
content = { DetailScreen() },
|
|
124
|
-
options = NavigationOptions(
|
|
125
|
-
headerTitle = HeaderTitle.Default("Custom Header"),
|
|
126
|
-
headerType = HeaderType.Default
|
|
127
|
-
)
|
|
128
|
-
)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Example: Present modal screen
|
|
133
|
-
*/
|
|
134
|
-
@Composable
|
|
135
|
-
fun PresentModalExample() {
|
|
136
|
-
val navigator = LocalNavigator.current
|
|
137
|
-
|
|
138
|
-
navigator.present {
|
|
139
|
-
ModalScreen()
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Modal Screen - Presented as modal
|
|
145
|
-
*/
|
|
146
|
-
@Composable
|
|
147
|
-
fun ModalScreen() {
|
|
148
|
-
val navigation = LocalNavigation.current
|
|
149
|
-
|
|
150
|
-
LaunchedEffect(Unit) {
|
|
151
|
-
navigation.setOptions(
|
|
152
|
-
headerTitle = HeaderTitle.Default("Modal"),
|
|
153
|
-
headerType = HeaderType.DEFAULT
|
|
154
|
-
)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
Box(
|
|
158
|
-
modifier = Modifier
|
|
159
|
-
.fillMaxSize()
|
|
160
|
-
.padding(16.dp)
|
|
161
|
-
) {
|
|
162
|
-
Text("Modal Screen")
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Example: Dynamic header title change
|
|
168
|
-
*/
|
|
169
|
-
@Composable
|
|
170
|
-
fun DynamicTitleExample() {
|
|
171
|
-
val navigation = LocalNavigation.current
|
|
172
|
-
var title by remember { mutableStateOf("Initial Title") }
|
|
173
|
-
|
|
174
|
-
LaunchedEffect(Unit) {
|
|
175
|
-
navigation.setOptions(
|
|
176
|
-
headerTitle = HeaderTitle.Default(title)
|
|
177
|
-
)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// When title changes, call setOptions again
|
|
181
|
-
LaunchedEffect(title) {
|
|
182
|
-
navigation.setOptions(
|
|
183
|
-
headerTitle = HeaderTitle.Default(title)
|
|
184
|
-
)
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
Box(
|
|
188
|
-
modifier = Modifier
|
|
189
|
-
.fillMaxSize()
|
|
190
|
-
.padding(16.dp)
|
|
191
|
-
) {
|
|
192
|
-
Text("Title: $title")
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Example: Extended header with search
|
|
198
|
-
*/
|
|
199
|
-
@Composable
|
|
200
|
-
fun ExtendedHeaderExample() {
|
|
201
|
-
val navigation = LocalNavigation.current
|
|
202
|
-
val searchText = remember { mutableStateOf("") }
|
|
203
|
-
|
|
204
|
-
LaunchedEffect(Unit) {
|
|
205
|
-
navigation.setOptions(
|
|
206
|
-
headerType = HeaderType.Extended(
|
|
207
|
-
useAnimated = true,
|
|
208
|
-
inputSearchProps = vn.momo.kits.navigation.component.InputSearchProps(
|
|
209
|
-
text = searchText,
|
|
210
|
-
placeholder = "Search...",
|
|
211
|
-
onChangeText = { searchText.value = it }
|
|
212
|
-
)
|
|
213
|
-
)
|
|
214
|
-
)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
Box(
|
|
218
|
-
modifier = Modifier
|
|
219
|
-
.fillMaxSize()
|
|
220
|
-
.padding(16.dp)
|
|
221
|
-
) {
|
|
222
|
-
Text("Search: ${searchText.value}")
|
|
223
|
-
}
|
|
224
|
-
}
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
package com.momo.app.navigation
|
|
2
|
-
|
|
3
|
-
import androidx.compose.foundation.layout.Box
|
|
4
|
-
import androidx.compose.foundation.layout.fillMaxSize
|
|
5
|
-
import androidx.compose.material3.Text
|
|
6
|
-
import androidx.compose.runtime.Composable
|
|
7
|
-
import androidx.compose.ui.Alignment
|
|
8
|
-
import androidx.compose.ui.Modifier
|
|
9
|
-
import androidx.navigation.NavHostController
|
|
10
|
-
import androidx.navigation.compose.NavHost
|
|
11
|
-
import androidx.navigation.compose.composable
|
|
12
|
-
import androidx.navigation.compose.rememberNavController
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* NavigationContainer Example for MoMo App
|
|
16
|
-
*
|
|
17
|
-
* NavigationContainer is part of the Accompanist Navigation library.
|
|
18
|
-
* It provides a declarative navigation pattern for Jetpack Compose apps.
|
|
19
|
-
*
|
|
20
|
-
* Key Pattern:
|
|
21
|
-
* 1. Create a NavHostController using rememberNavController()
|
|
22
|
-
* 2. Wrap your content with NavigationContainer
|
|
23
|
-
* 3. Define navigation destinations using NavHost
|
|
24
|
-
* 4. Use navigate() to move between screens
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
// Define navigation routes
|
|
28
|
-
sealed class Screen(val route: String) {
|
|
29
|
-
object Home : Screen("home")
|
|
30
|
-
object Detail : Screen("detail/{itemId}") {
|
|
31
|
-
fun createRoute(itemId: String) = "detail/$itemId"
|
|
32
|
-
}
|
|
33
|
-
object Profile : Screen("profile")
|
|
34
|
-
object Settings : Screen("settings")
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Main NavigationContainer setup
|
|
39
|
-
* This is the correct pattern for implementing NavigationContainer in MoMo app
|
|
40
|
-
*/
|
|
41
|
-
@Composable
|
|
42
|
-
fun NavigationContainerExample() {
|
|
43
|
-
// Step 1: Create NavHostController
|
|
44
|
-
val navController: NavHostController = rememberNavController()
|
|
45
|
-
|
|
46
|
-
// Step 2: Wrap with NavigationContainer (from Accompanist)
|
|
47
|
-
androidx.compose.material3.Surface(
|
|
48
|
-
modifier = Modifier.fillMaxSize()
|
|
49
|
-
) {
|
|
50
|
-
NavHost(
|
|
51
|
-
navController = navController,
|
|
52
|
-
startDestination = Screen.Home.route
|
|
53
|
-
) {
|
|
54
|
-
// Step 3: Define navigation destinations
|
|
55
|
-
composable(Screen.Home.route) {
|
|
56
|
-
HomeScreen(
|
|
57
|
-
onNavigateToDetail = { itemId ->
|
|
58
|
-
navController.navigate(Screen.Detail.createRoute(itemId))
|
|
59
|
-
},
|
|
60
|
-
onNavigateToProfile = {
|
|
61
|
-
navController.navigate(Screen.Profile.route)
|
|
62
|
-
}
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
composable(Screen.Detail.route) { backStackEntry ->
|
|
67
|
-
val itemId = backStackEntry.arguments?.getString("itemId") ?: ""
|
|
68
|
-
DetailScreen(
|
|
69
|
-
itemId = itemId,
|
|
70
|
-
onNavigateBack = {
|
|
71
|
-
navController.popBackStack()
|
|
72
|
-
}
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
composable(Screen.Profile.route) {
|
|
77
|
-
ProfileScreen(
|
|
78
|
-
onNavigateBack = {
|
|
79
|
-
navController.popBackStack()
|
|
80
|
-
},
|
|
81
|
-
onNavigateToSettings = {
|
|
82
|
-
navController.navigate(Screen.Settings.route)
|
|
83
|
-
}
|
|
84
|
-
)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
composable(Screen.Settings.route) {
|
|
88
|
-
SettingsScreen(
|
|
89
|
-
onNavigateBack = {
|
|
90
|
-
navController.popBackStack()
|
|
91
|
-
}
|
|
92
|
-
)
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Home Screen
|
|
100
|
-
*/
|
|
101
|
-
@Composable
|
|
102
|
-
fun HomeScreen(
|
|
103
|
-
onNavigateToDetail: (String) -> Unit,
|
|
104
|
-
onNavigateToProfile: () -> Unit
|
|
105
|
-
) {
|
|
106
|
-
Box(
|
|
107
|
-
modifier = Modifier.fillMaxSize(),
|
|
108
|
-
contentAlignment = Alignment.Center
|
|
109
|
-
) {
|
|
110
|
-
Text("Home Screen")
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Detail Screen
|
|
116
|
-
*/
|
|
117
|
-
@Composable
|
|
118
|
-
fun DetailScreen(
|
|
119
|
-
itemId: String,
|
|
120
|
-
onNavigateBack: () -> Unit
|
|
121
|
-
) {
|
|
122
|
-
Box(
|
|
123
|
-
modifier = Modifier.fillMaxSize(),
|
|
124
|
-
contentAlignment = Alignment.Center
|
|
125
|
-
) {
|
|
126
|
-
Text("Detail Screen - Item: $itemId")
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Profile Screen
|
|
132
|
-
*/
|
|
133
|
-
@Composable
|
|
134
|
-
fun ProfileScreen(
|
|
135
|
-
onNavigateBack: () -> Unit,
|
|
136
|
-
onNavigateToSettings: () -> Unit
|
|
137
|
-
) {
|
|
138
|
-
Box(
|
|
139
|
-
modifier = Modifier.fillMaxSize(),
|
|
140
|
-
contentAlignment = Alignment.Center
|
|
141
|
-
) {
|
|
142
|
-
Text("Profile Screen")
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Settings Screen
|
|
148
|
-
*/
|
|
149
|
-
@Composable
|
|
150
|
-
fun SettingsScreen(
|
|
151
|
-
onNavigateBack: () -> Unit
|
|
152
|
-
) {
|
|
153
|
-
Box(
|
|
154
|
-
modifier = Modifier.fillMaxSize(),
|
|
155
|
-
contentAlignment = Alignment.Center
|
|
156
|
-
) {
|
|
157
|
-
Text("Settings Screen")
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Alternative: Using NavigationContainer from Accompanist
|
|
163
|
-
* This provides additional features like deep linking support
|
|
164
|
-
*/
|
|
165
|
-
@Composable
|
|
166
|
-
fun NavigationContainerWithDeepLink() {
|
|
167
|
-
val navController = rememberNavController()
|
|
168
|
-
|
|
169
|
-
androidx.compose.material3.Surface(
|
|
170
|
-
modifier = Modifier.fillMaxSize()
|
|
171
|
-
) {
|
|
172
|
-
NavHost(
|
|
173
|
-
navController = navController,
|
|
174
|
-
startDestination = Screen.Home.route
|
|
175
|
-
) {
|
|
176
|
-
composable(
|
|
177
|
-
route = Screen.Home.route,
|
|
178
|
-
deepLinks = listOf(
|
|
179
|
-
androidx.navigation.navDeepLink {
|
|
180
|
-
uriPattern = "momo://home"
|
|
181
|
-
}
|
|
182
|
-
)
|
|
183
|
-
) {
|
|
184
|
-
HomeScreen(
|
|
185
|
-
onNavigateToDetail = { itemId ->
|
|
186
|
-
navController.navigate(Screen.Detail.createRoute(itemId))
|
|
187
|
-
},
|
|
188
|
-
onNavigateToProfile = {
|
|
189
|
-
navController.navigate(Screen.Profile.route)
|
|
190
|
-
}
|
|
191
|
-
)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
composable(
|
|
195
|
-
route = Screen.Detail.route,
|
|
196
|
-
deepLinks = listOf(
|
|
197
|
-
androidx.navigation.navDeepLink {
|
|
198
|
-
uriPattern = "momo://detail/{itemId}"
|
|
199
|
-
}
|
|
200
|
-
)
|
|
201
|
-
) { backStackEntry ->
|
|
202
|
-
val itemId = backStackEntry.arguments?.getString("itemId") ?: ""
|
|
203
|
-
DetailScreen(
|
|
204
|
-
itemId = itemId,
|
|
205
|
-
onNavigateBack = {
|
|
206
|
-
navController.popBackStack()
|
|
207
|
-
}
|
|
208
|
-
)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
composable(Screen.Profile.route) {
|
|
212
|
-
ProfileScreen(
|
|
213
|
-
onNavigateBack = { navController.popBackStack() },
|
|
214
|
-
onNavigateToSettings = { navController.navigate(Screen.Settings.route) }
|
|
215
|
-
)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
composable(Screen.Settings.route) {
|
|
219
|
-
SettingsScreen(
|
|
220
|
-
onNavigateBack = { navController.popBackStack() }
|
|
221
|
-
)
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|