@@ -31,6 +31,9 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
3131import androidx.compose.material3.AlertDialog
3232import androidx.compose.material3.Button
3333import androidx.compose.material3.CircularProgressIndicator
34+ import androidx.compose.material3.DatePicker
35+ import androidx.compose.material3.DatePickerDialog
36+ import androidx.compose.material3.rememberDatePickerState
3437import androidx.compose.material3.DropdownMenu
3538import androidx.compose.material3.DropdownMenuItem
3639import androidx.compose.material3.HorizontalDivider
@@ -247,6 +250,8 @@ fun Render(node: ViewNode) {
247250
248251 " Menu" -> RenderMenu (node)
249252
253+ " DatePicker" -> RenderDatePicker (node)
254+
250255 " Picker" -> RenderPicker (node)
251256
252257 " NavStack" -> RenderNavStack (node)
@@ -380,6 +385,48 @@ private fun RenderSection(node: ViewNode) {
380385 }
381386}
382387
388+ // A label row with a trailing formatted-date button; tapping opens a Material3
389+ // date picker dialog. Selection round-trips as UTC epoch millis, matching both
390+ // Date's representation and DatePickerState's currency, so no conversion.
391+ @OptIn(ExperimentalMaterial3Api ::class )
392+ @Composable
393+ private fun RenderDatePicker (node : ViewNode ) {
394+ val onChange = node.long(" onChange" )
395+ val millis = (node.double(" millis" ) ? : 0.0 ).toLong()
396+ var showDialog by remember { mutableStateOf(false ) }
397+ Row (verticalAlignment = Alignment .CenterVertically , modifier = node.composeModifiers().fillMaxWidth()) {
398+ RenderChildren (node)
399+ Spacer (modifier = Modifier .weight(1f ))
400+ TextButton (onClick = { showDialog = true }) { Text (formatDateMillis(millis)) }
401+ }
402+ if (showDialog) {
403+ val state = rememberDatePickerState(initialSelectedDateMillis = millis)
404+ DatePickerDialog (
405+ onDismissRequest = { showDialog = false },
406+ confirmButton = {
407+ TextButton (onClick = {
408+ showDialog = false
409+ state.selectedDateMillis?.let { picked -> onChange?.let { SwiftBridge .sink.invokeDouble(it, picked.toDouble()) } }
410+ }) { Text (" OK" ) }
411+ },
412+ dismissButton = { TextButton (onClick = { showDialog = false }) { Text (" Cancel" ) } },
413+ ) {
414+ DatePicker (state = state)
415+ }
416+ }
417+ }
418+
419+ private val monthAbbreviations = arrayOf(" Jan" , " Feb" , " Mar" , " Apr" , " May" , " Jun" , " Jul" , " Aug" , " Sep" , " Oct" , " Nov" , " Dec" )
420+
421+ private fun formatDateMillis (millis : Long ): String {
422+ val calendar = java.util.Calendar .getInstance(java.util.TimeZone .getTimeZone(" UTC" ))
423+ calendar.timeInMillis = millis
424+ val month = monthAbbreviations[calendar.get(java.util.Calendar .MONTH )]
425+ val day = calendar.get(java.util.Calendar .DAY_OF_MONTH )
426+ val year = calendar.get(java.util.Calendar .YEAR )
427+ return " $month $day , $year "
428+ }
429+
383430// A trigger button opening a dropdown; each child Button becomes a menu item
384431// firing its own tap callback.
385432@Composable
0 commit comments