CaldavDao shift down

pull/996/head
Alex Baker 5 years ago
parent aa00da4739
commit 056c194780

@ -0,0 +1,168 @@
package org.tasks.data
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.natpryce.makeiteasy.MakeItEasy.with
import com.natpryce.makeiteasy.PropertyValue
import com.todoroo.andlib.utility.DateUtilities.now
import com.todoroo.astrid.dao.TaskDao
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import org.junit.runner.RunWith
import org.tasks.Freeze.Companion.freezeAt
import org.tasks.injection.InjectingTestCase
import org.tasks.injection.TestComponent
import org.tasks.makers.TaskContainerMaker
import org.tasks.makers.TaskContainerMaker.CREATED
import org.tasks.time.DateTime
import javax.inject.Inject
@RunWith(AndroidJUnit4::class)
class CaldavDaoShiftTests : InjectingTestCase() {
@Inject lateinit var taskDao: TaskDao
@Inject lateinit var caldavDao: CaldavDao
private val tasks = ArrayList<TaskContainer>()
@Test
fun basicShiftDown() {
val created = DateTime(2020, 5, 17, 9, 53, 17)
addTask(with(CREATED, created))
addTask(with(CREATED, created.plusSeconds(1)))
addTask(with(CREATED, created.plusSeconds(2)))
caldavDao.shiftDown("calendar", 0, created.plusSeconds(1).toAppleEpoch())
checkOrder(null, tasks[0])
checkOrder(created.plusSeconds(2), tasks[1])
checkOrder(created.plusSeconds(3), tasks[2])
}
@Test
fun shiftDownOnlyWhenNecessary() {
val created = DateTime(2020, 5, 17, 9, 53, 17)
addTask(with(CREATED, created))
addTask(with(CREATED, created.plusSeconds(1)))
addTask(with(CREATED, created.plusSeconds(3)))
addTask(with(CREATED, created.plusSeconds(4)))
caldavDao.shiftDown("calendar", 0, created.plusSeconds(1).toAppleEpoch())
checkOrder(null, tasks[0])
checkOrder(created.plusSeconds(2), tasks[1])
checkOrder(null, tasks[2])
checkOrder(null, tasks[3])
}
@Test
fun ignoreUnnecessaryShiftDown() {
val created = DateTime(2020, 5, 17, 9, 53, 17)
addTask(with(CREATED, created))
addTask(with(CREATED, created.plusSeconds(2)))
caldavDao.shiftDown("calendar", 0, created.plusSeconds(1).toAppleEpoch())
checkOrder(null, tasks[0])
checkOrder(null, tasks[1])
}
@Test
fun ignoreOtherCalendarWhenShiftingDown() {
val created = DateTime(2020, 5, 17, 9, 53, 17)
addTask("calendar1", with(CREATED, created))
addTask("calendar2", with(CREATED, created))
caldavDao.shiftDown("calendar1", 0, created.toAppleEpoch())
checkOrder(created.plusSeconds(1), tasks[0])
checkOrder(null, tasks[1])
}
@Test
fun partialShiftDown() {
val created = DateTime(2020, 5, 17, 9, 53, 17)
addTask(with(CREATED, created))
addTask(with(CREATED, created.plusSeconds(1)))
addTask(with(CREATED, created.plusSeconds(2)))
addTask(with(CREATED, created.plusSeconds(3)))
addTask(with(CREATED, created.plusSeconds(4)))
caldavDao.shiftDown("calendar", 0, created.toAppleEpoch(), created.plusSeconds(3).toAppleEpoch())
checkOrder(created.plusSeconds(1), tasks[0])
checkOrder(created.plusSeconds(2), tasks[1])
checkOrder(created.plusSeconds(3), tasks[2])
checkOrder(null, tasks[3])
checkOrder(null, tasks[4])
}
@Test
fun ignoreMovedTasksWhenShiftingDown() {
val created = DateTime(2020, 5, 17, 9, 53, 17)
addTask(with(CREATED, created))
caldavDao.update(caldavDao.getTask(tasks[0].id).apply { this?.deleted = now() }!!)
caldavDao.shiftDown("calendar", 0, created.toAppleEpoch())
assertNull(caldavDao.getTasks(tasks[0].id)[0].order)
}
@Test
fun ignoreDeletedTasksWhenShiftingDown() {
val created = DateTime(2020, 5, 17, 9, 53, 17)
addTask(with(CREATED, created))
taskDao.update(taskDao.fetch(tasks[0].id).apply { this?.deletionDate = now() }!!)
caldavDao.shiftDown("calendar", 0, created.toAppleEpoch())
assertNull(caldavDao.getTasks(tasks[0].id)[0].order)
}
@Test
fun touchShiftedTasks() {
val created = DateTime(2020, 5, 17, 9, 53, 17)
addTask(with(CREATED, created))
addTask(with(CREATED, created.plusSeconds(1)))
freezeAt(created.plusMinutes(1)) {
caldavDao.shiftDown("calendar", 0, created.toAppleEpoch())
}
assertEquals(created.plusMinutes(1).millis, taskDao.fetch(tasks[0].id)!!.modificationDate)
assertEquals(created.plusMinutes(1).millis, taskDao.fetch(tasks[1].id)!!.modificationDate)
}
private fun checkOrder(dateTime: DateTime?, task: TaskContainer) {
if (dateTime == null) {
assertNull(caldavDao.getTask(task.id)!!.order)
} else {
assertEquals(dateTime.toAppleEpoch(), caldavDao.getTask(task.id)!!.order)
}
}
private fun addTask(vararg properties: PropertyValue<in TaskContainer?, *>) = addTask("calendar", *properties)
private fun addTask(calendar: String, vararg properties: PropertyValue<in TaskContainer?, *>) {
val t = TaskContainerMaker.newTaskContainer(*properties)
tasks.add(t)
val task = t.task
taskDao.createNew(task)
val caldavTask = CaldavTask(t.id, calendar)
if (task.parent > 0) {
caldavTask.remoteParent = caldavDao.getRemoteIdForTask(task.parent)
}
caldavTask.id = caldavDao.insert(caldavTask)
t.caldavTask = caldavTask.toSubset()
}
private fun CaldavTask.toSubset(): SubsetCaldav {
val result = SubsetCaldav()
result.cd_id = id
result.cd_calendar = calendar
result.cd_remote_parent = remoteParent
return result
}
override fun inject(component: TestComponent) = component.inject(this)
}

