You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tasks/app/src/main/java/com/todoroo/astrid/alarms/AlarmService.kt

101 lines
3.5 KiB
Kotlin

/*
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.alarms
import org.tasks.LocalBroadcastManager
import org.tasks.data.dao.AlarmDao
import org.tasks.data.dao.TaskDao
import org.tasks.data.entity.Alarm
import org.tasks.data.entity.Alarm.Companion.TYPE_SNOOZE
import org.tasks.jobs.AlarmEntry
import org.tasks.jobs.WorkManager
import org.tasks.notifications.NotificationManager
import org.tasks.time.DateTime
import org.tasks.time.DateTimeUtils2.currentTimeMillis
import timber.log.Timber
import javax.inject.Inject
/**
* Provides operations for working with alerts
*
* @author Tim Su <tim></tim>@todoroo.com>
*/
class AlarmService @Inject constructor(
private val alarmDao: AlarmDao,
private val taskDao: TaskDao,
private val localBroadcastManager: LocalBroadcastManager,
private val notificationManager: NotificationManager,
private val workManager: WorkManager,
private val alarmCalculator: AlarmCalculator,
) {
suspend fun getAlarms(taskId: Long): List<Alarm> = alarmDao.getAlarms(taskId)
/**
* Save the given array of alarms into the database
*
* @return true if data was changed
*/
suspend fun synchronizeAlarms(taskId: Long, alarms: MutableSet<Alarm>): Boolean {
var changed = false
for (existing in alarmDao.getAlarms(taskId)) {
if (!alarms.removeIf {
it.type == existing.type &&
it.time == existing.time &&
it.repeat == existing.repeat &&
it.interval == existing.interval
}) {
alarmDao.delete(existing)
changed = true
}
}
for (alarm in alarms) {
alarm.task = taskId
alarmDao.insert(alarm)
changed = true
}
if (changed) {
localBroadcastManager.broadcastRefreshList()
}
return changed
}
suspend fun snooze(time: Long, taskIds: List<Long>) {
notificationManager.cancel(taskIds)
alarmDao.getSnoozed(taskIds).let { alarmDao.delete(it) }
taskIds.map { Alarm(it, time, TYPE_SNOOZE) }.let { alarmDao.insert(it) }
taskDao.touch(taskIds)
workManager.triggerNotifications()
}
suspend fun getAlarms(): Pair<List<AlarmEntry>, List<AlarmEntry>> {
val start = currentTimeMillis()
val overdue = ArrayList<AlarmEntry>()
val future = ArrayList<AlarmEntry>()
alarmDao.getActiveAlarms()
.groupBy { it.task }
.forEach { (taskId, alarms) ->
val task = taskDao.fetch(taskId) ?: return@forEach
val alarmEntries = alarms.mapNotNull {
alarmCalculator.toAlarmEntry(task, it)
}
val (now, later) = alarmEntries.partition { it.time <= DateTime().startOfMinute().plusMinutes(1).millis }
later
.find { it.type == TYPE_SNOOZE }
?.let { future.add(it) }
?: run {
now.firstOrNull()?.let { overdue.add(it) }
later.minByOrNull { it.time }?.let { future.add(it) }
}
}
Timber.d("took ${currentTimeMillis() - start}ms overdue=${overdue.size} future=${future.size}")
return overdue to future
}
companion object {
internal const val NO_ALARM = 0L
}
}