Use coroutines in task adapters

pull/1051/head
Alex Baker 5 years ago
parent b394251afc
commit f8c06fdc07

@ -3,10 +3,11 @@ package com.todoroo.astrid.adapter
import com.natpryce.makeiteasy.MakeItEasy.with import com.natpryce.makeiteasy.MakeItEasy.with
import com.natpryce.makeiteasy.PropertyValue import com.natpryce.makeiteasy.PropertyValue
import com.todoroo.astrid.api.CaldavFilter import com.todoroo.astrid.api.CaldavFilter
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull import org.junit.Assert.assertNull
import org.junit.Before import org.junit.Before
@ -14,8 +15,8 @@ import org.junit.Test
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.R import org.tasks.R
import org.tasks.data.CaldavCalendar import org.tasks.data.CaldavCalendar
import org.tasks.data.CaldavDaoBlocking import org.tasks.data.CaldavDao
import org.tasks.data.GoogleTaskDaoBlocking import org.tasks.data.GoogleTaskDao
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.data.TaskListQuery.getQuery import org.tasks.data.TaskListQuery.getQuery
import org.tasks.injection.InjectingTestCase import org.tasks.injection.InjectingTestCase
@ -34,9 +35,9 @@ import javax.inject.Inject
@UninstallModules(ProductionModule::class) @UninstallModules(ProductionModule::class)
@HiltAndroidTest @HiltAndroidTest
class CaldavManualSortTaskAdapterTest : InjectingTestCase() { class CaldavManualSortTaskAdapterTest : InjectingTestCase() {
@Inject lateinit var googleTaskDao: GoogleTaskDaoBlocking @Inject lateinit var googleTaskDao: GoogleTaskDao
@Inject lateinit var taskDao: TaskDaoBlocking @Inject lateinit var taskDao: TaskDao
@Inject lateinit var caldavDao: CaldavDaoBlocking @Inject lateinit var caldavDao: CaldavDao
@Inject lateinit var preferences: Preferences @Inject lateinit var preferences: Preferences
@Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var localBroadcastManager: LocalBroadcastManager
@ -214,7 +215,7 @@ class CaldavManualSortTaskAdapterTest : InjectingTestCase() {
checkOrder(created.plusSeconds(6), 3) checkOrder(created.plusSeconds(6), 3)
} }
private fun move(from: Int, to: Int, indent: Int = 0) { private fun move(from: Int, to: Int, indent: Int = 0) = runBlocking {
tasks.addAll(taskDao.fetchTasks { getQuery(preferences, filter, it) }) tasks.addAll(taskDao.fetchTasks { getQuery(preferences, filter, it) })
val adjustedTo = if (from < to) to + 1 else to // match DragAndDropRecyclerAdapter behavior val adjustedTo = if (from < to) to + 1 else to // match DragAndDropRecyclerAdapter behavior
adapter.moved(from, adjustedTo, indent) adapter.moved(from, adjustedTo, indent)
@ -222,7 +223,7 @@ class CaldavManualSortTaskAdapterTest : InjectingTestCase() {
private fun checkOrder(dateTime: DateTime, index: Int) = checkOrder(dateTime.toAppleEpoch(), index) private fun checkOrder(dateTime: DateTime, index: Int) = checkOrder(dateTime.toAppleEpoch(), index)
private fun checkOrder(order: Long?, index: Int) { private fun checkOrder(order: Long?, index: Int) = runBlocking {
val sortOrder = caldavDao.getTask(adapter.getTask(index).id)!!.order val sortOrder = caldavDao.getTask(adapter.getTask(index).id)!!.order
if (order == null) { if (order == null) {
assertNull(sortOrder) assertNull(sortOrder)
@ -231,7 +232,7 @@ class CaldavManualSortTaskAdapterTest : InjectingTestCase() {
} }
} }
private fun addTask(vararg properties: PropertyValue<in Task?, *>): Long { private fun addTask(vararg properties: PropertyValue<in Task?, *>): Long = runBlocking {
val task = newTask(*properties) val task = newTask(*properties)
taskDao.createNew(task) taskDao.createNew(task)
val remoteParent = if (task.parent > 0) caldavDao.getRemoteIdForTask(task.parent) else null val remoteParent = if (task.parent > 0) caldavDao.getRemoteIdForTask(task.parent) else null
@ -240,6 +241,6 @@ class CaldavManualSortTaskAdapterTest : InjectingTestCase() {
with(TASK, task.id), with(TASK, task.id),
with(CALENDAR, "1234"), with(CALENDAR, "1234"),
with(REMOTE_PARENT, remoteParent))) with(REMOTE_PARENT, remoteParent)))
return task.id task.id
} }
} }

