Context
Per this comment, opening an issue so we can talk about the approach to add a cross-platform DatePicker composable in commonMain.
Two places currently use Android-only DatePickerDialog:
MarkCompletedConstructionForm (construction quest opening date)
DateTimeSelectField (log filtering screen)
Proposed approach
Two new files in commonMain, then wiring the component into both call sites above.
1. DateFormatElements.kt (util/locale/)
Locale-aware detection of date component ordering (DMY, MDY, YMD) and separator character, following the same approach as TimeFormatElements.kt. Formats a known reference date with the locale's short date formatter, then finds the positions of year, month, and day in the output to determine order.
2. DatePicker.kt (ui/common/)
A DatePicker composable using three WheelPickers (year, month, day), ordered according to the locale's DateFormatElements. Month wheel shows localized abbreviated month names.
State exposed via DatePickerState with a date: LocalDate property, created through rememberDatePickerState(initialDate, years).
Day clamping when month/year changes
The WheelPicker's items list is passed directly to a LazyColumn, so if the day list shrinks (e.g. 31 → 28) while day 31 is selected, the DatePicker must handle this explicitly.
The plan is to follow the convention used by both iOS UIDatePicker and Android's DatePicker (spinner mode):
- The day list updates immediately as the month wheel scrolls (not waiting for it to settle).
- If the selected day exceeds the new month's max, the day wheel animates to the new last day (e.g. 31 → 28 for February).
- The original day is not restored if you scroll back to a month that supports it.
Both platform pickers work this way (AOSP's DatePickerSpinnerDelegate recalculates maxValue on change; iOS's UIDatePicker clamps identically). This avoids invalid intermediate states where the user could see or submit "February 31".
In terms of implementation, a LaunchedEffect on month + year would call animateScrollToItem on the day WheelPickerState whenever the day count shrinks below the currently selected day.
Wiring it in
The PR would replace the Android DatePickerDialog in both MarkCompletedConstructionForm and DateTimeSelectField so we can verify the component works end-to-end. I'll include before/after screenshots in the PR.
As always, I'm happy for any feedback, edits, or pushback you may have on this approach!
Context
Per this comment, opening an issue so we can talk about the approach to add a cross-platform
DatePickercomposable in commonMain.Two places currently use Android-only
DatePickerDialog:MarkCompletedConstructionForm(construction quest opening date)DateTimeSelectField(log filtering screen)Proposed approach
Two new files in commonMain, then wiring the component into both call sites above.
1.
DateFormatElements.kt(util/locale/)Locale-aware detection of date component ordering (DMY, MDY, YMD) and separator character, following the same approach as
TimeFormatElements.kt. Formats a known reference date with the locale's short date formatter, then finds the positions of year, month, and day in the output to determine order.2.
DatePicker.kt(ui/common/)A
DatePickercomposable using threeWheelPickers (year, month, day), ordered according to the locale'sDateFormatElements. Month wheel shows localized abbreviated month names.State exposed via
DatePickerStatewith adate: LocalDateproperty, created throughrememberDatePickerState(initialDate, years).Day clamping when month/year changes
The
WheelPicker'sitemslist is passed directly to aLazyColumn, so if the day list shrinks (e.g. 31 → 28) while day 31 is selected, the DatePicker must handle this explicitly.The plan is to follow the convention used by both iOS
UIDatePickerand Android'sDatePicker(spinner mode):Both platform pickers work this way (AOSP's
DatePickerSpinnerDelegaterecalculatesmaxValueon change; iOS'sUIDatePickerclamps identically). This avoids invalid intermediate states where the user could see or submit "February 31".In terms of implementation, a
LaunchedEffecton month + year would callanimateScrollToItemon the dayWheelPickerStatewhenever the day count shrinks below the currently selected day.Wiring it in
The PR would replace the Android
DatePickerDialogin bothMarkCompletedConstructionFormandDateTimeSelectFieldso we can verify the component works end-to-end. I'll include before/after screenshots in the PR.As always, I'm happy for any feedback, edits, or pushback you may have on this approach!