Add option to notify at start date

pull/1652/head
Alex Baker 3 years ago
parent a0594df42e
commit b13f62a9fb

@ -3,6 +3,7 @@ package com.todoroo.astrid.reminders
import com.natpryce.makeiteasy.MakeItEasy.with
import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.data.Task
import com.todoroo.astrid.data.Task.Companion.HIDE_UNTIL_DUE
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules
import org.junit.Assert.assertEquals
@ -22,6 +23,7 @@ import org.tasks.makers.TaskMaker.CREATION_TIME
import org.tasks.makers.TaskMaker.DELETION_TIME
import org.tasks.makers.TaskMaker.DUE_DATE
import org.tasks.makers.TaskMaker.DUE_TIME
import org.tasks.makers.TaskMaker.HIDE_TYPE
import org.tasks.makers.TaskMaker.ID
import org.tasks.makers.TaskMaker.RANDOM_REMINDER_PERIOD
import org.tasks.makers.TaskMaker.REMINDERS
@ -52,6 +54,19 @@ class ReminderServiceTest : InjectingTestCase() {
service = ReminderService(preferences, jobs, random, taskDao)
}
@Test
fun dontScheduleStartDateReminderWhenFlagNotSet() {
service.scheduleAlarm(
newTask(
with(ID, 1L),
with(HIDE_TYPE, Task.HIDE_UNTIL_DUE),
with(DUE_TIME, DateTimeUtils.newDateTime())
)
)
assertTrue(jobs.isEmpty())
}
@Test
fun dontScheduleDueDateReminderWhenFlagNotSet() {
service.scheduleAlarm(newTask(with(ID, 1L), with(DUE_TIME, DateTimeUtils.newDateTime())))
@ -66,6 +81,34 @@ class ReminderServiceTest : InjectingTestCase() {
assertTrue(jobs.isEmpty())
}
@Test
fun schedulePastStartDate() {
val task = newTask(
with(ID, 1L),
with(DUE_TIME, DateTimeUtils.newDateTime().minusDays(1)),
with(HIDE_TYPE, HIDE_UNTIL_DUE),
with(REMINDERS, Task.NOTIFY_AT_START)
)
service.scheduleAlarm(task)
verify(ReminderEntry(1, task.hideUntil, ReminderService.TYPE_START))
}
@Test
fun scheduleFutureStartDate() {
val task = newTask(
with(ID, 1L),
with(DUE_TIME, DateTimeUtils.newDateTime().plusDays(1)),
with(HIDE_TYPE, HIDE_UNTIL_DUE),
with(REMINDERS, Task.NOTIFY_AT_START)
)
service.scheduleAlarm(task)
verify(ReminderEntry(1, task.hideUntil, ReminderService.TYPE_START))
}
@Test
fun schedulePastDueDate() {
val task = newTask(

@ -251,6 +251,9 @@ class Task : Parcelable {
val isNotifyAfterDeadline: Boolean
get() = isReminderFlagSet(NOTIFY_AFTER_DEADLINE)
val isNotifyAtStart: Boolean
get() = isReminderFlagSet(NOTIFY_AT_START)
val isNotifyAtDeadline: Boolean
get() = isReminderFlagSet(NOTIFY_AT_DEADLINE)
@ -516,6 +519,9 @@ class Task : Parcelable {
/** reminder mode five times (exclusive with non-stop) */
const val NOTIFY_MODE_FIVE = 1 shl 4
const val NOTIFY_AT_START = 1 shl 5
@JvmField val CREATOR: Parcelable.Creator<Task> = object : Parcelable.Creator<Task> {
override fun createFromParcel(source: Parcel): Task? {
return Task(source)

@ -66,6 +66,8 @@ class ReminderService internal constructor(
// random reminders
val whenRandom = calculateNextRandomReminder(task)
val whenStartDate = calculateStartDateReminder(task)
// notifications at due date
val whenDueDate = calculateNextDueDateReminder(task)
@ -75,8 +77,14 @@ class ReminderService internal constructor(
// snooze trumps all
if (whenSnooze != NO_ALARM) {
return ReminderEntry(taskId, whenSnooze, TYPE_SNOOZE)
} else if (whenRandom < whenDueDate && whenRandom < whenOverdue) {
} else if (
whenRandom < whenDueDate &&
whenRandom < whenOverdue &&
whenRandom < whenStartDate
) {
return ReminderEntry(taskId, whenRandom, TYPE_RANDOM)
} else if (whenStartDate < whenDueDate) {
return ReminderEntry(taskId, whenStartDate, TYPE_START)
} else if (whenDueDate < whenOverdue) {
return ReminderEntry(taskId, whenDueDate, TYPE_DUE)
} else if (whenOverdue != NO_ALARM) {
@ -108,6 +116,21 @@ class ReminderService internal constructor(
return NO_ALARM
}
private fun calculateStartDateReminder(task: Task): Long {
if (task.hasStartDate() && task.isNotifyAtStart) {
val startDate = task.hideUntil
val startDateAlarm = if (task.hasDueTime()) {
startDate
} else {
DateTime(startDate).withMillisOfDay(preferences.defaultDueTime).millis
}
if (task.reminderLast < startDateAlarm) {
return startDateAlarm
}
}
return NO_ALARM
}
/**
* Calculate the next alarm time for due date reminders.
*
@ -122,14 +145,14 @@ class ReminderService internal constructor(
private fun calculateNextDueDateReminder(task: Task): Long {
if (task.hasDueDate() && task.isNotifyAtDeadline) {
val dueDate = task.dueDate
val lastReminder = task.reminderLast
val dueDateAlarm: Long
dueDateAlarm = if (task.hasDueTime()) {
val dueDateAlarm = if (task.hasDueTime()) {
dueDate
} else {
DateTime(dueDate).withMillisOfDay(preferences.defaultDueTime).millis
}
return if (lastReminder < dueDateAlarm) dueDateAlarm else NO_ALARM
if (task.reminderLast < dueDateAlarm) {
return dueDateAlarm
}
}
return NO_ALARM
}
@ -165,6 +188,7 @@ class ReminderService internal constructor(
const val TYPE_ALARM = 4
const val TYPE_GEOFENCE_ENTER = 5
const val TYPE_GEOFENCE_EXIT = 6
const val TYPE_START = 7
private const val NO_ALARM = Long.MAX_VALUE
}
}

@ -52,6 +52,9 @@ class ReminderControlSet : TaskEditControlFragment() {
viewModel.ringFiveTimes!! -> setRingMode(1)
else -> setRingMode(0)
}
if (viewModel.whenStart!!) {
addStart()
}
if (viewModel.whenDue!!) {
addDue()
}
@ -97,6 +100,7 @@ class ReminderControlSet : TaskEditControlFragment() {
private fun addAlarm(selected: String) {
when (selected) {
getString(R.string.when_started) -> addStart()
getString(R.string.when_due) -> addDue()
getString(R.string.when_overdue) -> addOverdue()
getString(R.string.randomly) -> addRandomReminder(TimeUnit.DAYS.toMillis(14))
@ -147,9 +151,9 @@ class ReminderControlSet : TaskEditControlFragment() {
}
private fun addAlarmRow(timestamp: Long) {
addAlarmRow(
DateUtilities.getLongDateStringWithTime(timestamp, locale.locale),
View.OnClickListener { viewModel.selectedAlarms?.remove(timestamp) })
addAlarmRow(DateUtilities.getLongDateStringWithTime(timestamp, locale.locale)) {
viewModel.selectedAlarms?.remove(timestamp)
}
}
private fun addNewAlarm() {
@ -180,6 +184,9 @@ class ReminderControlSet : TaskEditControlFragment() {
private val options: List<String>
get() {
val options: MutableList<String> = ArrayList()
if (viewModel.whenStart != true) {
options.add(getString(R.string.when_started))
}
if (viewModel.whenDue != true) {
options.add(getString(R.string.when_due))
}
@ -193,25 +200,32 @@ class ReminderControlSet : TaskEditControlFragment() {
return options
}
private fun addStart() {
viewModel.whenStart = true
addAlarmRow(getString(R.string.when_started)) {
viewModel.whenStart = false
}
}
private fun addDue() {
viewModel.whenDue = true
addAlarmRow(getString(R.string.when_due), View.OnClickListener {
addAlarmRow(getString(R.string.when_due)) {
viewModel.whenDue = false
})
}
}
private fun addOverdue() {
viewModel.whenOverdue = true
addAlarmRow(getString(R.string.when_overdue), View.OnClickListener {
addAlarmRow(getString(R.string.when_overdue)) {
viewModel.whenOverdue = false
})
}
}
private fun addRandomReminder(reminderPeriod: Long) {
val alarmRow = addAlarmRow(getString(R.string.randomly_once) + " ", View.OnClickListener {
val alarmRow = addAlarmRow(getString(R.string.randomly_once) + " ") {
viewModel.reminderPeriod = 0
randomControlSet = null
})
}
randomControlSet = RandomReminderControlSet(activity, alarmRow, reminderPeriod, viewModel)
}

@ -236,6 +236,9 @@ class TaskEditViewModel @Inject constructor(
var selectedAlarms: HashSet<Long>? = null
var whenStart: Boolean? = null
get() = field ?: (task?.reminderFlags?.and(Task.NOTIFY_AT_START) ?: 0 > 0)
var whenDue: Boolean? = null
get() = field ?: (task?.reminderFlags?.and(Task.NOTIFY_AT_DEADLINE) ?: 0 > 0)
@ -416,6 +419,9 @@ class TaskEditViewModel @Inject constructor(
private fun getReminderFlags(): Int {
var value = 0
if (whenStart == true) {
value = value or Task.NOTIFY_AT_START
}
if (whenDue == true) {
value = value or Task.NOTIFY_AT_DEADLINE
}

@ -340,6 +340,7 @@ File %1$s contained %2$s.\n\n
<string name="pick_a_date_and_time">Pick a date and time</string>
<string name="when_overdue">When overdue</string>
<string name="when_due">When due</string>
<string name="when_started">When started</string>
<string name="geofence_radius">Radius</string>
<string name="location_radius_meters">%s m</string>
<string name="tags">Tags</string>

Loading…
Cancel
Save