@ -2,9 +2,10 @@ package com.todoroo.astrid.adapter
import com.natpryce.makeiteasy.MakeItEasy.with import com.natpryce.makeiteasy.MakeItEasy.with
import com.natpryce.makeiteasy.PropertyValue import com.natpryce.makeiteasy.PropertyValue
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking
import org.junit.Assert.* import org.junit.Assert.*
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -19,9 +20,9 @@ import javax.inject.Inject
@UninstallModules(ProductionModule::class) @UninstallModules(ProductionModule::class)
@HiltAndroidTest @HiltAndroidTest
class CaldavTaskAdapterTest : InjectingTestCase() { class CaldavTaskAdapterTest : InjectingTestCase() {
@Inject lateinit var taskDao: TaskDaoBlocking @Inject lateinit var taskDao: TaskDao
@Inject lateinit var caldavDao: CaldavDaoBlocking @Inject lateinit var caldavDao: CaldavDao
@Inject lateinit var googleTaskDao: GoogleTaskDaoBlocking @Inject lateinit var googleTaskDao: GoogleTaskDao
@Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var localBroadcastManager: LocalBroadcastManager
private lateinit var adapter: TaskAdapter private lateinit var adapter: TaskAdapter
@ -135,17 +136,17 @@ class CaldavTaskAdapterTest : InjectingTestCase() {
} }
@Test @Test
fun movingTaskToNewParentSetsId() { fun movingTaskToNewParentSetsId() = runBlocking {
addTask() addTask()
addTask() addTask()
adapter.moved(1, 1, 1) adapter.moved(1, 1, 1)
assertEquals(tasks[0].id, taskDao.fetchBlocking(tasks[1].id)!!.parent) assertEquals(tasks[0].id, taskDao.fetch(tasks[1].id)!!.parent)
} }
@Test @Test
fun movingTaskToNewParentSetsRemoteId() { fun movingTaskToNewParentSetsRemoteId() = runBlocking {
addTask() addTask()
addTask() addTask()
@ -158,29 +159,29 @@ class CaldavTaskAdapterTest : InjectingTestCase() {
} }
@Test @Test
fun unindentingTaskRemovesParent() { fun unindentingTaskRemovesParent() = runBlocking {
addTask() addTask()
addTask(with(PARENT, tasks[0])) addTask(with(PARENT, tasks[0]))
adapter.moved(1, 1, 0) adapter.moved(1, 1, 0)
assertTrue(caldavDao.getTask(tasks[1].id)!!.remoteParent.isNullOrBlank()) assertTrue(caldavDao.getTask(tasks[1].id)!!.remoteParent.isNullOrBlank())
assertEquals(0, taskDao.fetchBlocking(tasks[1].id)!!.parent) assertEquals(0, taskDao.fetch(tasks[1].id)!!.parent)
} }
@Test @Test
fun moveSubtaskUpToParent() { fun moveSubtaskUpToParent() = runBlocking {
addTask() addTask()
addTask(with(PARENT, tasks[0])) addTask(with(PARENT, tasks[0]))
addTask(with(PARENT, tasks[1])) addTask(with(PARENT, tasks[1]))
adapter.moved(2, 2, 1) adapter.moved(2, 2, 1)
assertEquals(tasks[0].id, taskDao.fetchBlocking(tasks[2].id)!!.parent) assertEquals(tasks[0].id, taskDao.fetch(tasks[2].id)!!.parent)
} }
@Test @Test
fun moveSubtaskUpToGrandparent() { fun moveSubtaskUpToGrandparent() = runBlocking {
addTask() addTask()
addTask(with(PARENT, tasks[0])) addTask(with(PARENT, tasks[0]))
addTask(with(PARENT, tasks[1])) addTask(with(PARENT, tasks[1]))
@ -188,10 +189,10 @@ class CaldavTaskAdapterTest : InjectingTestCase() {
adapter.moved(3, 3, 1) adapter.moved(3, 3, 1)
assertEquals(tasks[0].id, taskDao.fetchBlocking(tasks[3].id)!!.parent) assertEquals(tasks[0].id, taskDao.fetch(tasks[3].id)!!.parent)
} }
private fun addTask(vararg properties: PropertyValue<in TaskContainer?, *>) { private fun addTask(vararg properties: PropertyValue<in TaskContainer?, *>) = runBlocking {
val t = newTaskContainer(*properties) val t = newTaskContainer(*properties)
tasks.add(t) tasks.add(t)
val task = t.task val task = t.task

@ -3,17 +3,18 @@ package com.todoroo.astrid.adapter
import com.natpryce.makeiteasy.MakeItEasy.with import com.natpryce.makeiteasy.MakeItEasy.with
import com.natpryce.makeiteasy.PropertyValue import com.natpryce.makeiteasy.PropertyValue
import com.todoroo.astrid.api.GtasksFilter import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.R import org.tasks.R
import org.tasks.data.CaldavDaoBlocking import org.tasks.data.CaldavDao
import org.tasks.data.GoogleTaskDaoBlocking import org.tasks.data.GoogleTaskDao
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.data.TaskListQuery.getQuery import org.tasks.data.TaskListQuery.getQuery
import org.tasks.injection.InjectingTestCase import org.tasks.injection.InjectingTestCase
@ -32,9 +33,9 @@ import javax.inject.Inject
@UninstallModules(ProductionModule::class) @UninstallModules(ProductionModule::class)
@HiltAndroidTest @HiltAndroidTest
class GoogleTaskManualSortAdapterTest : InjectingTestCase() { class GoogleTaskManualSortAdapterTest : InjectingTestCase() {
@Inject lateinit var taskDao: TaskDaoBlocking @Inject lateinit var taskDao: TaskDao
@Inject lateinit var caldavDao: CaldavDaoBlocking @Inject lateinit var caldavDao: CaldavDao
@Inject lateinit var googleTaskDao: GoogleTaskDaoBlocking @Inject lateinit var googleTaskDao: GoogleTaskDao
@Inject lateinit var preferences: Preferences @Inject lateinit var preferences: Preferences
@Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var localBroadcastManager: LocalBroadcastManager
@ -419,19 +420,19 @@ class GoogleTaskManualSortAdapterTest : InjectingTestCase() {
adapter.setDataSource(dataSource) adapter.setDataSource(dataSource)
} }
private fun move(from: Int, to: Int, indent: Int = 0) { private fun move(from: Int, to: Int, indent: Int = 0) = runBlocking {
tasks.addAll(taskDao.fetchTasks { getQuery(preferences, filter, it) }) tasks.addAll(taskDao.fetchTasks { getQuery(preferences, filter, it) })
val adjustedTo = if (from < to) to + 1 else to val adjustedTo = if (from < to) to + 1 else to
adapter.moved(from, adjustedTo, indent) adapter.moved(from, adjustedTo, indent)
} }
private fun checkOrder(order: Long, index: Int, parent: Long = 0) { private fun checkOrder(order: Long, index: Int, parent: Long = 0) = runBlocking {
val googleTask = googleTaskDao.getByTaskId(adapter.getTask(index).id)!! val googleTask = googleTaskDao.getByTaskId(adapter.getTask(index).id)!!
assertEquals(order, googleTask.order) assertEquals(order, googleTask.order)
assertEquals(parent, googleTask.parent) assertEquals(parent, googleTask.parent)
} }
private fun addTask(vararg properties: PropertyValue<in Task?, *>): Long { private fun addTask(vararg properties: PropertyValue<in Task?, *>): Long = runBlocking {
val task = newTask(*properties) val task = newTask(*properties)
val parent = task.parent val parent = task.parent
task.parent = 0 task.parent = 0
@ -442,6 +443,6 @@ class GoogleTaskManualSortAdapterTest : InjectingTestCase() {
with(LIST, "1234"), with(LIST, "1234"),
with(GoogleTaskMaker.PARENT, parent)), with(GoogleTaskMaker.PARENT, parent)),
false) false)
return task.id task.id
} }
} }

@ -5,17 +5,18 @@ import androidx.test.core.app.ApplicationProvider
import com.natpryce.makeiteasy.MakeItEasy.with import com.natpryce.makeiteasy.MakeItEasy.with
import com.natpryce.makeiteasy.PropertyValue import com.natpryce.makeiteasy.PropertyValue
import com.todoroo.astrid.core.BuiltInFilterExposer import com.todoroo.astrid.core.BuiltInFilterExposer
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.R import org.tasks.R
import org.tasks.data.CaldavDaoBlocking import org.tasks.data.CaldavDao
import org.tasks.data.GoogleTaskDaoBlocking import org.tasks.data.GoogleTaskDao
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.data.TaskListQuery.getQuery import org.tasks.data.TaskListQuery.getQuery
import org.tasks.injection.InjectingTestCase import org.tasks.injection.InjectingTestCase
@ -28,9 +29,9 @@ import javax.inject.Inject
@UninstallModules(ProductionModule::class) @UninstallModules(ProductionModule::class)
@HiltAndroidTest @HiltAndroidTest
class NonRecursiveQueryTest : InjectingTestCase() { class NonRecursiveQueryTest : InjectingTestCase() {
@Inject lateinit var googleTaskDao: GoogleTaskDaoBlocking @Inject lateinit var googleTaskDao: GoogleTaskDao
@Inject lateinit var caldavDao: CaldavDaoBlocking @Inject lateinit var caldavDao: CaldavDao
@Inject lateinit var taskDao: TaskDaoBlocking @Inject lateinit var taskDao: TaskDao
@Inject lateinit var preferences: Preferences @Inject lateinit var preferences: Preferences
@Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var localBroadcastManager: LocalBroadcastManager
@ -65,13 +66,13 @@ class NonRecursiveQueryTest : InjectingTestCase() {
assertEquals(0, tasks[1].indent) assertEquals(0, tasks[1].indent)
} }
private fun addTask(vararg properties: PropertyValue<in Task?, *>): Long { private fun addTask(vararg properties: PropertyValue<in Task?, *>): Long = runBlocking {
val task = newTask(*properties) val task = newTask(*properties)
taskDao.createNew(task) taskDao.createNew(task)
return task.id task.id
} }
private fun query() { private fun query() = runBlocking {
tasks.addAll(taskDao.fetchTasks { getQuery(preferences, filter, it) }) tasks.addAll(taskDao.fetchTasks { getQuery(preferences, filter, it) })
} }
} }

