diff --git a/app/schemas/com.todoroo.astrid.dao.Database/75.json b/app/schemas/com.todoroo.astrid.dao.Database/75.json index d220ba80b..fb69513b3 100644 --- a/app/schemas/com.todoroo.astrid.dao.Database/75.json +++ b/app/schemas/com.todoroo.astrid.dao.Database/75.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 75, - "identityHash": "4a32edd266822b077c230270a019d9b3", + "identityHash": "ff70ddcfc863c0ebc97522480d78d23d", "entities": [ { "tableName": "notification", @@ -935,7 +935,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_vtodo` TEXT, `cd_remote_parent` TEXT, `cd_order` INTEGER, `cd_remote_order` INTEGER, `cd_moved` INTEGER NOT NULL)", + "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_vtodo` TEXT, `cd_remote_parent` TEXT, `cd_order` INTEGER)", "fields": [ { "fieldPath": "id", @@ -1002,18 +1002,6 @@ "columnName": "cd_order", "affinity": "INTEGER", "notNull": false - }, - { - "fieldPath": "remoteOrder", - "columnName": "cd_remote_order", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "moved", - "columnName": "cd_moved", - "affinity": "INTEGER", - "notNull": true } ], "primaryKey": { @@ -1162,7 +1150,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, '4a32edd266822b077c230270a019d9b3')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ff70ddcfc863c0ebc97522480d78d23d')" ] } } \ No newline at end of file diff --git a/app/src/main/java/com/todoroo/astrid/adapter/CaldavManualSortTaskAdapter.kt b/app/src/main/java/com/todoroo/astrid/adapter/CaldavManualSortTaskAdapter.kt index 07f0ed2cb..60032decc 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/CaldavManualSortTaskAdapter.kt +++ b/app/src/main/java/com/todoroo/astrid/adapter/CaldavManualSortTaskAdapter.kt @@ -25,35 +25,49 @@ open class CaldavManualSortTaskAdapter internal constructor(private val taskDao: override fun moved(from: Int, to: Int, indent: Int) { val task = getTask(from) val previous = if (to > 0) getTask(to - 1) else null - var newParent = task.parent - if (indent == 0) { - newParent = 0 - } else if (previous != null) { - when { - indent == previous.getIndent() -> newParent = previous.parent - indent > previous.getIndent() -> newParent = previous.id - indent < previous.getIndent() -> { - newParent = previous.parent - var currentIndex = to - for (i in 0 until previous.getIndent() - indent) { - var thisParent = newParent - while (newParent == thisParent) { - thisParent = getTask(--currentIndex).parent - } - newParent = thisParent - } - } - } - } + val newParent = findNewParent(indent, to) - // If nothing is changing, return - if (newParent == task.parent) { + if (newParent == task.parent && from == to) { return } - changeParent(task, newParent) + + if (newParent != task.parent) { + changeParent(task, newParent) + } + if (from != to) { + val newPosition = when { + previous == null -> 1 + indent > previous.getIndent() -> 1 + indent == previous.getIndent() -> previous.caldavSortOrder + 1 + else -> getTask((to - 1 downTo 0).find { getTask(it).indent == indent }!!).caldavSortOrder + 1 + } + caldavDao.move(task, newParent, newPosition) + } + taskDao.touch(task.id) } + internal fun findNewParent(indent: Int, to: Int): Long { + val previous = if (to > 0) getTask(to - 1) else null + return when { + indent == 0 || previous == null -> 0 + indent == previous.getIndent() -> previous.parent + indent > previous.getIndent() -> previous.id + else -> { + var newParent = previous.parent + var currentIndex = to + for (i in 0 until previous.getIndent() - indent) { + var thisParent = newParent + while (newParent == thisParent) { + thisParent = getTask(--currentIndex).parent + } + newParent = thisParent + } + newParent + } + } + } + internal fun changeParent(task: TaskContainer, newParent: Long) { val caldavTask = task.getCaldavTask() if (newParent == 0L) { @@ -64,9 +78,8 @@ open class CaldavManualSortTaskAdapter internal constructor(private val taskDao: caldavTask.cd_remote_parent = parentTask.remoteId task.parent = newParent } - caldavDao.update(caldavTask) + caldavDao.updateParent(caldavTask) taskDao.save(task.getTask(), null) - taskDao.touch(task.id) } private fun taskIsChild(source: TaskContainer, destinationIndex: Int): Boolean { diff --git a/app/src/main/java/com/todoroo/astrid/adapter/CaldavTaskAdapter.kt b/app/src/main/java/com/todoroo/astrid/adapter/CaldavTaskAdapter.kt index 50d640c69..3f34253dc 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/CaldavTaskAdapter.kt +++ b/app/src/main/java/com/todoroo/astrid/adapter/CaldavTaskAdapter.kt @@ -8,36 +8,9 @@ class CaldavTaskAdapter internal constructor(taskDao: TaskDao, caldavDao: Caldav override fun moved(from: Int, to: Int, indent: Int) { val task = getTask(from) - val previous = if (to > 0) getTask(to - 1) else null - var newParent = task.parent - if (indent == 0) { - newParent = 0 - } else if (previous != null) { - when { - indent == previous.getIndent() -> { - newParent = previous.parent - } - indent > previous.getIndent() -> { - newParent = previous.id - } - indent < previous.getIndent() -> { - newParent = previous.parent - var currentIndex = to - for (i in 0 until previous.getIndent() - indent) { - var thisParent = newParent - while (newParent == thisParent) { - thisParent = getTask(--currentIndex).parent - } - newParent = thisParent - } - } - } + val newParent = findNewParent(indent, to) + if (newParent != task.parent) { + changeParent(task, newParent) } - - // If nothing is changing, return - if (newParent == task.parent) { - return - } - changeParent(task, newParent) } } \ No newline at end of file diff --git a/app/src/main/java/com/todoroo/astrid/service/Upgrader.java b/app/src/main/java/com/todoroo/astrid/service/Upgrader.java index f257d7257..0adc5cb27 100644 --- a/app/src/main/java/com/todoroo/astrid/service/Upgrader.java +++ b/app/src/main/java/com/todoroo/astrid/service/Upgrader.java @@ -213,7 +213,6 @@ public class Upgrader { Long order = iCalendar.Companion.getOrder(remoteTask); if (order != null) { task.setOrder(order); - task.setRemoteOrder(order); caldavDao.update(task); } } diff --git a/app/src/main/java/org/tasks/caldav/iCalendar.kt b/app/src/main/java/org/tasks/caldav/iCalendar.kt index 8cd2f1fc5..1477716ba 100644 --- a/app/src/main/java/org/tasks/caldav/iCalendar.kt +++ b/app/src/main/java/org/tasks/caldav/iCalendar.kt @@ -7,9 +7,11 @@ import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.helper.UUIDHelper import com.todoroo.astrid.service.TaskCreator import net.fortuna.ical4j.model.Parameter +import net.fortuna.ical4j.model.Property import net.fortuna.ical4j.model.parameter.RelType import net.fortuna.ical4j.model.property.Geo import net.fortuna.ical4j.model.property.RelatedTo +import net.fortuna.ical4j.model.property.XProperty import org.tasks.Strings.isNullOrEmpty import org.tasks.caldav.GeoUtils.equalish import org.tasks.caldav.GeoUtils.toGeo @@ -36,10 +38,16 @@ class iCalendar @Inject constructor( private val caldavDao: CaldavDao) { companion object { + private const val APPLE_SORT_ORDER = "X-APPLE-SORT-ORDER" + private val IS_PARENT = { r: RelatedTo? -> r!!.parameters.isEmpty || r.getParameter(Parameter.RELTYPE) === RelType.PARENT } + private val IS_APPLE_SORT_ORDER = { x: Property? -> + x?.name.equals(APPLE_SORT_ORDER, true) + } + fun fromVtodo(vtodo: String): Task? { try { val tasks = tasksFromReader(StringReader(vtodo)) @@ -70,10 +78,24 @@ class iCalendar @Inject constructor( } } - val Task.order: Long? + var Task.order: Long? get() = unknownProperties - .find { it.name?.equals("x-apple-sort-order", true) == true } - .let { it?.value?.toLong() } + .find { it.name?.equals(APPLE_SORT_ORDER, true) == true } + .let { it?.value?.toLongOrNull() } + set(order) { + if (order == null) { + unknownProperties.removeAll(unknownProperties.filter(IS_APPLE_SORT_ORDER)) + } else { + val existingOrder = unknownProperties + .find { it.name?.equals(APPLE_SORT_ORDER, true) == true } + + if (existingOrder != null) { + existingOrder.value = order.toString() + } else { + unknownProperties.add(XProperty(APPLE_SORT_ORDER, order.toString())) + } + } + } } fun setPlace(taskId: Long, geo: Geo) { @@ -116,6 +138,7 @@ class iCalendar @Inject constructor( fun toVtodo(caldavTask: CaldavTask, task: com.todoroo.astrid.data.Task): ByteArray { val remoteModel = CaldavConverter.toCaldav(caldavTask, task) + remoteModel.order = caldavTask.order val categories = remoteModel.categories categories.clear() categories.addAll(tagDataDao.getTagDataForTask(task.id).map { it.name!! }) @@ -155,8 +178,7 @@ class iCalendar @Inject constructor( caldavTask = existing } CaldavConverter.apply(task, remote) - caldavTask.remoteOrder = remote.order - caldavTask.order = caldavTask.remoteOrder // TODO: remove me + caldavTask.order = remote.order val geo = remote.geoPosition if (geo == null) { locationDao.getActiveGeofences(task.id).forEach { diff --git a/app/src/main/java/org/tasks/data/CaldavDao.kt b/app/src/main/java/org/tasks/data/CaldavDao.kt index db875f7f1..3e0091141 100644 --- a/app/src/main/java/org/tasks/data/CaldavDao.kt +++ b/app/src/main/java/org/tasks/data/CaldavDao.kt @@ -53,12 +53,15 @@ abstract class CaldavDao { @Update abstract fun update(caldavTask: CaldavTask) - fun update(caldavTask: SubsetCaldav) { + fun updateParent(caldavTask: SubsetCaldav) { update(caldavTask.cd_id, caldavTask.cd_remote_parent) } + @Query("UPDATE caldav_tasks SET cd_order = :position WHERE cd_id = :id") + internal abstract fun update(id: Long, position: Long) + @Query("UPDATE caldav_tasks SET cd_remote_parent = :remoteParent WHERE cd_id = :id") - abstract fun update(id: Long, remoteParent: String?) + internal abstract fun update(id: Long, remoteParent: String?) @Update abstract fun update(tasks: Iterable) @@ -167,6 +170,20 @@ abstract class CaldavDao { + "WHERE _id IN (SELECT _id FROM tasks INNER JOIN caldav_tasks ON _id = cd_task WHERE cd_deleted = 0 AND cd_calendar = :calendar)") abstract fun updateParents(calendar: String) + @Transaction + open fun move(task: TaskContainer, newParent: Long, newPosition: Long) { + val previousParent = task.parent + val caldavTask = task.caldavTask + val previousPosition = task.caldavSortOrder + if (newParent == previousParent && newPosition < previousPosition) { + shiftDown(task.caldav, newParent, newPosition, previousPosition) + } else { + shiftDown(task.caldav, newParent, newPosition) + } + caldavTask.cd_order = newPosition + update(caldavTask.cd_id, caldavTask.cd_order) + } + @Transaction open fun shiftDown(calendar: String, parent: Long, from: Long, to: Long? = null) { val updated = ArrayList() diff --git a/app/src/main/java/org/tasks/data/CaldavTask.kt b/app/src/main/java/org/tasks/data/CaldavTask.kt index 9c00e27a1..c91198437 100644 --- a/app/src/main/java/org/tasks/data/CaldavTask.kt +++ b/app/src/main/java/org/tasks/data/CaldavTask.kt @@ -44,13 +44,6 @@ class CaldavTask { @Transient var order: Long? = null - @ColumnInfo(name = "cd_remote_order") - var remoteOrder: Long? = null - - @ColumnInfo(name = "cd_moved") - @Transient - var moved = false - constructor() @Ignore @@ -72,7 +65,7 @@ class CaldavTask { fun isDeleted() = deleted > 0 override fun toString(): String { - return "CaldavTask(id=$id, task=$task, calendar=$calendar, `object`=$`object`, remoteId=$remoteId, etag=$etag, lastSync=$lastSync, deleted=$deleted, vtodo=$vtodo, remoteParent=$remoteParent, order=$order, remoteOrder=$remoteOrder, moved=$moved)" + return "CaldavTask(id=$id, task=$task, calendar=$calendar, `object`=$`object`, remoteId=$remoteId, etag=$etag, lastSync=$lastSync, deleted=$deleted, vtodo=$vtodo, remoteParent=$remoteParent, order=$order)" } companion object { diff --git a/app/src/main/java/org/tasks/data/TaskContainer.java b/app/src/main/java/org/tasks/data/TaskContainer.java index 883622af2..5e42dd9ac 100644 --- a/app/src/main/java/org/tasks/data/TaskContainer.java +++ b/app/src/main/java/org/tasks/data/TaskContainer.java @@ -197,4 +197,8 @@ public class TaskContainer { public boolean isCollapsed() { return task.isCollapsed(); } + + public long getCaldavSortOrder() { + return indent == 0 ? primarySort : secondarySort; + } } diff --git a/app/src/main/java/org/tasks/db/Migrations.java b/app/src/main/java/org/tasks/db/Migrations.java index 8dba62a4b..13cf832d7 100644 --- a/app/src/main/java/org/tasks/db/Migrations.java +++ b/app/src/main/java/org/tasks/db/Migrations.java @@ -433,8 +433,6 @@ public class Migrations { @Override public void migrate(@NonNull SupportSQLiteDatabase database) { database.execSQL("ALTER TABLE `caldav_tasks` ADD COLUMN `cd_order` INTEGER"); - database.execSQL("ALTER TABLE `caldav_tasks` ADD COLUMN `cd_remote_order` INTEGER"); - database.execSQL("ALTER TABLE `caldav_tasks` ADD COLUMN `cd_moved` INTEGER NOT NULL DEFAULT 0"); } };