Time Picker
A time of day to choose from columns: the hours, the minutes, and by a clock of twelve hours the half of the day, each a column of five rows that scrolls through the rest, the chosen value filled in the middle of it.
import com.pantrixui.components.date.timepicker.PantrixTimePicker
- Choosing. A press on a value gives a whole time, and the other column stays as it is. With nothing chosen yet, an hour comes with its first minute that can be chosen, and a minute with the first such hour. The chosen value scrolls to the middle of its column.
- Times that cannot be chosen. The minutes outside
minTimeandmaxTime, and the hours none of whose minutes are between them, are drawn faint and cannot be pressed. WheremaxTimecomes beforeminTime, the times that can be chosen run past midnight. - Minute step.
minuteStepsets how far apart the minutes are: with 15, 00, 15, 30 and 45. - 12 or 24 hours.
is24Hourgives the picker its shape:true22:00 with two columns,false10:00 PM with a column of the half of the day (AM/PM, ÖÖ/ÖS, ص/م). It is 24 hours in every language by default. To write the time on a screen by the same clock,strings.time(hour, minute, is24Hour = …). - Platform. A row is the platform's least touch target on a phone (48dp on Android, 44pt on iOS), and 36dp on the desktop and the web.
- Time type. Times are
PantrixTimes; a day and a time become a moment on the device's clock withPantrixDate.at. For turning them intokotlinx-datetime's orjava.time's, see docs/guide/date-time/DATE_TIME_GUIDE.md.
Examples
An appointment on the quarter hour in a popover
A button shows the chosen time and opens the picker under it in a popover. The minutes are a quarter of an hour apart; the popover stays open while the hour and the minute are chosen, and closes on a press outside it.
var at by remember { mutableStateOf<PantrixTime?>(null) }
var open by remember { mutableStateOf(false) }
val strings = PantrixTheme.strings
PantrixPopover(
visible = open,
onDismissRequest = { open = false },
anchor = {
PantrixButton(
text = at?.let { strings.clock(it.hour, it.minute) } ?: "Choose the appointment time",
onClick = { open = !open },
variant = ButtonVariant.Outline,
leadingIcon = { PantrixIcon(PantrixIcons.Clock, contentDescription = null) },
tagKey = "at"
)
},
alignment = PopoverAlignment.Start,
tagKey = "at"
) {
PantrixTimePicker(
selected = at,
onSelect = { at = it },
minuteStep = QUARTER,
tagKey = "at"
)
}
private const val QUARTER = 15
Working hours on the page
A time within working hours from a picker on the page: from 09:00 to 17:30, half an hour apart. The times outside them are faint; the chosen time is written under it.
var call by remember { mutableStateOf<PantrixTime?>(PantrixTime(OPENS, 0)) }
val strings = PantrixTheme.strings
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
PantrixTimePicker(
selected = call,
onSelect = { call = it },
minTime = PantrixTime(OPENS, 0),
maxTime = PantrixTime(LAST_CALL, HALF_HOUR),
minuteStep = HALF_HOUR,
tagKey = "call"
)
PantrixText(
text = call?.let { "Call at: ${strings.clock(it.hour, it.minute)}" } ?: "Choose a time for the call",
style = PantrixTheme.typography.body
)
}
private const val HALF_HOUR = 30
private const val OPENS = 9
private const val LAST_CALL = 17
A day and a time together in a dialog
A meeting's day and time in a dialog. Where there is room the time stands to the right of the calendar; in a window too narrow for the two, as on a phone, it goes under the calendar (FlowRow). What the calendar and the picker show is a draft: OK turns the two into a moment on the device's clock with PantrixDate.at; the moment is written in UTC too.
var meeting by remember { mutableStateOf<Instant?>(null) }
var day by remember { mutableStateOf<PantrixDate?>(null) }
var time by remember { mutableStateOf<PantrixTime?>(null) }
var open by remember { mutableStateOf(false) }
val today = rememberToday()
val strings = PantrixTheme.strings
val report = LocalExampleEvents.current
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
PantrixButton(
text = "Choose the meeting time",
onClick = { open = true },
variant = ButtonVariant.Outline,
tagKey = "meeting"
)
meeting?.let { moment ->
val shown = PantrixDate.of(moment)
val clock = PantrixTime.of(moment)
PantrixText(
text = "Meeting: ${strings.date(shown.day, shown.month, shown.year)} " +
strings.clock(clock.hour, clock.minute),
style = PantrixTheme.typography.body
)
PantrixText(text = "UTC: $moment", style = PantrixTheme.typography.footnote)
}
}
PantrixDialog(
visible = open,
onDismissRequest = { open = false },
title = "Meeting time",
actions = {
PantrixButton(text = "Cancel", onClick = { open = false }, variant = ButtonVariant.Text, tagKey = "cancel")
PantrixButton(
text = "OK",
onClick = {
val chosenDay = day
val chosenTime = time
if (chosenDay != null && chosenTime != null) meeting = chosenDay.at(chosenTime)
open = false
report("Meeting time chosen")
},
enabled = day != null && time != null,
tagKey = "accept"
)
},
tagKey = "meeting"
) {
FlowRow(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md, Alignment.CenterHorizontally),
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
) {
PantrixDatePicker(selected = day, onSelect = { day = it }, minDate = today, tagKey = "meeting")
PantrixTimePicker(
selected = time,
onSelect = { time = it },
minuteStep = FIVE_MINUTES,
tagKey = "meeting"
)
}
}
private const val FIVE_MINUTES = 5
12 or 24 hours
A reminder's time by the clock chosen. is24Hour gives the picker its shape: true two columns (00 to 23, 22:00), false the hours from 12 to 11 and a column of the half of the day (10:00 PM). The time is still a PantrixTime of 24 hours; only how it is shown changes.
var reminder by remember { mutableStateOf<PantrixTime?>(PantrixTime(REMINDER_HOUR, 0)) }
var is24Hour by remember { mutableStateOf(true) }
val strings = PantrixTheme.strings
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
PantrixSegmentButton(
options = listOf(
SegmentOption(true, "24 hours", tagKey = "twenty_four"),
SegmentOption(false, "12 hours", tagKey = "twelve")
),
selected = is24Hour,
onSelect = { is24Hour = it },
fullWidth = false,
tagKey = "cycle"
)
PantrixTimePicker(
selected = reminder,
onSelect = { reminder = it },
is24Hour = is24Hour,
tagKey = "reminder"
)
PantrixText(
text = reminder?.let { "Reminder: ${strings.time(it.hour, it.minute, is24Hour = is24Hour)} ($it)" }
?: "Choose a time for the reminder",
style = PantrixTheme.typography.body
)
}
private const val REMINDER_HOUR = 22
Hours past midnight
The start of a night shift: between 22:00 and 06:00, half an hour apart. As maxTime is before minTime, the hours that can be chosen pass midnight: 22 and 23, then 00 to 06; the hours between are faint. An hour after midnight falls on the next day, and the line under it says so.
val opens = PantrixTime(NIGHT_STARTS, 0)
var start by remember { mutableStateOf<PantrixTime?>(opens) }
val strings = PantrixTheme.strings
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
PantrixTimePicker(
selected = start,
onSelect = { start = it },
minTime = opens,
maxTime = PantrixTime(NIGHT_ENDS, 0),
minuteStep = HALF_HOUR,
tagKey = "night"
)
PantrixText(
text = start?.let {
val clock = strings.clock(it.hour, it.minute)
if (it < opens) "Shift starts: $clock, the next day" else "Shift starts: $clock"
} ?: "Choose when the shift starts",
style = PantrixTheme.typography.body
)
}
private const val HALF_HOUR = 30
private const val NIGHT_STARTS = 22
private const val NIGHT_ENDS = 6
Its own colours and disabled
The picker's own colours and measure, and a switch that disables it. The chosen time's fill and the columns' names are in the info colour; every colour not given is the theme's. The picker has no padding of its own (padding = 0.dp): it stands in the card's. With the switch off the picker is faint and takes no press, and the chosen time stays.
var alarm by remember { mutableStateOf<PantrixTime?>(PantrixTime(ALARM_HOUR, HALF_HOUR)) }
var enabled by remember { mutableStateOf(true) }
val colors = PantrixTheme.colors
Column(verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
PantrixSwitchButton(
checked = enabled,
onCheckedChange = { enabled = it },
label = "Can be chosen",
tagKey = "alarm_enabled"
)
PantrixTimePicker(
selected = alarm,
onSelect = { alarm = it },
enabled = enabled,
style = TimePickerStyle(padding = 0.dp),
colors = TimePickerColors(selectedContainer = colors.info.color, heading = colors.info.color),
tagKey = "alarm"
)
}
private const val HALF_HOUR = 30
private const val ALARM_HOUR = 7
API
selected
A time of day to choose from columns: the hours, the minutes, and by a clock of twelve hours the half of the day, each a column of five rows that scrolls through the rest, the chosen value filled in the middle of it.
| Parameter | Type | Default | What it is |
|---|---|---|---|
selected | PantrixTime? | the chosen time, or null while none is. Its seconds are kept in every time a press makes of it. | |
onSelect | (PantrixTime) -> Unit | handed the time a press or a key chose: one the picker takes. | |
modifier | Modifier | Modifier | the picker's modifier. The picker is as wide as its columns; given more room, it stands in the middle of it. |
minTime | PantrixTime? | null | the first time that can be chosen, or null for none so early: its hour and minute. |
maxTime | PantrixTime? | null | the last time that can be chosen, or null for none so late. Where it comes before minTime, the times that can be chosen run past midnight, from minTime to maxTime of the next day: a night's. |
minuteStep | Int | 1 | how far apart the minutes in their column are, 1 to 60: 15 offers the hour's first, a quarter past, half past and a quarter to. A chosen minute between them is shown all the same. |
is24Hour | Boolean | true | whether the hours are counted by twenty-four, and so the picker's shape: two columns that choose 22:00; or by twelve, with a third column of the half of the day, 10:00 PM. Twenty-four by default, in every language. Either way the time chosen is a PantrixTime of twenty-four hours; a screen writes it by the same clock with PantrixStrings.time(hour, minute, is24Hour = …). |
enabled | Boolean | true | whether a time can be chosen at all. A picker that takes no choice is drawn faint. |
style | TimePickerStyle? | null | this call's own style: over every enclosing one and under the density. Only the fields it sets change, on every platform. |
colors | TimePickerColors? | null | this picker's own colours: the ones it sets, with the theme's for the rest. |
tagKey | String? | null | the picker's automation key: it is TimePicker_<tagKey>, and its values are TimePicker_<tagKey>.Hour_14, .Minute_30 and .Period_pm. |
TimePickerStyle
PantrixTimePicker's geometry: the room of a value in a column, the pill a chosen value is drawn in, how wide a column is, and the room around the columns.
| Parameter | Type | Default | What it is |
|---|---|---|---|
cellSize | Dp | Dp.Unspecified | The height of a value's room: a row. |
markHeight | Dp | Dp.Unspecified | The height of the pill a chosen value and the value under a pointer are drawn in, in the middle of its room. It is most of the column wide. |
columnWidth | Dp | Dp.Unspecified | The width of a column of values. |
padding | Dp | Dp.Unspecified | The room between the picker's edge and its columns. |
gap | Dp | Dp.Unspecified | Between the columns' names and their values. |
TimePickerColors
What a PantrixTimePicker is painted with, in place of the theme's colours: a colour that is set is used, and one that is left out stays the theme's.
| Parameter | Type | Default | What it is |
|---|---|---|---|
content | Color | Color.Unspecified | The values' numbers and the mark between the hours and the minutes. The theme's textPrimary. |
heading | Color | Color.Unspecified | The columns' names over them. The theme's textSecondary. |
selectedContainer | Color | Color.Unspecified | The pill of a chosen value. The primary role's color. |
selectedContent | Color | Color.Unspecified | The number on it. The primary role's onColor, or the colour a role's fill given as selectedContainer gives what stands on it. |
hover | Color | Color.Unspecified | The pill under a pointer: which value a press would choose. A share of content. |
disabled | Color | Color.Unspecified | The values that cannot be chosen, and everything of a picker that takes no choice. The theme's textDisabled. |
Accessibility
- Keyboard. Each column is one Tab stop. The arrows choose a value on, Page Up and Page Down six hours or fifteen minutes, Home and End the first and the last value; typing digits goes to the value they write ("1" then "4" is hour 14). ← and → move between the columns.
- Screen reader. Each column is read by its name and each value as a button; the chosen time is announced politely.