@ -5,16 +5,17 @@ import androidx.test.core.app.ApplicationProvider
import com.natpryce.makeiteasy.MakeItEasy.with import com.natpryce.makeiteasy.MakeItEasy.with
import com.natpryce.makeiteasy.PropertyValue import com.natpryce.makeiteasy.PropertyValue
import com.todoroo.astrid.core.BuiltInFilterExposer import com.todoroo.astrid.core.BuiltInFilterExposer
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.data.CaldavDaoBlocking import org.tasks.data.CaldavDao
import org.tasks.data.GoogleTaskDaoBlocking import org.tasks.data.GoogleTaskDao
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.data.TaskListQuery.getQuery import org.tasks.data.TaskListQuery.getQuery
import org.tasks.injection.InjectingTestCase import org.tasks.injection.InjectingTestCase
@ -27,9 +28,9 @@ import javax.inject.Inject
@UninstallModules(ProductionModule::class) @UninstallModules(ProductionModule::class)
@HiltAndroidTest @HiltAndroidTest
class OfflineSubtaskTest : InjectingTestCase() { class OfflineSubtaskTest : InjectingTestCase() {
@Inject lateinit var googleTaskDao: GoogleTaskDaoBlocking @Inject lateinit var googleTaskDao: GoogleTaskDao
@Inject lateinit var caldavDao: CaldavDaoBlocking @Inject lateinit var caldavDao: CaldavDao
@Inject lateinit var taskDao: TaskDaoBlocking @Inject lateinit var taskDao: TaskDao
@Inject lateinit var preferences: Preferences @Inject lateinit var preferences: Preferences
@Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var localBroadcastManager: LocalBroadcastManager
@ -76,13 +77,13 @@ class OfflineSubtaskTest : InjectingTestCase() {
assertEquals(2, tasks[2].indent) assertEquals(2, tasks[2].indent)
} }
private fun addTask(vararg properties: PropertyValue<in Task?, *>): Long { private fun addTask(vararg properties: PropertyValue<in Task?, *>): Long = runBlocking {
val task = newTask(*properties) val task = newTask(*properties)
taskDao.createNew(task) taskDao.createNew(task)
return task.id task.id
} }
private fun query() { private fun query() = runBlocking {
tasks.addAll(taskDao.fetchTasks { getQuery(preferences, filter, it) }) tasks.addAll(taskDao.fetchTasks { getQuery(preferences, filter, it) })
} }
} }

