Convert ReminderService to Kotlin

pull/1055/head
Alex Baker 5 years ago
parent 9cd9f1ada2
commit 20353023d8

@ -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<Long> 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.
*
* <p>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.
*
* <p>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.
*
* <p>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;
}
}

@ -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<Long>) {
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
}
}
Loading…
Cancel
Save