@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.
Files changed (106) hide show
  1. package/.claude/momo-native-kits-skill/SKILL.md +51 -0
  2. package/.claude/momo-native-kits-skill/evals/evals.json +95 -0
  3. package/.claude/momo-native-kits-skill/references/badge.md +52 -0
  4. package/.claude/momo-native-kits-skill/references/button.md +182 -0
  5. package/.claude/momo-native-kits-skill/references/card.md +48 -0
  6. package/.claude/momo-native-kits-skill/references/checkbox.md +51 -0
  7. package/.claude/momo-native-kits-skill/references/chip.md +48 -0
  8. package/.claude/momo-native-kits-skill/references/constants.md +260 -0
  9. package/.claude/momo-native-kits-skill/references/divider.md +26 -0
  10. package/.claude/momo-native-kits-skill/references/input.md +408 -0
  11. package/.claude/momo-native-kits-skill/references/navigation.md +475 -0
  12. package/.claude/momo-native-kits-skill/references/popup.md +97 -0
  13. package/.claude/momo-native-kits-skill/references/radio.md +60 -0
  14. package/.claude/momo-native-kits-skill/references/skeleton.md +40 -0
  15. package/.claude/momo-native-kits-skill/references/snackbar.md +54 -0
  16. package/.claude/momo-native-kits-skill/references/switch.md +62 -0
  17. package/.claude/momo-native-kits-skill/references/text.md +195 -0
  18. package/.claude/momo-native-kits-skill/references/tooltip.md +34 -0
  19. package/.claude/momo-native-kits-skill/references/trustbanner.md +61 -0
  20. package/.claude/momo-native-kits-skill/workspace/iteration-1/benchmark.json +20 -0
  21. package/.claude/momo-native-kits-skill/workspace/iteration-1/benchmark.md +13 -0
  22. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-0-button/eval_metadata.json +6 -0
  23. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-0-button/with_skill/outputs/ButtonExample.kt +55 -0
  24. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-0-button/without_skill/outputs/ButtonExample.kt +45 -0
  25. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-1-input/eval_metadata.json +6 -0
  26. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-1-input/with_skill/outputs/InputPhoneExample.kt +40 -0
  27. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-1-input/without_skill/outputs/InputPhoneExample.kt +42 -0
  28. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-2-bottomtab/eval_metadata.json +6 -0
  29. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-2-bottomtab/with_skill/outputs/BottomTabExample.kt +236 -0
  30. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-2-bottomtab/without_skill/outputs/BottomTabExample.kt +152 -0
  31. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-3-checkbox/eval_metadata.json +6 -0
  32. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-3-checkbox/with_skill/outputs/CheckBoxExample.kt +49 -0
  33. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-3-checkbox/without_skill/outputs/CheckBoxExample.kt +123 -0
  34. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-4-datetimepicker/eval_metadata.json +6 -0
  35. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-4-datetimepicker/with_skill/outputs/DateTimePickerExample.kt +318 -0
  36. package/.claude/momo-native-kits-skill/workspace/iteration-1/eval-4-datetimepicker/without_skill/outputs/DateTimePickerExample.kt +330 -0
  37. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-card/with_skill/outputs/CardExample.kt +124 -0
  38. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-card/without_skill/outputs/CardExample.kt +71 -0
  39. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-loginform/with_skill/outputs/LoginFormExample.kt +134 -0
  40. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-loginform/without_skill/outputs/LoginFormExample.kt +199 -0
  41. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-navcontainer/with_skill/outputs/NavigationContainerExample.kt +224 -0
  42. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-navcontainer/without_skill/outputs/NavigationContainerExample.kt +225 -0
  43. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-popup/with_skill/outputs/PopupExample.kt +79 -0
  44. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-popup/without_skill/outputs/PopupExample.kt +169 -0
  45. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-setoptions/eval_metadata.json +6 -0
  46. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-setoptions/with_skill/outputs/SetOptionsExample.kt +255 -0
  47. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-setoptions/without_skill/outputs/SetOptionsExample.kt +212 -0
  48. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-skeleton/with_skill/outputs/SkeletonExample.kt +199 -0
  49. package/.claude/momo-native-kits-skill/workspace/iteration-2/eval-skeleton/without_skill/outputs/SkeletonExample.kt +229 -0
  50. package/.claude/momo-native-kits-skill/workspace/iteration-3/benchmark.json +20 -0
  51. package/.claude/momo-native-kits-skill/workspace/iteration-3/benchmark.md +13 -0
  52. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/eval_metadata.json +22 -0
  53. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/with_skill/outputs/PrimaryButtonExample.kt +38 -0
  54. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/with_skill/timing.json +5 -0
  55. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/without_skill/outputs/PrimaryButtonExample.kt +83 -0
  56. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-button/without_skill/timing.json +5 -0
  57. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/eval_metadata.json +22 -0
  58. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/with_skill/outputs/NavigationContainerExample.kt +547 -0
  59. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/with_skill/timing.json +5 -0
  60. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/without_skill/outputs/MoMoNavigationContainer.kt +519 -0
  61. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-navcontainer/without_skill/timing.json +5 -0
  62. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/eval_metadata.json +27 -0
  63. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/with_skill/outputs/SetOptionsExample.kt +429 -0
  64. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/with_skill/timing.json +5 -0
  65. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/without_skill/outputs/SetOptionsExample.kt +353 -0
  66. package/.claude/momo-native-kits-skill/workspace/iteration-3/eval-setoptions/without_skill/timing.json +5 -0
  67. package/.claude/settings.local.json +35 -7
  68. package/compose/build.gradle.kts +1 -1
  69. package/gradle.properties +1 -1
  70. package/ios/Input/Input.swift +112 -50
  71. package/local.properties +1 -1
  72. package/package.json +1 -1
  73. package/.claude/momo-native-kits/SKILL.md +0 -87
  74. package/.claude/momo-native-kits/references/Badge.md +0 -39
  75. package/.claude/momo-native-kits/references/BadgeDot.md +0 -37
  76. package/.claude/momo-native-kits/references/BottomSheet.md +0 -51
  77. package/.claude/momo-native-kits/references/BottomTab.md +0 -65
  78. package/.claude/momo-native-kits/references/Button.md +0 -197
  79. package/.claude/momo-native-kits/references/CheckBox.md +0 -51
  80. package/.claude/momo-native-kits/references/Chip.md +0 -47
  81. package/.claude/momo-native-kits/references/Divider.md +0 -29
  82. package/.claude/momo-native-kits/references/HeaderTitle.md +0 -45
  83. package/.claude/momo-native-kits/references/HeaderType.md +0 -47
  84. package/.claude/momo-native-kits/references/Icon.md +0 -32
  85. package/.claude/momo-native-kits/references/Image.md +0 -38
  86. package/.claude/momo-native-kits/references/Information.md +0 -36
  87. package/.claude/momo-native-kits/references/Input.md +0 -334
  88. package/.claude/momo-native-kits/references/InputDropDown.md +0 -47
  89. package/.claude/momo-native-kits/references/InputMoney.md +0 -241
  90. package/.claude/momo-native-kits/references/InputOTP.md +0 -52
  91. package/.claude/momo-native-kits/references/InputPhoneNumber.md +0 -175
  92. package/.claude/momo-native-kits/references/InputSearch.md +0 -57
  93. package/.claude/momo-native-kits/references/InputTextArea.md +0 -46
  94. package/.claude/momo-native-kits/references/NavigationContainer.md +0 -51
  95. package/.claude/momo-native-kits/references/Navigator.md +0 -287
  96. package/.claude/momo-native-kits/references/PaginationDot.md +0 -28
  97. package/.claude/momo-native-kits/references/PaginationNumber.md +0 -28
  98. package/.claude/momo-native-kits/references/PopupNotify.md +0 -47
  99. package/.claude/momo-native-kits/references/Radio.md +0 -44
  100. package/.claude/momo-native-kits/references/Skeleton.md +0 -32
  101. package/.claude/momo-native-kits/references/Switch.md +0 -36
  102. package/.claude/momo-native-kits/references/Tag.md +0 -40
  103. package/.claude/momo-native-kits/references/Text.md +0 -37
  104. package/.claude/momo-native-kits/references/Title.md +0 -43
  105. package/.claude/momo-native-kits/references/Tooltip.md +0 -30
  106. 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
+ }