@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,318 @@
|
|
|
1
|
+
package com.example
|
|
2
|
+
|
|
3
|
+
import android.app.DatePickerDialog
|
|
4
|
+
import android.app.TimePickerDialog
|
|
5
|
+
import androidx.compose.foundation.layout.Column
|
|
6
|
+
import androidx.compose.foundation.layout.Spacer
|
|
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.material3.Button
|
|
11
|
+
import androidx.compose.material3.Text
|
|
12
|
+
import androidx.compose.runtime.Composable
|
|
13
|
+
import androidx.compose.runtime.getValue
|
|
14
|
+
import androidx.compose.runtime.mutableLongStateOf
|
|
15
|
+
import androidx.compose.runtime.mutableStateOf
|
|
16
|
+
import androidx.compose.runtime.remember
|
|
17
|
+
import androidx.compose.runtime.setValue
|
|
18
|
+
import androidx.compose.ui.Modifier
|
|
19
|
+
import androidx.compose.ui.platform.LocalContext
|
|
20
|
+
import androidx.compose.ui.unit.dp
|
|
21
|
+
import vn.momo.kits.components.DateTimePicker
|
|
22
|
+
import vn.momo.kits.components.Title
|
|
23
|
+
import vn.momo.kits.components.TitleType
|
|
24
|
+
import java.text.SimpleDateFormat
|
|
25
|
+
import java.util.Calendar
|
|
26
|
+
import java.util.Date
|
|
27
|
+
import java.util.Locale
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* DateTimePicker Component Example
|
|
31
|
+
*
|
|
32
|
+
* This example demonstrates how to use the DateTimePicker component from MoMo Native Kits
|
|
33
|
+
* for date selection in a Kotlin Multiplatform Compose project.
|
|
34
|
+
*
|
|
35
|
+
* The DateTimePicker supports:
|
|
36
|
+
* - Single date selection
|
|
37
|
+
* - Date range selection (isRangeMode)
|
|
38
|
+
* - Minimum and maximum date constraints
|
|
39
|
+
* - Custom date format
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
@Composable
|
|
43
|
+
fun DateTimePickerExample() {
|
|
44
|
+
val context = LocalContext.current
|
|
45
|
+
|
|
46
|
+
// State for single date selection
|
|
47
|
+
var selectedDate by remember { mutableLongStateOf<Long?>(null) }
|
|
48
|
+
|
|
49
|
+
// State for date range selection
|
|
50
|
+
var startDate by remember { mutableLongStateOf<Long?>(null) }
|
|
51
|
+
var endDate by remember { mutableLongStateOf<Long?>(null) }
|
|
52
|
+
|
|
53
|
+
// State to toggle between single and range mode
|
|
54
|
+
var isRangeMode by remember { mutableStateOf(false) }
|
|
55
|
+
|
|
56
|
+
// Date formatter
|
|
57
|
+
val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())
|
|
58
|
+
|
|
59
|
+
// Calculate min and max dates (e.g., today and 1 year from now)
|
|
60
|
+
val calendar = Calendar.getInstance()
|
|
61
|
+
val today = calendar.timeInMillis
|
|
62
|
+
|
|
63
|
+
calendar.add(Calendar.YEAR, 1)
|
|
64
|
+
val oneYearFromNow = calendar.timeInMillis
|
|
65
|
+
|
|
66
|
+
Column(
|
|
67
|
+
modifier = Modifier
|
|
68
|
+
.fillMaxWidth()
|
|
69
|
+
.padding(16.dp)
|
|
70
|
+
) {
|
|
71
|
+
// Title
|
|
72
|
+
Title(
|
|
73
|
+
text = "DateTimePicker Example",
|
|
74
|
+
type = TitleType.TITLE_1
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
Spacer(modifier = Modifier.height(24.dp))
|
|
78
|
+
|
|
79
|
+
// Single Date Selection Mode
|
|
80
|
+
Text(text = "Single Date Selection:")
|
|
81
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
82
|
+
|
|
83
|
+
// Display selected date
|
|
84
|
+
Text(
|
|
85
|
+
text = if (selectedDate != null) {
|
|
86
|
+
"Selected: ${dateFormat.format(Date(selectedDate!!))}"
|
|
87
|
+
} else {
|
|
88
|
+
"No date selected"
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
93
|
+
|
|
94
|
+
// Using DateTimePicker for single date selection
|
|
95
|
+
DateTimePicker(
|
|
96
|
+
selectedDate = selectedDate,
|
|
97
|
+
onDateSelected = { timestamp ->
|
|
98
|
+
selectedDate = timestamp
|
|
99
|
+
},
|
|
100
|
+
minDate = today,
|
|
101
|
+
maxDate = oneYearFromNow,
|
|
102
|
+
dateFormat = "dd/MM/yyyy",
|
|
103
|
+
isRangeMode = false,
|
|
104
|
+
modifier = Modifier.fillMaxWidth()
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
Spacer(modifier = Modifier.height(24.dp))
|
|
108
|
+
|
|
109
|
+
// Date Range Selection Mode
|
|
110
|
+
Text(text = "Date Range Selection:")
|
|
111
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
112
|
+
|
|
113
|
+
// Display selected range
|
|
114
|
+
Text(
|
|
115
|
+
text = buildString {
|
|
116
|
+
if (startDate != null && endDate != null) {
|
|
117
|
+
append("From: ${dateFormat.format(Date(startDate!!))}")
|
|
118
|
+
append(" To: ${dateFormat.format(Date(endDate!!))}")
|
|
119
|
+
} else if (startDate != null) {
|
|
120
|
+
append("Start: ${dateFormat.format(Date(startDate!!))}")
|
|
121
|
+
append(" (Select end date)")
|
|
122
|
+
} else {
|
|
123
|
+
append("No range selected")
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
129
|
+
|
|
130
|
+
// Using DateTimePicker for date range selection
|
|
131
|
+
DateTimePicker(
|
|
132
|
+
selectedDate = startDate,
|
|
133
|
+
onDateSelected = { timestamp ->
|
|
134
|
+
if (isRangeMode) {
|
|
135
|
+
// In range mode, handle start/end based on current state
|
|
136
|
+
if (startDate == null || (startDate != null && endDate != null)) {
|
|
137
|
+
startDate = timestamp
|
|
138
|
+
endDate = null
|
|
139
|
+
} else if (timestamp > startDate) {
|
|
140
|
+
endDate = timestamp
|
|
141
|
+
} else {
|
|
142
|
+
startDate = timestamp
|
|
143
|
+
endDate = null
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
selectedDate = timestamp
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
minDate = today,
|
|
150
|
+
maxDate = oneYearFromNow,
|
|
151
|
+
dateFormat = "dd/MM/yyyy",
|
|
152
|
+
isRangeMode = true,
|
|
153
|
+
onRangeSelected = { start, end ->
|
|
154
|
+
startDate = start
|
|
155
|
+
endDate = end
|
|
156
|
+
},
|
|
157
|
+
modifier = Modifier.fillMaxWidth()
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
Spacer(modifier = Modifier.height(24.dp))
|
|
161
|
+
|
|
162
|
+
// Toggle mode button
|
|
163
|
+
Button(
|
|
164
|
+
onClick = {
|
|
165
|
+
isRangeMode = !isRangeMode
|
|
166
|
+
// Reset selection when toggling mode
|
|
167
|
+
selectedDate = null
|
|
168
|
+
startDate = null
|
|
169
|
+
endDate = null
|
|
170
|
+
},
|
|
171
|
+
modifier = Modifier.fillMaxWidth()
|
|
172
|
+
) {
|
|
173
|
+
Text(
|
|
174
|
+
text = if (isRangeMode) "Switch to Single Date Mode" else "Switch to Range Mode"
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
Spacer(modifier = Modifier.height(16.dp))
|
|
179
|
+
|
|
180
|
+
// Clear selection button
|
|
181
|
+
Button(
|
|
182
|
+
onClick = {
|
|
183
|
+
selectedDate = null
|
|
184
|
+
startDate = null
|
|
185
|
+
endDate = null
|
|
186
|
+
},
|
|
187
|
+
modifier = Modifier.fillMaxWidth()
|
|
188
|
+
) {
|
|
189
|
+
Text(text = "Clear Selection")
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Alternative implementation using Android's built-in DatePickerDialog
|
|
196
|
+
* for more customization options
|
|
197
|
+
*/
|
|
198
|
+
@Composable
|
|
199
|
+
fun AlternativeDatePickerExample() {
|
|
200
|
+
val context = LocalContext.current
|
|
201
|
+
var selectedDate by remember { mutableStateOf<Long?>(null) }
|
|
202
|
+
val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())
|
|
203
|
+
|
|
204
|
+
Column(
|
|
205
|
+
modifier = Modifier
|
|
206
|
+
.fillMaxWidth()
|
|
207
|
+
.padding(16.dp)
|
|
208
|
+
) {
|
|
209
|
+
Text(
|
|
210
|
+
text = if (selectedDate != null) {
|
|
211
|
+
"Selected: ${dateFormat.format(Date(selectedDate!!))}"
|
|
212
|
+
} else {
|
|
213
|
+
"Tap to select a date"
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
Spacer(modifier = Modifier.height(16.dp))
|
|
218
|
+
|
|
219
|
+
Button(
|
|
220
|
+
onClick = {
|
|
221
|
+
val calendar = Calendar.getInstance()
|
|
222
|
+
selectedDate?.let { calendar.timeInMillis = it }
|
|
223
|
+
|
|
224
|
+
DatePickerDialog(
|
|
225
|
+
context,
|
|
226
|
+
{ _, year, month, dayOfMonth ->
|
|
227
|
+
val selectedCalendar = Calendar.getInstance()
|
|
228
|
+
selectedCalendar.set(year, month, dayOfMonth)
|
|
229
|
+
selectedDate = selectedCalendar.timeInMillis
|
|
230
|
+
},
|
|
231
|
+
calendar.get(Calendar.YEAR),
|
|
232
|
+
calendar.get(Calendar.MONTH),
|
|
233
|
+
calendar.get(Calendar.DAY_OF_MONTH)
|
|
234
|
+
).show()
|
|
235
|
+
},
|
|
236
|
+
modifier = Modifier.fillMaxWidth()
|
|
237
|
+
) {
|
|
238
|
+
Text(text = "Open Date Picker Dialog")
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Example with TimePicker
|
|
245
|
+
*/
|
|
246
|
+
@Composable
|
|
247
|
+
fun DateTimePickerWithTimeExample() {
|
|
248
|
+
var selectedDate by remember { mutableLongStateOf<Long?>(null) }
|
|
249
|
+
var selectedHour by remember { mutableIntStateOf(0) }
|
|
250
|
+
var selectedMinute by remember { mutableIntStateOf(0) }
|
|
251
|
+
|
|
252
|
+
val context = LocalContext.current
|
|
253
|
+
val dateFormat = SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.getDefault())
|
|
254
|
+
|
|
255
|
+
Column(
|
|
256
|
+
modifier = Modifier
|
|
257
|
+
.fillMaxWidth()
|
|
258
|
+
.padding(16.dp)
|
|
259
|
+
) {
|
|
260
|
+
Text(
|
|
261
|
+
text = if (selectedDate != null) {
|
|
262
|
+
val calendar = Calendar.getInstance()
|
|
263
|
+
calendar.timeInMillis = selectedDate!!
|
|
264
|
+
calendar.set(Calendar.HOUR_OF_DAY, selectedHour)
|
|
265
|
+
calendar.set(Calendar.MINUTE, selectedMinute)
|
|
266
|
+
"Selected: ${dateFormat.format(calendar.time)}"
|
|
267
|
+
} else {
|
|
268
|
+
"Select date and time"
|
|
269
|
+
}
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
Spacer(modifier = Modifier.height(16.dp))
|
|
273
|
+
|
|
274
|
+
// Date selection
|
|
275
|
+
Button(
|
|
276
|
+
onClick = {
|
|
277
|
+
val calendar = Calendar.getInstance()
|
|
278
|
+
selectedDate?.let { calendar.timeInMillis = it }
|
|
279
|
+
|
|
280
|
+
DatePickerDialog(
|
|
281
|
+
context,
|
|
282
|
+
{ _, year, month, dayOfMonth ->
|
|
283
|
+
val selectedCalendar = Calendar.getInstance()
|
|
284
|
+
selectedCalendar.set(year, month, dayOfMonth)
|
|
285
|
+
selectedDate = selectedCalendar.timeInMillis
|
|
286
|
+
},
|
|
287
|
+
calendar.get(Calendar.YEAR),
|
|
288
|
+
calendar.get(Calendar.MONTH),
|
|
289
|
+
calendar.get(Calendar.DAY_OF_MONTH)
|
|
290
|
+
).show()
|
|
291
|
+
},
|
|
292
|
+
modifier = Modifier.fillMaxWidth()
|
|
293
|
+
) {
|
|
294
|
+
Text(text = "Select Date")
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
298
|
+
|
|
299
|
+
// Time selection
|
|
300
|
+
Button(
|
|
301
|
+
onClick = {
|
|
302
|
+
TimePickerDialog(
|
|
303
|
+
context,
|
|
304
|
+
{ _, hourOfDay, minute ->
|
|
305
|
+
selectedHour = hourOfDay
|
|
306
|
+
selectedMinute = minute
|
|
307
|
+
},
|
|
308
|
+
selectedHour,
|
|
309
|
+
selectedMinute,
|
|
310
|
+
true // 24-hour format
|
|
311
|
+
).show()
|
|
312
|
+
},
|
|
313
|
+
modifier = Modifier.fillMaxWidth()
|
|
314
|
+
) {
|
|
315
|
+
Text(text = "Select Time")
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
package com.example.datetimepicker
|
|
2
|
+
|
|
3
|
+
import android.app.DatePickerDialog
|
|
4
|
+
import android.app.TimePickerDialog
|
|
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.material3.Button
|
|
12
|
+
import androidx.compose.material3.MaterialTheme
|
|
13
|
+
import androidx.compose.material3.OutlinedButton
|
|
14
|
+
import androidx.compose.material3.OutlinedTextField
|
|
15
|
+
import androidx.compose.material3.Scaffold
|
|
16
|
+
import androidx.compose.material3.Text
|
|
17
|
+
import androidx.compose.material3.TextButton
|
|
18
|
+
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
19
|
+
import androidx.compose.material3.TopAppBar
|
|
20
|
+
import androidx.compose.runtime.Composable
|
|
21
|
+
import androidx.compose.runtime.getValue
|
|
22
|
+
import androidx.compose.runtime.mutableStateOf
|
|
23
|
+
import androidx.compose.runtime.remember
|
|
24
|
+
import androidx.compose.runtime.setValue
|
|
25
|
+
import androidx.compose.ui.Modifier
|
|
26
|
+
import androidx.compose.ui.platform.LocalContext
|
|
27
|
+
import androidx.compose.ui.unit.dp
|
|
28
|
+
import java.text.SimpleDateFormat
|
|
29
|
+
import java.util.Calendar
|
|
30
|
+
import java.util.Date
|
|
31
|
+
import java.util.Locale
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* DateTimePicker Example in Jetpack Compose
|
|
35
|
+
*
|
|
36
|
+
* This example demonstrates different ways to use DatePicker and TimePicker
|
|
37
|
+
* dialogs in Android Jetpack Compose applications.
|
|
38
|
+
*/
|
|
39
|
+
@OptIn(ExperimentalMaterial3Api::class)
|
|
40
|
+
@Composable
|
|
41
|
+
fun DateTimePickerScreen() {
|
|
42
|
+
// State for selected date and time
|
|
43
|
+
var selectedDate by remember { mutableStateOf<Long?>(null) }
|
|
44
|
+
var selectedTime by remember { mutableStateOf<Long?>(null) }
|
|
45
|
+
|
|
46
|
+
// Formatters for displaying date and time
|
|
47
|
+
val dateFormatter = remember { SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()) }
|
|
48
|
+
val timeFormatter = remember { SimpleDateFormat("HH:mm", Locale.getDefault()) }
|
|
49
|
+
val dateTimeFormatter = remember { SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.getDefault()) }
|
|
50
|
+
|
|
51
|
+
// Calendar instance for dialogs
|
|
52
|
+
val calendar = remember { Calendar.getInstance() }
|
|
53
|
+
|
|
54
|
+
// Context for showing dialogs
|
|
55
|
+
val context = LocalContext.current
|
|
56
|
+
|
|
57
|
+
Scaffold(
|
|
58
|
+
topBar = {
|
|
59
|
+
TopAppBar(
|
|
60
|
+
title = { Text("DateTimePicker Example") }
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
) { paddingValues ->
|
|
64
|
+
Column(
|
|
65
|
+
modifier = Modifier
|
|
66
|
+
.fillMaxSize()
|
|
67
|
+
.padding(paddingValues)
|
|
68
|
+
.padding(16.dp)
|
|
69
|
+
) {
|
|
70
|
+
Text(
|
|
71
|
+
text = "Date & Time Selection",
|
|
72
|
+
style = MaterialTheme.typography.headlineSmall
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
Spacer(modifier = Modifier.height(24.dp))
|
|
76
|
+
|
|
77
|
+
// ===== Date Picker Example =====
|
|
78
|
+
Text(
|
|
79
|
+
text = "Date Picker",
|
|
80
|
+
style = MaterialTheme.typography.titleMedium
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
84
|
+
|
|
85
|
+
OutlinedTextField(
|
|
86
|
+
value = selectedDate?.let { dateFormatter.format(Date(it)) } ?: "",
|
|
87
|
+
onValueChange = { },
|
|
88
|
+
label = { Text("Select Date") },
|
|
89
|
+
readOnly = true,
|
|
90
|
+
modifier = Modifier.fillMaxWidth(),
|
|
91
|
+
trailingIcon = {
|
|
92
|
+
TextButton(onClick = {
|
|
93
|
+
// Show DatePickerDialog
|
|
94
|
+
val datePickerDialog = DatePickerDialog(
|
|
95
|
+
context,
|
|
96
|
+
{ _, year, month, dayOfMonth ->
|
|
97
|
+
calendar.set(year, month, dayOfMonth)
|
|
98
|
+
selectedDate = calendar.timeInMillis
|
|
99
|
+
},
|
|
100
|
+
calendar.get(Calendar.YEAR),
|
|
101
|
+
calendar.get(Calendar.MONTH),
|
|
102
|
+
calendar.get(Calendar.DAY_OF_MONTH)
|
|
103
|
+
)
|
|
104
|
+
datePickerDialog.show()
|
|
105
|
+
}) {
|
|
106
|
+
Text("Pick")
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
Spacer(modifier = Modifier.height(16.dp))
|
|
112
|
+
|
|
113
|
+
// ===== Time Picker Example =====
|
|
114
|
+
Text(
|
|
115
|
+
text = "Time Picker",
|
|
116
|
+
style = MaterialTheme.typography.titleMedium
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
120
|
+
|
|
121
|
+
OutlinedTextField(
|
|
122
|
+
value = selectedTime?.let {
|
|
123
|
+
val cal = Calendar.getInstance().apply { timeInMillis = it }
|
|
124
|
+
String.format(
|
|
125
|
+
Locale.getDefault(),
|
|
126
|
+
"%02d:%02d",
|
|
127
|
+
cal.get(Calendar.HOUR_OF_DAY),
|
|
128
|
+
cal.get(Calendar.MINUTE)
|
|
129
|
+
)
|
|
130
|
+
} ?: "",
|
|
131
|
+
onValueChange = { },
|
|
132
|
+
label = { Text("Select Time") },
|
|
133
|
+
readOnly = true,
|
|
134
|
+
modifier = Modifier.fillMaxWidth(),
|
|
135
|
+
trailingIcon = {
|
|
136
|
+
TextButton(onClick = {
|
|
137
|
+
// Show TimePickerDialog
|
|
138
|
+
val timePickerDialog = TimePickerDialog(
|
|
139
|
+
context,
|
|
140
|
+
{ _, hourOfDay, minute ->
|
|
141
|
+
calendar.set(Calendar.HOUR_OF_DAY, hourOfDay)
|
|
142
|
+
calendar.set(Calendar.MINUTE, minute)
|
|
143
|
+
selectedTime = calendar.timeInMillis
|
|
144
|
+
},
|
|
145
|
+
calendar.get(Calendar.HOUR_OF_DAY),
|
|
146
|
+
calendar.get(Calendar.MINUTE),
|
|
147
|
+
true // 24-hour format
|
|
148
|
+
)
|
|
149
|
+
timePickerDialog.show()
|
|
150
|
+
}) {
|
|
151
|
+
Text("Pick")
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
Spacer(modifier = Modifier.height(16.dp))
|
|
157
|
+
|
|
158
|
+
// ===== Combined Date & Time Example =====
|
|
159
|
+
Text(
|
|
160
|
+
text = "Date & Time Picker",
|
|
161
|
+
style = MaterialTheme.typography.titleMedium
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
165
|
+
|
|
166
|
+
OutlinedTextField(
|
|
167
|
+
value = if (selectedDate != null && selectedTime != null) {
|
|
168
|
+
val combinedCal = Calendar.getInstance().apply {
|
|
169
|
+
timeInMillis = selectedDate!!
|
|
170
|
+
val timeCal = Calendar.getInstance().apply { timeInMillis = selectedTime!! }
|
|
171
|
+
set(Calendar.HOUR_OF_DAY, timeCal.get(Calendar.HOUR_OF_DAY))
|
|
172
|
+
set(Calendar.MINUTE, timeCal.get(Calendar.MINUTE))
|
|
173
|
+
}
|
|
174
|
+
dateTimeFormatter.format(Date(combinedCal.timeInMillis))
|
|
175
|
+
} else if (selectedDate != null) {
|
|
176
|
+
dateFormatter.format(Date(selectedDate!!))
|
|
177
|
+
} else {
|
|
178
|
+
""
|
|
179
|
+
},
|
|
180
|
+
onValueChange = { },
|
|
181
|
+
label = { Text("Select Date & Time") },
|
|
182
|
+
readOnly = true,
|
|
183
|
+
modifier = Modifier.fillMaxWidth(),
|
|
184
|
+
trailingIcon = {
|
|
185
|
+
TextButton(onClick = {
|
|
186
|
+
// First show DatePicker, then TimePicker
|
|
187
|
+
val datePickerDialog = DatePickerDialog(
|
|
188
|
+
context,
|
|
189
|
+
{ _, year, month, dayOfMonth ->
|
|
190
|
+
calendar.set(year, month, dayOfMonth)
|
|
191
|
+
selectedDate = calendar.timeInMillis
|
|
192
|
+
|
|
193
|
+
// After date is selected, show time picker
|
|
194
|
+
val timePickerDialog = TimePickerDialog(
|
|
195
|
+
context,
|
|
196
|
+
{ _, hourOfDay, minute ->
|
|
197
|
+
calendar.set(Calendar.HOUR_OF_DAY, hourOfDay)
|
|
198
|
+
calendar.set(Calendar.MINUTE, minute)
|
|
199
|
+
selectedTime = calendar.timeInMillis
|
|
200
|
+
},
|
|
201
|
+
calendar.get(Calendar.HOUR_OF_DAY),
|
|
202
|
+
calendar.get(Calendar.MINUTE),
|
|
203
|
+
true
|
|
204
|
+
)
|
|
205
|
+
timePickerDialog.show()
|
|
206
|
+
},
|
|
207
|
+
calendar.get(Calendar.YEAR),
|
|
208
|
+
calendar.get(Calendar.MONTH),
|
|
209
|
+
calendar.get(Calendar.DAY_OF_MONTH)
|
|
210
|
+
)
|
|
211
|
+
datePickerDialog.show()
|
|
212
|
+
}) {
|
|
213
|
+
Text("Pick")
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
Spacer(modifier = Modifier.height(32.dp))
|
|
219
|
+
|
|
220
|
+
// ===== Display Selected Values =====
|
|
221
|
+
Text(
|
|
222
|
+
text = "Selected Values:",
|
|
223
|
+
style = MaterialTheme.typography.titleMedium
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
227
|
+
|
|
228
|
+
Text(
|
|
229
|
+
text = "Date: ${selectedDate?.let { dateFormatter.format(Date(it)) } ?: "Not selected"}"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
Text(
|
|
233
|
+
text = "Time: ${selectedTime?.let {
|
|
234
|
+
val cal = Calendar.getInstance().apply { timeInMillis = it }
|
|
235
|
+
String.format(Locale.getDefault(), "%02d:%02d", cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE))
|
|
236
|
+
} ?: "Not selected"}"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
Spacer(modifier = Modifier.height(24.dp))
|
|
240
|
+
|
|
241
|
+
// ===== Clear Button =====
|
|
242
|
+
OutlinedButton(
|
|
243
|
+
onClick = {
|
|
244
|
+
selectedDate = null
|
|
245
|
+
selectedTime = null
|
|
246
|
+
},
|
|
247
|
+
modifier = Modifier.fillMaxWidth()
|
|
248
|
+
) {
|
|
249
|
+
Text("Clear Selection")
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Alternative approach using Material3 DatePicker and TimePicker composables
|
|
257
|
+
* (Available in newer versions of Material3)
|
|
258
|
+
*/
|
|
259
|
+
@OptIn(ExperimentalMaterial3Api::class)
|
|
260
|
+
@Composable
|
|
261
|
+
fun DateTimePickerWithMaterial3(
|
|
262
|
+
onDateTimeSelected: (Long) -> Unit = {}
|
|
263
|
+
) {
|
|
264
|
+
// This requires Material3 1.1.0+ and shows inline pickers
|
|
265
|
+
// For full implementation, use the datePicker and timePicker state APIs
|
|
266
|
+
|
|
267
|
+
var showDatePicker by remember { mutableStateOf(false) }
|
|
268
|
+
var showTimePicker by remember { mutableStateOf(false) }
|
|
269
|
+
var selectedDateMillis by remember { mutableStateOf<Long?>(null) }
|
|
270
|
+
|
|
271
|
+
Column(
|
|
272
|
+
modifier = Modifier
|
|
273
|
+
.fillMaxSize()
|
|
274
|
+
.padding(16.dp)
|
|
275
|
+
) {
|
|
276
|
+
Button(
|
|
277
|
+
onClick = { showDatePicker = true },
|
|
278
|
+
modifier = Modifier.fillMaxWidth()
|
|
279
|
+
) {
|
|
280
|
+
Text("Show Date Picker Dialog")
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
Spacer(modifier = Modifier.height(8.dp))
|
|
284
|
+
|
|
285
|
+
Button(
|
|
286
|
+
onClick = { showTimePicker = true },
|
|
287
|
+
modifier = Modifier.fillMaxWidth(),
|
|
288
|
+
enabled = selectedDateMillis != null
|
|
289
|
+
) {
|
|
290
|
+
Text("Show Time Picker Dialog")
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Note: Material3 also provides DatePicker and TimePicker composables
|
|
294
|
+
// that can be used inline (not as dialogs) for more customization
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Example of custom DatePickerDialog styling
|
|
300
|
+
*/
|
|
301
|
+
@Composable
|
|
302
|
+
fun StyledDatePickerExample() {
|
|
303
|
+
val context = LocalContext.current
|
|
304
|
+
val calendar = remember { Calendar.getInstance() }
|
|
305
|
+
|
|
306
|
+
Button(
|
|
307
|
+
onClick = {
|
|
308
|
+
val dialog = DatePickerDialog(
|
|
309
|
+
context,
|
|
310
|
+
{ _, year, month, dayOfMonth ->
|
|
311
|
+
// Handle date selection
|
|
312
|
+
calendar.set(year, month, dayOfMonth)
|
|
313
|
+
println("Selected date: ${calendar.time}")
|
|
314
|
+
},
|
|
315
|
+
calendar.get(Calendar.YEAR),
|
|
316
|
+
calendar.get(Calendar.MONTH),
|
|
317
|
+
calendar.get(Calendar.DAY_OF_MONTH)
|
|
318
|
+
).apply {
|
|
319
|
+
// Customize dialog
|
|
320
|
+
datePicker.firstDayOfWeek = Calendar.MONDAY
|
|
321
|
+
// Set min/max date if needed
|
|
322
|
+
// datePicker.minDate = ...
|
|
323
|
+
// datePicker.maxDate = ...
|
|
324
|
+
}
|
|
325
|
+
dialog.show()
|
|
326
|
+
}
|
|
327
|
+
) {
|
|
328
|
+
Text("Styled Date Picker")
|
|
329
|
+
}
|
|
330
|
+
}
|