Move more Start and due date logic into composables

pull/1952/head
Alex Baker 2 years ago
parent e39bc8b8cc
commit 5c3af50c9d

@ -5,6 +5,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import android.view.ViewGroup
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.ContentAlpha import androidx.compose.material.ContentAlpha
@ -12,6 +13,7 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -26,6 +28,8 @@ import com.todoroo.andlib.utility.DateUtilities.now
import com.todoroo.astrid.ui.StartDateControlSet.Companion.getRelativeDateString import com.todoroo.astrid.ui.StartDateControlSet.Companion.getRelativeDateString
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R import org.tasks.R
import org.tasks.compose.TaskEditIcon
import org.tasks.compose.TaskEditRow
import org.tasks.compose.collectAsStateLifecycleAware import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.date.DateTimeUtils.newDateTime import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.dialogs.StartDatePicker import org.tasks.dialogs.StartDatePicker
@ -39,6 +43,7 @@ import org.tasks.dialogs.StartDatePicker.Companion.NO_TIME
import org.tasks.dialogs.StartDatePicker.Companion.WEEK_BEFORE_DUE import org.tasks.dialogs.StartDatePicker.Companion.WEEK_BEFORE_DUE
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.ui.TaskEditControlComposeFragment import org.tasks.ui.TaskEditControlComposeFragment
import org.tasks.ui.TaskEditViewModel
import java.time.format.FormatStyle import java.time.format.FormatStyle
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -50,19 +55,6 @@ class StartDateControlSet : TaskEditControlComposeFragment() {
private val vm: StartDateViewModel by viewModels() private val vm: StartDateViewModel by viewModels()
override fun onRowClick() {
val fragmentManager = parentFragmentManager
if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) == null) {
StartDatePicker.newDateTimePicker(
this,
REQUEST_START_DATE,
vm.selectedDay.value,
vm.selectedTime.value,
preferences.getBoolean(R.string.p_auto_dismiss_datetime_edit_screen, false))
.show(fragmentManager, FRAG_TAG_DATE_PICKER)
}
}
override fun createView(savedInstanceState: Bundle?) { override fun createView(savedInstanceState: Bundle?) {
if (savedInstanceState == null) { if (savedInstanceState == null) {
vm.init(viewModel.dueDate.value, viewModel.startDate.value, viewModel.isNew) vm.init(viewModel.dueDate.value, viewModel.startDate.value, viewModel.isNew)
@ -74,23 +66,39 @@ class StartDateControlSet : TaskEditControlComposeFragment() {
} }
} }
@Composable override fun bind(parent: ViewGroup?) =
override fun Body() { (parent as ComposeView).apply {
StartDate( setContent {
startDate = viewModel.startDate.collectAsStateLifecycleAware().value, MdcTheme {
selectedDay = vm.selectedDay.collectAsStateLifecycleAware().value, StartDateRow(
selectedTime = vm.selectedTime.collectAsStateLifecycleAware().value, viewModel = viewModel,
displayFullDate = preferences.alwaysDisplayFullDate, vm = vm,
locale = locale, preferences = preferences,
) locale = locale,
} onClick = {
val fragmentManager = parentFragmentManager
override val icon = R.drawable.ic_pending_actions_24px if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) == null) {
StartDatePicker.newDateTimePicker(
this@StartDateControlSet,
REQUEST_START_DATE,
vm.selectedDay.value,
vm.selectedTime.value,
preferences.getBoolean(
R.string.p_auto_dismiss_datetime_edit_screen,
false
)
)
.show(fragmentManager, FRAG_TAG_DATE_PICKER)
}
}
)
}
}
}
override fun controlId() = TAG override fun controlId() = TAG
override val isClickable = true @Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_START_DATE) { if (requestCode == REQUEST_START_DATE) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
@ -123,6 +131,41 @@ class StartDateControlSet : TaskEditControlComposeFragment() {
} }
} }
@Composable
fun StartDateRow(
viewModel: TaskEditViewModel,
vm: StartDateViewModel,
preferences: Preferences,
locale: Locale,
onClick: () -> Unit,
) {
TaskEditRow(
icon = {
TaskEditIcon(
id = R.drawable.ic_pending_actions_24px,
modifier = Modifier
.padding(
start = 16.dp,
top = 20.dp,
end = 32.dp,
bottom = 20.dp
)
)
},
content = {
StartDate(
startDate = viewModel.startDate.collectAsStateLifecycleAware().value,
selectedDay = vm.selectedDay.collectAsStateLifecycleAware().value,
selectedTime = vm.selectedTime.collectAsStateLifecycleAware().value,
displayFullDate = preferences.alwaysDisplayFullDate,
locale = locale,
hasDueDate = viewModel.dueDate.collectAsStateLifecycleAware().value > 0
)
},
onClick = onClick
)
}
@Composable @Composable
fun StartDate( fun StartDate(
startDate: Long, startDate: Long,
@ -131,6 +174,7 @@ fun StartDate(
displayFullDate: Boolean, displayFullDate: Boolean,
locale: Locale = Locale.getDefault(), locale: Locale = Locale.getDefault(),
currentTime: Long = now(), currentTime: Long = now(),
hasDueDate: Boolean,
) { ) {
val context = LocalContext.current val context = LocalContext.current
Text( Text(
@ -150,11 +194,14 @@ fun StartDate(
else -> stringResource(id = R.string.no_start_date) else -> stringResource(id = R.string.no_start_date)
}, },
color = when { color = when {
selectedDay < 0 && !hasDueDate -> colorResource(id = R.color.overdue)
startDate == 0L -> MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled) startDate == 0L -> MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled)
startDate < currentTime -> colorResource(id = R.color.overdue) startDate < currentTime -> colorResource(id = R.color.overdue)
else -> MaterialTheme.colors.onSurface else -> MaterialTheme.colors.onSurface
}, },
modifier = Modifier.padding(vertical = 20.dp).height(24.dp), modifier = Modifier
.padding(vertical = 20.dp)
.height(24.dp),
) )
} }
@ -168,7 +215,8 @@ fun NoStartDate() {
selectedDay = NO_DAY, selectedDay = NO_DAY,
selectedTime = NO_TIME, selectedTime = NO_TIME,
displayFullDate = false, displayFullDate = false,
currentTime = 1657080392000L currentTime = 1657080392000L,
hasDueDate = false,
) )
} }
} }
@ -183,7 +231,8 @@ fun FutureStartDate() {
selectedDay = DUE_DATE, selectedDay = DUE_DATE,
selectedTime = NO_TIME, selectedTime = NO_TIME,
displayFullDate = false, displayFullDate = false,
currentTime = 1657080392000L currentTime = 1657080392000L,
hasDueDate = false,
) )
} }
} }
@ -198,7 +247,8 @@ fun PastStartDate() {
selectedDay = DUE_TIME, selectedDay = DUE_TIME,
selectedTime = NO_TIME, selectedTime = NO_TIME,
displayFullDate = false, displayFullDate = false,
currentTime = 1657080392001L currentTime = 1657080392001L,
hasDueDate = false,
) )
} }
} }

