Remove gt_parent from CaldavTask

pull/2146/head
Alex Baker 3 years ago
parent f6ca98e096
commit c2222657ec

@ -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')"
]
}
}

@ -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")))

@ -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)

@ -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) {

@ -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() {

@ -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";

@ -35,11 +35,9 @@ class TaskCompleter @Inject internal constructor(
ArrayList<Task?>()
.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)

@ -55,7 +55,10 @@ class TaskCreator @Inject constructor(
val addToTop = preferences.addTasksToTop()
if (task.hasTransitory(GoogleTask.KEY)) {
googleTaskDao.insertAndShift(
CaldavTask(task.id, task.getTransitory<String>(GoogleTask.KEY)!!), addToTop)
task,
CaldavTask(task.id, task.getTransitory<String>(GoogleTask.KEY)!!),
addToTop
)
} else if (task.hasTransitory(CaldavTask.KEY)) {
caldavDao.insert(
task, CaldavTask(task.id, task.getTransitory<String>(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)

@ -28,7 +28,6 @@ class TaskDeleter @Inject constructor(
suspend fun markDeleted(taskIds: List<Long>): List<Task> {
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
}

@ -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) {

@ -46,11 +46,8 @@ class TaskMover @Inject constructor(
suspend fun move(ids: List<Long>, 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<Long>, 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) }
}
}

@ -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" }

@ -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

@ -35,6 +35,7 @@ import org.tasks.data.TaskContainer
fun SubtaskRow(
filter: Filter?,
googleTask: CaldavTask?,
hasParent: Boolean,
desaturate: Boolean,
existingSubtasks: List<TaskContainer>,
newSubtasks: List<Task>,
@ -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 {

@ -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")

@ -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<CaldavTask>)
@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<CaldavTask?>
@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<Long>): List<String>
@Query("SELECT cd_task FROM caldav_tasks WHERE gt_parent IN (:ids) AND cd_deleted = 0")
abstract suspend fun getChildren(ids: List<Long>): List<Long>
suspend fun hasRecurringParent(ids: List<Long>): List<Long> =
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<Long>): List<Long>
@Query("SELECT tasks.* FROM tasks JOIN caldav_tasks ON tasks._id = cd_task WHERE gt_parent = :taskId")
abstract suspend fun getChildTasks(taskId: Long): List<Task>
@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<CaldavTask>
@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<CaldavTask>
internal abstract suspend fun getByLocalOrder(listId: String): List<Task>
@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<CaldavTask>
internal abstract suspend fun getByRemoteOrder(listId: String): List<Task>
@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)
}

@ -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;
}
}

@ -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() {

@ -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<Task>
@ -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])

@ -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<String> = 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)
}
}

@ -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<String> {
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()
}

@ -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()
)

@ -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) {

@ -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

@ -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)
)
)
}

@ -99,6 +99,8 @@ class TaskEditViewModel @Inject constructor(
val estimatedSeconds = MutableStateFlow(task.estimatedSeconds)
val elapsedSeconds = MutableStateFlow(task.elapsedSeconds)
var newSubtasks = MutableStateFlow(emptyList<Task>())
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)

Loading…
Cancel
Save