@ -3,6 +3,7 @@ package com.todoroo.astrid.subtasks
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -18,11 +19,13 @@ class SubtasksHelperTest : SubtasksTestCase() {
createTasks() createTasks()
val m = TaskListMetadata() val m = TaskListMetadata()
m.filter = TaskListMetadata.FILTER_ID_ALL m.filter = TaskListMetadata.FILTER_ID_ALL
runBlocking {
updater.initializeFromSerializedTree( updater.initializeFromSerializedTree(
m, filter, SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE)) m, filter, SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE))
} }
}
private fun createTask(title: String, uuid: String) { private fun createTask(title: String, uuid: String) = runBlocking {
val t = Task() val t = Task()
t.title = title t.title = title
t.uuid = uuid t.uuid = uuid
@ -49,7 +52,7 @@ class SubtasksHelperTest : SubtasksTestCase() {
} }
@Test @Test
fun testLocalToRemoteIdMapping() { fun testLocalToRemoteIdMapping() = runBlocking {
val mapped = SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE) val mapped = SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE)
.replace("\\s".toRegex(), "") .replace("\\s".toRegex(), "")
assertEquals(EXPECTED_REMOTE, mapped) assertEquals(EXPECTED_REMOTE, mapped)

@ -3,6 +3,7 @@ package com.todoroo.astrid.subtasks
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.runBlocking
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.tasks.data.TaskListMetadata import org.tasks.data.TaskListMetadata
@ -24,8 +25,10 @@ class SubtasksMovingTest : SubtasksTestCase() {
createTasks() createTasks()
val m = TaskListMetadata() val m = TaskListMetadata()
m.filter = TaskListMetadata.FILTER_ID_ALL m.filter = TaskListMetadata.FILTER_ID_ALL
runBlocking {
updater.initializeFromSerializedTree( updater.initializeFromSerializedTree(
m, filter, SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE)) m, filter, SubtasksHelper.convertTreeToRemoteIds(taskDao, DEFAULT_SERIALIZED_TREE))
}
// Assert initial state is correct // Assert initial state is correct
expectParentAndPosition(A, null, 0) expectParentAndPosition(A, null, 0)
@ -45,16 +48,16 @@ class SubtasksMovingTest : SubtasksTestCase() {
F = createTask("F") F = createTask("F")
} }
private fun createTask(title: String): Task { private fun createTask(title: String): Task = runBlocking {
val task = Task() val task = Task()
task.title = title task.title = title
taskDao.createNew(task) taskDao.createNew(task)
return task task
} }
private fun whenTriggerMoveBefore(target: Task?, before: Task?) { private fun whenTriggerMoveBefore(target: Task?, before: Task?) = runBlocking {
val beforeId = if (before == null) "-1" else before.uuid val beforeId = before?.uuid ?: "-1"
updater.moveTo(null, filter, target!!.uuid, beforeId) updater.moveTo(TaskListMetadata(), filter, target!!.uuid, beforeId)
} }
/* Starting State (see SubtasksTestCase): /* Starting State (see SubtasksTestCase):

@ -3,11 +3,11 @@ package com.todoroo.astrid.subtasks
import androidx.test.InstrumentationRegistry import androidx.test.InstrumentationRegistry
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.core.BuiltInFilterExposer import com.todoroo.astrid.core.BuiltInFilterExposer
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull import org.junit.Assert.assertNotNull
import org.tasks.data.TaskListMetadataDaoBlocking import org.tasks.data.TaskListMetadataDao
import org.tasks.injection.InjectingTestCase import org.tasks.injection.InjectingTestCase
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import javax.inject.Inject import javax.inject.Inject
@ -15,8 +15,8 @@ import javax.inject.Inject
abstract class SubtasksTestCase : InjectingTestCase() { abstract class SubtasksTestCase : InjectingTestCase() {
lateinit var updater: SubtasksFilterUpdater lateinit var updater: SubtasksFilterUpdater
lateinit var filter: Filter lateinit var filter: Filter
@Inject lateinit var taskListMetadataDao: TaskListMetadataDaoBlocking @Inject lateinit var taskListMetadataDao: TaskListMetadataDao
@Inject lateinit var taskDao: TaskDaoBlocking @Inject lateinit var taskDao: TaskDao
@Inject lateinit var preferences: Preferences @Inject lateinit var preferences: Preferences
override fun setUp() { override fun setUp() {
@ -27,11 +27,11 @@ abstract class SubtasksTestCase : InjectingTestCase() {
} }
fun expectParentAndPosition(task: Task, parent: Task?, positionInParent: Int) { fun expectParentAndPosition(task: Task, parent: Task?, positionInParent: Int) {
val parentId = if (parent == null) "-1" else parent.uuid val parentId = parent?.uuid ?: "-1"
val n = updater.findNodeForTask(task.uuid) val n = updater.findNodeForTask(task.uuid)
assertNotNull("No node found for task " + task.title, n) assertNotNull("No node found for task " + task.title, n)
assertEquals("Parent mismatch", parentId, n.parent.uuid) assertEquals("Parent mismatch", parentId, n!!.parent!!.uuid)
assertEquals("Position mismatch", positionInParent, n.parent.children.indexOf(n)) assertEquals("Position mismatch", positionInParent, n.parent!!.children.indexOf(n))
} }
companion object { companion object {

@ -235,7 +235,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
} else if (recyclerAdapter !is DragAndDropRecyclerAdapter) { } else if (recyclerAdapter !is DragAndDropRecyclerAdapter) {
setAdapter( setAdapter(
DragAndDropRecyclerAdapter( DragAndDropRecyclerAdapter(
taskAdapter, recyclerView, viewHolderFactory, this, tasks, preferences)) lifecycleScope, taskAdapter, recyclerView, viewHolderFactory, this, tasks, preferences))
return return
} }
recyclerAdapter?.submitList(tasks) recyclerAdapter?.submitList(tasks)
@ -497,8 +497,10 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
} }
fun onTaskCreated(uuid: String) { fun onTaskCreated(uuid: String) {
lifecycleScope.launch {
taskAdapter.onTaskCreated(uuid) taskAdapter.onTaskCreated(uuid)
} }
}
private fun onTaskDelete(task: Task) { private fun onTaskDelete(task: Task) {
(activity as MainActivity?)?.taskEditFragment?.let { (activity as MainActivity?)?.taskEditFragment?.let {
@ -507,9 +509,11 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
} }
} }
timerPlugin.stopTimer(task) timerPlugin.stopTimer(task)
lifecycleScope.launch {
taskAdapter.onTaskDeleted(task) taskAdapter.onTaskDeleted(task)
loadTaskListContent() loadTaskListContent()
} }
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) { when (requestCode) {

@ -2,26 +2,27 @@ package com.todoroo.astrid.adapter
import com.todoroo.andlib.utility.DateUtilities import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import com.todoroo.astrid.subtasks.SubtasksFilterUpdater import com.todoroo.astrid.subtasks.SubtasksFilterUpdater
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.Strings.isNullOrEmpty import org.tasks.Strings.isNullOrEmpty
import org.tasks.data.CaldavDaoBlocking import org.tasks.data.CaldavDao
import org.tasks.data.GoogleTaskDaoBlocking import org.tasks.data.GoogleTaskDao
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.data.TaskListMetadata import org.tasks.data.TaskListMetadata
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
import kotlin.math.abs import kotlin.math.abs
@Deprecated("legacy astrid manual sorting")
class AstridTaskAdapter internal constructor( class AstridTaskAdapter internal constructor(
private val list: TaskListMetadata, private val list: TaskListMetadata,
private val filter: Filter, private val filter: Filter,
private val updater: SubtasksFilterUpdater, private val updater: SubtasksFilterUpdater,
googleTaskDao: GoogleTaskDaoBlocking, googleTaskDao: GoogleTaskDao,
caldavDao: CaldavDaoBlocking, caldavDao: CaldavDao,
private val taskDao: TaskDaoBlocking, private val taskDao: TaskDao,
private val localBroadcastManager: LocalBroadcastManager) private val localBroadcastManager: LocalBroadcastManager)
: TaskAdapter(false, googleTaskDao, caldavDao, taskDao, localBroadcastManager) { : TaskAdapter(false, googleTaskDao, caldavDao, taskDao, localBroadcastManager) {
@ -38,7 +39,7 @@ class AstridTaskAdapter internal constructor(
override fun supportsAstridSorting() = true override fun supportsAstridSorting() = true
override fun moved(from: Int, to: Int, indent: Int) { override suspend fun moved(from: Int, to: Int, indent: Int) {
val source = getTask(from) val source = getTask(from)
val targetTaskId = source.uuid val targetTaskId = source.uuid
try { try {
@ -59,11 +60,11 @@ class AstridTaskAdapter internal constructor(
} }
} }
override fun onTaskCreated(uuid: String) = updater.onCreateTask(list, filter, uuid) override suspend fun onTaskCreated(uuid: String) = updater.onCreateTask(list, filter, uuid)
override fun onTaskDeleted(task: Task) = updater.onDeleteTask(list, filter, task.uuid) override suspend fun onTaskDeleted(task: Task) = updater.onDeleteTask(list, filter, task.uuid)
override fun onCompletedTask(task: TaskContainer, newState: Boolean) { override suspend fun onCompletedTask(task: TaskContainer, newState: Boolean) {
val itemId = task.uuid val itemId = task.uuid
val completionDate = if (newState) DateUtilities.now() else 0 val completionDate = if (newState) DateUtilities.now() else 0
if (!newState) { if (!newState) {

@ -1,19 +1,19 @@
package com.todoroo.astrid.adapter package com.todoroo.astrid.adapter
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.data.CaldavDaoBlocking import org.tasks.data.CaldavDao
import org.tasks.data.GoogleTaskDaoBlocking import org.tasks.data.GoogleTaskDao
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
class CaldavManualSortTaskAdapter internal constructor( class CaldavManualSortTaskAdapter internal constructor(
googleTaskDao: GoogleTaskDaoBlocking, googleTaskDao: GoogleTaskDao,
private val caldavDao: CaldavDaoBlocking, private val caldavDao: CaldavDao,
private val taskDao: TaskDaoBlocking, private val taskDao: TaskDao,
private val localBroadcastManager: LocalBroadcastManager) private val localBroadcastManager: LocalBroadcastManager)
: TaskAdapter(false, googleTaskDao, caldavDao, taskDao, localBroadcastManager) { : TaskAdapter(false, googleTaskDao, caldavDao, taskDao, localBroadcastManager) {
override fun moved(from: Int, to: Int, indent: Int) { override suspend fun moved(from: Int, to: Int, indent: Int) {
val task = getTask(from) val task = getTask(from)
val oldParent = task.parent val oldParent = task.parent
val newParent = changeParent(task, indent, to) val newParent = changeParent(task, indent, to)
@ -37,7 +37,7 @@ class CaldavManualSortTaskAdapter internal constructor(
localBroadcastManager.broadcastRefresh() localBroadcastManager.broadcastRefresh()
} }
private fun changeParent(task: TaskContainer, indent: Int, to: Int): Long { private suspend fun changeParent(task: TaskContainer, indent: Int, to: Int): Long {
val newParent = findParent(indent, to)?.id ?: 0 val newParent = findParent(indent, to)?.id ?: 0
if (task.parent != newParent) { if (task.parent != newParent) {
changeParent(task, newParent) changeParent(task, newParent)
@ -45,7 +45,7 @@ class CaldavManualSortTaskAdapter internal constructor(
return newParent return newParent
} }
private fun changeParent(task: TaskContainer, newParent: Long) { private suspend fun changeParent(task: TaskContainer, newParent: Long) {
val caldavTask = task.getCaldavTask() val caldavTask = task.getCaldavTask()
if (newParent == 0L) { if (newParent == 0L) {
caldavTask.cd_remote_parent = "" caldavTask.cd_remote_parent = ""

@ -1,19 +1,19 @@
package com.todoroo.astrid.adapter package com.todoroo.astrid.adapter
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import org.tasks.BuildConfig import org.tasks.BuildConfig
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.data.CaldavDaoBlocking import org.tasks.data.CaldavDao
import org.tasks.data.GoogleTaskDaoBlocking import org.tasks.data.GoogleTaskDao
class GoogleTaskManualSortAdapter internal constructor( class GoogleTaskManualSortAdapter internal constructor(
private val googleTaskDao: GoogleTaskDaoBlocking, private val googleTaskDao: GoogleTaskDao,
caldavDao: CaldavDaoBlocking, caldavDao: CaldavDao,
private val taskDao: TaskDaoBlocking, private val taskDao: TaskDao,
private val localBroadcastManager: LocalBroadcastManager) private val localBroadcastManager: LocalBroadcastManager)
: TaskAdapter(false, googleTaskDao, caldavDao, taskDao, localBroadcastManager) { : TaskAdapter(false, googleTaskDao, caldavDao, taskDao, localBroadcastManager) {
override fun moved(from: Int, to: Int, indent: Int) { override suspend fun moved(from: Int, to: Int, indent: Int) {
val task = getTask(from) val task = getTask(from)
val googleTask = task.googleTask val googleTask = task.googleTask
val previous = if (to > 0) getTask(to - 1) else null val previous = if (to > 0) getTask(to - 1) else null

@ -7,7 +7,7 @@ package com.todoroo.astrid.adapter
import com.todoroo.astrid.core.SortHelper.SORT_DUE import com.todoroo.astrid.core.SortHelper.SORT_DUE
import com.todoroo.astrid.core.SortHelper.SORT_IMPORTANCE import com.todoroo.astrid.core.SortHelper.SORT_IMPORTANCE
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import org.tasks.BuildConfig import org.tasks.BuildConfig
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
@ -19,9 +19,9 @@ import kotlin.collections.HashSet
open class TaskAdapter( open class TaskAdapter(
private val newTasksOnTop: Boolean, private val newTasksOnTop: Boolean,
private val googleTaskDao: GoogleTaskDaoBlocking, private val googleTaskDao: GoogleTaskDao,
private val caldavDao: CaldavDaoBlocking, private val caldavDao: CaldavDao,
private val taskDao: TaskDaoBlocking, private val taskDao: TaskDao,
private val localBroadcastManager: LocalBroadcastManager) { private val localBroadcastManager: LocalBroadcastManager) {
private val selected = HashSet<Long>() private val selected = HashSet<Long>()
@ -126,7 +126,7 @@ open class TaskAdapter(
open fun supportsAstridSorting(): Boolean = false open fun supportsAstridSorting(): Boolean = false
open fun moved(from: Int, to: Int, indent: Int) { open suspend fun moved(from: Int, to: Int, indent: Int) {
val task = getTask(from) val task = getTask(from)
val newParent = findParent(indent, to) val newParent = findParent(indent, to)
if (newParent?.id ?: 0 == task.parent) { if (newParent?.id ?: 0 == task.parent) {
@ -162,11 +162,11 @@ open class TaskAdapter(
fun getItemUuid(position: Int): String = getTask(position).uuid fun getItemUuid(position: Int): String = getTask(position).uuid
open fun onCompletedTask(task: TaskContainer, newState: Boolean) {} open suspend fun onCompletedTask(task: TaskContainer, newState: Boolean) {}
open fun onTaskCreated(uuid: String) {} open suspend fun onTaskCreated(uuid: String) {}
open fun onTaskDeleted(task: Task) {} open suspend fun onTaskDeleted(task: Task) {}
open fun supportsHiddenTasks(): Boolean = true open fun supportsHiddenTasks(): Boolean = true
@ -197,7 +197,7 @@ open class TaskAdapter(
return null return null
} }
private fun changeSortGroup(task: TaskContainer, pos: Int) { private suspend fun changeSortGroup(task: TaskContainer, pos: Int) {
when(dataSource.sortMode) { when(dataSource.sortMode) {
SORT_IMPORTANCE -> { SORT_IMPORTANCE -> {
val newPriority = dataSource.nearestHeader(if (pos == 0) 1 else pos).toInt() val newPriority = dataSource.nearestHeader(if (pos == 0) 1 else pos).toInt()
@ -211,7 +211,7 @@ open class TaskAdapter(
} }
} }
private fun applyDate(task: Task, date: Long) { private suspend fun applyDate(task: Task, date: Long) {
val original = task.dueDate val original = task.dueDate
task.setDueDateAdjustingHideUntil(if (date == 0L) { task.setDueDateAdjustingHideUntil(if (date == 0L) {
0L 0L
@ -223,14 +223,14 @@ open class TaskAdapter(
} }
} }
private fun moveToTopLevel(task: TaskContainer) { private suspend fun moveToTopLevel(task: TaskContainer) {
when { when {
task.isGoogleTask -> changeGoogleTaskParent(task, null) task.isGoogleTask -> changeGoogleTaskParent(task, null)
task.isCaldavTask -> changeCaldavParent(task, null) task.isCaldavTask -> changeCaldavParent(task, null)
} }
} }
private fun changeGoogleTaskParent(task: TaskContainer, newParent: TaskContainer?) { private suspend fun changeGoogleTaskParent(task: TaskContainer, newParent: TaskContainer?) {
val list = newParent?.googleTaskList ?: task.googleTaskList!! val list = newParent?.googleTaskList ?: task.googleTaskList!!
if (newParent == null || task.googleTaskList == newParent.googleTaskList) { if (newParent == null || task.googleTaskList == newParent.googleTaskList) {
googleTaskDao.move( googleTaskDao.move(
@ -254,7 +254,7 @@ open class TaskAdapter(
} }
} }
private fun changeCaldavParent(task: TaskContainer, newParent: TaskContainer?) { private suspend fun changeCaldavParent(task: TaskContainer, newParent: TaskContainer?) {
val list = newParent?.caldav ?: task.caldav!! val list = newParent?.caldav ?: task.caldav!!
val caldavTask = task.getCaldavTask() ?: SubsetCaldav() val caldavTask = task.getCaldavTask() ?: SubsetCaldav()
val newParentId = newParent?.id ?: 0 val newParentId = newParent?.id ?: 0

@ -6,27 +6,28 @@ import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.GtasksFilter import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.api.TagFilter import com.todoroo.astrid.api.TagFilter
import com.todoroo.astrid.core.BuiltInFilterExposer import com.todoroo.astrid.core.BuiltInFilterExposer
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task.Companion.isUuidEmpty import com.todoroo.astrid.data.Task.Companion.isUuidEmpty
import com.todoroo.astrid.subtasks.SubtasksFilterUpdater import com.todoroo.astrid.subtasks.SubtasksFilterUpdater
import com.todoroo.astrid.subtasks.SubtasksHelper import com.todoroo.astrid.subtasks.SubtasksHelper
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.runBlocking
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.Strings.isNullOrEmpty import org.tasks.Strings.isNullOrEmpty
import org.tasks.data.CaldavDaoBlocking import org.tasks.data.CaldavDao
import org.tasks.data.GoogleTaskDaoBlocking import org.tasks.data.GoogleTaskDao
import org.tasks.data.TaskListMetadata import org.tasks.data.TaskListMetadata
import org.tasks.data.TaskListMetadataDaoBlocking import org.tasks.data.TaskListMetadataDao
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import javax.inject.Inject import javax.inject.Inject
class TaskAdapterProvider @Inject constructor( class TaskAdapterProvider @Inject constructor(
@param:ApplicationContext private val context: Context, @param:ApplicationContext private val context: Context,
private val preferences: Preferences, private val preferences: Preferences,
private val taskListMetadataDao: TaskListMetadataDaoBlocking, private val taskListMetadataDao: TaskListMetadataDao,
private val taskDao: TaskDaoBlocking, private val taskDao: TaskDao,
private val googleTaskDao: GoogleTaskDaoBlocking, private val googleTaskDao: GoogleTaskDao,
private val caldavDao: CaldavDaoBlocking, private val caldavDao: CaldavDao,
private val localBroadcastManager: LocalBroadcastManager) { private val localBroadcastManager: LocalBroadcastManager) {
fun createTaskAdapter(filter: Filter): TaskAdapter { fun createTaskAdapter(filter: Filter): TaskAdapter {
if (filter.supportsAstridSorting() && preferences.isAstridSort) { if (filter.supportsAstridSorting() && preferences.isAstridSort) {
@ -49,7 +50,7 @@ class TaskAdapterProvider @Inject constructor(
return TaskAdapter(preferences.addTasksToTop(), googleTaskDao, caldavDao, taskDao, localBroadcastManager) return TaskAdapter(preferences.addTasksToTop(), googleTaskDao, caldavDao, taskDao, localBroadcastManager)
} }
private fun createManualTagTaskAdapter(filter: TagFilter): TaskAdapter { private fun createManualTagTaskAdapter(filter: TagFilter): TaskAdapter = runBlocking {
val tagData = filter.tagData val tagData = filter.tagData
val tdId = tagData.remoteId val tdId = tagData.remoteId
var list = taskListMetadataDao.fetchByTagOrFilter(tagData.remoteId!!) var list = taskListMetadataDao.fetchByTagOrFilter(tagData.remoteId!!)
@ -60,10 +61,10 @@ class TaskAdapterProvider @Inject constructor(
} }
val updater = SubtasksFilterUpdater(taskListMetadataDao, taskDao) val updater = SubtasksFilterUpdater(taskListMetadataDao, taskDao)
updater.initialize(list, filter) updater.initialize(list, filter)
return AstridTaskAdapter(list!!, filter, updater, googleTaskDao, caldavDao, taskDao, localBroadcastManager) AstridTaskAdapter(list!!, filter, updater, googleTaskDao, caldavDao, taskDao, localBroadcastManager)
} }
private fun createManualFilterTaskAdapter(filter: Filter): TaskAdapter? { private fun createManualFilterTaskAdapter(filter: Filter): TaskAdapter? = runBlocking {
var filterId: String? = null var filterId: String? = null
var prefId: String? = null var prefId: String? = null
if (BuiltInFilterExposer.isInbox(context, filter)) { if (BuiltInFilterExposer.isInbox(context, filter)) {
@ -74,7 +75,7 @@ class TaskAdapterProvider @Inject constructor(
prefId = SubtasksFilterUpdater.TODAY_TASKS_ORDER prefId = SubtasksFilterUpdater.TODAY_TASKS_ORDER
} }
if (filterId.isNullOrBlank()) { if (filterId.isNullOrBlank()) {
return null return@runBlocking null
} }
var list = taskListMetadataDao.fetchByTagOrFilter(filterId) var list = taskListMetadataDao.fetchByTagOrFilter(filterId)
if (list == null) { if (list == null) {
@ -90,6 +91,6 @@ class TaskAdapterProvider @Inject constructor(
} }
val updater = SubtasksFilterUpdater(taskListMetadataDao, taskDao) val updater = SubtasksFilterUpdater(taskListMetadataDao, taskDao)
updater.initialize(list, filter) updater.initialize(list, filter)
return AstridTaskAdapter(list, filter, updater, googleTaskDao, caldavDao, taskDao, localBroadcastManager) AstridTaskAdapter(list, filter, updater, googleTaskDao, caldavDao, taskDao, localBroadcastManager)
} }
} }

@ -108,12 +108,12 @@ abstract class TaskDao(private val database: Database) {
abstract suspend fun clearCompletedCalendarEvents(): Int abstract suspend fun clearCompletedCalendarEvents(): Int
@Transaction @Transaction
open suspend fun fetchTasks(callback: (SubtaskInfo) -> List<String>): List<TaskContainer> { open suspend fun fetchTasks(callback: suspend (SubtaskInfo) -> List<String>): List<TaskContainer> {
return fetchTasks(callback, getSubtaskInfo()) return fetchTasks(callback, getSubtaskInfo())
} }
@Transaction @Transaction
open suspend fun fetchTasks(callback: (SubtaskInfo) -> List<String>, subtasks: SubtaskInfo): List<TaskContainer> { open suspend fun fetchTasks(callback: suspend (SubtaskInfo) -> List<String>, subtasks: SubtaskInfo): List<TaskContainer> {
val start = if (BuildConfig.DEBUG) DateUtilities.now() else 0 val start = if (BuildConfig.DEBUG) DateUtilities.now() else 0
val queries = callback.invoke(subtasks) val queries = callback.invoke(subtasks)
val db = database.openHelper.writableDatabase val db = database.openHelper.writableDatabase

@ -94,7 +94,9 @@ class TaskDaoBlocking @Inject constructor(private val dao: TaskDao) {
} }
fun fetchTasks(callback: (SubtaskInfo) -> List<String>): List<TaskContainer> = runBlocking { fun fetchTasks(callback: (SubtaskInfo) -> List<String>): List<TaskContainer> = runBlocking {
dao.fetchTasks(callback) dao.fetchTasks {
callback.invoke(it)
}
} }
fun fetchTasks(callback: (SubtaskInfo) -> List<String>, subtasks: SubtaskInfo): List<TaskContainer> = runBlocking { fun fetchTasks(callback: (SubtaskInfo) -> List<String>, subtasks: SubtaskInfo): List<TaskContainer> = runBlocking {

@ -1,22 +1,22 @@
package com.todoroo.astrid.subtasks package com.todoroo.astrid.subtasks
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import com.todoroo.astrid.data.Task.Companion.isValidUuid import com.todoroo.astrid.data.Task.Companion.isValidUuid
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.tasks.Strings.isNullOrEmpty import org.tasks.Strings.isNullOrEmpty
import org.tasks.data.TaskListMetadata import org.tasks.data.TaskListMetadata
import org.tasks.data.TaskListMetadataDaoBlocking import org.tasks.data.TaskListMetadataDao
import org.tasks.db.QueryUtils.showHiddenAndCompleted import org.tasks.db.QueryUtils.showHiddenAndCompleted
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
class SubtasksFilterUpdater @Inject constructor( class SubtasksFilterUpdater @Inject constructor(
private val taskListMetadataDao: TaskListMetadataDaoBlocking, private val taskListMetadataDao: TaskListMetadataDao,
private val taskDao: TaskDaoBlocking) { private val taskDao: TaskDao) {
private val idToNode = HashMap<String, Node?>() private val idToNode = HashMap<String, Node?>()
private var treeRoot: Node? = null private var treeRoot: Node? = null
private fun getSerializedTree(list: TaskListMetadata?): String? { private fun getSerializedTree(list: TaskListMetadata?): String? {
@ -31,14 +31,14 @@ class SubtasksFilterUpdater @Inject constructor(
return order return order
} }
fun writeSerialization(list: TaskListMetadata?, serialized: String?) { suspend fun writeSerialization(list: TaskListMetadata?, serialized: String?) {
if (list != null) { if (list != null) {
list.taskIds = serialized list.taskIds = serialized
taskListMetadataDao.update(list) taskListMetadataDao.update(list)
} }
} }
fun initialize(list: TaskListMetadata?, filter: Filter) { suspend fun initialize(list: TaskListMetadata?, filter: Filter) {
initializeFromSerializedTree(list, filter, getSerializedTree(list)) initializeFromSerializedTree(list, filter, getSerializedTree(list))
applyToFilter(filter) applyToFilter(filter)
} }
@ -56,13 +56,13 @@ class SubtasksFilterUpdater @Inject constructor(
return n.indent return n.indent
} }
fun initializeFromSerializedTree(list: TaskListMetadata?, filter: Filter, serializedTree: String?) { suspend fun initializeFromSerializedTree(list: TaskListMetadata?, filter: Filter, serializedTree: String?) {
idToNode.clear() idToNode.clear()
treeRoot = buildTreeModel(serializedTree) { node -> node?.let { idToNode[it.uuid] = it } } treeRoot = buildTreeModel(serializedTree) { node -> node?.let { idToNode[it.uuid] = it } }
verifyTreeModel(list, filter) verifyTreeModel(list, filter)
} }
private fun verifyTreeModel(list: TaskListMetadata?, filter: Filter) { private suspend fun verifyTreeModel(list: TaskListMetadata?, filter: Filter) {
var changedThings = false var changedThings = false
val keySet: Set<String> = idToNode.keys val keySet: Set<String> = idToNode.keys
val currentIds: MutableSet<String> = HashSet(keySet) val currentIds: MutableSet<String> = HashSet(keySet)
@ -133,12 +133,12 @@ class SubtasksFilterUpdater @Inject constructor(
} }
} }
fun applyToDescendants(taskId: String?, visitor: (Node) -> Unit) { suspend fun applyToDescendants(taskId: String?, visitor: suspend (Node) -> Unit) {
val n = idToNode[taskId] ?: return val n = idToNode[taskId] ?: return
applyToDescendantsHelper(n, visitor) applyToDescendantsHelper(n, visitor)
} }
private fun applyToDescendantsHelper(n: Node, visitor: (Node) -> Unit) { private suspend fun applyToDescendantsHelper(n: Node, visitor: suspend (Node) -> Unit) {
val children = n.children val children = n.children
for (child in children) { for (child in children) {
visitor.invoke(child) visitor.invoke(child)
@ -146,12 +146,12 @@ class SubtasksFilterUpdater @Inject constructor(
} }
} }
fun indent(list: TaskListMetadata, filter: Filter, targetTaskId: String?, delta: Int) { suspend fun indent(list: TaskListMetadata, filter: Filter, targetTaskId: String?, delta: Int) {
val node = idToNode[targetTaskId] val node = idToNode[targetTaskId]
indentHelper(list, filter, node, delta) indentHelper(list, filter, node, delta)
} }
private fun indentHelper(list: TaskListMetadata, filter: Filter, node: Node?, delta: Int) { private suspend fun indentHelper(list: TaskListMetadata, filter: Filter, node: Node?, delta: Int) {
if (node == null) { if (node == null) {
return return
} }
@ -205,7 +205,7 @@ class SubtasksFilterUpdater @Inject constructor(
} }
} }
fun moveTo(list: TaskListMetadata, filter: Filter, targetTaskId: String?, beforeTaskId: String) { suspend fun moveTo(list: TaskListMetadata, filter: Filter, targetTaskId: String?, beforeTaskId: String) {
val target = idToNode[targetTaskId] ?: return val target = idToNode[targetTaskId] ?: return
if ("-1" == beforeTaskId) { // $NON-NLS-1$ if ("-1" == beforeTaskId) { // $NON-NLS-1$
moveToEndOfList(list, filter, target) moveToEndOfList(list, filter, target)
@ -229,7 +229,7 @@ class SubtasksFilterUpdater @Inject constructor(
setNodeIndent(toMove, toMove.parent!!.indent + 1) setNodeIndent(toMove, toMove.parent!!.indent + 1)
} }
private fun moveHelper(list: TaskListMetadata, filter: Filter, moveThis: Node, beforeThis: Node) { private suspend fun moveHelper(list: TaskListMetadata, filter: Filter, moveThis: Node, beforeThis: Node) {
val oldParent = moveThis.parent val oldParent = moveThis.parent
val oldSiblings = oldParent!!.children val oldSiblings = oldParent!!.children
val newParent = beforeThis.parent val newParent = beforeThis.parent
@ -269,7 +269,7 @@ class SubtasksFilterUpdater @Inject constructor(
return false return false
} }
private fun moveToEndOfList(list: TaskListMetadata, filter: Filter, moveThis: Node) { private suspend fun moveToEndOfList(list: TaskListMetadata, filter: Filter, moveThis: Node) {
val parent = moveThis.parent val parent = moveThis.parent
parent!!.children.remove(moveThis) parent!!.children.remove(moveThis)
treeRoot!!.children.add(moveThis) treeRoot!!.children.add(moveThis)
@ -279,7 +279,7 @@ class SubtasksFilterUpdater @Inject constructor(
applyToFilter(filter) applyToFilter(filter)
} }
fun onCreateTask(list: TaskListMetadata?, filter: Filter, uuid: String) { suspend fun onCreateTask(list: TaskListMetadata?, filter: Filter, uuid: String) {
if (idToNode.containsKey(uuid) || !isValidUuid(uuid)) { if (idToNode.containsKey(uuid) || !isValidUuid(uuid)) {
return return
} }
@ -290,7 +290,7 @@ class SubtasksFilterUpdater @Inject constructor(
applyToFilter(filter) applyToFilter(filter)
} }
fun onDeleteTask(list: TaskListMetadata?, filter: Filter, taskId: String?) { suspend fun onDeleteTask(list: TaskListMetadata?, filter: Filter, taskId: String?) {
val task = idToNode[taskId] ?: return val task = idToNode[taskId] ?: return
val parent = task.parent val parent = task.parent
val siblings = parent!!.children val siblings = parent!!.children

@ -4,7 +4,7 @@ import android.content.Context
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.core.BuiltInFilterExposer.Companion.isInbox import com.todoroo.astrid.core.BuiltInFilterExposer.Companion.isInbox
import com.todoroo.astrid.core.BuiltInFilterExposer.Companion.isTodayFilter import com.todoroo.astrid.core.BuiltInFilterExposer.Companion.isTodayFilter
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task.Companion.isValidUuid import com.todoroo.astrid.data.Task.Companion.isValidUuid
import com.todoroo.astrid.subtasks.SubtasksFilterUpdater.Companion.buildOrderString import com.todoroo.astrid.subtasks.SubtasksFilterUpdater.Companion.buildOrderString
import com.todoroo.astrid.subtasks.SubtasksFilterUpdater.Companion.buildTreeModel import com.todoroo.astrid.subtasks.SubtasksFilterUpdater.Companion.buildTreeModel
@ -12,9 +12,9 @@ import com.todoroo.astrid.subtasks.SubtasksFilterUpdater.Companion.serializeTree
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import org.tasks.Strings.isNullOrEmpty import org.tasks.Strings.isNullOrEmpty
import org.tasks.data.TagData import org.tasks.data.TagData
import org.tasks.data.TagDataDaoBlocking import org.tasks.data.TagDataDao
import org.tasks.data.TaskListMetadata import org.tasks.data.TaskListMetadata
import org.tasks.data.TaskListMetadataDaoBlocking import org.tasks.data.TaskListMetadataDao
import org.tasks.db.QueryUtils.showHiddenAndCompleted import org.tasks.db.QueryUtils.showHiddenAndCompleted
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import timber.log.Timber import timber.log.Timber
@ -24,10 +24,10 @@ import javax.inject.Inject
class SubtasksHelper @Inject constructor( class SubtasksHelper @Inject constructor(
@param:ApplicationContext private val context: Context, @param:ApplicationContext private val context: Context,
private val preferences: Preferences, private val preferences: Preferences,
private val taskDao: TaskDaoBlocking, private val taskDao: TaskDao,
private val tagDataDao: TagDataDaoBlocking, private val tagDataDao: TagDataDao,
private val taskListMetadataDao: TaskListMetadataDaoBlocking) { private val taskListMetadataDao: TaskListMetadataDao) {
fun applySubtasksToWidgetFilter(filter: Filter, query: String): String { suspend fun applySubtasksToWidgetFilter(filter: Filter, query: String): String {
var query = query var query = query
if (filter.supportsAstridSorting() && preferences.isAstridSort) { if (filter.supportsAstridSorting() && preferences.isAstridSort) {
val tagData = tagDataDao.getTagByName(filter.listingTitle) val tagData = tagDataDao.getTagByName(filter.listingTitle)
@ -49,7 +49,7 @@ class SubtasksHelper @Inject constructor(
return query return query
} }
private fun getOrderString(tagData: TagData?, tlm: TaskListMetadata?): String { private suspend fun getOrderString(tagData: TagData?, tlm: TaskListMetadata?): String {
val serialized: String? = when { val serialized: String? = when {
tlm != null -> tlm.taskIds tlm != null -> tlm.taskIds
tagData != null -> convertTreeToRemoteIds(taskDao, tagData.tagOrdering) tagData != null -> convertTreeToRemoteIds(taskDao, tagData.tagOrdering)
@ -87,7 +87,7 @@ class SubtasksHelper @Inject constructor(
} }
/** Takes a subtasks string containing local ids and remaps it to one containing UUIDs */ /** Takes a subtasks string containing local ids and remaps it to one containing UUIDs */
fun convertTreeToRemoteIds(taskDao: TaskDaoBlocking, localTree: String?): String { suspend fun convertTreeToRemoteIds(taskDao: TaskDao, localTree: String?): String {
val localIds = getIdList(localTree) val localIds = getIdList(localTree)
val idMap = getIdMap(taskDao, localIds) val idMap = getIdMap(taskDao, localIds)
idMap[-1L] = "-1" // $NON-NLS-1$ idMap[-1L] = "-1" // $NON-NLS-1$
@ -127,7 +127,7 @@ class SubtasksHelper @Inject constructor(
} }
} }
private fun getIdMap(taskDao: TaskDaoBlocking, keys: List<Long>): MutableMap<Long, String> { private suspend fun getIdMap(taskDao: TaskDao, keys: List<Long>): MutableMap<Long, String> {
val tasks = taskDao.fetch(keys) val tasks = taskDao.fetch(keys)
val map: MutableMap<Long, String> = HashMap() val map: MutableMap<Long, String> = HashMap()
for (task in tasks) { for (task in tasks) {

@ -2,6 +2,7 @@ package org.tasks.tasklist
import android.graphics.Canvas import android.graphics.Canvas
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.ItemTouchHelper.* import androidx.recyclerview.widget.ItemTouchHelper.*
@ -12,6 +13,9 @@ import com.todoroo.astrid.adapter.TaskAdapter
import com.todoroo.astrid.utility.Flags import com.todoroo.astrid.utility.Flags
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.PublishSubject
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.tasks.activities.DragAndDropDiffer import org.tasks.activities.DragAndDropDiffer
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
@ -20,6 +24,7 @@ import kotlin.math.max
import kotlin.math.min import kotlin.math.min
class DragAndDropRecyclerAdapter( class DragAndDropRecyclerAdapter(
private val scope: LifecycleCoroutineScope,
private val adapter: TaskAdapter, private val adapter: TaskAdapter,
private val recyclerView: RecyclerView, private val recyclerView: RecyclerView,
viewHolderFactory: ViewHolderFactory, viewHolderFactory: ViewHolderFactory,
@ -235,12 +240,16 @@ class DragAndDropRecyclerAdapter(
} else { } else {
from from
} }
scope.launch {
withContext(NonCancellable) {
adapter.moved(from, to, indent) adapter.moved(from, to, indent)
}
val task: TaskContainer = items.removeAt(from) val task: TaskContainer = items.removeAt(from)
items.add(if (from < to) to - 1 else to, task) items.add(if (from < to) to - 1 else to, task)
taskList.loadTaskListContent() taskList.loadTaskListContent()
} }
} }
}
companion object { companion object {
private const val LONG_LIST_SIZE = 500 private const val LONG_LIST_SIZE = 500

@ -9,7 +9,7 @@ import android.widget.RemoteViews
import android.widget.RemoteViewsService.RemoteViewsFactory import android.widget.RemoteViewsService.RemoteViewsFactory
import com.todoroo.andlib.utility.DateUtilities import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import com.todoroo.astrid.subtasks.SubtasksHelper import com.todoroo.astrid.subtasks.SubtasksHelper
import org.tasks.BuildConfig import org.tasks.BuildConfig
@ -17,6 +17,7 @@ import org.tasks.R
import org.tasks.data.SubtaskInfo import org.tasks.data.SubtaskInfo
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.data.TaskListQuery.getQuery import org.tasks.data.TaskListQuery.getQuery
import org.tasks.data.runBlocking
import org.tasks.locale.Locale import org.tasks.locale.Locale
import org.tasks.preferences.DefaultFilterProvider import org.tasks.preferences.DefaultFilterProvider
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
@ -31,7 +32,7 @@ internal class ScrollableViewsFactory(
private val preferences: Preferences, private val preferences: Preferences,
private val context: Context, private val context: Context,
private val widgetId: Int, private val widgetId: Int,
private val taskDao: TaskDaoBlocking, private val taskDao: TaskDao,
private val defaultFilterProvider: DefaultFilterProvider, private val defaultFilterProvider: DefaultFilterProvider,
private val checkBoxProvider: CheckBoxProvider, private val checkBoxProvider: CheckBoxProvider,
private val locale: Locale) : RemoteViewsFactory { private val locale: Locale) : RemoteViewsFactory {
@ -56,9 +57,14 @@ internal class ScrollableViewsFactory(
private var isRtl = false private var isRtl = false
private var tasks: List<TaskContainer> = ArrayList() private var tasks: List<TaskContainer> = ArrayList()
override fun onCreate() {} override fun onCreate() {}
override fun onDataSetChanged() { override fun onDataSetChanged() {
updateSettings() updateSettings()
tasks = taskDao.fetchTasks { subtasks: SubtaskInfo -> getQuery(filter, subtasks) } tasks = runBlocking {
taskDao.fetchTasks {
subtasks: SubtaskInfo -> getQuery(filter, subtasks)
}
}
} }
override fun onDestroy() {} override fun onDestroy() {}
@ -194,7 +200,7 @@ internal class ScrollableViewsFactory(
return if (position < tasks.size) tasks[position] else null return if (position < tasks.size) tasks[position] else null
} }
private fun getQuery(filter: Filter?, subtasks: SubtaskInfo): List<String> { private suspend fun getQuery(filter: Filter?, subtasks: SubtaskInfo): List<String> {
val queries = getQuery(preferences, filter!!, subtasks) val queries = getQuery(preferences, filter!!, subtasks)
val last = queries.size - 1 val last = queries.size - 1
queries[last] = subtasksHelper.applySubtasksToWidgetFilter(filter, queries[last]) queries[last] = subtasksHelper.applySubtasksToWidgetFilter(filter, queries[last])

@ -5,7 +5,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.widget.RemoteViewsService; import android.widget.RemoteViewsService;
import com.todoroo.astrid.dao.TaskDaoBlocking; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.subtasks.SubtasksHelper; import com.todoroo.astrid.subtasks.SubtasksHelper;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
import javax.inject.Inject; import javax.inject.Inject;
@ -18,7 +18,7 @@ import org.tasks.ui.CheckBoxProvider;
@AndroidEntryPoint @AndroidEntryPoint
public class ScrollableWidgetUpdateService extends RemoteViewsService { public class ScrollableWidgetUpdateService extends RemoteViewsService {
@Inject TaskDaoBlocking taskDao; @Inject TaskDao taskDao;
@Inject Preferences preferences; @Inject Preferences preferences;
@Inject SubtasksHelper subtasksHelper; @Inject SubtasksHelper subtasksHelper;
@Inject DefaultFilterProvider defaultFilterProvider; @Inject DefaultFilterProvider defaultFilterProvider;

Loading…
Cancel
Save