diff --git a/app/schemas/com.todoroo.astrid.dao.Database/88.json b/app/schemas/com.todoroo.astrid.dao.Database/88.json index 52581d3c8..3ed3ff7a0 100644 --- a/app/schemas/com.todoroo.astrid.dao.Database/88.json +++ b/app/schemas/com.todoroo.astrid.dao.Database/88.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 88, - "identityHash": "2b5bd6d7c523006b902d035f71093be2", + "identityHash": "a2597380bdfaeeb040d40bab2fc653c1", "entities": [ { "tableName": "notification", @@ -875,7 +875,7 @@ }, { "tableName": "caldav_tasks", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cd_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cd_task` INTEGER NOT NULL, `cd_calendar` TEXT, `cd_object` TEXT, `cd_remote_id` TEXT, `cd_etag` TEXT, `cd_last_sync` INTEGER NOT NULL, `cd_deleted` INTEGER NOT NULL, `cd_remote_parent` TEXT, `gt_moved` INTEGER NOT NULL, `gt_remote_order` INTEGER NOT NULL, `gt_parent` INTEGER NOT NULL, `cd_order` INTEGER, FOREIGN KEY(`cd_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cd_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cd_task` INTEGER NOT NULL, `cd_calendar` TEXT, `cd_object` TEXT, `cd_remote_id` TEXT, `cd_etag` TEXT, `cd_last_sync` INTEGER NOT NULL, `cd_deleted` INTEGER NOT NULL, `cd_remote_parent` TEXT, `gt_moved` INTEGER NOT NULL, `gt_remote_order` INTEGER NOT NULL, FOREIGN KEY(`cd_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -942,18 +942,6 @@ "columnName": "gt_remote_order", "affinity": "INTEGER", "notNull": true - }, - { - "fieldPath": "parent", - "columnName": "gt_parent", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "order", - "columnName": "cd_order", - "affinity": "INTEGER", - "notNull": false } ], "primaryKey": { @@ -1309,7 +1297,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2b5bd6d7c523006b902d035f71093be2')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a2597380bdfaeeb040d40bab2fc653c1')" ] } } \ No newline at end of file diff --git a/app/src/androidTest/java/org/tasks/data/GoogleTaskDaoTests.kt b/app/src/androidTest/java/org/tasks/data/GoogleTaskDaoTests.kt index 08a7dda84..ea743329a 100644 --- a/app/src/androidTest/java/org/tasks/data/GoogleTaskDaoTests.kt +++ b/app/src/androidTest/java/org/tasks/data/GoogleTaskDaoTests.kt @@ -151,13 +151,6 @@ class GoogleTaskDaoTests : InjectingTestCase() { assertEquals(2, googleTaskDao.getByRemoteId("1")!!.order) } - @Test - fun findChildrenInList() = runBlocking { - insert(newGoogleTask(with(TASK, 1), with(LIST, "1"))) - insert(newGoogleTask(with(TASK, 2), with(LIST, "1"), with(PARENT, 1L))) - assertEquals(listOf(2L), googleTaskDao.getChildren(listOf(1L, 2L))) - } - @Test fun dontAllowEmptyParent() = runBlocking { insert(newGoogleTask(with(TASK, 1), with(LIST, "1"), with(REMOTE_ID, "1234"))) diff --git a/app/src/main/java/com/todoroo/astrid/adapter/GoogleTaskManualSortAdapter.kt b/app/src/main/java/com/todoroo/astrid/adapter/GoogleTaskManualSortAdapter.kt index cc931357d..4df89c343 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/GoogleTaskManualSortAdapter.kt +++ b/app/src/main/java/com/todoroo/astrid/adapter/GoogleTaskManualSortAdapter.kt @@ -17,21 +17,75 @@ class GoogleTaskManualSortAdapter internal constructor( val task = getTask(from) val googleTask = task.caldavTask val previous = if (to > 0) getTask(to - 1) else null + val list = googleTask.calendar!! if (previous == null) { - googleTaskDao.move(googleTask, 0, 0) + googleTaskDao.move( + task = task.task, + list = list, + newParent = 0, + newPosition = 0, + ) } else if (to == count || to <= from) { when { - indent == 0 -> googleTaskDao.move(googleTask, 0, previous.getPrimarySort() + if (to == count) 0 else 1) - previous.hasParent() && previous.parent == task.parent -> googleTaskDao.move(googleTask, previous.parent, previous.getSecondarySort() + if (to == count) 0 else 1) - previous.hasParent() -> googleTaskDao.move(googleTask, previous.parent, previous.getSecondarySort() + 1) - else -> googleTaskDao.move(googleTask, previous.id, 0) + indent == 0 -> + googleTaskDao.move( + task = task.task, + list = list, + newParent = 0, + newPosition = previous.getPrimarySort() + if (to == count) 0 else 1, + ) + previous.hasParent() && previous.parent == task.parent -> + googleTaskDao.move( + task = task.task, + list = list, + newParent = previous.parent, + newPosition = previous.getSecondarySort() + if (to == count) 0 else 1, + ) + previous.hasParent() -> + googleTaskDao.move( + task = task.task, + list = list, + newParent = previous.parent, + newPosition = previous.getSecondarySort() + 1, + ) + else -> + googleTaskDao.move( + task = task.task, + list = list, + newParent = previous.id, + newPosition = 0, + ) } } else { when { - indent == 0 -> googleTaskDao.move(googleTask, 0, previous.getPrimarySort() + if (task.hasParent()) 1 else 0) - previous.hasParent() && previous.parent == task.parent -> googleTaskDao.move(googleTask, previous.parent, previous.getSecondarySort()) - previous.hasParent() -> googleTaskDao.move(googleTask, previous.parent, previous.getSecondarySort() + 1) - else -> googleTaskDao.move(googleTask, previous.id, 0) + indent == 0 -> + googleTaskDao.move( + task = task.task, + list = list, + newParent = 0, + newPosition = previous.getPrimarySort() + if (task.hasParent()) 1 else 0, + ) + previous.hasParent() && previous.parent == task.parent -> + googleTaskDao.move( + task = task.task, + list = list, + newParent = previous.parent, + newPosition = previous.getSecondarySort(), + ) + previous.hasParent() -> + googleTaskDao.move( + task = task.task, + list = list, + newParent = previous.parent, + newPosition = previous.getSecondarySort() + 1, + ) + else -> + googleTaskDao.move( + task = task.task, + list = list, + newParent = previous.id, + newPosition = 0, + ) } } taskDao.touch(task.id) diff --git a/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.kt b/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.kt index 5427e807e..b1f48716e 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.kt +++ b/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.kt @@ -11,7 +11,10 @@ import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task.Companion.HIDE_UNTIL_SPECIFIC_DAY import org.tasks.BuildConfig import org.tasks.LocalBroadcastManager -import org.tasks.data.* +import org.tasks.data.CaldavDao +import org.tasks.data.CaldavTask +import org.tasks.data.GoogleTaskDao +import org.tasks.data.TaskContainer import org.tasks.date.DateTimeUtils.toAppleEpoch import org.tasks.date.DateTimeUtils.toDateTime import org.tasks.tasklist.SectionedDataSource.Companion.HEADER_COMPLETED @@ -241,15 +244,15 @@ open class TaskAdapter( val list = newParent?.caldav ?: task.caldav!! if (newParent == null || task.caldav == newParent.caldav) { googleTaskDao.move( - task.caldavTask, + task.task, + list, newParent?.id ?: 0, if (newTasksOnTop) 0 else googleTaskDao.getBottom(list, newParent?.id ?: 0) ) } else { - task.caldavTask = CaldavTask(task.id, list).apply { - parent = newParent.id - } - googleTaskDao.insertAndShift(task.caldavTask, newTasksOnTop) + task.parent = newParent.id + task.caldavTask = CaldavTask(task.id, list) + googleTaskDao.insertAndShift(task.task, task.caldavTask, newTasksOnTop) } taskDao.touch(task.id) if (BuildConfig.DEBUG) { diff --git a/app/src/main/java/com/todoroo/astrid/api/GtasksFilter.java b/app/src/main/java/com/todoroo/astrid/api/GtasksFilter.java index dd8073b25..fb7c1d143 100644 --- a/app/src/main/java/com/todoroo/astrid/api/GtasksFilter.java +++ b/app/src/main/java/com/todoroo/astrid/api/GtasksFilter.java @@ -72,8 +72,8 @@ public class GtasksFilter extends Filter { return values; } - public long getStoreId() { - return list.getId(); + public String getListId() { + return list.getUuid(); } public String getAccount() { diff --git a/app/src/main/java/com/todoroo/astrid/core/SortHelper.java b/app/src/main/java/com/todoroo/astrid/core/SortHelper.java index 6ae6665ee..5017db4fd 100644 --- a/app/src/main/java/com/todoroo/astrid/core/SortHelper.java +++ b/app/src/main/java/com/todoroo/astrid/core/SortHelper.java @@ -176,7 +176,7 @@ public class SortHelper { select = "tasks.created AS sort_created"; break; case SORT_GTASKS: - select = "caldav_tasks.cd_order AS sort_manual"; + select = "tasks.`order` AS sort_manual"; break; case SORT_CALDAV: select = CALDAV_ORDER_COLUMN + " AS sort_manual"; 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 d52fab2a1..db7b62247 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskCompleter.kt +++ b/app/src/main/java/com/todoroo/astrid/service/TaskCompleter.kt @@ -35,11 +35,9 @@ class TaskCompleter @Inject internal constructor( ArrayList() .apply { if (includeChildren) { - addAll(googleTaskDao.getChildTasks(item.id)) addAll(taskDao.getChildren(item.id).let { taskDao.fetch(it) }) } if (!completed) { - add(googleTaskDao.getParentTask(item.id)) addAll(taskDao.getParents(item.id).let { taskDao.fetch(it) }) } add(item) diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskCreator.kt b/app/src/main/java/com/todoroo/astrid/service/TaskCreator.kt index 0410a715c..d39c72994 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskCreator.kt +++ b/app/src/main/java/com/todoroo/astrid/service/TaskCreator.kt @@ -55,7 +55,10 @@ class TaskCreator @Inject constructor( val addToTop = preferences.addTasksToTop() if (task.hasTransitory(GoogleTask.KEY)) { googleTaskDao.insertAndShift( - CaldavTask(task.id, task.getTransitory(GoogleTask.KEY)!!), addToTop) + task, + CaldavTask(task.id, task.getTransitory(GoogleTask.KEY)!!), + addToTop + ) } else if (task.hasTransitory(CaldavTask.KEY)) { caldavDao.insert( task, CaldavTask(task.id, task.getTransitory(CaldavTask.KEY)), addToTop) @@ -63,7 +66,10 @@ class TaskCreator @Inject constructor( val remoteList = defaultFilterProvider.getDefaultList() if (remoteList is GtasksFilter) { googleTaskDao.insertAndShift( - CaldavTask(task.id, remoteList.remoteId), addToTop) + task, + CaldavTask(task.id, remoteList.remoteId), + addToTop + ) } else if (remoteList is CaldavFilter) { caldavDao.insert( task, CaldavTask(task.id, remoteList.uuid), addToTop) diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt b/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt index afbd65734..93ac31014 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt +++ b/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.kt @@ -28,7 +28,6 @@ class TaskDeleter @Inject constructor( suspend fun markDeleted(taskIds: List): List { val ids = taskIds .toSet() - .plus(taskIds.chunkedMap(googleTaskDao::getChildren)) .plus(taskIds.chunkedMap(taskDao::getChildren)) .let { taskDao.fetch(it.toList()) } .filterNot { it.readOnly } @@ -50,7 +49,6 @@ class TaskDeleter @Inject constructor( .map(TaskContainer::getId) .toMutableList() completed.removeAll(deletionDao.hasRecurringAncestors(completed)) - completed.removeAll(googleTaskDao.hasRecurringParent(completed)) markDeleted(completed) return completed.size } diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskDuplicator.kt b/app/src/main/java/com/todoroo/astrid/service/TaskDuplicator.kt index 6b84a2230..a1ac00faf 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskDuplicator.kt +++ b/app/src/main/java/com/todoroo/astrid/service/TaskDuplicator.kt @@ -28,8 +28,7 @@ class TaskDuplicator @Inject constructor( return taskIds .dbchunk() .flatMap { - it.minus(googleTaskDao.getChildren(it).toSet()) - .minus(taskDao.getChildren(it).toSet()) + it.minus(taskDao.getChildren(it).toSet()) } .let { taskDao.fetch(it) } .filterNot { it.readOnly } @@ -58,7 +57,7 @@ class TaskDuplicator @Inject constructor( val googleTask = googleTaskDao.getByTaskId(originalId) val addToTop = preferences.addTasksToTop() if (googleTask != null) { - googleTaskDao.insertAndShift(CaldavTask(clone.id, googleTask.calendar!!), addToTop) + googleTaskDao.insertAndShift(clone, CaldavTask(clone.id, googleTask.calendar!!), addToTop) } val caldavTask = caldavDao.getTask(originalId) if (caldavTask != null) { diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskMover.kt b/app/src/main/java/com/todoroo/astrid/service/TaskMover.kt index fef892e9e..2abb486cd 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskMover.kt +++ b/app/src/main/java/com/todoroo/astrid/service/TaskMover.kt @@ -46,11 +46,8 @@ class TaskMover @Inject constructor( suspend fun move(ids: List, selectedList: Filter) { val tasks = ids .dbchunk() - .flatMap { - it.minus(googleTaskDao.getChildren(it).toSet()) - .minus(taskDao.getChildren(it).toSet()) - } - .let { taskDao.fetch(it) } + .flatMap { taskDao.getChildren(it) } + .let { taskDao.fetch(ids.minus(it.toSet())) } .filterNot { it.readOnly } val taskIds = tasks.map { it.id } taskDao.setParent(0, ids.intersect(taskIds.toSet()).toList()) @@ -86,28 +83,22 @@ class TaskMover @Inject constructor( if (selected is GtasksFilter && googleTask.calendar == selected.remoteId) { return } - val id = googleTask.task - val children = googleTaskDao.getChildren(id) - val childIds = children.map(CaldavTask::task) - googleTaskDao.markDeleted(id, DateUtilities.now()) + val id = task.id + val children = taskDao.getChildren(id) + caldavDao.markDeleted(children + id, DateUtilities.now()) when(selected) { is GtasksFilter -> { val listId = selected.remoteId - googleTaskDao.insertAndShift(CaldavTask(id, listId), preferences.addTasksToTop()) + googleTaskDao.insertAndShift(task, CaldavTask(id, listId), preferences.addTasksToTop()) children.takeIf { it.isNotEmpty() } - ?.map { - val newChild = CaldavTask(it.task, listId) - newChild.order = it.order - newChild.parent = id - newChild - } + ?.map { CaldavTask(it, listId) } ?.let { googleTaskDao.insert(it) } } is CaldavFilter -> { val listId = selected.uuid val newParent = CaldavTask(id, listId) caldavDao.insert(task, newParent, preferences.addTasksToTop()) - childIds.map { + children.map { val newChild = CaldavTask(it, listId) newChild.remoteParent = newParent.remoteId newChild @@ -176,16 +167,16 @@ class TaskMover @Inject constructor( } private suspend fun moveToGoogleTasks(id: Long, children: List, filter: GtasksFilter) { - taskDao.setParent(0, children) + val task = taskDao.fetch(id) ?: return + taskDao.setParent(id, children) val listId = filter.remoteId - googleTaskDao.insertAndShift(CaldavTask(id, listId), preferences.addTasksToTop()) + googleTaskDao.insertAndShift( + task, + CaldavTask(id, listId, remoteId = null, `object` = null), + preferences.addTasksToTop() + ) children.takeIf { it.isNotEmpty() } - ?.mapIndexed { index, task -> - val newChild = CaldavTask(task, listId) - newChild.order = index.toLong() - newChild.parent = id - newChild - } + ?.map { CaldavTask(it, listId, remoteId = null, `object` = null) } ?.let { googleTaskDao.insert(it) } } } \ No newline at end of file diff --git a/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt b/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt index 382a2a16d..b6f2a1643 100644 --- a/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt +++ b/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt @@ -72,7 +72,7 @@ class Upgrader @Inject constructor( taskMover.migrateLocalTasks() } run(from, V9_7) { caldavDao.resetOrders() } - run(from, V9_7_3) { googleTaskDao.updateParents() } + run(from, V9_7_3) { caldavDao.updateParents() } run(from, V10_0_2) { filterDao.getFilters() .filter { it.getSql().trim() == "WHERE" } diff --git a/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt b/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt index 383d15200..56ada8e2f 100644 --- a/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt +++ b/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt @@ -39,7 +39,6 @@ class TasksJsonImporter @Inject constructor( private val localBroadcastManager: LocalBroadcastManager, private val alarmDao: AlarmDao, private val tagDao: TagDao, - private val googleTaskDao: GoogleTaskDao, private val filterDao: FilterDao, private val taskAttachmentDao: TaskAttachmentDao, private val caldavDao: CaldavDao, @@ -187,13 +186,17 @@ class TasksJsonImporter @Inject constructor( userActivityDao.createNew(comment) } for (googleTask in backup.google) { - googleTaskDao.insert( + caldavDao.insert( CaldavTask( task = taskId, calendar = googleTask.listId, remoteId = googleTask.remoteId, `object` = null, - ) + ).apply { + remoteOrder = googleTask.remoteOrder + remoteParent = googleTask.remoteParent + lastSync = googleTask.lastSync + } ) } for (location in backup.locations) { @@ -246,7 +249,6 @@ class TasksJsonImporter @Inject constructor( } result.importCount++ } - googleTaskDao.updateParents() caldavDao.updateParents() val ignoreKeys = ignorePrefs.map { context.getString(it) } backupContainer diff --git a/app/src/main/java/org/tasks/compose/edit/SubtaskRow.kt b/app/src/main/java/org/tasks/compose/edit/SubtaskRow.kt index 96d4265aa..d0b53e711 100644 --- a/app/src/main/java/org/tasks/compose/edit/SubtaskRow.kt +++ b/app/src/main/java/org/tasks/compose/edit/SubtaskRow.kt @@ -35,6 +35,7 @@ import org.tasks.data.TaskContainer fun SubtaskRow( filter: Filter?, googleTask: CaldavTask?, + hasParent: Boolean, desaturate: Boolean, existingSubtasks: List, newSubtasks: List, @@ -63,7 +64,7 @@ fun SubtaskRow( Column { val isGoogleTaskChild = - filter is GtasksFilter && googleTask != null && googleTask.parent > 0 && googleTask.calendar == filter.remoteId + filter is GtasksFilter && hasParent && googleTask?.calendar == filter.remoteId if (isGoogleTaskChild) { DisabledText( text = stringResource(id = org.tasks.R.string.subtasks_multilevel_google_task), @@ -209,6 +210,7 @@ fun NoSubtasks() { SubtaskRow( filter = null, googleTask = null, + hasParent = false, desaturate = true, existingSubtasks = emptyList(), newSubtasks = emptyList(), @@ -230,6 +232,7 @@ fun SubtasksPreview() { SubtaskRow( filter = null, googleTask = null, + hasParent = false, desaturate = true, existingSubtasks = listOf( TaskContainer().apply { diff --git a/app/src/main/java/org/tasks/data/CaldavTask.kt b/app/src/main/java/org/tasks/data/CaldavTask.kt index ec61f87f2..252755b05 100644 --- a/app/src/main/java/org/tasks/data/CaldavTask.kt +++ b/app/src/main/java/org/tasks/data/CaldavTask.kt @@ -54,12 +54,9 @@ class CaldavTask { @ColumnInfo(name = "gt_remote_order") var remoteOrder: Long = 0 - @ColumnInfo(name = "gt_parent") - var parent: Long = 0 - @Transient - @Deprecated("For google tasks and importing old backup files") - @ColumnInfo(name = "cd_order") + @Ignore + @Deprecated("For importing old backup files") var order: Long? = null constructor() @@ -89,7 +86,6 @@ class CaldavTask { const val KEY = "caldav" @JvmField val TABLE = Table("caldav_tasks") val ID = TABLE.column("cd_id") - val PARENT = TABLE.column("gt_parent") @JvmField val TASK = TABLE.column("cd_task") @JvmField val DELETED = TABLE.column("cd_deleted") @JvmField val CALENDAR = TABLE.column("cd_calendar") diff --git a/app/src/main/java/org/tasks/data/GoogleTaskDao.kt b/app/src/main/java/org/tasks/data/GoogleTaskDao.kt index 73df5aa53..fff3a2b26 100644 --- a/app/src/main/java/org/tasks/data/GoogleTaskDao.kt +++ b/app/src/main/java/org/tasks/data/GoogleTaskDao.kt @@ -3,8 +3,7 @@ package org.tasks.data import androidx.room.* import com.todoroo.astrid.data.Task import kotlinx.coroutines.flow.Flow -import org.tasks.db.SuspendDbUtils.chunkedMap -import org.tasks.time.DateTimeUtils.currentTimeMillis +import org.tasks.data.CaldavAccount.Companion.TYPE_GOOGLE_TASKS @Dao abstract class GoogleTaskDao { @@ -15,61 +14,63 @@ abstract class GoogleTaskDao { abstract suspend fun insert(tasks: Iterable) @Transaction - open suspend fun insertAndShift(task: CaldavTask, top: Boolean) { + open suspend fun insertAndShift(task: Task, caldavTask: CaldavTask, top: Boolean) { if (top) { task.order = 0 - shiftDown(task.calendar!!, task.parent, 0) + shiftDown(caldavTask.calendar!!, task.parent, 0) } else { - task.order = getBottom(task.calendar!!, task.parent) + task.order = getBottom(caldavTask.calendar!!, task.parent) } - task.id = insert(task) + caldavTask.id = insert(caldavTask) + update(task) } - @Query("UPDATE caldav_tasks SET cd_order = cd_order + 1 WHERE cd_calendar = :listId AND gt_parent = :parent AND cd_order >= :position") + @Query("UPDATE tasks SET `order` = `order` + 1 WHERE parent = :parent AND `order` >= :position AND _id IN (SELECT cd_task FROM caldav_tasks WHERE cd_calendar = :listId)") internal abstract suspend fun shiftDown(listId: String, parent: Long, position: Long) - @Query("UPDATE caldav_tasks SET cd_order = cd_order - 1 WHERE cd_calendar = :listId AND gt_parent = :parent AND cd_order > :from AND cd_order <= :to") + @Query("UPDATE tasks SET `order` = `order` - 1 WHERE parent = :parent AND `order` > :from AND `order` <= :to AND _id IN (SELECT cd_task FROM caldav_tasks WHERE cd_calendar = :listId)") internal abstract suspend fun shiftUp(listId: String, parent: Long, from: Long, to: Long) - @Query("UPDATE caldav_tasks SET cd_order = cd_order + 1 WHERE cd_calendar = :listId AND gt_parent = :parent AND cd_order < :from AND cd_order >= :to") + @Query("UPDATE tasks SET `order` = `order` + 1 WHERE parent = :parent AND `order` < :from AND `order` >= :to AND _id IN (SELECT cd_task FROM caldav_tasks WHERE cd_calendar = :listId)") internal abstract suspend fun shiftDown(listId: String, parent: Long, from: Long, to: Long) - @Query("UPDATE caldav_tasks SET cd_order = cd_order - 1 WHERE cd_calendar = :listId AND gt_parent = :parent AND cd_order >= :position") + @Query("UPDATE tasks SET `order` = `order` - 1 WHERE parent = :parent AND `order` >= :position AND _id IN (SELECT cd_task FROM caldav_tasks WHERE cd_calendar = :listId)") internal abstract suspend fun shiftUp(listId: String, parent: Long, position: Long) @Transaction - open suspend fun move(task: CaldavTask, newParent: Long, newPosition: Long) { + open suspend fun move(task: Task, list: String, newParent: Long, newPosition: Long) { val previousParent = task.parent val previousPosition = task.order!! if (newParent == previousParent) { if (previousPosition < newPosition) { - shiftUp(task.calendar!!, newParent, previousPosition, newPosition) + shiftUp(list, newParent, previousPosition, newPosition) } else { - shiftDown(task.calendar!!, newParent, previousPosition, newPosition) + shiftDown(list, newParent, previousPosition, newPosition) } } else { - shiftUp(task.calendar!!, previousParent, previousPosition) - shiftDown(task.calendar!!, newParent, newPosition) + shiftUp(list, previousParent, previousPosition) + shiftDown(list, newParent, newPosition) } task.parent = newParent task.order = newPosition update(task) + setMoved(task.id, list) } - @Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId AND cd_deleted = 0 LIMIT 1") + @Query("UPDATE caldav_tasks SET gt_moved = 1 WHERE cd_task = :task and cd_calendar = :list") + internal abstract suspend fun setMoved(task: Long, list: String) + + @Query("SELECT caldav_tasks.* FROM caldav_tasks INNER JOIN caldav_lists ON cdl_uuid = cd_calendar INNER JOIN caldav_accounts ON cda_uuid = cdl_account WHERE cd_task = :taskId AND cd_deleted = 0 AND cda_account_type = $TYPE_GOOGLE_TASKS LIMIT 1") abstract suspend fun getByTaskId(taskId: Long): CaldavTask? - @Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId AND cd_deleted = 0 LIMIT 1") + @Query("SELECT caldav_tasks.* FROM caldav_tasks INNER JOIN caldav_lists ON cdl_uuid = cd_calendar INNER JOIN caldav_accounts ON cda_uuid = cdl_account WHERE cd_task = :taskId AND cd_deleted = 0 AND cda_account_type = $TYPE_GOOGLE_TASKS LIMIT 1") abstract fun watchGoogleTask(taskId: Long): Flow @Update abstract suspend fun update(googleTask: CaldavTask) - @Query("UPDATE caldav_tasks SET cd_order = :order, gt_parent = :parent, gt_moved = 1 WHERE cd_id = :id") - abstract suspend fun update(id: Long, parent: Long, order: Long) - - @Query("UPDATE caldav_tasks SET cd_deleted = :now WHERE cd_task = :task OR gt_parent = :task") - abstract suspend fun markDeleted(task: Long, now: Long = currentTimeMillis()) + @Update + abstract suspend fun update(task: Task) @Delete abstract suspend fun delete(deleted: CaldavTask) @@ -86,48 +87,21 @@ abstract class GoogleTaskDao { @Query("SELECT DISTINCT cd_calendar FROM caldav_tasks WHERE cd_deleted = 0 AND cd_task IN (:tasks)") abstract suspend fun getLists(tasks: List): List - @Query("SELECT cd_task FROM caldav_tasks WHERE gt_parent IN (:ids) AND cd_deleted = 0") - abstract suspend fun getChildren(ids: List): List - - suspend fun hasRecurringParent(ids: List): List = - ids.chunkedMap { internalHasRecurringParent(it) } - - @Query(""" -SELECT cd_task -FROM caldav_tasks - INNER JOIN tasks ON gt_parent = _id -WHERE cd_task IN (:ids) - AND cd_deleted = 0 - AND tasks.recurrence IS NOT NULL - AND tasks.recurrence != '' - AND tasks.completed = 0 - """) - abstract suspend fun internalHasRecurringParent(ids: List): List - - @Query("SELECT tasks.* FROM tasks JOIN caldav_tasks ON tasks._id = cd_task WHERE gt_parent = :taskId") - abstract suspend fun getChildTasks(taskId: Long): List - - @Query("SELECT tasks.* FROM tasks JOIN caldav_tasks ON tasks._id = gt_parent WHERE cd_task = :taskId") - abstract suspend fun getParentTask(taskId: Long): Task? - - @Query("SELECT * FROM caldav_tasks WHERE gt_parent = :id AND cd_deleted = 0") - abstract suspend fun getChildren(id: Long): List - - @Query("SELECT IFNULL(MAX(cd_order), -1) + 1 FROM caldav_tasks WHERE cd_calendar = :listId AND gt_parent = :parent") + @Query("SELECT IFNULL(MAX(`order`), -1) + 1 FROM tasks INNER JOIN caldav_tasks ON cd_task = tasks._id WHERE cd_calendar = :listId AND parent = :parent") abstract suspend fun getBottom(listId: String, parent: Long): Long @Query( """ SELECT cd_remote_id FROM caldav_tasks - JOIN tasks ON tasks._id = cd_task + INNER JOIN tasks ON tasks._id = cd_task WHERE deleted = 0 AND cd_calendar = :listId - AND gt_parent = :parent - AND cd_order < :order + AND parent = :parent + AND `order` < :order AND cd_remote_id IS NOT NULL AND cd_remote_id != '' -ORDER BY cd_order DESC +ORDER BY `order` DESC """ ) abstract suspend fun getPrevious(listId: String, parent: Long, order: Long): String? @@ -138,81 +112,49 @@ ORDER BY cd_order DESC @Query("SELECT cd_task FROM caldav_tasks WHERE cd_remote_id = :remoteId") abstract suspend fun getTask(remoteId: String): Long? - @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) @Query( """ -SELECT caldav_tasks.*, cd_order AS primary_sort, NULL AS secondary_sort -FROM caldav_tasks - JOIN tasks ON tasks._id = cd_task -WHERE gt_parent = 0 +SELECT tasks.*, `order` AS primary_sort, NULL AS secondary_sort +FROM tasks + INNER JOIN caldav_tasks ON tasks._id = cd_task +WHERE parent = 0 AND cd_calendar = :listId AND tasks.deleted = 0 UNION -SELECT c.*, p.cd_order AS primary_sort, c.cd_order AS secondary_sort -FROM caldav_tasks AS c - LEFT JOIN caldav_tasks AS p ON c.gt_parent = p.cd_task - JOIN tasks ON tasks._id = c.cd_task -WHERE c.gt_parent > 0 - AND c.cd_calendar = :listId - AND tasks.deleted = 0 +SELECT c.*, p.`order` AS primary_sort, c.`order` AS secondary_sort +FROM tasks AS c + INNER JOIN tasks AS p ON c.parent = p._id + INNER JOIN caldav_tasks ON c._id = cd_task +WHERE c.parent > 0 + AND cd_calendar = :listId + AND c.deleted = 0 ORDER BY primary_sort ASC, secondary_sort ASC """ ) - abstract suspend fun getByLocalOrder(listId: String): List + internal abstract suspend fun getByLocalOrder(listId: String): List - @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) @Query( """ -SELECT caldav_tasks.*, gt_remote_order AS primary_sort, NULL AS secondary_sort -FROM caldav_tasks - JOIN tasks ON tasks._id = cd_task -WHERE gt_parent = 0 +SELECT tasks.*, gt_remote_order AS primary_sort, NULL AS secondary_sort +FROM tasks + JOIN caldav_tasks ON tasks._id = cd_task +WHERE parent = 0 AND cd_calendar = :listId AND tasks.deleted = 0 UNION -SELECT c.*, p.gt_remote_order AS primary_sort, c.gt_remote_order AS secondary_sort -FROM caldav_tasks AS c - LEFT JOIN caldav_tasks AS p ON c.gt_parent = p.cd_task - JOIN tasks ON tasks._id = c.cd_task -WHERE c.gt_parent > 0 - AND c.cd_calendar = :listId - AND tasks.deleted = 0 +SELECT c.*, parent.gt_remote_order AS primary_sort, child.gt_remote_order AS secondary_sort +FROM tasks AS c + INNER JOIN tasks AS p ON c.parent = p._id + INNER JOIN caldav_tasks AS child ON c._id = child.cd_task + INNER JOIN caldav_tasks AS parent ON p._id = parent.cd_task +WHERE c.parent > 0 + AND child.cd_calendar = :listId + AND c.deleted = 0 ORDER BY primary_sort ASC, secondary_sort ASC """ ) - internal abstract suspend fun getByRemoteOrder(listId: String): List + internal abstract suspend fun getByRemoteOrder(listId: String): List - @Query( - """ -UPDATE caldav_tasks -SET gt_parent = IFNULL((SELECT cd_task - FROM caldav_tasks AS p - WHERE caldav_tasks.cd_remote_parent IS NOT NULL - AND caldav_tasks.cd_remote_parent != '' - AND p.cd_remote_id = caldav_tasks.cd_remote_parent - AND p.cd_calendar = caldav_tasks.cd_calendar - AND p.cd_deleted = 0), 0) -WHERE gt_moved = 0 - """ - ) - abstract suspend fun updateParents() - - @Query( - """ -UPDATE caldav_tasks -SET gt_parent = IFNULL((SELECT cd_task - FROM caldav_tasks AS p - WHERE caldav_tasks.cd_remote_parent IS NOT NULL - AND caldav_tasks.cd_remote_parent != '' - AND p.cd_remote_id = caldav_tasks.cd_remote_parent - AND p.cd_calendar = caldav_tasks.cd_calendar - AND p.cd_deleted = 0), 0) -WHERE cd_calendar = :listId - AND gt_moved = 0 - """ - ) - abstract suspend fun updateParents(listId: String) - @Query(""" UPDATE caldav_tasks SET cd_remote_parent = CASE WHEN :parent == '' THEN NULL ELSE :parent END, @@ -222,21 +164,21 @@ WHERE cd_remote_id = :id abstract suspend fun updatePosition(id: String, parent: String?, position: String) @Transaction - open suspend fun reposition(listId: String) { - updateParents(listId) + open suspend fun reposition(caldavDao: CaldavDao, listId: String) { + caldavDao.updateParents(listId) val orderedTasks = getByRemoteOrder(listId) var subtasks = 0L var parent = 0L for (task in orderedTasks) { if (task.parent > 0) { - if (task.order != subtasks && !task.isMoved) { + if (task.order != subtasks) { task.order = subtasks update(task) } subtasks++ } else { subtasks = 0 - if (task.order != parent && !task.isMoved) { + if (task.order != parent) { task.order = parent update(task) } diff --git a/app/src/main/java/org/tasks/data/SubtaskInfo.java b/app/src/main/java/org/tasks/data/SubtaskInfo.java index 69dfaf31a..0397ecabe 100644 --- a/app/src/main/java/org/tasks/data/SubtaskInfo.java +++ b/app/src/main/java/org/tasks/data/SubtaskInfo.java @@ -2,9 +2,7 @@ package org.tasks.data; public class SubtaskInfo { public boolean hasSubtasks; - public boolean hasGoogleSubtasks; - public boolean usesSubtasks() { - return hasSubtasks || hasGoogleSubtasks; + return hasSubtasks; } } diff --git a/app/src/main/java/org/tasks/data/TaskContainer.java b/app/src/main/java/org/tasks/data/TaskContainer.java index 120e043f8..a82dfbfd0 100644 --- a/app/src/main/java/org/tasks/data/TaskContainer.java +++ b/app/src/main/java/org/tasks/data/TaskContainer.java @@ -175,19 +175,11 @@ public class TaskContainer { } public long getParent() { - if (isGoogleTask) { - return caldavTask.getParent(); - } else { - return task.getParent(); - } + return task.getParent(); } public void setParent(long parent) { - if (isGoogleTask) { - caldavTask.setParent(parent); - } else { - task.setParent(parent); - } + task.setParent(parent); } public boolean hasParent() { diff --git a/app/src/main/java/org/tasks/data/TaskDao.kt b/app/src/main/java/org/tasks/data/TaskDao.kt index 6c06cd981..53d6eceb6 100644 --- a/app/src/main/java/org/tasks/data/TaskDao.kt +++ b/app/src/main/java/org/tasks/data/TaskDao.kt @@ -64,7 +64,7 @@ abstract class TaskDao(private val database: Database) { + "LEFT JOIN caldav_tasks ON tasks._id = caldav_tasks.cd_task " + "LEFT JOIN caldav_lists ON caldav_tasks.cd_calendar = caldav_lists.cdl_uuid " + "WHERE cdl_account = :account " - + "AND (tasks.modified > caldav_tasks.cd_last_sync OR caldav_tasks.cd_remote_id = '' OR caldav_tasks.cd_deleted > 0) " + + "AND (tasks.modified > caldav_tasks.cd_last_sync OR caldav_tasks.cd_remote_id = '' OR caldav_tasks.cd_remote_id IS NULL OR caldav_tasks.cd_deleted > 0) " + "ORDER BY CASE WHEN parent = 0 THEN 0 ELSE 1 END, `order` ASC") abstract suspend fun getGoogleTasksToPush(account: String): List @@ -127,15 +127,7 @@ abstract class TaskDao(private val database: Database) { @RawQuery abstract suspend fun count(query: SimpleSQLiteQuery): Int - @Query(""" -SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtasks, - EXISTS(SELECT 1 - FROM caldav_tasks - INNER JOIN tasks ON cd_task = _id - WHERE deleted = 0 - AND gt_parent > 0 - AND cd_deleted = 0) AS hasGoogleSubtasks - """) + @Query("SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtasks") abstract suspend fun getSubtaskInfo(): SubtaskInfo @RawQuery(observedEntities = [Place::class]) diff --git a/app/src/main/java/org/tasks/data/TaskListQuery.kt b/app/src/main/java/org/tasks/data/TaskListQuery.kt index c620f755c..7fdf5b65e 100644 --- a/app/src/main/java/org/tasks/data/TaskListQuery.kt +++ b/app/src/main/java/org/tasks/data/TaskListQuery.kt @@ -16,9 +16,9 @@ object TaskListQuery { Task.ID.eq(field("${TaskListFragment.CALDAV_METADATA_JOIN}.cd_task")), field("${TaskListFragment.CALDAV_METADATA_JOIN}.cd_deleted").eq(0)) val JOINS = """ - ${Join.left(CaldavTask.TABLE.`as`(TaskListFragment.CALDAV_METADATA_JOIN), JOIN_CALDAV)} - ${Join.left(CaldavCalendar.TABLE, field("${TaskListFragment.CALDAV_METADATA_JOIN}.cd_calendar").eq(CaldavCalendar.UUID))} - ${Join.left(CaldavAccount.TABLE, CaldavCalendar.ACCOUNT.eq(CaldavAccount.UUID))} + ${Join.inner(CaldavTask.TABLE.`as`(TaskListFragment.CALDAV_METADATA_JOIN), JOIN_CALDAV)} + ${Join.inner(CaldavCalendar.TABLE, field("${TaskListFragment.CALDAV_METADATA_JOIN}.cd_calendar").eq(CaldavCalendar.UUID))} + ${Join.inner(CaldavAccount.TABLE, CaldavCalendar.ACCOUNT.eq(CaldavAccount.UUID))} ${Join.left(Geofence.TABLE, Geofence.TASK.eq(Task.ID))} ${Join.left(Place.TABLE, Place.UID.eq(Geofence.PLACE))} """.trimIndent() @@ -36,11 +36,11 @@ object TaskListQuery { subtasks: SubtaskInfo ): MutableList = when { filter.supportsManualSort() && preferences.isManualSort -> - getRecursiveQuery(filter, preferences, subtasks) + getRecursiveQuery(filter, preferences) filter.supportsAstridSorting() && preferences.isAstridSort -> getNonRecursiveQuery(filter, preferences) filter.supportsSubtasks() && subtasks.usesSubtasks() && !preferences.usePagedQueries() -> - getRecursiveQuery(filter, preferences, subtasks) + getRecursiveQuery(filter, preferences) else -> getNonRecursiveQuery(filter, preferences) } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/data/TaskListQueryRecursive.kt b/app/src/main/java/org/tasks/data/TaskListQueryRecursive.kt index 20d235e7e..55556a1b0 100644 --- a/app/src/main/java/org/tasks/data/TaskListQueryRecursive.kt +++ b/app/src/main/java/org/tasks/data/TaskListQueryRecursive.kt @@ -33,21 +33,15 @@ internal object TaskListQueryRecursive { LEFT JOIN (SELECT parent, count(distinct recursive_tasks.task) AS children FROM recursive_tasks GROUP BY parent) AS recursive_children ON recursive_children.parent = tasks._id ${TaskListQuery.JOINS} """.trimIndent() - private val GOOGLE_SUBTASKS = + private val SUBTASK_QUERY = QueryTemplate() - .join(Join.inner(RECURSIVE, CaldavTask.PARENT.eq(RECURSIVE_TASK))) - .join(Join.inner(CaldavTask.TABLE, Criterion.and(CaldavTask.TASK.eq(Task.ID), CaldavTask.DELETED.eq(0)))) - .where(activeAndVisible()) - private val ALL_SUBTASKS = - QueryTemplate() - .join(Join.inner(RECURSIVE, Criterion.or(CaldavTask.PARENT.eq(RECURSIVE_TASK), Task.PARENT.eq(RECURSIVE_TASK)))) - .join(Join.left(CaldavTask.TABLE, Criterion.and(CaldavTask.TASK.eq(Task.ID), CaldavTask.DELETED.eq(0)))) + .join(Join.inner(RECURSIVE, Task.PARENT.eq(RECURSIVE_TASK))) +// .join(Join.left(CaldavTask.TABLE, Criterion.and(CaldavTask.TASK.eq(Task.ID), CaldavTask.DELETED.eq(0)))) .where(activeAndVisible()) fun getRecursiveQuery( filter: Filter, preferences: QueryPreferences, - subtasks: SubtaskInfo ): MutableList { var joinedQuery = JOINS var where = " WHERE recursive_tasks.hidden = 0" @@ -55,25 +49,16 @@ internal object TaskListQueryRecursive { val subtaskQuery: QueryTemplate when (filter) { is CaldavFilter -> { - parentQuery = newCaldavQuery(filter) - subtaskQuery = QueryTemplate() - .join(Join.inner(RECURSIVE, Task.PARENT.eq(RECURSIVE_TASK))) - .join(Join.inner(CaldavTask.TABLE, Criterion.and(CaldavTask.TASK.eq(Task.ID), CaldavTask.DELETED.eq(0)))) - .where(activeAndVisible()) + parentQuery = newCaldavQuery(filter.uuid) + subtaskQuery = SUBTASK_QUERY } is GtasksFilter -> { - parentQuery = newGoogleTaskQuery(filter) - subtaskQuery = GOOGLE_SUBTASKS + parentQuery = newCaldavQuery(filter.list.uuid!!) + subtaskQuery = SUBTASK_QUERY } else -> { parentQuery = PermaSql.replacePlaceholdersForQuery(filter.getSqlQuery()) - subtaskQuery = when { - subtasks.hasGoogleSubtasks && subtasks.hasSubtasks -> ALL_SUBTASKS - subtasks.hasGoogleSubtasks -> GOOGLE_SUBTASKS - else -> QueryTemplate() - .join(Join.inner(RECURSIVE, Task.PARENT.eq(RECURSIVE_TASK))) - .where(activeAndVisible()) - } + subtaskQuery = SUBTASK_QUERY joinedQuery += " LEFT JOIN (SELECT task, max(indent) AS max_indent FROM recursive_tasks GROUP BY task) AS recursive_indents ON recursive_indents.task = tasks._id " where += " AND indent = max_indent " } @@ -85,7 +70,7 @@ internal object TaskListQueryRecursive { when { manualSort && filter is GtasksFilter -> { sortMode = SortHelper.SORT_GTASKS - sortField = "caldav_tasks.cd_order" + sortField = "tasks.`order`" } manualSort && filter is CaldavFilter -> { sortMode = SortHelper.SORT_CALDAV @@ -127,26 +112,14 @@ internal object TaskListQueryRecursive { .toString()) } - private fun newCaldavQuery(filter: CaldavFilter) = + private fun newCaldavQuery(list: String) = QueryTemplate() .join(Join.inner( CaldavTask.TABLE, Criterion.and( - CaldavTask.CALENDAR.eq(filter.uuid), + CaldavTask.CALENDAR.eq(list), CaldavTask.TASK.eq(Task.ID), CaldavTask.DELETED.eq(0)))) .where(Criterion.and(activeAndVisible(), Task.PARENT.eq(0))) .toString() - - private fun newGoogleTaskQuery(filter: GtasksFilter) = - QueryTemplate() - .join(Join.inner( - CaldavTask.TABLE, - Criterion.and( - CaldavTask.CALENDAR.eq(filter.remoteId), - CaldavTask.PARENT.eq(0), - CaldavTask.TASK.eq(Task.ID), - CaldavTask.DELETED.eq(0)))) - .where(activeAndVisible()) - .toString() } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.kt b/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.kt index cae4cc8d4..206bc7052 100644 --- a/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.kt +++ b/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.kt @@ -6,7 +6,6 @@ import com.todoroo.andlib.sql.Criterion.Companion.exists import com.todoroo.andlib.sql.Criterion.Companion.or import com.todoroo.andlib.sql.Field.Companion.field import com.todoroo.andlib.sql.Join.Companion.inner -import com.todoroo.andlib.sql.Join.Companion.left import com.todoroo.andlib.sql.Query.Companion.select import com.todoroo.andlib.sql.UnaryCriterion.Companion.isNotNull import com.todoroo.astrid.api.* @@ -136,12 +135,8 @@ class FilterCriteriaProvider @Inject constructor( context.getString(R.string.custom_filter_has_subtask), select(Task.ID) .from(Task.TABLE) - .join(left(Task.TABLE.`as`("children"), Task.ID.eq(field("children.parent")))) - .join(left(CaldavTask.TABLE, CaldavTask.PARENT.eq(Task.ID))) - .where(or( - isNotNull(field("children._id")), - isNotNull(CaldavTask.ID) - )) + .join(inner(Task.TABLE.`as`("children"), Task.ID.eq(field("children.parent")))) + .where(isNotNull(field("children._id"))) .toString() ) @@ -151,11 +146,8 @@ class FilterCriteriaProvider @Inject constructor( context.getString(R.string.custom_filter_is_subtask), select(Task.ID) .from(Task.TABLE) - .join(left(CaldavTask.TABLE, CaldavTask.TASK.eq(Task.ID))) - .where(or( - field("${Task.PARENT}>0").eq(1), - field("${CaldavTask.PARENT}>0").eq(1) - )) + .join(inner(CaldavTask.TABLE, CaldavTask.TASK.eq(Task.ID))) + .where(field("${Task.PARENT}>0").eq(1)) .toString() ) diff --git a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt index 89d0f1fe6..50d6d9c4a 100644 --- a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt +++ b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.kt @@ -137,7 +137,7 @@ class GoogleTaskSynchronizer @Inject constructor( } fetchAndApplyRemoteChanges(gtasksInvoker, list) if (!preferences.isPositionHackEnabled) { - googleTaskDao.reposition(list.uuid!!) + googleTaskDao.reposition(caldavDao, list.uuid!!) } } if (preferences.isPositionHackEnabled) { @@ -146,7 +146,7 @@ class GoogleTaskSynchronizer @Inject constructor( for (task in tasks) { googleTaskDao.updatePosition(task.id, task.parent, task.position) } - googleTaskDao.reposition(list.id) + googleTaskDao.reposition(caldavDao, list.id) } } // account.etag = eTag @@ -224,12 +224,11 @@ class GoogleTaskSynchronizer @Inject constructor( remoteModel.status = "needsAction" // $NON-NLS-1$ } if (newlyCreated) { - val parent = gtasksMetadata.parent + val parent = task.parent val localParent = if (parent > 0) googleTaskDao.getRemoteId(parent) else null val previous = googleTaskDao.getPrevious( - listId!!, if (isNullOrEmpty(localParent)) 0 else parent, gtasksMetadata.order ?: 0) - val created: Task? - created = try { + listId!!, if (isNullOrEmpty(localParent)) 0 else parent, task.order ?: 0) + val created: Task? = try { gtasksInvoker.createGtask(listId, remoteModel, localParent, previous) } catch (e: HttpNotFoundException) { gtasksInvoker.createGtask(listId, remoteModel, null, null) @@ -238,7 +237,7 @@ class GoogleTaskSynchronizer @Inject constructor( // Update the metadata for the newly created task gtasksMetadata.remoteId = created.id gtasksMetadata.calendar = listId - setOrderAndParent(gtasksMetadata, created) + setOrderAndParent(gtasksMetadata, created, task) } else { return } @@ -246,15 +245,15 @@ class GoogleTaskSynchronizer @Inject constructor( try { if (!task.isDeleted && gtasksMetadata.isMoved) { try { - val parent = gtasksMetadata.parent + val parent = task.parent val localParent = if (parent > 0) googleTaskDao.getRemoteId(parent) else null val previous = googleTaskDao.getPrevious( listId!!, - if (isNullOrEmpty(localParent)) 0 else parent, - gtasksMetadata.order ?: 0) + if (localParent.isNullOrBlank()) 0 else parent, + task.order ?: 0) gtasksInvoker .moveGtask(listId, remoteModel.id, localParent, previous) - ?.let { setOrderAndParent(gtasksMetadata, it) } + ?.let { setOrderAndParent(gtasksMetadata, it, task) } } catch (e: GoogleJsonResponseException) { if (e.statusCode == 400) { Timber.e(e) @@ -328,12 +327,12 @@ class GoogleTaskSynchronizer @Inject constructor( continue } } else { - setOrderAndParent(googleTask, gtask) + if (task == null) { + task = taskCreator.createWithValues("") + } + setOrderAndParent(googleTask, gtask, task) googleTask.remoteId = gtask.id } - if (task == null) { - task = taskCreator.createWithValues("") - } task.title = getTruncatedValue(task.title, gtask.title, MAX_TITLE_LENGTH) task.completionDate = GtasksApiUtilities.gtasksCompletedTimeToUnixTime(gtask.completed?.let(::DateTime)) val dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(gtask.due?.let(::DateTime)) @@ -351,10 +350,10 @@ class GoogleTaskSynchronizer @Inject constructor( ) } - private suspend fun setOrderAndParent(googleTask: CaldavTask, task: Task) { + private suspend fun setOrderAndParent(googleTask: CaldavTask, task: Task, local: com.todoroo.astrid.data.Task) { task.position?.toLongOrNull()?.let { googleTask.remoteOrder = it } googleTask.remoteParent = task.parent?.takeIf { it.isNotBlank() } - googleTask.parent = googleTask.remoteParent?.let { googleTaskDao.getTask(it) } ?: 0L + local.parent = googleTask.remoteParent?.let { googleTaskDao.getTask(it) } ?: 0L } private suspend fun write(task: com.todoroo.astrid.data.Task, googleTask: CaldavTask) { diff --git a/app/src/main/java/org/tasks/preferences/DefaultFilterProvider.kt b/app/src/main/java/org/tasks/preferences/DefaultFilterProvider.kt index c5d40d4b8..bdb27db87 100644 --- a/app/src/main/java/org/tasks/preferences/DefaultFilterProvider.kt +++ b/app/src/main/java/org/tasks/preferences/DefaultFilterProvider.kt @@ -115,7 +115,7 @@ class DefaultFilterProvider @Inject constructor( TYPE_FILTER -> getFilterPreference(filterType, getBuiltInFilterId(filter)) TYPE_CUSTOM_FILTER -> getFilterPreference(filterType, (filter as CustomFilter).id) TYPE_TAG -> getFilterPreference(filterType, (filter as TagFilter).uuid) - TYPE_GOOGLE_TASKS -> getFilterPreference(filterType, (filter as GtasksFilter).storeId) + TYPE_GOOGLE_TASKS -> getFilterPreference(filterType, (filter as GtasksFilter).listId) TYPE_CALDAV -> getFilterPreference(filterType, (filter as CaldavFilter).uuid) TYPE_LOCATION -> getFilterPreference(filterType, (filter as PlaceFilter).uid) else -> null diff --git a/app/src/main/java/org/tasks/ui/SubtaskControlSet.kt b/app/src/main/java/org/tasks/ui/SubtaskControlSet.kt index 81ce3fa95..d01e98e20 100644 --- a/app/src/main/java/org/tasks/ui/SubtaskControlSet.kt +++ b/app/src/main/java/org/tasks/ui/SubtaskControlSet.kt @@ -10,7 +10,6 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import com.google.android.material.composethemeadapter.MdcTheme import com.todoroo.andlib.sql.Criterion -import com.todoroo.andlib.sql.Join import com.todoroo.andlib.sql.QueryTemplate import com.todoroo.andlib.utility.DateUtilities.now import com.todoroo.astrid.api.Filter @@ -23,7 +22,6 @@ import kotlinx.coroutines.launch import org.tasks.R import org.tasks.compose.collectAsStateLifecycleAware import org.tasks.compose.edit.SubtaskRow -import org.tasks.data.CaldavTask import org.tasks.data.GoogleTaskDao import org.tasks.data.TaskDao.TaskCriteria.activeAndVisible import org.tasks.preferences.Preferences @@ -59,6 +57,7 @@ class SubtaskControlSet : TaskEditControlFragment() { SubtaskRow( filter = viewModel.selectedList.collectAsStateLifecycleAware().value, googleTask = googleTaskDao.watchGoogleTask(viewModel.task.id).collectAsStateLifecycleAware(initial = null).value, + hasParent = viewModel.hasParent, desaturate = preferences.desaturateDarkMode, existingSubtasks = listViewModel.tasks.observeAsState(initial = emptyList()).value, newSubtasks = viewModel.newSubtasks.collectAsStateLifecycleAware().value, @@ -109,20 +108,10 @@ class SubtaskControlSet : TaskEditControlFragment() { companion object { const val TAG = R.string.TEA_ctrl_subtask_pref private fun getQueryTemplate(task: Task): QueryTemplate = QueryTemplate() - .join( - Join.left( - CaldavTask.TABLE, - Criterion.and( - CaldavTask.PARENT.eq(task.id), - CaldavTask.TASK.eq(Task.ID), - CaldavTask.DELETED.eq(0) - ) - ) - ) .where( Criterion.and( activeAndVisible(), - Criterion.or(Task.PARENT.eq(task.id), CaldavTask.TASK.gt(0)) + Task.PARENT.eq(task.id) ) ) } diff --git a/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt b/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt index 2c18e159e..22b1eca8d 100644 --- a/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt +++ b/app/src/main/java/org/tasks/ui/TaskEditViewModel.kt @@ -99,6 +99,8 @@ class TaskEditViewModel @Inject constructor( val estimatedSeconds = MutableStateFlow(task.estimatedSeconds) val elapsedSeconds = MutableStateFlow(task.elapsedSeconds) var newSubtasks = MutableStateFlow(emptyList()) + val hasParent: Boolean + get() = task.parent > 0 val dueDate = MutableStateFlow(task.dueDate) @@ -293,9 +295,9 @@ class TaskEditViewModel @Inject constructor( when (selectedList.value) { is GtasksFilter -> { val googleTask = CaldavTask(subtask.id, (selectedList.value as GtasksFilter).remoteId) - googleTask.parent = task.id + subtask.parent = task.id googleTask.isMoved = true - googleTaskDao.insertAndShift(googleTask, false) + googleTaskDao.insertAndShift(subtask, googleTask, false) } is CaldavFilter -> { val caldavTask = CaldavTask(subtask.id, (selectedList.value as CaldavFilter).uuid)