pull/3735/merge
Hady 1 week ago committed by GitHub
commit 92869eb818
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -7,17 +7,134 @@ import androidx.compose.material.ContentAlpha
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
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.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.todoroo.astrid.ui.StartDateControlSet.Companion.getRelativeDateString
import kotlinx.coroutines.runBlocking
import org.tasks.R
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.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.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
fun StartDateRow(

@ -270,7 +270,19 @@ fun TaskEditScreen(
)
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>()
LocationControlSet.TAG -> AndroidFragment<LocationControlSet>()
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