StartDateRow now works in Compose

pull/3735/head
hady 5 months ago committed by Alex Baker
parent 9808ca1745
commit a779500095

@ -7,17 +7,134 @@ import androidx.compose.material.ContentAlpha
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.todoroo.astrid.ui.StartDateControlSet.Companion.getRelativeDateString import com.todoroo.astrid.ui.StartDateControlSet.Companion.getRelativeDateString
import kotlinx.coroutines.runBlocking
import org.tasks.R import org.tasks.R
import org.tasks.compose.TaskEditRow import org.tasks.compose.TaskEditRow
import org.tasks.compose.pickers.StartDateTimePicker
import org.tasks.data.entity.Task
import org.tasks.date.DateTimeUtils.toDateTime
import org.tasks.dialogs.StartDatePicker import org.tasks.dialogs.StartDatePicker
import org.tasks.extensions.Context.is24HourFormat
import org.tasks.kmp.org.tasks.time.DateStyle
import org.tasks.kmp.org.tasks.time.getRelativeDateTime
import org.tasks.preferences.Preferences
import org.tasks.themes.TasksTheme import org.tasks.themes.TasksTheme
import org.tasks.time.DateTimeUtils2.currentTimeMillis import org.tasks.time.DateTimeUtils2.currentTimeMillis
import org.tasks.time.millisOfDay
import org.tasks.time.startOfDay
@Composable
fun StartDateRow(
current: Long,
setCurrent: (Long) -> Unit,
dueDate: Long,
isNew: Boolean,
hasStartAlarm: Boolean,
showDueDate: Boolean
) {
val context = LocalContext.current
val preferences = remember { Preferences(context) }
val day =
if (current <= 0L) {
if (isNew) when (preferences.getIntegerFromString(R.string.p_default_hideUntil_key, Task.HIDE_UNTIL_NONE)) {
Task.HIDE_UNTIL_DUE -> StartDatePicker.DUE_DATE
Task.HIDE_UNTIL_DUE_TIME -> StartDatePicker.DUE_TIME
Task.HIDE_UNTIL_DAY_BEFORE -> StartDatePicker.DAY_BEFORE_DUE
Task.HIDE_UNTIL_WEEK_BEFORE -> StartDatePicker.WEEK_BEFORE_DUE
else -> 0L
}
else current
} else {
val dueDay = dueDate.startOfDay()
val dueTime = dueDate.millisOfDay
val hideUntil = current.toDateTime()
when (current) {
dueDay -> if (hideUntil.millisOfDay == dueTime) {
StartDatePicker.DUE_TIME
} else {
StartDatePicker.DUE_DATE
}
dueDay.toDateTime().minusDays(1).millis ->
StartDatePicker.DAY_BEFORE_DUE
dueDay.toDateTime().minusDays(7).millis ->
StartDatePicker.WEEK_BEFORE_DUE
else -> current
}
}
val time =
if (current > 0L &&
day == dueDate.startOfDay() &&
current.millisOfDay == dueDate.millisOfDay)
StartDatePicker.NO_TIME
else
current.millisOfDay
val selectedDay = rememberSaveable { mutableLongStateOf(day) }
val selectedTime = rememberSaveable { mutableIntStateOf(time) }
fun getSelectedValue(dueDate: Long): Long {
val due = dueDate.takeIf { it > 0 }?.toDateTime()
return when (selectedDay.longValue) {
StartDatePicker.DUE_DATE -> due?.withMillisOfDay(selectedTime.intValue)?.millis ?: 0
StartDatePicker.DUE_TIME -> due?.millis ?: 0
StartDatePicker.DAY_BEFORE_DUE -> due?.minusDays(1)?.withMillisOfDay(selectedTime.intValue)?.millis ?: 0
StartDatePicker.WEEK_BEFORE_DUE -> due?.minusDays(7)?.withMillisOfDay(selectedTime.intValue)?.millis ?: 0
else -> selectedDay.longValue + selectedTime.intValue
}
}
val showPicker = remember { mutableStateOf(false) }
StartDateRow(
startDate = current,
selectedDay = selectedDay.longValue,
selectedTime = selectedTime.intValue,
hasStartAlarm = hasStartAlarm,
hasDueDate = dueDate > 0L,
printDate = {
runBlocking {
getRelativeDateTime(
selectedDay.longValue + selectedTime.intValue,
context.is24HourFormat,
DateStyle.FULL,
alwaysDisplayFullDate = preferences.alwaysDisplayFullDate
)
}
},
onClick = { showPicker.value = true}
)
LaunchedEffect(dueDate) { setCurrent(getSelectedValue(dueDate)) }
if (showPicker.value) {
StartDateTimePicker(
selectedDay = selectedDay.longValue,
selectedTime = selectedTime.intValue,
updateValues = { day, time -> selectedDay.longValue = day; selectedTime.intValue = time },
accept = { setCurrent(getSelectedValue(dueDate)); showPicker.value = false },
dismiss = { showPicker.value = false },
autoclose = preferences.getBoolean(
R.string.p_auto_dismiss_datetime_edit_screen,
false
),
showDueDate = showDueDate
)
}
}
@Composable @Composable
fun StartDateRow( fun StartDateRow(

@ -270,7 +270,19 @@ fun TaskEditScreen(
) )
CalendarControlSet.TAG -> AndroidFragment<CalendarControlSet>() CalendarControlSet.TAG -> AndroidFragment<CalendarControlSet>()
StartDateControlSet.TAG -> AndroidFragment<StartDateControlSet>() StartDateControlSet.TAG -> {
//AndroidFragment<StartDateControlSet>()
StartDateRow(
current = editViewModel.startDate.collectAsStateWithLifecycle().value,
setCurrent = { editViewModel.setStartDate(it) },
dueDate = editViewModel.dueDate.collectAsStateWithLifecycle().value,
isNew = viewState.isNew,
hasStartAlarm = remember (viewState.alarms) {
viewState.alarms.any { it.type == Alarm.TYPE_REL_START }
},
showDueDate = !viewState.list.account.isOpenTasks
)
}
ReminderControlSet.TAG -> AndroidFragment<ReminderControlSet>() ReminderControlSet.TAG -> AndroidFragment<ReminderControlSet>()
LocationControlSet.TAG -> AndroidFragment<LocationControlSet>() LocationControlSet.TAG -> AndroidFragment<LocationControlSet>()
FilesControlSet.TAG -> AndroidFragment<FilesControlSet>() FilesControlSet.TAG -> AndroidFragment<FilesControlSet>()

@ -0,0 +1,138 @@
package org.tasks.compose.pickers
import androidx.compose.material3.ExperimentalMaterial3Api
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.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import org.tasks.data.entity.Task
import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.dialogs.BaseDateTimePicker
import org.tasks.dialogs.StartDatePicker.Companion.DUE_DATE
import org.tasks.dialogs.StartDatePicker.Companion.DUE_TIME
import org.tasks.extensions.Context.is24HourFormat
import org.tasks.preferences.Preferences
import org.tasks.time.DateTime
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun StartDateTimePicker (
selectedDay: Long,
selectedTime: Int,
updateValues: (Long, Int) -> Unit,
accept: () -> Unit,
dismiss: () -> Unit,
autoclose: Boolean,
showDueDate: Boolean,
onDismissHandler: BaseDateTimePicker.OnDismissHandler? = null
) {
val context = LocalContext.current
val preferences = remember { Preferences(context) }
val state = rememberDatePickerState(
initialDisplayMode = remember { preferences.calendarDisplayMode },
)
val today = remember { newDateTime().startOfDay() }
fun returnDate(day: Long = selectedDay, time: Int = selectedTime) {
if (day != selectedDay || time != selectedTime) {
updateValues(day, time)
}
if (autoclose) accept()
}
fun returnSelectedTime(millisOfDay: Int) {
val day = when {
selectedDay == DUE_TIME -> DUE_DATE
selectedDay != 0L -> selectedDay
today.withMillisOfDay(millisOfDay).isAfterNow -> today.millis
else -> today.plusDays(1).millis
}
returnDate(day = day, time = millisOfDay)
}
DatePickerBottomSheet(
sheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true
),
state = state,
showButtons = !autoclose,
setDisplayMode = { preferences.calendarDisplayMode = it },
cancel = { dismiss(); onDismissHandler?.onDismiss() },
accept = accept,
dateShortcuts = {
StartDateShortcuts(
selected = selectedDay,
selectedDay = { returnDate(it) },
selectedDayTime = { day, time -> returnDate(day, time) },
showDueDate = showDueDate,
clearDate = { returnDate(day = 0, time = 0) },
)
},
timeShortcuts = {
var showTimePicker by rememberSaveable { mutableStateOf(false) }
if (showTimePicker) {
val time = if (selectedTime < 0 || !Task.hasDueTime(
today.withMillisOfDay(selectedTime).millis
)
) {
today.noon().millisOfDay
} else {
selectedTime
}
TimePickerDialog(
state = rememberTimePickerState(
initialHour = time / (60 * 60_000),
initialMinute = (time / (60_000)) % 60,
is24Hour = LocalContext.current.is24HourFormat
),
initialDisplayMode = remember { preferences.timeDisplayMode },
setDisplayMode = { preferences.timeDisplayMode = it },
selected = { returnSelectedTime(it + 1000) },
dismiss = { showTimePicker = false }
)
}
TimeShortcuts(
day = selectedDay,
selected = selectedTime,
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(
day = when (selectedDay) {
DUE_TIME -> DUE_DATE
else -> selectedDay
},
time = 0
)
}
)
}
)
LaunchedEffect(selectedDay) {
if (selectedDay > 0) {
state.selectedDateMillis = selectedDay + (DateTime(selectedDay).offset)
} else {
state.selectedDateMillis = null
}
}
LaunchedEffect(state.selectedDateMillis) {
if (state.selectedDateMillis == selectedDay + (DateTime(selectedDay).offset)) {
return@LaunchedEffect
}
state.selectedDateMillis?.let {
returnDate(day = it - DateTime(it).offset)
}
}
}
Loading…
Cancel
Save