Add DueDatePicker preview and fix layout issues

pull/3441/head
Alex Baker 9 months ago
parent 7ee578ba64
commit 41f2f51c37

@ -5,6 +5,7 @@ import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.rememberTimePickerState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
@ -41,8 +42,11 @@ class DateAndTimePickerActivity : AppCompatActivity() {
var showTimePicker by rememberSaveable { mutableStateOf(false) }
if (showTimePicker) {
TimePickerDialog(
millisOfDay = 0,
is24Hour = is24HourFormat,
state = rememberTimePickerState(
initialHour = 0,
initialMinute = 0,
is24Hour = is24HourFormat
),
initialDisplayMode = remember { preferences.timeDisplayMode },
setDisplayMode = { preferences.timeDisplayMode = it },
selected = {

@ -25,6 +25,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.SheetState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
@ -39,6 +40,7 @@ import org.tasks.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DatePickerBottomSheet(
sheetState: SheetState,
showButtons: Boolean,
dismiss: () -> Unit,
accept: () -> Unit,
@ -49,9 +51,7 @@ fun DatePickerBottomSheet(
) {
ModalBottomSheet(
modifier = Modifier.statusBarsPadding(),
sheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true,
),
sheetState = sheetState,
onDismissRequest = { dismiss() },
containerColor = MaterialTheme.colorScheme.surface,
) {

@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.NextWeek
import androidx.compose.material.icons.outlined.AccessTime
@ -34,8 +35,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.runBlocking
import org.tasks.R
@ -77,6 +80,7 @@ fun DatePickerShortcuts(
) {
Column(
horizontalAlignment = Alignment.Start,
modifier = Modifier.widthIn(max = LocalConfiguration.current.screenWidthDp.dp / 2)
) {
dateShortcuts()
}
@ -344,6 +348,8 @@ fun ShortcutButton(
)
Text(
text = text,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}

@ -24,7 +24,7 @@ import androidx.compose.material3.TimeInput
import androidx.compose.material3.TimePicker
import androidx.compose.material3.TimePickerDefaults
import androidx.compose.material3.TimePickerLayoutType
import androidx.compose.material3.rememberTimePickerState
import androidx.compose.material3.TimePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -41,18 +41,12 @@ import org.tasks.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TimePickerDialog(
millisOfDay: Int,
is24Hour: Boolean,
state: TimePickerState,
initialDisplayMode: DisplayMode,
setDisplayMode: (DisplayMode) -> Unit,
selected: (Int) -> Unit,
dismiss: () -> Unit,
) {
val state = rememberTimePickerState(
initialHour = millisOfDay / (60 * 60_000),
initialMinute = (millisOfDay / (60_000)) % 60,
is24Hour = is24Hour
)
var displayMode by remember { mutableStateOf(initialDisplayMode) }
val layoutType = with(LocalConfiguration.current) {
if (screenHeightDp < screenWidthDp) {

@ -6,8 +6,14 @@ import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.compose.material3.DatePickerState
import androidx.compose.material3.DisplayMode
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SheetState
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.material3.rememberTimePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
@ -16,6 +22,10 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewFontScale
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewScreenSizes
import androidx.fragment.app.Fragment
import androidx.fragment.compose.content
import androidx.lifecycle.lifecycleScope
@ -23,6 +33,7 @@ import com.todoroo.astrid.dao.TaskDao
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.tasks.compose.pickers.DatePickerBottomSheet
import org.tasks.compose.pickers.DueDateShortcuts
import org.tasks.compose.pickers.TimePickerDialog
@ -31,12 +42,19 @@ import org.tasks.data.createDueDate
import org.tasks.data.entity.Task
import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.date.DateTimeUtils.toDateTime
import org.tasks.dialogs.DateTimePicker.Companion.MULTIPLE_TIMES
import org.tasks.dialogs.DateTimePicker.Companion.NO_TIME
import org.tasks.extensions.Context.is24HourFormat
import org.tasks.notifications.NotificationManager
import org.tasks.themes.TasksTheme
import org.tasks.time.DateTime
import org.tasks.time.DateTimeUtils2.currentTimeMillis
import org.tasks.time.millisOfDay
import org.tasks.time.noon
import org.tasks.time.plusDays
import org.tasks.time.startOfDay
import org.tasks.time.withMillisOfDay
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@AndroidEntryPoint
@ -116,83 +134,49 @@ class DateTimePicker : BaseDateTimePicker() {
savedInstanceState: Bundle?,
) = content {
TasksTheme(theme = theme.themeBase.index) {
val state = rememberDatePickerState(
val datePickerState = rememberDatePickerState(
initialDisplayMode = remember { preferences.calendarDisplayMode },
)
DatePickerBottomSheet(
state = state,
DueDatePicker(
sheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true
),
datePickerState = datePickerState,
initialTimeDisplayMode = remember { preferences.timeDisplayMode },
selectedDay = selectedDay,
selectedTime = selectedTime,
showButtons = !autoclose,
setDisplayMode = { preferences.calendarDisplayMode = it },
dismiss = { onDismissHandler?.onDismiss() ?: dismiss() },
accept = { sendSelected() },
dateShortcuts = {
DueDateShortcuts(
today = today.millis,
tomorrow = remember { today.plusDays(1).millis },
nextWeek = remember { today.plusDays(7).millis },
selected = selectedDay,
showNoDate = remember {
!requireArguments().getBoolean(
EXTRA_HIDE_NO_DATE,
false
)
},
selectedDay = { returnDate(it.startOfDay()) },
clearDate = { returnDate(day = 0, time = 0) },
)
},
timeShortcuts = {
var showTimePicker by rememberSaveable {
mutableStateOf(
false
)
}
if (showTimePicker) {
val time = if (selectedTime == MULTIPLE_TIMES
|| !Task.hasDueTime(
today.withMillisOfDay(
selectedTime
).millis
)
) {
today.noon().millisOfDay
} else {
selectedTime
}
TimePickerDialog(
millisOfDay = time,
setDateDisplayMode = { preferences.calendarDisplayMode = it },
setTimeDisplayMode = { preferences.timeDisplayMode = it },
dismiss = { onDismissHandler?.onDismiss() ?: dismiss() },
accept = { sendSelected() },
setDateTime = { day, time -> returnDate(day, time) },
setTime = { returnSelectedTime(it) },
is24Hour = remember { requireContext().is24HourFormat },
initialDisplayMode = remember { preferences.timeDisplayMode },
setDisplayMode = { preferences.timeDisplayMode = it },
selected = { returnSelectedTime(it + 1000) },
dismiss = { showTimePicker = false },
)
}
TimeShortcuts(
day = 0,
selected = selectedTime,
today = today.millis,
morning = remember { preferences.dateShortcutMorning + 1000 },
afternoon = remember { preferences.dateShortcutAfternoon + 1000 },
evening = remember { preferences.dateShortcutEvening + 1000 },
night = remember { preferences.dateShortcutNight + 1000 },
selectedMillisOfDay = { returnSelectedTime(it) },
pickTime = { showTimePicker = true },
clearTime = { returnDate(time = 0) },
)
}
)
LaunchedEffect(selectedDay) {
if (selectedDay > 0) {
state.selectedDateMillis = selectedDay + (DateTime(selectedDay).offset)
datePickerState.selectedDateMillis = selectedDay + (DateTime(selectedDay).offset)
} else {
state.selectedDateMillis = null
datePickerState.selectedDateMillis = null
}
}
LaunchedEffect(state.selectedDateMillis) {
if (state.selectedDateMillis == selectedDay + (DateTime(selectedDay).offset)) {
LaunchedEffect(datePickerState.selectedDateMillis) {
if (datePickerState.selectedDateMillis == selectedDay + (DateTime(selectedDay).offset)) {
return@LaunchedEffect
}
state.selectedDateMillis?.let {
datePickerState.selectedDateMillis?.let {
returnDate(day = it - DateTime(it).offset)
}
}
@ -201,6 +185,7 @@ class DateTimePicker : BaseDateTimePicker() {
private fun returnSelectedTime(millisOfDay: Int) {
val day = when {
millisOfDay == NO_TIME -> selectedDay
selectedDay == MULTIPLE_DAYS -> MULTIPLE_DAYS
selectedDay > 0 -> selectedDay
today.withMillisOfDay(millisOfDay).isAfterNow -> today.millis
@ -278,3 +263,140 @@ class DateTimePicker : BaseDateTimePicker() {
outState.putInt(EXTRA_TIME, selectedTime)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DueDatePicker(
sheetState: SheetState,
datePickerState: DatePickerState,
initialTimeDisplayMode: DisplayMode,
selectedDay: Long,
selectedTime: Int,
today: Long,
morning: Int,
afternoon: Int,
evening: Int,
night: Int,
is24Hour: Boolean,
showButtons: Boolean,
showNoDate: Boolean,
setDateDisplayMode: (DisplayMode) -> Unit,
setTimeDisplayMode: (DisplayMode) -> Unit,
dismiss: () -> Unit,
accept: () -> Unit,
setDateTime: (Long, Int) -> Unit,
setTime: (Int) -> Unit,
) {
DatePickerBottomSheet(
sheetState = sheetState,
state = datePickerState,
showButtons = showButtons,
setDisplayMode = setDateDisplayMode,
dismiss = dismiss,
accept = accept,
dateShortcuts = {
DueDateShortcuts(
today = today,
tomorrow = remember { today.plusDays(1) },
nextWeek = remember { today.plusDays(7) },
selected = selectedDay,
showNoDate = showNoDate,
selectedDay = { setDateTime(it.startOfDay(), selectedTime) },
clearDate = { setDateTime(0, 0) },
)
},
timeShortcuts = {
var showTimePicker by rememberSaveable {
mutableStateOf(
false
)
}
if (showTimePicker) {
val time = if (selectedTime == MULTIPLE_TIMES
|| !Task.hasDueTime(
today.withMillisOfDay(
selectedTime
)
)
) {
today.noon().millisOfDay
} else {
selectedTime
}
TimePickerDialog(
state = rememberTimePickerState(
initialHour = time / (60 * 60_000),
initialMinute = (time / (60_000)) % 60,
is24Hour = is24Hour,
),
initialDisplayMode = initialTimeDisplayMode,
setDisplayMode = setTimeDisplayMode,
selected = { setTime(it + 1000) },
dismiss = { showTimePicker = false },
)
}
TimeShortcuts(
day = 0,
selected = selectedTime,
morning = morning,
afternoon = afternoon,
evening = evening,
night = night,
selectedMillisOfDay = { setTime(it) },
pickTime = { showTimePicker = true },
clearTime = { setTime(NO_TIME) },
)
}
)
}
@OptIn(ExperimentalMaterial3Api::class)
@PreviewLightDark
@PreviewFontScale
@PreviewScreenSizes
@Preview(
locale = "es",
fontScale = 2f
)
@Preview(
locale = "es",
)
@Preview(
locale = "de",
fontScale = 2f
)
@Preview(
locale = "de",
)
@Composable
fun DueDatePickerPreview() {
TasksTheme {
val today = currentTimeMillis().startOfDay()
val sheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true
).apply {
runBlocking { show() }
}
DueDatePicker(
sheetState = sheetState,
datePickerState = rememberDatePickerState(),
initialTimeDisplayMode = DisplayMode.Input,
selectedDay = 0,
selectedTime = 0,
today = today,
morning = TimeUnit.HOURS.toMillis(9).toInt(),
afternoon = TimeUnit.HOURS.toMillis(13).toInt(),
evening = TimeUnit.HOURS.toMillis(17).toInt(),
night = TimeUnit.HOURS.toMillis(20).toInt(),
is24Hour = true,
showButtons = true,
showNoDate = true,
setDateDisplayMode = {},
setTimeDisplayMode = {},
dismiss = {},
accept = {},
setDateTime = { _, _ -> },
setTime = {},
)
}
}

@ -6,6 +6,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.rememberTimePickerState
import androidx.compose.runtime.remember
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
@ -39,8 +40,11 @@ class MyTimePickerDialog : DialogFragment() {
primary = theme.themeColor.primaryColor,
) {
TimePickerDialog(
millisOfDay = remember { initial.millisOfDay },
is24Hour = remember { requireContext().is24HourFormat },
state = rememberTimePickerState(
initialHour = initial.millisOfDay / (60 * 60_000),
initialMinute = (initial.millisOfDay / (60_000)) % 60,
is24Hour = requireContext().is24HourFormat
),
initialDisplayMode = remember { preferences.timeDisplayMode },
setDisplayMode = { preferences.timeDisplayMode = it },
selected = {

@ -8,6 +8,8 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.material3.rememberTimePickerState
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
@ -87,6 +89,9 @@ class StartDatePicker : BaseDateTimePicker() {
initialDisplayMode = remember { preferences.calendarDisplayMode },
)
DatePickerBottomSheet(
sheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true
),
state = state,
showButtons = !autoclose,
setDisplayMode = { preferences.calendarDisplayMode = it },
@ -112,8 +117,11 @@ class StartDatePicker : BaseDateTimePicker() {
selectedTime
}
TimePickerDialog(
millisOfDay = time,
is24Hour = remember { requireContext().is24HourFormat },
state = rememberTimePickerState(
initialHour = time / (60 * 60_000),
initialMinute = (time / (60_000)) % 60,
is24Hour = requireContext().is24HourFormat
),
initialDisplayMode = remember { preferences.timeDisplayMode },
setDisplayMode = { preferences.timeDisplayMode = it },
selected = { returnSelectedTime(it + 1000) },

Loading…
Cancel
Save