@ -43,4 +43,5 @@ interface TestComponent : ApplicationComponent {
fun inject(tests: GoogleTaskListDaoTest)
fun inject(tests: CaldavTaskAdapterTest)
fun inject(tests: ManualGoogleTaskQueryTest)
fun inject(tests: CaldavDaoShiftTests)
}

@ -8,19 +8,24 @@ import com.natpryce.makeiteasy.PropertyLookup
import com.natpryce.makeiteasy.PropertyValue
import com.todoroo.astrid.data.Task.Companion.NO_ID
import org.tasks.data.TaskContainer
import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.makers.Maker.make
import org.tasks.makers.TaskMaker.newTask
import org.tasks.time.DateTime
object TaskContainerMaker {
val ID: Property<TaskContainer, Long> = newProperty()
val PARENT: Property<TaskContainer, TaskContainer?> = newProperty()
val PARENT: Property<TaskContainer, TaskContainer> = newProperty()
val CREATED: Property<TaskContainer, DateTime> = newProperty()
private val instantiator = Instantiator { lookup: PropertyLookup<TaskContainer> ->
val container = TaskContainer()
val parent = lookup.valueOf(PARENT, null as TaskContainer?)
val taskId = lookup.valueOf(ID, NO_ID)
val created = lookup.valueOf(CREATED, newDateTime())
container.task = newTask(
with(TaskMaker.ID, taskId),
with(TaskMaker.CREATION_TIME, created),
with(TaskMaker.PARENT, parent?.id ?: 0L))
container.indent = parent?.indent?.plus(1) ?: 0
container

@ -89,6 +89,7 @@ object TaskMaker {
task.uuid = lookup.valueOf(UUID, NO_UUID)
val creationTime = lookup.valueOf(CREATION_TIME, DateTimeUtils.newDateTime())
task.creationDate = creationTime.millis
task.modificationDate = creationTime.millis
task.parent = lookup.valueOf(PARENT, 0L)
task
}

@ -33,7 +33,7 @@ public class SortHelper {
public static final int SORT_GTASKS = 6;
public static final int SORT_CALDAV = 7;
private static long APPLE_EPOCH = 978307200000L; // 1/1/2001 GMT
public static final long APPLE_EPOCH = 978307200000L; // 1/1/2001 GMT
@SuppressLint("DefaultLocale")
public static final String CALDAV_ORDER_COLUMN =
String.format("IFNULL(caldav_tasks.cd_order, (tasks.created - %d) / 1000)", APPLE_EPOCH);

@ -2,6 +2,8 @@ package org.tasks.data
import androidx.lifecycle.LiveData
import androidx.room.*
import com.todoroo.andlib.utility.DateUtilities.now
import com.todoroo.astrid.core.SortHelper.APPLE_EPOCH
import io.reactivex.Single
import org.tasks.db.DbUtils
import org.tasks.filters.CaldavFilters
@ -164,4 +166,29 @@ abstract class CaldavDao {
+ " AND caldav_tasks.cd_deleted = 0), 0)"
+ "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 shiftDown(calendar: String, parent: Long, from: Long, to: Long? = null) {
val updated = ArrayList<CaldavTask>()
val tasks = getTasksToShift(calendar, parent, from, to)
for (i in tasks.indices) {
val task = tasks[i]
val current = from + i
if (task.sortOrder == current) {
val caldavTask = task.caldavTask
caldavTask.order = current + 1
updated.add(caldavTask)
} else if (task.sortOrder > current) {
break
}
}
update(updated)
touchInternal(updated.map(CaldavTask::task))
}
@Query("UPDATE tasks SET modified = :modificationTime WHERE _id in (:ids)")
internal abstract fun touchInternal(ids: List<Long>, modificationTime: Long = now())
@Query("SELECT task.*, caldav_task.*, IFNULL(cd_order, (created - $APPLE_EPOCH) / 1000) AS primary_sort FROM caldav_tasks AS caldav_task INNER JOIN tasks AS task ON _id = cd_task WHERE cd_calendar = :calendar AND parent = :parent AND cd_deleted = 0 AND deleted = 0 AND primary_sort >= :from AND primary_sort < IFNULL(:to, ${Long.MAX_VALUE}) ORDER BY primary_sort")
internal abstract fun getTasksToShift(calendar: String, parent: Long, from: Long, to: Long?): List<CaldavTaskContainer>
}

@ -2,6 +2,7 @@ package org.tasks.data
import androidx.room.Embedded
import com.todoroo.astrid.data.Task
import org.tasks.time.DateTime
class CaldavTaskContainer {
@Embedded lateinit var task: Task
@ -16,6 +17,9 @@ class CaldavTaskContainer {
val vtodo: String?
get() = caldavTask.vtodo
val sortOrder: Long
get() = caldavTask.order ?: DateTime(task.creationDate).toAppleEpoch()
override fun toString(): String {
return "CaldavTaskContainer{task=$task, caldavTask=$caldavTask}"
}

@ -1,5 +1,6 @@
package org.tasks.time;
import static com.todoroo.astrid.core.SortHelper.APPLE_EPOCH;
import static java.util.Calendar.FRIDAY;
import static java.util.Calendar.MONDAY;
import static java.util.Calendar.SATURDAY;
@ -340,6 +341,10 @@ public class DateTime {
return timestamp == 0 ? null : LocalDateTime.of(getYear(), getMonthOfYear(), getDayOfMonth(), getHourOfDay(), getMinuteOfHour());
}
public long toAppleEpoch() {
return (timestamp - APPLE_EPOCH) / 1000;
}
public int getDayOfWeekInMonth() {
return getCalendar().get(Calendar.DAY_OF_WEEK_IN_MONTH);
}

Loading…
Cancel
Save