From 20353023d8ba2bec162e908015d6eb617a6d2513 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Tue, 28 Jul 2020 09:25:25 -0500 Subject: [PATCH] Convert ReminderService to Kotlin --- .../astrid/reminders/ReminderService.java | 198 ------------------ .../astrid/reminders/ReminderService.kt | 178 ++++++++++++++++ 2 files changed, 178 insertions(+), 198 deletions(-) delete mode 100644 app/src/main/java/com/todoroo/astrid/reminders/ReminderService.java create mode 100644 app/src/main/java/com/todoroo/astrid/reminders/ReminderService.kt diff --git a/app/src/main/java/com/todoroo/astrid/reminders/ReminderService.java b/app/src/main/java/com/todoroo/astrid/reminders/ReminderService.java deleted file mode 100644 index 13b1d0841..000000000 --- a/app/src/main/java/com/todoroo/astrid/reminders/ReminderService.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2012 Todoroo Inc - * - * See the file "LICENSE" for the full license governing this code. - */ - -package com.todoroo.astrid.reminders; - -import static com.google.common.collect.Lists.transform; - -import androidx.annotation.Nullable; -import com.todoroo.andlib.utility.DateUtilities; -import com.todoroo.astrid.dao.TaskDaoBlocking; -import com.todoroo.astrid.data.Task; -import java.util.List; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.tasks.jobs.NotificationQueue; -import org.tasks.jobs.ReminderEntry; -import org.tasks.preferences.Preferences; -import org.tasks.reminders.Random; -import org.tasks.time.DateTime; - -@Singleton -public final class ReminderService { - - public static final int TYPE_DUE = 0; - public static final int TYPE_OVERDUE = 1; - public static final int TYPE_RANDOM = 2; - public static final int TYPE_SNOOZE = 3; - public static final int TYPE_ALARM = 4; - public static final int TYPE_GEOFENCE_ENTER = 5; - public static final int TYPE_GEOFENCE_EXIT = 6; - - private static final long NO_ALARM = Long.MAX_VALUE; - - private final NotificationQueue jobs; - private final Random random; - private final TaskDaoBlocking taskDao; - private final Preferences preferences; - - @Inject - ReminderService(Preferences preferences, NotificationQueue notificationQueue, TaskDaoBlocking taskDao) { - this(preferences, notificationQueue, new Random(), taskDao); - } - - ReminderService(Preferences preferences, NotificationQueue jobs, Random random, TaskDaoBlocking taskDao) { - this.preferences = preferences; - this.jobs = jobs; - this.random = random; - this.taskDao = taskDao; - } - - public void scheduleAllAlarms(List taskIds) { - jobs.add(transform(taskDao.fetch(taskIds), this::getReminderEntry)); - } - - public void scheduleAllAlarms() { - jobs.add(transform(taskDao.getTasksWithReminders(), this::getReminderEntry)); - } - - public void scheduleAlarm(Task task) { - ReminderEntry reminder = getReminderEntry(task); - if (reminder != null) { - jobs.add(reminder); - } - } - - public void cancelReminder(long taskId) { - jobs.cancelReminder(taskId); - } - - private @Nullable ReminderEntry getReminderEntry(Task task) { - if (task == null || !task.isSaved()) { - return null; - } - - long taskId = task.getId(); - - // Make sure no alarms are scheduled other than the next one. When that one is shown, it - // will schedule the next one after it, and so on and so forth. - cancelReminder(taskId); - - if (task.isCompleted() || task.isDeleted()) { - return null; - } - - // snooze reminder - long whenSnooze = calculateNextSnoozeReminder(task); - - // random reminders - long whenRandom = calculateNextRandomReminder(task); - - // notifications at due date - long whenDueDate = calculateNextDueDateReminder(task); - - // notifications after due date - long whenOverdue = calculateNextOverdueReminder(task); - - // snooze trumps all - if (whenSnooze != NO_ALARM) { - return new ReminderEntry(taskId, whenSnooze, TYPE_SNOOZE); - } else if (whenRandom < whenDueDate && whenRandom < whenOverdue) { - return new ReminderEntry(taskId, whenRandom, TYPE_RANDOM); - } else if (whenDueDate < whenOverdue) { - return new ReminderEntry(taskId, whenDueDate, TYPE_DUE); - } else if (whenOverdue != NO_ALARM) { - return new ReminderEntry(taskId, whenOverdue, TYPE_OVERDUE); - } - - return null; - } - - private long calculateNextSnoozeReminder(Task task) { - if (task.getReminderSnooze() > task.getReminderLast()) { - return task.getReminderSnooze(); - } - return NO_ALARM; - } - - private long calculateNextOverdueReminder(Task task) { - // Uses getNowValue() instead of DateUtilities.now() - if (task.hasDueDate() && task.isNotifyAfterDeadline()) { - DateTime overdueDate = new DateTime(task.getDueDate()).plusDays(1); - if (!task.hasDueTime()) { - overdueDate = overdueDate.withMillisOfDay(preferences.getDefaultDueTime()); - } - - DateTime lastReminder = new DateTime(task.getReminderLast()); - - if (overdueDate.isAfter(lastReminder)) { - return overdueDate.getMillis(); - } - - overdueDate = lastReminder.withMillisOfDay(overdueDate.getMillisOfDay()); - - return overdueDate.isAfter(lastReminder) - ? overdueDate.getMillis() - : overdueDate.plusDays(1).getMillis(); - } - return NO_ALARM; - } - - /** - * Calculate the next alarm time for due date reminders. - * - *

This alarm always returns the due date, and is triggered if the last reminder time occurred - * before the due date. This means it is possible to return due dates in the past. - * - *

If the date was indicated to not have a due time, we read from preferences and assign a - * time. - */ - private long calculateNextDueDateReminder(Task task) { - if (task.hasDueDate() && task.isNotifyAtDeadline()) { - long dueDate = task.getDueDate(); - long lastReminder = task.getReminderLast(); - - long dueDateAlarm; - - if (task.hasDueTime()) { - dueDateAlarm = dueDate; - } else { - dueDateAlarm = - new DateTime(dueDate).withMillisOfDay(preferences.getDefaultDueTime()).getMillis(); - } - - return lastReminder < dueDateAlarm ? dueDateAlarm : NO_ALARM; - } - return NO_ALARM; - } - - /** - * Calculate the next alarm time for random reminders. - * - *

We take the last reminder time and add approximately the reminder period. If it's still in - * the past, we set it to some time in the near future. - */ - private long calculateNextRandomReminder(Task task) { - long reminderPeriod = task.getReminderPeriod(); - if ((reminderPeriod) > 0) { - long when = task.getReminderLast(); - - if (when == 0) { - when = task.getCreationDate(); - } - - when += (long) (reminderPeriod * (0.85f + 0.3f * random.nextFloat())); - - if (when < DateUtilities.now()) { - when = - DateUtilities.now() + (long) ((0.5f + 6 * random.nextFloat()) * DateUtilities.ONE_HOUR); - } - - return when; - } - return NO_ALARM; - } -} diff --git a/app/src/main/java/com/todoroo/astrid/reminders/ReminderService.kt b/app/src/main/java/com/todoroo/astrid/reminders/ReminderService.kt new file mode 100644 index 000000000..7440b7ccb --- /dev/null +++ b/app/src/main/java/com/todoroo/astrid/reminders/ReminderService.kt @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2012 Todoroo Inc + * + * See the file "LICENSE" for the full license governing this code. + */ +package com.todoroo.astrid.reminders + +import com.todoroo.andlib.utility.DateUtilities +import com.todoroo.astrid.dao.TaskDao +import com.todoroo.astrid.data.Task +import org.tasks.jobs.NotificationQueue +import org.tasks.jobs.ReminderEntry +import org.tasks.preferences.Preferences +import org.tasks.reminders.Random +import org.tasks.time.DateTime +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ReminderService internal constructor( + private val preferences: Preferences, + private val jobs: NotificationQueue, + private val random: Random, + private val taskDao: TaskDao) { + + @Inject + internal constructor( + preferences: Preferences, + notificationQueue: NotificationQueue, + taskDao: TaskDao + ) : this(preferences, notificationQueue, Random(), taskDao) + + suspend fun scheduleAllAlarms(taskIds: List) { + taskDao + .fetch(taskIds) + .map { getReminderEntry(it) } + .let { jobs.add(it) } + } + + suspend fun scheduleAllAlarms() { + taskDao + .getTasksWithReminders() + .map { getReminderEntry(it) } + .let { jobs.add(it) } + } + + fun scheduleAlarm(task: Task?) { + val reminder = getReminderEntry(task) + if (reminder != null) { + jobs.add(reminder) + } + } + + fun cancelReminder(taskId: Long) { + jobs.cancelReminder(taskId) + } + + private fun getReminderEntry(task: Task?): ReminderEntry? { + if (task == null || !task.isSaved) { + return null + } + val taskId = task.id + + // Make sure no alarms are scheduled other than the next one. When that one is shown, it + // will schedule the next one after it, and so on and so forth. + cancelReminder(taskId) + if (task.isCompleted || task.isDeleted) { + return null + } + + // snooze reminder + val whenSnooze = calculateNextSnoozeReminder(task) + + // random reminders + val whenRandom = calculateNextRandomReminder(task) + + // notifications at due date + val whenDueDate = calculateNextDueDateReminder(task) + + // notifications after due date + val whenOverdue = calculateNextOverdueReminder(task) + + // snooze trumps all + if (whenSnooze != NO_ALARM) { + return ReminderEntry(taskId, whenSnooze, TYPE_SNOOZE) + } else if (whenRandom < whenDueDate && whenRandom < whenOverdue) { + return ReminderEntry(taskId, whenRandom, TYPE_RANDOM) + } else if (whenDueDate < whenOverdue) { + return ReminderEntry(taskId, whenDueDate, TYPE_DUE) + } else if (whenOverdue != NO_ALARM) { + return ReminderEntry(taskId, whenOverdue, TYPE_OVERDUE) + } + return null + } + + private fun calculateNextSnoozeReminder(task: Task): Long { + return if (task.reminderSnooze > task.reminderLast) { + task.reminderSnooze + } else NO_ALARM + } + + private fun calculateNextOverdueReminder(task: Task): Long { + // Uses getNowValue() instead of DateUtilities.now() + if (task.hasDueDate() && task.isNotifyAfterDeadline) { + var overdueDate = DateTime(task.dueDate).plusDays(1) + if (!task.hasDueTime()) { + overdueDate = overdueDate.withMillisOfDay(preferences.defaultDueTime) + } + val lastReminder = DateTime(task.reminderLast) + if (overdueDate.isAfter(lastReminder)) { + return overdueDate.millis + } + overdueDate = lastReminder.withMillisOfDay(overdueDate.millisOfDay) + return if (overdueDate.isAfter(lastReminder)) overdueDate.millis else overdueDate.plusDays(1).millis + } + return NO_ALARM + } + + /** + * Calculate the next alarm time for due date reminders. + * + * + * This alarm always returns the due date, and is triggered if the last reminder time occurred + * before the due date. This means it is possible to return due dates in the past. + * + * + * If the date was indicated to not have a due time, we read from preferences and assign a + * time. + */ + 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()) { + dueDate + } else { + DateTime(dueDate).withMillisOfDay(preferences.defaultDueTime).millis + } + return if (lastReminder < dueDateAlarm) dueDateAlarm else NO_ALARM + } + return NO_ALARM + } + + /** + * Calculate the next alarm time for random reminders. + * + * + * We take the last reminder time and add approximately the reminder period. If it's still in + * the past, we set it to some time in the near future. + */ + private fun calculateNextRandomReminder(task: Task): Long { + val reminderPeriod = task.reminderPeriod + if (reminderPeriod > 0) { + var `when` = task.reminderLast + if (`when` == 0L) { + `when` = task.creationDate + } + `when` += (reminderPeriod * (0.85f + 0.3f * random.nextFloat())).toLong() + if (`when` < DateUtilities.now()) { + `when` = DateUtilities.now() + ((0.5f + 6 * random.nextFloat()) * DateUtilities.ONE_HOUR).toLong() + } + return `when` + } + return NO_ALARM + } + + companion object { + const val TYPE_DUE = 0 + const val TYPE_OVERDUE = 1 + const val TYPE_RANDOM = 2 + const val TYPE_SNOOZE = 3 + const val TYPE_ALARM = 4 + const val TYPE_GEOFENCE_ENTER = 5 + const val TYPE_GEOFENCE_EXIT = 6 + private const val NO_ALARM = Long.MAX_VALUE + } +} \ No newline at end of file