Jetpack Compose Show TextField with Popup Date and Time Picker

December 15, 2021
fun CardContent(
    posted: LocalDateTime?,
    onPostedChange: (LocalDateTime) -> Unit,
) {

    val date = posted?.toLocalDate() ?: now.toLocalDate()
    val time = posted?.toLocalTime() ?: now.toLocalTime().truncatedTo(ChronoUnit.MINUTES)

    if (posted == null) {
        onPostedChange(date.atTime(time))
    }

    fun formatDate(date: LocalDate): String? {
        return date.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM))
    }

    fun formatTime(date: LocalTime): String? {
        return date.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT))
    }

    val activity = LocalContext.current as AppCompatActivity

    fun showDatePicker(activity: AppCompatActivity, date: LocalDate? = null, onSelected: (LocalDate) -> Unit) {
        val dateBuilder = MaterialDatePicker.Builder.datePicker().apply {
            // setCalendarConstraints(constraintsBuilder.build())
            if (date != null) {
                val millis = date.atStartOfDay().atZone(ZoneOffset.UTC)?.toInstant()?.toEpochMilli()
                setSelection(millis)
            }

        }

        val picker = dateBuilder.build()

        picker.show(activity.supportFragmentManager, picker.toString())
        picker.addOnPositiveButtonClickListener { millis ->
            @Suppress("NAME_SHADOWING")
            val date = LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault())
            onSelected(date.toLocalDate())
        }
    }

    fun showTimePicker(activity: AppCompatActivity, time: LocalTime? = null, onSelected: (LocalTime) -> Unit) {
        val timeBuilder = MaterialTimePicker.Builder().apply {
            if (time != null) {
                setHour(time.hour).setMinute(time.minute)
            }
        }

        val picker = timeBuilder.build()
        picker.show(activity.supportFragmentManager, picker.toString())
        picker.addOnPositiveButtonClickListener {
            @Suppress("NAME_SHADOWING")
            val time = LocalTime.of(picker.hour, picker.minute)
            onSelected(time)
        }
    }

    Column(
        modifier = Modifier
            .padding(4.dp)
            // .verticalScroll(rememberScrollState())
    ) {

        Row {
            val dateInteractionSource = remember {
                MutableInteractionSource()
            }

            if (dateInteractionSource.collectIsPressedAsState().value) {
                showDatePicker(activity, date) { onPostedChange(it.atTime(time)) }
            }

            OutlinedTextField(
                modifier = modifier.weight(1f) /* .clickable {
                    Timber.d("Date.click")
                    showDatePicker(activity) { date = it }
                } */,
                value = formatDate(date) ?: "",
                onValueChange = {  },
                label = { Text("Date") },
                singleLine = true,
                readOnly = true,
                interactionSource = dateInteractionSource
                /*
                enabled = false,
                colors = TextFieldDefaults.textFieldColors(
                    disabledTextColor = LocalContentColor.current.copy(LocalContentAlpha.current),
                    disabledLabelColor =  MaterialTheme.colors.onSurface.copy(ContentAlpha.medium)
                )
                 */
            )

            Spacer(modifier = Modifier.padding(4.dp))

            val timeInteractionSource = remember {
                MutableInteractionSource()
            }

            if (timeInteractionSource.collectIsPressedAsState().value) {
                showTimePicker(activity, time) { onPostedChange(date.atTime(it)) }
            }

            OutlinedTextField(
                modifier = modifier.weight(1f),
                value = formatTime(time) ?: "",
                onValueChange = {  },
                label = { Text("Time") },
                singleLine = true,
                readOnly = true,
                interactionSource = timeInteractionSource
            )
        }
    }
}
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.