Skip to content

Commit 3df0782

Browse files
committed
Render DatePicker with a Material date dialog
1 parent 18141e6 commit 3df0782

1 file changed

Lines changed: 47 additions & 0 deletions

File tree

  • Demo/swiftui/src/commonMain/kotlin/com/pureswift/swiftui

Demo/swiftui/src/commonMain/kotlin/com/pureswift/swiftui/Render.kt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
3131
import androidx.compose.material3.AlertDialog
3232
import androidx.compose.material3.Button
3333
import androidx.compose.material3.CircularProgressIndicator
34+
import androidx.compose.material3.DatePicker
35+
import androidx.compose.material3.DatePickerDialog
36+
import androidx.compose.material3.rememberDatePickerState
3437
import androidx.compose.material3.DropdownMenu
3538
import androidx.compose.material3.DropdownMenuItem
3639
import 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

Comments
 (0)