@ -13,6 +13,6 @@ fun TaskEditIcon(@DrawableRes id: Int, modifier: Modifier = Modifier) {
Icon( Icon(
painter = painterResource(id = id), painter = painterResource(id = id),
contentDescription = null, contentDescription = null,
modifier = modifier.alpha(ContentAlpha.high), modifier = modifier.alpha(ContentAlpha.medium),
) )
} }

@ -2,25 +2,30 @@ package org.tasks.ui
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.view.ViewGroup
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.google.android.material.composethemeadapter.MdcTheme
import com.todoroo.andlib.utility.DateUtilities import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.data.Task.Companion.hasDueTime import com.todoroo.astrid.data.Task.Companion.hasDueTime
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R import org.tasks.R
import org.tasks.compose.DisabledText import org.tasks.compose.DisabledText
import org.tasks.compose.TaskEditIcon
import org.tasks.compose.TaskEditRow
import org.tasks.compose.collectAsStateLifecycleAware import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.date.DateTimeUtils import org.tasks.date.DateTimeUtils
import org.tasks.dialogs.DateTimePicker import org.tasks.dialogs.DateTimePicker
import org.tasks.dialogs.DateTimePicker.Companion.newDateTimePicker
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.ui.DeadlineControlSet.Companion.isOverdue
import java.time.format.FormatStyle import java.time.format.FormatStyle
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -30,49 +35,29 @@ class DeadlineControlSet : TaskEditControlComposeFragment() {
@Inject lateinit var locale: Locale @Inject lateinit var locale: Locale
@Inject lateinit var preferences: Preferences @Inject lateinit var preferences: Preferences
override fun onRowClick() { override fun bind(parent: ViewGroup?) =
val fragmentManager = parentFragmentManager (parent as ComposeView).apply {
if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) == null) { setContent {
newDateTimePicker( MdcTheme {
this, DueDateRow(
REQUEST_DATE, viewModel = viewModel,
viewModel.dueDate.value, locale = locale,
preferences.getBoolean(R.string.p_auto_dismiss_datetime_edit_screen, false)) displayFullDate = preferences.alwaysDisplayFullDate,
.show(fragmentManager, FRAG_TAG_DATE_PICKER) onClick = {
} val fragmentManager = parentFragmentManager
} if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) == null) {
DateTimePicker.newDateTimePicker(
override val isClickable = true this@DeadlineControlSet,
REQUEST_DATE,
@Composable viewModel.dueDate.value,
override fun Body() { preferences.getBoolean(R.string.p_auto_dismiss_datetime_edit_screen, false))
val dueDate = viewModel.dueDate.collectAsStateLifecycleAware().value .show(fragmentManager, FRAG_TAG_DATE_PICKER)
if (dueDate == 0L) { }
DisabledText( }
text = stringResource(id = R.string.no_due_date), )
modifier = Modifier.padding(vertical = 20.dp) }
) }
} else {
Text(
text = DateUtilities.getRelativeDateTime(
LocalContext.current,
dueDate,
locale,
FormatStyle.FULL,
preferences.alwaysDisplayFullDate,
false
),
color = if (dueDate.isOverdue) {
colorResource(id = R.color.overdue)
} else {
MaterialTheme.colors.onSurface
},
modifier = Modifier.padding(vertical = 20.dp)
)
} }
}
override val icon = R.drawable.ic_outline_schedule_24px
override fun controlId() = TAG override fun controlId() = TAG
@ -91,11 +76,68 @@ class DeadlineControlSet : TaskEditControlComposeFragment() {
private const val REQUEST_DATE = 504 private const val REQUEST_DATE = 504
private const val FRAG_TAG_DATE_PICKER = "frag_tag_date_picker" private const val FRAG_TAG_DATE_PICKER = "frag_tag_date_picker"
private val Long.isOverdue: Boolean val Long.isOverdue: Boolean
get() = if (hasDueTime(this)) { get() = if (hasDueTime(this)) {
DateTimeUtils.newDateTime(this).isBeforeNow DateTimeUtils.newDateTime(this).isBeforeNow
} else { } else {
DateTimeUtils.newDateTime(this).endOfDay().isBeforeNow DateTimeUtils.newDateTime(this).endOfDay().isBeforeNow
} }
} }
}
@Composable
fun DueDateRow(
viewModel: TaskEditViewModel,
locale: Locale,
displayFullDate: Boolean,
onClick: () -> Unit,
) {
TaskEditRow(
icon = {
TaskEditIcon(
id = R.drawable.ic_outline_schedule_24px,
modifier = Modifier.padding(
start = 16.dp,
top = 20.dp,
end = 32.dp,
bottom = 20.dp
)
)
},
content = {
DueDate(
dueDate = viewModel.dueDate.collectAsStateLifecycleAware().value,
locale = locale,
displayFullDate = displayFullDate,
)
},
onClick = onClick,
)
}
@Composable
fun DueDate(dueDate: Long, locale: Locale, displayFullDate: Boolean) {
if (dueDate == 0L) {
DisabledText(
text = stringResource(id = R.string.no_due_date),
modifier = Modifier.padding(vertical = 20.dp)
)
} else {
Text(
text = DateUtilities.getRelativeDateTime(
LocalContext.current,
dueDate,
locale,
FormatStyle.FULL,
displayFullDate,
false
),
color = if (dueDate.isOverdue) {
colorResource(id = R.color.overdue)
} else {
MaterialTheme.colors.onSurface
},
modifier = Modifier.padding(vertical = 20.dp)
)
}
} }

@ -57,5 +57,5 @@ abstract class TaskEditControlComposeFragment : TaskEditControlFragment() {
} }
@Composable @Composable
protected abstract fun Body() protected open fun Body() {}
} }

@ -15,7 +15,7 @@ abstract class TaskEditControlFragment : Fragment() {
protected open val isClickable: Boolean protected open val isClickable: Boolean
get() = false get() = false
protected abstract val icon: Int protected open val icon = 0
abstract fun controlId(): Int abstract fun controlId(): Int
protected abstract fun bind(parent: ViewGroup?): View protected abstract fun bind(parent: ViewGroup?): View
} }
Loading…
Cancel
Save