diff --git a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.kt b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.kt index de8e3d3cd..a490d2e05 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.kt +++ b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.kt @@ -48,7 +48,10 @@ class TaskDao @Inject constructor( taskDao.getRecurringTasks(remoteIds) suspend fun setCompletionDate(remoteId: String, completionDate: Long) = - taskDao.setCompletionDate(remoteId, completionDate) + setCompletionDate(listOf(remoteId), completionDate) + + suspend fun setCompletionDate(remoteIds: List, completionDate: Long) = + taskDao.setCompletionDate(remoteIds, completionDate) suspend fun snooze(taskIds: List, snoozeTime: Long, updateTime: Long = now()) { taskDao.snooze(taskIds, snoozeTime, updateTime) @@ -93,44 +96,55 @@ class TaskDao @Inject constructor( * Saves the given task to the database.getDatabase(). Task must already exist. Returns true on * success. */ - suspend fun save(task: Task) = save(task, fetch(task.id)) + suspend fun saved(original: Task, suppressRefresh: Boolean) = + fetch(original.id)?.let { + afterUpdate( + it.apply { if (suppressRefresh) suppressRefresh() }, + original + ) + } + suspend fun save(task: Task, original: Task?) { if (taskDao.update(task, original)) { - val completionDateModified = task.completionDate != original?.completionDate ?: 0 - val deletionDateModified = task.deletionDate != original?.deletionDate ?: 0 - val justCompleted = completionDateModified && task.isCompleted - val justDeleted = deletionDateModified && task.isDeleted - if (justCompleted && task.isRecurring) { - workManager.scheduleRepeat(task) - } else if (!task.calendarURI.isNullOrBlank()) { - workManager.updateCalendar(task) - } - coroutineScope { - launch(Dispatchers.Default) { - if (justCompleted || justDeleted) { - notificationManager.cancel(task.id) - if (task.timerStart > 0) { - timerPlugin.stopTimer(task) - } - } - if (task.reminderSnooze.isAfterNow()) { - notificationManager.cancel(task.id) - } - if (task.dueDate != original?.dueDate && task.dueDate.isAfterNow()) { - notificationManager.cancel(task.id) - } - if (completionDateModified || deletionDateModified) { - geofenceApi.update(task.id) - } - reminderService.scheduleAlarm(task) - refreshScheduler.scheduleRefresh(task) - if (!task.checkTransitory(Task.TRANS_SUPPRESS_REFRESH)) { - localBroadcastManager.broadcastRefresh() + afterUpdate(task, original) + } + } + + private suspend fun afterUpdate(task: Task, original: Task?) { + val completionDateModified = task.completionDate != original?.completionDate ?: 0 + val deletionDateModified = task.deletionDate != original?.deletionDate ?: 0 + val justCompleted = completionDateModified && task.isCompleted + val justDeleted = deletionDateModified && task.isDeleted + if (justCompleted && task.isRecurring) { + workManager.scheduleRepeat(task) + } else if (!task.calendarURI.isNullOrBlank()) { + workManager.updateCalendar(task) + } + coroutineScope { + launch(Dispatchers.Default) { + if (justCompleted || justDeleted) { + notificationManager.cancel(task.id) + if (task.timerStart > 0) { + timerPlugin.stopTimer(task) } - syncAdapters.sync(task, original) } + if (task.reminderSnooze.isAfterNow()) { + notificationManager.cancel(task.id) + } + if (task.dueDate != original?.dueDate && task.dueDate.isAfterNow()) { + notificationManager.cancel(task.id) + } + if (completionDateModified || deletionDateModified) { + geofenceApi.update(task.id) + } + reminderService.scheduleAlarm(task) + refreshScheduler.scheduleRefresh(task) + if (!task.checkTransitory(Task.TRANS_SUPPRESS_REFRESH)) { + localBroadcastManager.broadcastRefresh() + } + syncAdapters.sync(task, original) } } } diff --git a/app/src/main/java/com/todoroo/astrid/repeats/RepeatTaskHelper.kt b/app/src/main/java/com/todoroo/astrid/repeats/RepeatTaskHelper.kt index bc47b08e4..a7a9decd6 100644 --- a/app/src/main/java/com/todoroo/astrid/repeats/RepeatTaskHelper.kt +++ b/app/src/main/java/com/todoroo/astrid/repeats/RepeatTaskHelper.kt @@ -73,7 +73,7 @@ class RepeatTaskHelper @Inject constructor( .takeIf { it > 0 } ?: newDueDate - (computeNextDueDate(task, recurrence, repeatAfterCompletion) - newDueDate) alarmService.rescheduleAlarms(task.id, previousDueDate, newDueDate) - taskCompleter.completeChildren(task.id, 0L) + taskCompleter.setComplete(task, false) localBroadcastManager.broadcastRepeat(task.id, previousDueDate, newDueDate) } diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskCompleter.kt b/app/src/main/java/com/todoroo/astrid/service/TaskCompleter.kt index 1a9c9bc7a..b6230853e 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskCompleter.kt +++ b/app/src/main/java/com/todoroo/astrid/service/TaskCompleter.kt @@ -28,32 +28,25 @@ class TaskCompleter @Inject internal constructor( suspend fun setComplete(item: Task, completed: Boolean) { val completionDate = if (completed) DateUtilities.now() else 0L - completeChildren(item.id, completionDate) - setComplete(listOf(item), completionDate) - } - - suspend fun completeChildren(id: Long, completionDate: Long) { googleTaskDao - .getChildTasks(id) - .plus(taskDao.getChildren(id) - .takeIf { it.isNotEmpty() } - ?.let { taskDao.fetch(it) } - ?: emptyList() - ) - .filter { it.isCompleted != completionDate > 0 } - .let { setComplete(it, completionDate)} + .getChildTasks(item.id) + .plus(taskDao.getChildren(item.id) + .takeIf { it.isNotEmpty() } + ?.let { taskDao.fetch(it) } + ?: emptyList() + ) + .plus(listOf(item)) + .filter { it.isCompleted != completionDate > 0 } + .let { setComplete(it, completionDate) } } private suspend fun setComplete(tasks: List, completionDate: Long) { + taskDao.setCompletionDate(tasks.mapNotNull { it.remoteId }, completionDate) tasks.forEachIndexed { i, task -> - task.completionDate = completionDate - if (i < tasks.size - 1) { - task.suppressRefresh() - } - taskDao.save(task) + taskDao.saved(task, i < tasks.size - 1) } if ( - tasks.size == 1 && + tasks.isNotEmpty() && completionDate > 0 && notificationManager.currentInterruptionFilter == INTERRUPTION_FILTER_ALL ) { diff --git a/app/src/main/java/org/tasks/data/TaskDao.kt b/app/src/main/java/org/tasks/data/TaskDao.kt index 58cf8b344..317eee8f5 100644 --- a/app/src/main/java/org/tasks/data/TaskDao.kt +++ b/app/src/main/java/org/tasks/data/TaskDao.kt @@ -1,7 +1,12 @@ package org.tasks.data import androidx.paging.DataSource -import androidx.room.* +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.RawQuery +import androidx.room.Update +import androidx.room.withTransaction import androidx.sqlite.db.SimpleSQLiteQuery import com.todoroo.andlib.sql.Criterion import com.todoroo.andlib.sql.Field @@ -50,8 +55,8 @@ abstract class TaskDao(private val database: Database) { + "AND recurrence IS NOT NULL AND LENGTH(recurrence) > 0") abstract suspend fun getRecurringTasks(remoteIds: List): List - @Query("UPDATE tasks SET completed = :completionDate " + "WHERE remoteId = :remoteId") - abstract suspend fun setCompletionDate(remoteId: String, completionDate: Long) + @Query("UPDATE tasks SET completed = :completionDate, modified = :updateTime WHERE remoteId IN (:remoteIds)") + abstract suspend fun setCompletionDate(remoteIds: List, completionDate: Long, updateTime: Long = now()) @Query("UPDATE tasks SET snoozeTime = :snoozeTime, modified = :updateTime WHERE _id in (:taskIds)") internal abstract suspend fun snooze(taskIds: List, snoozeTime: Long, updateTime: Long = now())