Convert GoogleTask to CaldavTask

pull/2146/head
Alex Baker 1 year ago
parent 513f8b017f
commit 2006e2c84b

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 88,
"identityHash": "d9d2cc4048325dbde272d8d4f8e3880f",
"identityHash": "8ddd120bc22139ab9c9d69dbc727df37",
"entities": [
{
"tableName": "notification",
@ -725,118 +725,6 @@
}
]
},
{
"tableName": "google_tasks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`gt_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `gt_task` INTEGER NOT NULL, `gt_remote_id` TEXT, `gt_list_id` TEXT, `gt_parent` INTEGER NOT NULL, `gt_remote_parent` TEXT, `gt_moved` INTEGER NOT NULL, `gt_order` INTEGER NOT NULL, `gt_remote_order` INTEGER NOT NULL, `gt_last_sync` INTEGER NOT NULL, `gt_deleted` INTEGER NOT NULL, FOREIGN KEY(`gt_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "gt_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "gt_task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "remoteId",
"columnName": "gt_remote_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "listId",
"columnName": "gt_list_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "parent",
"columnName": "gt_parent",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "remoteParent",
"columnName": "gt_remote_parent",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "isMoved",
"columnName": "gt_moved",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "order",
"columnName": "gt_order",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "remoteOrder",
"columnName": "gt_remote_order",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastSync",
"columnName": "gt_last_sync",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "deleted",
"columnName": "gt_deleted",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"gt_id"
],
"autoGenerate": true
},
"indices": [
{
"name": "gt_list_parent",
"unique": false,
"columnNames": [
"gt_list_id",
"gt_parent"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `gt_list_parent` ON `${TABLE_NAME}` (`gt_list_id`, `gt_parent`)"
},
{
"name": "index_google_tasks_gt_task",
"unique": false,
"columnNames": [
"gt_task"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_google_tasks_gt_task` ON `${TABLE_NAME}` (`gt_task`)"
}
],
"foreignKeys": [
{
"table": "tasks",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"gt_task"
],
"referencedColumns": [
"_id"
]
}
]
},
{
"tableName": "filters",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `sql` TEXT, `values` TEXT, `criterion` TEXT, `f_color` INTEGER, `f_icon` INTEGER, `f_order` INTEGER NOT NULL)",
@ -981,7 +869,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, `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, `gt_parent` INTEGER NOT NULL, `cd_order` INTEGER, FOREIGN KEY(`cd_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
@ -1037,6 +925,24 @@
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "isMoved",
"columnName": "gt_moved",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "remoteOrder",
"columnName": "gt_remote_order",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "parent",
"columnName": "gt_parent",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "order",
"columnName": "cd_order",
@ -1397,7 +1303,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, 'd9d2cc4048325dbde272d8d4f8e3880f')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8ddd120bc22139ab9c9d69dbc727df37')"
]
}
}

@ -13,7 +13,6 @@ import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Test
import org.tasks.data.GoogleTask
import org.tasks.data.GoogleTaskDao
import org.tasks.injection.InjectingTestCase
import org.tasks.injection.ProductionModule

@ -49,7 +49,7 @@ class TaskMoverTest : InjectingTestCase() {
createTasks(1)
googleTaskDao.insert(newGoogleTask(with(TASK, 1), with(LIST, "1")))
moveToGoogleTasks("2", 1)
assertEquals("2", googleTaskDao.getByTaskId(1)!!.listId)
assertEquals("2", googleTaskDao.getByTaskId(1)!!.calendar)
}
@Test
@ -75,7 +75,7 @@ class TaskMoverTest : InjectingTestCase() {
assertTrue(deleted[0].deleted > 0)
val task = googleTaskDao.getByTaskId(2)!!
assertEquals(1, task.parent)
assertEquals("2", task.listId)
assertEquals("2", task.calendar)
}
@Test
@ -194,7 +194,7 @@ class TaskMoverTest : InjectingTestCase() {
moveToGoogleTasks("2", 2)
val task = googleTaskDao.getByTaskId(2)!!
assertEquals(0L, task.parent)
assertEquals("2", task.listId)
assertEquals("2", task.calendar)
}
@Test
@ -228,7 +228,7 @@ class TaskMoverTest : InjectingTestCase() {
createTasks(1)
caldavDao.insert(newCaldavTask(with(CaldavTaskMaker.TASK, 1L), with(CALENDAR, "1")))
moveToGoogleTasks("2", 1)
assertEquals("2", googleTaskDao.getByTaskId(1L)!!.listId)
assertEquals("2", googleTaskDao.getByTaskId(1L)!!.calendar)
}
@Test

@ -264,7 +264,7 @@ class GoogleTaskDaoTests : InjectingTestCase() {
val googleTask = googleTaskDao.getByRemoteId(remoteId)!!
val result = SubsetGoogleTask()
result.gt_id = googleTask.id
result.gt_list_id = googleTask.listId
result.gt_list_id = googleTask.calendar
result.gt_order = googleTask.order
result.gt_parent = googleTask.parent
return result

@ -980,7 +980,6 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
companion object {
const val TAGS_METADATA_JOIN = "for_tags" // $NON-NLS-1$
const val GTASK_METADATA_JOIN = "googletask" // $NON-NLS-1$
const val CALDAV_METADATA_JOIN = "for_caldav" // $NON-NLS-1$
const val ACTION_RELOAD = "action_reload"
const val ACTION_DELETED = "action_deleted"

@ -15,21 +15,21 @@ class GoogleTaskManualSortAdapter internal constructor(
override suspend fun moved(from: Int, to: Int, indent: Int) {
val task = getTask(from)
val googleTask = task.googleTask
val googleTask = task.caldavTask
val previous = if (to > 0) getTask(to - 1) else null
if (previous == null) {
googleTaskDao.move(googleTask, 0, 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 == googleTask.parent -> googleTaskDao.move(googleTask, previous.parent, previous.getSecondarySort() + 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)
}
} else {
when {
indent == 0 -> googleTaskDao.move(googleTask, 0, previous.getPrimarySort() + if (task.hasParent()) 1 else 0)
previous.hasParent() && previous.parent == googleTask.parent -> googleTaskDao.move(googleTask, previous.parent, previous.getSecondarySort())
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)
}
@ -37,7 +37,7 @@ class GoogleTaskManualSortAdapter internal constructor(
taskDao.touch(task.id)
localBroadcastManager.broadcastRefresh()
if (BuildConfig.DEBUG) {
googleTaskDao.validateSorting(task.googleTaskList!!)
googleTaskDao.validateSorting(task.caldav!!)
}
}
}

@ -135,21 +135,15 @@ open class TaskAdapter(
open suspend fun moved(from: Int, to: Int, indent: Int) {
val task = getTask(from)
val newParent = findParent(indent, to)
if (newParent?.id ?: 0 == task.parent) {
if ((newParent?.id ?: 0) == task.parent) {
if (indent == 0) {
changeSortGroup(task, if (from < to) to - 1 else to)
}
return
} else if (newParent != null) {
when {
task.isGoogleTask -> if (task.googleTaskList != newParent.googleTaskList) {
googleTaskDao.markDeleted(task.id)
task.googletask = null
}
task.isCaldavTask -> if (task.caldav != newParent.caldav) {
caldavDao.markDeleted(listOf(task.id))
task.caldavTask = null
}
if (task.caldav != newParent.caldav) {
caldavDao.markDeleted(listOf(task.id))
task.caldavTask = null
}
}
when {
@ -250,20 +244,21 @@ open class TaskAdapter(
}
private suspend fun changeGoogleTaskParent(task: TaskContainer, newParent: TaskContainer?) {
val list = newParent?.googleTaskList ?: task.googleTaskList!!
if (newParent == null || task.googleTaskList == newParent.googleTaskList) {
val list = newParent?.caldav ?: task.caldav!!
if (newParent == null || task.caldav == newParent.caldav) {
googleTaskDao.move(
task.googleTask,
newParent?.id ?: 0,
if (newTasksOnTop) 0 else googleTaskDao.getBottom(list, newParent?.id ?: 0))
task.caldavTask,
newParent?.id ?: 0,
if (newTasksOnTop) 0 else googleTaskDao.getBottom(list, newParent?.id ?: 0)
)
} else {
val googleTask = GoogleTask(task.id, list)
val googleTask = CaldavTask(task.id, list)
googleTask.parent = newParent.id
googleTaskDao.insertAndShift(googleTask, newTasksOnTop)
task.googletask = SubsetGoogleTask().apply {
gt_id = googleTask.id
gt_list_id = googleTask.listId
gt_order = googleTask.order
task.caldavTask = SubsetCaldav().apply {
cd_id = googleTask.id
cd_calendar = googleTask.calendar
cd_order = googleTask.order ?: 0
gt_parent = googleTask.parent
}
}

@ -12,6 +12,7 @@ import com.todoroo.astrid.data.Task;
import org.tasks.R;
import org.tasks.data.CaldavCalendar;
import org.tasks.data.CaldavTask;
import org.tasks.data.GoogleTask;
import org.tasks.data.TaskDao;
@ -57,12 +58,12 @@ public class GtasksFilter extends Filter {
private static QueryTemplate getQueryTemplate(CaldavCalendar list) {
return new QueryTemplate()
.join(Join.left(GoogleTask.TABLE, Task.ID.eq(GoogleTask.TASK)))
.join(Join.left(CaldavTask.TABLE, Task.ID.eq(CaldavTask.TASK)))
.where(
Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(),
GoogleTask.DELETED.eq(0),
GoogleTask.LIST.eq(list.getUuid())));
CaldavTask.DELETED.eq(0),
CaldavTask.CALENDAR.eq(list.getUuid())));
}
private static Map<String, Object> getValuesForNewTasks(CaldavCalendar list) {

@ -61,11 +61,6 @@ class SearchFilter : Filter {
.from(CaldavTask.TABLE)
.join(Join.inner(CaldavCalendar.TABLE, CaldavCalendar.UUID.eq(CaldavTask.CALENDAR)))
.where(CaldavCalendar.NAME.like(matcher))),
Task.ID.`in`(
Query.select(GoogleTask.TASK)
.from(GoogleTask.TABLE)
.join(Join.inner(CaldavCalendar.TABLE, CaldavCalendar.UUID.eq(GoogleTask.LIST)))
.where(CaldavCalendar.NAME.like(matcher)))
)))
}
}

@ -101,9 +101,8 @@ class BuiltInFilterExposer @Inject constructor(
Filter(
"No list",
QueryTemplate()
.join(Join.left(GoogleTask.TABLE, GoogleTask.TASK.eq(Task.ID)))
.join(Join.left(CaldavTask.TABLE, CaldavTask.TASK.eq(Task.ID)))
.where(and(GoogleTask.ID.eq(null), CaldavTask.ID.eq(null)))
.where(CaldavTask.ID.eq(null))
).apply {
icon = R.drawable.ic_outline_cloud_off_24px
}
@ -116,13 +115,9 @@ class BuiltInFilterExposer @Inject constructor(
Filter(
"Missing list",
QueryTemplate()
.join(Join.left(GoogleTask.TABLE, GoogleTask.TASK.eq(Task.ID)))
.join(Join.left(CaldavTask.TABLE, CaldavTask.TASK.eq(Task.ID)))
.join(Join.left(CaldavCalendar.TABLE.`as`("google_task_lists"), CaldavCalendar.TABLE.`as`("google_task_lists").column("cdl_uuid").eq(GoogleTask.LIST)))
.join(Join.left(CaldavCalendar.TABLE, CaldavCalendar.UUID.eq(CaldavTask.CALENDAR)))
.where(or(
and(GoogleTask.ID.gt(0), CaldavCalendar.TABLE.`as`("google_task_lists").column("cdl_uuid").eq(null)),
and(CaldavTask.ID.gt(0), CaldavCalendar.UUID.eq(null))))
.where(and(CaldavTask.ID.gt(0), CaldavCalendar.UUID.eq(null)))
).apply {
icon = R.drawable.ic_outline_cloud_off_24px
}
@ -131,14 +126,10 @@ class BuiltInFilterExposer @Inject constructor(
Filter(
"Missing account",
QueryTemplate()
.join(Join.left(GoogleTask.TABLE, and(GoogleTask.TASK.eq(Task.ID))))
.join(Join.left(CaldavTask.TABLE, and(CaldavTask.TASK.eq(Task.ID))))
.join(Join.left(CaldavCalendar.TABLE.`as`("google_task_lists"), CaldavCalendar.TABLE.`as`("google_task_lists").column("cdl_uuid").eq(GoogleTask.LIST)))
.join(Join.left(CaldavCalendar.TABLE, CaldavCalendar.UUID.eq(CaldavTask.CALENDAR)))
.join(Join.left(CaldavAccount.TABLE, CaldavAccount.UUID.eq(CaldavCalendar.ACCOUNT)))
.where(or(
and(GoogleTask.ID.gt(0), CaldavCalendar.TABLE.`as`("google_task_lists").column("cdl_uuid").eq(null)),
and(CaldavTask.ID.gt(0), CaldavAccount.UUID.eq(null))))
.where(and(CaldavTask.ID.gt(0), CaldavAccount.UUID.eq(null)))
).apply {
icon = R.drawable.ic_outline_cloud_off_24px
}

@ -176,7 +176,7 @@ public class SortHelper {
select = "tasks.created AS sort_created";
break;
case SORT_GTASKS:
select = "google_tasks.gt_order AS sort_manual";
select = "caldav_tasks.cd_order AS sort_manual";
break;
case SORT_CALDAV:
select = CALDAV_ORDER_COLUMN + " AS sort_manual";

@ -22,7 +22,6 @@ import org.tasks.notifications.NotificationDao
Place::class,
Geofence::class,
Tag::class,
GoogleTask::class,
Filter::class,
CaldavCalendar::class,
CaldavTask::class,

@ -53,7 +53,7 @@ class GtasksListService @Inject constructor(
// check for lists that aren't on remote server
for (listId in previousLists) {
taskDeleter.deleteGoogleTaskList(googleTaskListDao.getById(listId)!!)
taskDeleter.delete(googleTaskListDao.getById(listId)!!)
}
localBroadcastManager.broadcastRefreshList()
}

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

@ -2,7 +2,6 @@ package com.todoroo.astrid.service
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.data.Task
import kotlinx.coroutines.runBlocking
import org.tasks.LocalBroadcastManager
import org.tasks.caldav.VtodoCache
import org.tasks.data.*
@ -66,12 +65,6 @@ class TaskDeleter @Inject constructor(
localBroadcastManager.broadcastRefresh()
}
fun deleteGoogleTaskList(list: CaldavCalendar) = runBlocking {
val tasks = deletionDao.deleteGoogleTaskList(list)
delete(tasks)
localBroadcastManager.broadcastRefreshList()
}
suspend fun delete(list: CaldavCalendar) {
vtodoCache.delete(list)
val tasks = deletionDao.delete(list)

@ -58,7 +58,7 @@ class TaskDuplicator @Inject constructor(
val googleTask = googleTaskDao.getByTaskId(originalId)
val addToTop = preferences.addTasksToTop()
if (googleTask != null) {
googleTaskDao.insertAndShift(GoogleTask(clone.id, googleTask.listId!!), addToTop)
googleTaskDao.insertAndShift(CaldavTask(clone.id, googleTask.calendar!!), addToTop)
}
val caldavTask = caldavDao.getTask(originalId)
if (caldavTask != null) {

@ -82,21 +82,21 @@ class TaskMover @Inject constructor(
moveLocalTask(task, selectedList)
}
private suspend fun moveGoogleTask(task: Task, googleTask: GoogleTask, selected: Filter) {
if (selected is GtasksFilter && googleTask.listId == selected.remoteId) {
private suspend fun moveGoogleTask(task: Task, googleTask: CaldavTask, selected: Filter) {
if (selected is GtasksFilter && googleTask.calendar == selected.remoteId) {
return
}
val id = googleTask.task
val children = googleTaskDao.getChildren(id)
val childIds = children.map(GoogleTask::task)
val childIds = children.map(CaldavTask::task)
googleTaskDao.markDeleted(id, DateUtilities.now())
when(selected) {
is GtasksFilter -> {
val listId = selected.remoteId
googleTaskDao.insertAndShift(GoogleTask(id, listId), preferences.addTasksToTop())
googleTaskDao.insertAndShift(CaldavTask(id, listId), preferences.addTasksToTop())
children.takeIf { it.isNotEmpty() }
?.map {
val newChild = GoogleTask(it.task, listId)
val newChild = CaldavTask(it.task, listId)
newChild.order = it.order
newChild.parent = id
newChild
@ -178,10 +178,10 @@ class TaskMover @Inject constructor(
private suspend fun moveToGoogleTasks(id: Long, children: List<Long>, filter: GtasksFilter) {
taskDao.setParent(0, children)
val listId = filter.remoteId
googleTaskDao.insertAndShift(GoogleTask(id, listId), preferences.addTasksToTop())
googleTaskDao.insertAndShift(CaldavTask(id, listId), preferences.addTasksToTop())
children.takeIf { it.isNotEmpty() }
?.mapIndexed { index, task ->
val newChild = GoogleTask(task, listId)
val newChild = CaldavTask(task, listId)
newChild.order = index.toLong()
newChild.parent = id
newChild

@ -8,6 +8,7 @@ import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.ProgressBar
import androidx.activity.viewModels
import androidx.lifecycle.lifecycleScope
import com.google.android.material.textfield.TextInputEditText
import com.google.api.services.tasks.model.TaskList
import com.todoroo.astrid.activity.MainActivity
@ -15,6 +16,9 @@ import com.todoroo.astrid.activity.TaskListFragment
import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.service.TaskDeleter
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.tasks.R
import org.tasks.Strings.isNullOrEmpty
import org.tasks.data.CaldavAccount
@ -177,9 +181,13 @@ class GoogleTaskListSettingsActivity : BaseListSettingsActivity() {
private fun onListDeleted(deleted: Boolean) {
if (deleted) {
taskDeleter.deleteGoogleTaskList(gtasksList)
setResult(Activity.RESULT_OK, Intent(TaskListFragment.ACTION_DELETED))
finish()
lifecycleScope.launch {
withContext(NonCancellable) {
taskDeleter.delete(gtasksList)
}
setResult(Activity.RESULT_OK, Intent(TaskListFragment.ACTION_DELETED))
finish()
}
}
}

@ -26,11 +26,11 @@ class BackupContainer(
val alarms: List<Alarm>,
val geofences: List<Geofence>?,
val tags: List<Tag>,
val google: List<GoogleTask>,
val comments: List<UserActivity>,
val attachments: List<Attachment>?,
val caldavTasks: List<CaldavTask>?,
val vtodo: String?,
val google: List<GoogleTask> = emptyList(),
) {
val locations: List<LegacyLocation> = emptyList()
}

@ -37,9 +37,7 @@ class TasksJsonExporter @Inject constructor(
private val alarmDao: AlarmDao,
private val locationDao: LocationDao,
private val tagDao: TagDao,
private val googleTaskDao: GoogleTaskDao,
private val filterDao: FilterDao,
private val googleTaskListDao: GoogleTaskListDao,
private val taskAttachmentDao: TaskAttachmentDao,
private val caldavDao: CaldavDao,
private val workManager: WorkManager,
@ -117,7 +115,6 @@ class TasksJsonExporter @Inject constructor(
alarmDao.getAlarms(taskId),
locationDao.getGeofencesForTask(taskId),
tagDao.getTagsForTask(taskId),
googleTaskDao.getAllByTaskId(taskId),
userActivityDao.getComments(taskId),
taskAttachmentDao.getAttachmentsForTask(taskId),
caldavTasks,

@ -187,8 +187,14 @@ class TasksJsonImporter @Inject constructor(
userActivityDao.createNew(comment)
}
for (googleTask in backup.google) {
googleTask.task = taskId
googleTaskDao.insert(googleTask)
googleTaskDao.insert(
CaldavTask(
task = taskId,
calendar = googleTask.listId,
remoteId = googleTask.remoteId,
`object` = null,
)
)
}
for (location in backup.locations) {
val place = newPlace()

@ -28,13 +28,13 @@ import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.data.Task
import org.tasks.compose.*
import org.tasks.data.GoogleTask
import org.tasks.data.CaldavTask
import org.tasks.data.TaskContainer
@Composable
fun SubtaskRow(
filter: Filter?,
googleTask: GoogleTask?,
googleTask: CaldavTask?,
desaturate: Boolean,
existingSubtasks: List<TaskContainer>,
newSubtasks: List<Task>,
@ -63,7 +63,7 @@ fun SubtaskRow(
Column {
val isGoogleTaskChild =
filter is GtasksFilter && googleTask != null && googleTask.parent > 0 && googleTask.listId == filter.remoteId
filter is GtasksFilter && googleTask != null && googleTask.parent > 0 && googleTask.calendar == filter.remoteId
if (isGoogleTaskChild) {
DisabledText(
text = stringResource(id = org.tasks.R.string.subtasks_multilevel_google_task),

@ -230,6 +230,7 @@ class CaldavAccount : Parcelable {
companion object {
val TABLE = Table("caldav_accounts")
val UUID = TABLE.column("cda_uuid")
val ACCOUNT_TYPE = TABLE.column("cda_account_type")
const val TYPE_CALDAV = 0
@Deprecated("use etebase") const val TYPE_ETESYNC = 1

@ -108,10 +108,26 @@ ORDER BY CASE cda_account_type
return insert(caldavTask)
}
@Query("SELECT MIN(IFNULL(cd_order, (created - $APPLE_EPOCH) / 1000)) FROM caldav_tasks INNER JOIN tasks ON _id = cd_task WHERE cd_calendar = :calendar AND cd_deleted = 0 AND deleted = 0 AND parent = :parent")
@Query("""
SELECT MIN(IFNULL(cd_order, (created - $APPLE_EPOCH) / 1000))
FROM caldav_tasks
INNER JOIN tasks ON _id = cd_task
WHERE cd_calendar = :calendar
AND cd_deleted = 0
AND deleted = 0
AND parent = :parent
""")
internal abstract suspend fun findFirstTask(calendar: String, parent: Long): Long?
@Query("SELECT MAX(IFNULL(cd_order, (created - $APPLE_EPOCH) / 1000)) FROM caldav_tasks INNER JOIN tasks ON _id = cd_task WHERE cd_calendar = :calendar AND cd_deleted = 0 AND deleted = 0 AND parent = :parent")
@Query("""
SELECT MAX(IFNULL(cd_order, (created - $APPLE_EPOCH) / 1000))
FROM caldav_tasks
INNER JOIN tasks ON _id = cd_task
WHERE cd_calendar = :calendar
AND cd_deleted = 0
AND deleted = 0
AND parent = :parent
""")
internal abstract suspend fun findLastTask(calendar: String, parent: Long): Long?
@Insert
@ -250,12 +266,16 @@ SELECT EXISTS(SELECT 1
@Query("""
SELECT caldav_lists.*, COUNT(DISTINCT(tasks._id)) AS count, COUNT(DISTINCT(principal_access.id)) AS principals
FROM caldav_lists
LEFT JOIN caldav_tasks
ON caldav_tasks.cd_calendar = caldav_lists.cdl_uuid
LEFT JOIN tasks ON caldav_tasks.cd_task = tasks._id AND tasks.deleted = 0 AND tasks.completed = 0 AND
tasks.hideUntil < :now AND cd_deleted = 0
LEFT JOIN caldav_tasks ON caldav_tasks.cd_calendar = caldav_lists.cdl_uuid
LEFT JOIN tasks ON caldav_tasks.cd_task = tasks._id AND
tasks.deleted = 0 AND
tasks.completed = 0 AND
tasks.hideUntil < :now AND
cd_deleted = 0
LEFT JOIN principal_access ON caldav_lists.cdl_id = principal_access.list
INNER JOIN caldav_accounts ON caldav_accounts.cda_uuid = caldav_lists.cdl_account
WHERE caldav_lists.cdl_account = :uuid
AND caldav_accounts.cda_account_type != $TYPE_GOOGLE_TASKS
GROUP BY caldav_lists.cdl_uuid
""")
abstract suspend fun getCaldavFilters(uuid: String, now: Long = currentTimeMillis()): List<CaldavFilters>
@ -321,7 +341,18 @@ GROUP BY caldav_lists.cdl_uuid
@Query("UPDATE tasks SET modified = :modificationTime WHERE _id in (:ids)")
internal abstract suspend 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")
@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 suspend fun getTasksToShift(calendar: String, parent: Long, from: Long, to: Long?): List<CaldavTaskContainer>
@Query("UPDATE caldav_lists SET cdl_order = $NO_ORDER")

@ -52,8 +52,18 @@ class CaldavTask {
@ColumnInfo(name = "cd_remote_parent")
var remoteParent: String? = null
@ColumnInfo(name = "cd_order")
@ColumnInfo(name = "gt_moved")
var isMoved: Boolean = false
@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")
var order: Long? = null
constructor()
@ -83,8 +93,9 @@ 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")
}
}
}

@ -55,17 +55,6 @@ WHERE recurring = 1
ids.eachChunk(this::markDeletedInternal)
}
@Query("SELECT gt_task FROM google_tasks WHERE gt_deleted = 0 AND gt_list_id = :listId")
internal abstract suspend fun getActiveGoogleTasks(listId: String): List<Long>
@Transaction
open suspend fun deleteGoogleTaskList(googleTaskList: CaldavCalendar): List<Long> {
val tasks = getActiveGoogleTasks(googleTaskList.uuid!!)
delete(tasks)
delete(googleTaskList)
return tasks
}
@Query("SELECT * FROM caldav_lists WHERE cdl_account = :account ORDER BY cdl_name ASC")
abstract suspend fun getLists(account: String): List<CaldavCalendar>
@ -95,14 +84,8 @@ WHERE recurring = 1
@Transaction
open suspend fun delete(caldavAccount: CaldavAccount): List<Long> {
val deleted = ArrayList<Long>()
if (caldavAccount.isGoogleTasks) {
for (list in getLists(caldavAccount.uuid!!)) {
deleted.addAll(deleteGoogleTaskList(list))
}
} else {
for (calendar in getCalendars(caldavAccount.uuid!!)) {
deleted.addAll(delete(calendar))
}
for (calendar in getCalendars(caldavAccount.uuid!!)) {
deleted.addAll(delete(calendar))
}
deleteCaldavAccount(caldavAccount)
return deleted

@ -1,126 +1,15 @@
package org.tasks.data
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import com.todoroo.andlib.data.Table
import com.todoroo.astrid.data.Task
@Entity(
tableName = "google_tasks",
indices = [
Index(name = "gt_list_parent", value = ["gt_list_id", "gt_parent"])
],
foreignKeys = [
ForeignKey(
entity = Task::class,
parentColumns = ["_id"],
childColumns = ["gt_task"],
onDelete = ForeignKey.CASCADE,
),
]
)
class GoogleTask {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "gt_id")
@Transient
var id: Long = 0
@ColumnInfo(name = "gt_task", index = true)
@Transient
var task: Long = 0
@ColumnInfo(name = "gt_remote_id")
var remoteId: String? = ""
@ColumnInfo(name = "gt_list_id")
var listId: String? = ""
@ColumnInfo(name = "gt_parent")
@Transient
var parent: Long = 0
@ColumnInfo(name = "gt_remote_parent")
var remoteParent: String? = null
set(value) {
field = if (value?.isNotBlank() == true) value else null
}
@ColumnInfo(name = "gt_moved")
@Transient
var isMoved = false
@ColumnInfo(name = "gt_order")
@Transient
var order: Long = 0
@ColumnInfo(name = "gt_remote_order")
var remoteOrder: Long = 0
@ColumnInfo(name = "gt_last_sync")
var lastSync: Long = 0
@ColumnInfo(name = "gt_deleted")
var deleted: Long = 0
constructor()
@Ignore
constructor(task: Long, listId: String) {
this.task = task
this.listId = listId
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is GoogleTask) return false
if (id != other.id) return false
if (task != other.task) return false
if (remoteId != other.remoteId) return false
if (listId != other.listId) return false
if (parent != other.parent) return false
if (remoteParent != other.remoteParent) return false
if (isMoved != other.isMoved) return false
if (order != other.order) return false
if (remoteOrder != other.remoteOrder) return false
if (lastSync != other.lastSync) return false
if (deleted != other.deleted) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + task.hashCode()
result = 31 * result + remoteId.hashCode()
result = 31 * result + listId.hashCode()
result = 31 * result + parent.hashCode()
result = 31 * result + (remoteParent?.hashCode() ?: 0)
result = 31 * result + isMoved.hashCode()
result = 31 * result + order.hashCode()
result = 31 * result + remoteOrder.hashCode()
result = 31 * result + lastSync.hashCode()
result = 31 * result + deleted.hashCode()
return result
}
override fun toString(): String =
"GoogleTask(id=$id, task=$task, remoteId='$remoteId', listId='$listId', parent=$parent, remoteParent=$remoteParent, isMoved=$isMoved, order=$order, remoteOrder=$remoteOrder, lastSync=$lastSync, deleted=$deleted)"
val isNew: Boolean
get() = id == 0L
@Deprecated("For backup use only")
data class GoogleTask(
var remoteId: String? = "",
var listId: String? = "",
var remoteParent: String? = null,
var remoteOrder: Long = 0,
var lastSync: Long = 0,
var deleted: Long = 0,
) {
companion object {
const val KEY = "gtasks"
@JvmField val TABLE = Table("google_tasks")
val ID = TABLE.column("gt_id")
@JvmField val PARENT = TABLE.column("gt_parent")
@JvmField val TASK = TABLE.column("gt_task")
@JvmField val DELETED = TABLE.column("gt_deleted")
@JvmField val LIST = TABLE.column("gt_list_id")
}
}

@ -9,166 +9,219 @@ import org.tasks.time.DateTimeUtils.currentTimeMillis
@Dao
abstract class GoogleTaskDao {
@Insert
abstract suspend fun insert(task: GoogleTask): Long
abstract suspend fun insert(task: CaldavTask): Long
@Insert
abstract suspend fun insert(tasks: Iterable<GoogleTask>)
abstract suspend fun insert(tasks: Iterable<CaldavTask>)
@Transaction
open suspend fun insertAndShift(task: GoogleTask, top: Boolean) {
open suspend fun insertAndShift(task: CaldavTask, top: Boolean) {
if (top) {
task.order = 0
shiftDown(task.listId!!, task.parent, 0)
shiftDown(task.calendar!!, task.parent, 0)
} else {
task.order = getBottom(task.listId!!, task.parent)
task.order = getBottom(task.calendar!!, task.parent)
}
task.id = insert(task)
}
@Query("UPDATE google_tasks SET gt_order = gt_order + 1 WHERE gt_list_id = :listId AND gt_parent = :parent AND gt_order >= :position")
@Query("UPDATE caldav_tasks SET cd_order = cd_order + 1 WHERE cd_calendar = :listId AND gt_parent = :parent AND cd_order >= :position")
internal abstract suspend fun shiftDown(listId: String, parent: Long, position: Long)
@Query("UPDATE google_tasks SET gt_order = gt_order - 1 WHERE gt_list_id = :listId AND gt_parent = :parent AND gt_order > :from AND gt_order <= :to")
@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")
internal abstract suspend fun shiftUp(listId: String, parent: Long, from: Long, to: Long)
@Query("UPDATE google_tasks SET gt_order = gt_order + 1 WHERE gt_list_id = :listId AND gt_parent = :parent AND gt_order < :from AND gt_order >= :to")
@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")
internal abstract suspend fun shiftDown(listId: String, parent: Long, from: Long, to: Long)
@Query("UPDATE google_tasks SET gt_order = gt_order - 1 WHERE gt_list_id = :listId AND gt_parent = :parent AND gt_order >= :position")
@Query("UPDATE caldav_tasks SET cd_order = cd_order - 1 WHERE cd_calendar = :listId AND gt_parent = :parent AND cd_order >= :position")
internal abstract suspend fun shiftUp(listId: String, parent: Long, position: Long)
@Transaction
open suspend fun move(task: SubsetGoogleTask, newParent: Long, newPosition: Long) {
val previousParent = task.parent
val previousPosition = task.order
open suspend fun move(task: SubsetCaldav, newParent: Long, newPosition: Long) {
val previousParent = task.gt_parent
val previousPosition = task.cd_order!!
if (newParent == previousParent) {
if (previousPosition < newPosition) {
shiftUp(task.listId, newParent, previousPosition, newPosition)
shiftUp(task.cd_calendar!!, newParent, previousPosition, newPosition)
} else {
shiftDown(task.listId, newParent, previousPosition, newPosition)
shiftDown(task.cd_calendar!!, newParent, previousPosition, newPosition)
}
} else {
shiftUp(task.listId, previousParent, previousPosition)
shiftDown(task.listId, newParent, newPosition)
shiftUp(task.cd_calendar!!, previousParent, previousPosition)
shiftDown(task.cd_calendar!!, newParent, newPosition)
}
task.parent = newParent
task.order = newPosition
task.gt_parent = newParent
task.cd_order = newPosition
update(task)
}
@Query("SELECT * FROM google_tasks WHERE gt_task = :taskId AND gt_deleted = 0 LIMIT 1")
abstract suspend fun getByTaskId(taskId: Long): GoogleTask?
@Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId AND cd_deleted = 0 LIMIT 1")
abstract suspend fun getByTaskId(taskId: Long): CaldavTask?
@Query("SELECT * FROM google_tasks WHERE gt_task = :taskId AND gt_deleted = 0 LIMIT 1")
abstract fun watchGoogleTask(taskId: Long): Flow<GoogleTask?>
@Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId AND cd_deleted = 0 LIMIT 1")
abstract fun watchGoogleTask(taskId: Long): Flow<CaldavTask?>
@Update
abstract suspend fun update(googleTask: GoogleTask)
abstract suspend fun update(googleTask: CaldavTask)
private suspend fun update(googleTask: SubsetGoogleTask) {
update(googleTask.id, googleTask.parent, googleTask.order)
private suspend fun update(googleTask: SubsetCaldav) {
update(googleTask.cd_id, googleTask.gt_parent, googleTask.cd_order!!)
}
@Query("UPDATE google_tasks SET gt_order = :order, gt_parent = :parent, gt_moved = 1 WHERE gt_id = :id")
@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 google_tasks SET gt_deleted = :now WHERE gt_task = :task OR gt_parent = :task")
@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())
@Delete
abstract suspend fun delete(deleted: GoogleTask)
abstract suspend fun delete(deleted: CaldavTask)
@Query("SELECT * FROM google_tasks WHERE gt_remote_id = :remoteId LIMIT 1")
abstract suspend fun getByRemoteId(remoteId: String): GoogleTask?
@Query("SELECT * FROM caldav_tasks WHERE cd_remote_id = :remoteId LIMIT 1")
abstract suspend fun getByRemoteId(remoteId: String): CaldavTask?
@Query("SELECT * FROM google_tasks WHERE gt_task = :taskId AND gt_deleted > 0")
abstract suspend fun getDeletedByTaskId(taskId: Long): List<GoogleTask>
@Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId AND cd_deleted > 0")
abstract suspend fun getDeletedByTaskId(taskId: Long): List<CaldavTask>
@Query("SELECT * FROM google_tasks WHERE gt_task = :taskId")
abstract suspend fun getAllByTaskId(taskId: Long): List<GoogleTask>
@Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId")
abstract suspend fun getAllByTaskId(taskId: Long): List<CaldavTask>
@Query("SELECT DISTINCT gt_list_id FROM google_tasks WHERE gt_deleted = 0 AND gt_task IN (:tasks)")
@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 gt_task FROM google_tasks WHERE gt_parent IN (:ids) AND gt_deleted = 0")
@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 gt_task
FROM google_tasks
SELECT cd_task
FROM caldav_tasks
INNER JOIN tasks ON gt_parent = _id
WHERE gt_task IN (:ids)
AND gt_deleted = 0
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 google_tasks ON tasks._id = gt_task WHERE gt_parent = :taskId")
@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 google_tasks ON tasks._id = gt_parent WHERE gt_task = :taskId")
@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 google_tasks WHERE gt_parent = :id AND gt_deleted = 0")
abstract suspend fun getChildren(id: Long): List<GoogleTask>
@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(gt_order), -1) + 1 FROM google_tasks WHERE gt_list_id = :listId AND gt_parent = :parent")
@Query("SELECT IFNULL(MAX(cd_order), -1) + 1 FROM caldav_tasks WHERE cd_calendar = :listId AND gt_parent = :parent")
abstract suspend fun getBottom(listId: String, parent: Long): Long
@Query("SELECT gt_remote_id FROM google_tasks JOIN tasks ON tasks._id = gt_task WHERE deleted = 0 AND gt_list_id = :listId AND gt_parent = :parent AND gt_order < :order AND gt_remote_id IS NOT NULL AND gt_remote_id != '' ORDER BY gt_order DESC")
@Query(
"""
SELECT cd_remote_id
FROM caldav_tasks
JOIN tasks ON tasks._id = cd_task
WHERE deleted = 0
AND cd_calendar = :listId
AND gt_parent = :parent
AND cd_order < :order
AND cd_remote_id IS NOT NULL
AND cd_remote_id != ''
ORDER BY cd_order DESC
"""
)
abstract suspend fun getPrevious(listId: String, parent: Long, order: Long): String?
@Query("SELECT gt_remote_id FROM google_tasks WHERE gt_task = :task")
@Query("SELECT cd_remote_id FROM caldav_tasks WHERE cd_task = :task")
abstract suspend fun getRemoteId(task: Long): String?
@Query("SELECT gt_task FROM google_tasks WHERE gt_remote_id = :remoteId")
@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 google_tasks.*, gt_order AS primary_sort, NULL AS secondary_sort FROM google_tasks JOIN tasks ON tasks._id = gt_task WHERE gt_parent = 0 AND gt_list_id = :listId AND tasks.deleted = 0 UNION SELECT c.*, p.gt_order AS primary_sort, c.gt_order AS secondary_sort FROM google_tasks AS c LEFT JOIN google_tasks AS p ON c.gt_parent = p.gt_task JOIN tasks ON tasks._id = c.gt_task WHERE c.gt_parent > 0 AND c.gt_list_id = :listId AND tasks.deleted = 0 ORDER BY primary_sort ASC, secondary_sort ASC")
abstract suspend fun getByLocalOrder(listId: String): List<GoogleTask>
@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
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
ORDER BY primary_sort ASC, secondary_sort ASC
"""
)
abstract suspend fun getByLocalOrder(listId: String): List<CaldavTask>
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
@Query("SELECT google_tasks.*, gt_remote_order AS primary_sort, NULL AS secondary_sort FROM google_tasks JOIN tasks ON tasks._id = gt_task WHERE gt_parent = 0 AND gt_list_id = :listId AND tasks.deleted = 0 UNION SELECT c.*, p.gt_remote_order AS primary_sort, c.gt_remote_order AS secondary_sort FROM google_tasks AS c LEFT JOIN google_tasks AS p ON c.gt_parent = p.gt_task JOIN tasks ON tasks._id = c.gt_task WHERE c.gt_parent > 0 AND c.gt_list_id = :listId AND tasks.deleted = 0 ORDER BY primary_sort ASC, secondary_sort ASC")
internal abstract suspend fun getByRemoteOrder(listId: String): List<GoogleTask>
@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
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
ORDER BY primary_sort ASC, secondary_sort ASC
"""
)
internal abstract suspend fun getByRemoteOrder(listId: String): List<CaldavTask>
@Query("""
UPDATE google_tasks
SET gt_parent = IFNULL((SELECT gt_task
FROM google_tasks AS p
WHERE google_tasks.gt_remote_parent IS NOT NULL
AND google_tasks.gt_remote_parent != ''
AND p.gt_remote_id = google_tasks.gt_remote_parent
AND p.gt_list_id = google_tasks.gt_list_id
AND p.gt_deleted = 0), 0)
@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 google_tasks
SET gt_parent = IFNULL((SELECT gt_task
FROM google_tasks AS p
WHERE google_tasks.gt_remote_parent IS NOT NULL
AND google_tasks.gt_remote_parent != ''
AND p.gt_remote_id = google_tasks.gt_remote_parent
AND p.gt_list_id = google_tasks.gt_list_id
AND p.gt_deleted = 0), 0)
WHERE gt_list_id = :listId
@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 google_tasks
SET gt_remote_parent = CASE WHEN :parent == '' THEN NULL ELSE :parent END,
UPDATE caldav_tasks
SET cd_remote_parent = CASE WHEN :parent == '' THEN NULL ELSE :parent END,
gt_remote_order = :position
WHERE gt_remote_id = :id
WHERE cd_remote_id = :id
""")
abstract suspend fun updatePosition(id: String, parent: String?, position: String)

@ -30,8 +30,8 @@ interface GoogleTaskListDao {
@Query("SELECT caldav_lists.*, COUNT(tasks._id) AS count"
+ " FROM caldav_lists "
+ " LEFT JOIN google_tasks ON google_tasks.gt_list_id = caldav_lists.cdl_uuid"
+ " LEFT JOIN tasks ON google_tasks.gt_task = tasks._id AND tasks.deleted = 0 AND tasks.completed = 0 AND tasks.hideUntil < :now AND gt_deleted = 0"
+ " LEFT JOIN caldav_tasks ON caldav_tasks.cd_calendar = caldav_lists.cdl_uuid"
+ " LEFT JOIN tasks ON caldav_tasks.cd_task = tasks._id AND tasks.deleted = 0 AND tasks.completed = 0 AND tasks.hideUntil < :now AND cd_deleted = 0"
+ " WHERE caldav_lists.cdl_account = :account"
+ " GROUP BY caldav_lists.cdl_uuid")
suspend fun getGoogleTaskFilters(account: String, now: Long = currentTimeMillis()): List<GoogleTaskFilters>

@ -4,6 +4,7 @@ class SubsetCaldav {
var cd_id: Long = 0
var cd_calendar: String? = null
var cd_remote_parent: String? = null
var gt_parent: Long = 0
var cd_order: Long? = null
override fun equals(other: Any?): Boolean {
@ -13,6 +14,7 @@ class SubsetCaldav {
if (cd_id != other.cd_id) return false
if (cd_calendar != other.cd_calendar) return false
if (cd_remote_parent != other.cd_remote_parent) return false
if (gt_parent != other.gt_parent) return false
if (cd_order != other.cd_order) return false
return true
@ -22,10 +24,11 @@ class SubsetCaldav {
var result = cd_id.hashCode()
result = 31 * result + (cd_calendar?.hashCode() ?: 0)
result = 31 * result + (cd_remote_parent?.hashCode() ?: 0)
result = 31 * result + cd_order.hashCode()
result = 31 * result + (gt_parent.hashCode())
result = 31 * result + (cd_order.hashCode())
return result
}
override fun toString(): String =
"SubsetCaldav(cd_id=$cd_id, cd_calendar=$cd_calendar, cd_remote_parent=$cd_remote_parent, cd_order=$cd_order)"
"SubsetCaldav(cd_id=$cd_id, cd_calendar=$cd_calendar, cd_remote_parent=$cd_remote_parent, gt_parent=$gt_parent, cd_order=$cd_order)"
}

@ -1,70 +0,0 @@
package org.tasks.data;
import java.util.Objects;
public class SubsetGoogleTask {
public long gt_id;
public long gt_parent;
public String gt_list_id;
public long gt_order;
public long getId() {
return gt_id;
}
public String getListId() {
return gt_list_id;
}
public long getParent() {
return gt_parent;
}
public void setParent(long parent) {
gt_parent = parent;
}
public long getOrder() {
return gt_order;
}
public void setOrder(long order) {
gt_order = order;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof SubsetGoogleTask)) {
return false;
}
SubsetGoogleTask that = (SubsetGoogleTask) o;
return gt_id == that.gt_id
&& gt_parent == that.gt_parent
&& gt_order == that.gt_order
&& Objects.equals(gt_list_id, that.gt_list_id);
}
@Override
public int hashCode() {
return Objects.hash(gt_id, gt_parent, gt_list_id, gt_order);
}
@Override
public String toString() {
return "SubsetGoogleTask{"
+ "gt_id="
+ gt_id
+ ", gt_parent="
+ gt_parent
+ ", gt_list_id='"
+ gt_list_id
+ '\''
+ ", gt_order="
+ gt_order
+ '}';
}
}

@ -7,9 +7,9 @@ import java.util.Objects;
public class TaskContainer {
@Embedded public Task task;
@Embedded public SubsetGoogleTask googletask;
@Embedded public SubsetCaldav caldavTask;
@Embedded public Location location;
public boolean isGoogleTask;
public boolean parentComplete;
public String tags;
public int children;
@ -23,16 +23,8 @@ public class TaskContainer {
return tags;
}
public @Nullable String getGoogleTaskList() {
return isGoogleTask() ? googletask.getListId() : null;
}
public boolean isGoogleTask() {
return googletask != null;
}
public @Nullable String getCaldav() {
return isCaldavTask() ? caldavTask.getCd_calendar() : null;
return caldavTask.getCd_calendar();
}
public boolean isCaldavTask() {
@ -127,7 +119,6 @@ public class TaskContainer {
&& indent == that.indent
&& targetIndent == that.targetIndent
&& Objects.equals(task, that.task)
&& Objects.equals(googletask, that.googletask)
&& Objects.equals(caldavTask, that.caldavTask)
&& Objects.equals(location, that.location)
&& Objects.equals(tags, that.tags)
@ -138,7 +129,6 @@ public class TaskContainer {
public int hashCode() {
return Objects.hash(
task,
googletask,
caldavTask,
location,
tags,
@ -155,8 +145,6 @@ public class TaskContainer {
return "TaskContainer{"
+ "task="
+ task
+ ", googletask="
+ googletask
+ ", caldavTask="
+ caldavTask
+ ", location="
@ -184,17 +172,16 @@ public class TaskContainer {
}
public long getParent() {
if (googletask != null) {
return googletask.getParent();
if (isGoogleTask) {
return caldavTask.getGt_parent();
} else {
return task.getParent();
}
}
public void setParent(long parent) {
if (googletask != null) {
task.setParent(0);
googletask.setParent(parent);
if (isGoogleTask) {
caldavTask.setGt_parent(parent);
} else {
task.setParent(parent);
}
@ -208,10 +195,6 @@ public class TaskContainer {
return children > 0;
}
public SubsetGoogleTask getGoogleTask() {
return googletask;
}
public SubsetCaldav getCaldavTask() {
return caldavTask;
}

@ -61,11 +61,11 @@ abstract class TaskDao(private val database: Database) {
abstract suspend fun setCompletionDate(remoteIds: List<String>, completionDate: Long, updateTime: Long = now())
@Query("SELECT tasks.* FROM tasks "
+ "LEFT JOIN google_tasks ON tasks._id = google_tasks.gt_task "
+ "LEFT JOIN caldav_lists ON google_tasks.gt_list_id = caldav_lists.cdl_uuid "
+ "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 > google_tasks.gt_last_sync OR google_tasks.gt_remote_id = '' OR google_tasks.gt_deleted > 0) "
+ "ORDER BY CASE WHEN gt_parent = 0 THEN 0 ELSE 1 END, gt_order ASC")
+ "AND (tasks.modified > caldav_tasks.cd_last_sync OR caldav_tasks.cd_remote_id = '' 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>
@Query("""
@ -130,11 +130,11 @@ abstract class TaskDao(private val database: Database) {
@Query("""
SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtasks,
EXISTS(SELECT 1
FROM google_tasks
INNER JOIN tasks ON gt_task = _id
FROM caldav_tasks
INNER JOIN tasks ON cd_task = _id
WHERE deleted = 0
AND gt_parent > 0
AND gt_deleted = 0) AS hasGoogleSubtasks
AND cd_deleted = 0) AS hasGoogleSubtasks
""")
abstract suspend fun getSubtaskInfo(): SubtaskInfo
@ -246,10 +246,8 @@ FROM recursive_tasks
@Query("""
SELECT _id
FROM tasks
LEFT JOIN google_tasks ON _id = gt_task AND gt_deleted = 0
LEFT JOIN caldav_tasks ON _id = cd_task AND cd_deleted = 0
WHERE gt_id IS NULL
AND cd_id IS NULL
WHERE cd_id IS NULL
AND parent = 0
""")
abstract suspend fun getLocalTasks(): List<Long>

@ -6,27 +6,26 @@ import com.todoroo.andlib.sql.Join
import com.todoroo.astrid.activity.TaskListFragment
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.data.Task
import org.tasks.data.CaldavAccount.Companion.TYPE_GOOGLE_TASKS
import org.tasks.data.TaskListQueryNonRecursive.getNonRecursiveQuery
import org.tasks.data.TaskListQueryRecursive.getRecursiveQuery
import org.tasks.preferences.QueryPreferences
object TaskListQuery {
private val JOIN_GTASK = Criterion.and(
Task.ID.eq(field("${TaskListFragment.GTASK_METADATA_JOIN}.gt_task")),
field("${TaskListFragment.GTASK_METADATA_JOIN}.gt_deleted").eq(0))
private val JOIN_CALDAV = Criterion.and(
Task.ID.eq(field("${TaskListFragment.CALDAV_METADATA_JOIN}.cd_task")),
field("${TaskListFragment.CALDAV_METADATA_JOIN}.cd_deleted").eq(0))
val JOINS = """
${Join.left(GoogleTask.TABLE.`as`(TaskListFragment.GTASK_METADATA_JOIN), JOIN_GTASK)}
${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.left(Geofence.TABLE, Geofence.TASK.eq(Task.ID))}
${Join.left(Place.TABLE, Place.UID.eq(Geofence.PLACE))}
""".trimIndent()
val FIELDS = listOf(
field("tasks.*"),
field("${TaskListFragment.GTASK_METADATA_JOIN}.*"),
field("${TaskListFragment.CALDAV_METADATA_JOIN}.*"),
field("CASE ${CaldavAccount.ACCOUNT_TYPE} WHEN $TYPE_GOOGLE_TASKS THEN 1 ELSE 0 END").`as`("isGoogleTask"),
field("geofences.*"),
field("places.*"))

@ -35,13 +35,13 @@ internal object TaskListQueryRecursive {
""".trimIndent()
private val GOOGLE_SUBTASKS =
QueryTemplate()
.join(Join.inner(RECURSIVE, GoogleTask.PARENT.eq(RECURSIVE_TASK)))
.join(Join.inner(GoogleTask.TABLE, Criterion.and(GoogleTask.TASK.eq(Task.ID), GoogleTask.DELETED.eq(0))))
.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(GoogleTask.PARENT.eq(RECURSIVE_TASK), Task.PARENT.eq(RECURSIVE_TASK))))
.join(Join.left(GoogleTask.TABLE, Criterion.and(GoogleTask.TASK.eq(Task.ID), GoogleTask.DELETED.eq(0))))
.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))))
.where(activeAndVisible())
fun getRecursiveQuery(
@ -85,7 +85,7 @@ internal object TaskListQueryRecursive {
when {
manualSort && filter is GtasksFilter -> {
sortMode = SortHelper.SORT_GTASKS
sortField = "google_tasks.gt_order"
sortField = "caldav_tasks.cd_order"
}
manualSort && filter is CaldavFilter -> {
sortMode = SortHelper.SORT_CALDAV
@ -141,12 +141,12 @@ internal object TaskListQueryRecursive {
private fun newGoogleTaskQuery(filter: GtasksFilter) =
QueryTemplate()
.join(Join.inner(
GoogleTask.TABLE,
CaldavTask.TABLE,
Criterion.and(
GoogleTask.LIST.eq(filter.remoteId),
GoogleTask.PARENT.eq(0),
GoogleTask.TASK.eq(Task.ID),
GoogleTask.DELETED.eq(0))))
CaldavTask.CALENDAR.eq(filter.remoteId),
CaldavTask.PARENT.eq(0),
CaldavTask.TASK.eq(Task.ID),
CaldavTask.DELETED.eq(0))))
.where(activeAndVisible())
.toString()
}

@ -137,10 +137,10 @@ class FilterCriteriaProvider @Inject constructor(
select(Task.ID)
.from(Task.TABLE)
.join(left(Task.TABLE.`as`("children"), Task.ID.eq(field("children.parent"))))
.join(left(GoogleTask.TABLE, GoogleTask.PARENT.eq(Task.ID)))
.join(left(CaldavTask.TABLE, CaldavTask.PARENT.eq(Task.ID)))
.where(or(
isNotNull(field("children._id")),
isNotNull(GoogleTask.ID)
isNotNull(CaldavTask.ID)
))
.toString()
)
@ -151,10 +151,10 @@ class FilterCriteriaProvider @Inject constructor(
context.getString(R.string.custom_filter_is_subtask),
select(Task.ID)
.from(Task.TABLE)
.join(left(GoogleTask.TABLE, GoogleTask.TASK.eq(Task.ID)))
.join(left(CaldavTask.TABLE, CaldavTask.TASK.eq(Task.ID)))
.where(or(
field("${Task.PARENT}>0").eq(1),
field("${GoogleTask.PARENT}>0").eq(1)
field("${CaldavTask.PARENT}>0").eq(1)
))
.toString()
)
@ -298,14 +298,14 @@ class FilterCriteriaProvider @Inject constructor(
return MultipleSelectCriterion(
IDENTIFIER_GTASKS,
context.getString(R.string.CFC_gtasks_list_text),
select(GoogleTask.TASK)
.from(GoogleTask.TABLE)
.join(inner(Task.TABLE, GoogleTask.TASK.eq(Task.ID)))
select(CaldavTask.TASK)
.from(CaldavTask.TABLE)
.join(inner(Task.TABLE, CaldavTask.TASK.eq(Task.ID)))
.where(
and(
activeAndVisible(),
GoogleTask.DELETED.eq(0),
GoogleTask.LIST.eq("?")))
CaldavTask.DELETED.eq(0),
CaldavTask.CALENDAR.eq("?")))
.toString(),
values,
listNames,

@ -179,7 +179,7 @@ class GoogleTaskSynchronizer @Inject constructor(
@Throws(IOException::class)
private suspend fun pushTask(task: com.todoroo.astrid.data.Task, gtasksInvoker: GtasksInvoker) {
for (deleted in googleTaskDao.getDeletedByTaskId(task.id)) {
gtasksInvoker.deleteGtask(deleted.listId, deleted.remoteId)
gtasksInvoker.deleteGtask(deleted.calendar, deleted.remoteId)
googleTaskDao.delete(deleted)
}
val gtasksMetadata = googleTaskDao.getByTaskId(task.id) ?: return
@ -189,14 +189,14 @@ class GoogleTaskSynchronizer @Inject constructor(
val defaultRemoteList = defaultFilterProvider.defaultList
var listId = if (defaultRemoteList is GtasksFilter) defaultRemoteList.remoteId else DEFAULT_LIST
if (isNullOrEmpty(gtasksMetadata.remoteId)) { // Create case
val selectedList = gtasksMetadata.listId
val selectedList = gtasksMetadata.calendar
if (!isNullOrEmpty(selectedList)) {
listId = selectedList
}
newlyCreated = true
} else { // update case
remoteId = gtasksMetadata.remoteId
listId = gtasksMetadata.listId
listId = gtasksMetadata.calendar
remoteModel.id = remoteId
}
@ -227,7 +227,7 @@ class GoogleTaskSynchronizer @Inject constructor(
val parent = gtasksMetadata.parent
val localParent = if (parent > 0) googleTaskDao.getRemoteId(parent) else null
val previous = googleTaskDao.getPrevious(
listId!!, if (isNullOrEmpty(localParent)) 0 else parent, gtasksMetadata.order)
listId!!, if (isNullOrEmpty(localParent)) 0 else parent, gtasksMetadata.order ?: 0)
val created: Task?
created = try {
gtasksInvoker.createGtask(listId, remoteModel, localParent, previous)
@ -237,7 +237,7 @@ class GoogleTaskSynchronizer @Inject constructor(
if (created != null) {
// Update the metadata for the newly created task
gtasksMetadata.remoteId = created.id
gtasksMetadata.listId = listId
gtasksMetadata.calendar = listId
setOrderAndParent(gtasksMetadata, created)
} else {
return
@ -251,7 +251,7 @@ class GoogleTaskSynchronizer @Inject constructor(
val previous = googleTaskDao.getPrevious(
listId!!,
if (isNullOrEmpty(localParent)) 0 else parent,
gtasksMetadata.order)
gtasksMetadata.order ?: 0)
gtasksInvoker
.moveGtask(listId, remoteModel.id, localParent, previous)
?.let { setOrderAndParent(gtasksMetadata, it) }
@ -303,7 +303,7 @@ class GoogleTaskSynchronizer @Inject constructor(
var googleTask = googleTaskDao.getByRemoteId(remoteId)
var task: com.todoroo.astrid.data.Task? = null
if (googleTask == null) {
googleTask = GoogleTask(0, "")
googleTask = CaldavTask(0, "")
} else if (googleTask.task > 0) {
task = taskDao.fetch(googleTask.task)
}
@ -339,7 +339,7 @@ class GoogleTaskSynchronizer @Inject constructor(
val dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(gtask.due?.let(::DateTime))
mergeDates(createDueDate(com.todoroo.astrid.data.Task.URGENCY_SPECIFIC_DAY, dueDate), task)
task.notes = getTruncatedValue(task.notes, gtask.notes, MAX_DESCRIPTION_LENGTH)
googleTask.listId = listId
googleTask.calendar = listId
if (task.title?.isNotBlank() == true || task.notes?.isNotBlank() == true) {
write(task, googleTask)
}
@ -351,13 +351,13 @@ class GoogleTaskSynchronizer @Inject constructor(
)
}
private suspend fun setOrderAndParent(googleTask: GoogleTask, task: Task) {
private suspend fun setOrderAndParent(googleTask: CaldavTask, task: Task) {
task.position?.toLongOrNull()?.let { googleTask.remoteOrder = it }
googleTask.remoteParent = task.parent?.takeIf { it.isNotBlank() }
googleTask.parent = googleTask.remoteParent?.let { googleTaskDao.getTask(it) } ?: 0L
}
private suspend fun write(task: com.todoroo.astrid.data.Task, googleTask: GoogleTask) {
private suspend fun write(task: com.todoroo.astrid.data.Task, googleTask: CaldavTask) {
task.suppressSync()
task.suppressRefresh()
if (task.isNew) {
@ -367,7 +367,7 @@ class GoogleTaskSynchronizer @Inject constructor(
taskDao.save(task)
googleTask.lastSync = task.modificationDate
googleTask.task = task.id
if (googleTask.isNew) {
if (googleTask.id == 0L) {
googleTaskDao.insert(googleTask)
} else {
googleTaskDao.update(googleTask)

@ -170,7 +170,7 @@ class DefaultFilterProvider @Inject constructor(
val googleTask = googleTaskDao.getByTaskId(task.id)
val caldavTask = caldavDao.getTask(task.id)
if (googleTask != null) {
val googleTaskList = googleTaskListDao.getByRemoteId(googleTask.listId!!)
val googleTaskList = googleTaskListDao.getByRemoteId(googleTask.calendar!!)
if (googleTaskList != null) {
originalList = GtasksFilter(googleTaskList)
}

@ -99,29 +99,16 @@ class ChipProvider @Inject constructor(
)
}
}
if (!isSubtask && preferences.showListChip) {
if (!isNullOrEmpty(task.googleTaskList) && filter !is GtasksFilter) {
lists.getCaldavList(task.googleTaskList)?.let { list ->
FilterChip(
filter = GtasksFilter(list),
defaultIcon = R.drawable.ic_list_24px,
onClick = onClick,
showText = showText,
showIcon = showIcon,
colorProvider = this::getColor,
)
}
} else if (!isNullOrEmpty(task.caldav) && filter !is CaldavFilter) {
lists.getCaldavList(task.caldav)?.let { list ->
FilterChip(
filter = CaldavFilter(list),
defaultIcon = R.drawable.ic_list_24px,
onClick = onClick,
showText = showText,
showIcon = showIcon,
colorProvider = this::getColor,
)
}
if (!isSubtask && preferences.showListChip && filter !is CaldavFilter) {
lists.getCaldavList(task.caldav)?.let { list ->
FilterChip(
filter = if (task.isGoogleTask) GtasksFilter(list) else CaldavFilter(list),
defaultIcon = R.drawable.ic_list_24px,
onClick = onClick,
showText = showText,
showIcon = showIcon,
colorProvider = this::getColor,
)
}
}
val tagString = task.tagsString

@ -16,6 +16,7 @@ import kotlinx.coroutines.launch
import org.tasks.LocalBroadcastManager
import org.tasks.data.TaskDao
import org.tasks.filters.FilterProvider
import timber.log.Timber
import javax.inject.Inject
@HiltViewModel
@ -51,7 +52,12 @@ class NavigationDrawerViewModel @Inject constructor(
.navDrawerItems()
.onEach {
if (it is Filter && it.count == -1) {
it.count = taskDao.count(it)
it.count = try {
taskDao.count(it)
} catch (e: Exception) {
Timber.e(e)
0
}
}
}
.let { filters -> _viewState.update { it.copy(filters = filters) } }

@ -23,7 +23,7 @@ import kotlinx.coroutines.launch
import org.tasks.R
import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.compose.edit.SubtaskRow
import org.tasks.data.GoogleTask
import org.tasks.data.CaldavTask
import org.tasks.data.GoogleTaskDao
import org.tasks.data.TaskDao.TaskCriteria.activeAndVisible
import org.tasks.preferences.Preferences
@ -111,18 +111,18 @@ class SubtaskControlSet : TaskEditControlFragment() {
private fun getQueryTemplate(task: Task): QueryTemplate = QueryTemplate()
.join(
Join.left(
GoogleTask.TABLE,
CaldavTask.TABLE,
Criterion.and(
GoogleTask.PARENT.eq(task.id),
GoogleTask.TASK.eq(Task.ID),
GoogleTask.DELETED.eq(0)
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), GoogleTask.TASK.gt(0))
Criterion.or(Task.PARENT.eq(task.id), CaldavTask.TASK.gt(0))
)
)
}

@ -292,7 +292,7 @@ class TaskEditViewModel @Inject constructor(
firebase?.addTask("subtasks")
when (selectedList.value) {
is GtasksFilter -> {
val googleTask = GoogleTask(subtask.id, (selectedList.value as GtasksFilter).remoteId)
val googleTask = CaldavTask(subtask.id, (selectedList.value as GtasksFilter).remoteId)
googleTask.parent = task.id
googleTask.isMoved = true
googleTaskDao.insertAndShift(googleTask, false)

@ -5,7 +5,6 @@ import android.widget.RemoteViews
import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.api.CaldavFilter
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.api.TagFilter
import com.todoroo.astrid.data.Task
import dagger.hilt.android.qualifiers.ApplicationContext
@ -74,10 +73,6 @@ class ChipProvider @Inject constructor(
}
fun getListChip(filter: Filter?, task: TaskContainer): RemoteViews? {
task.googleTaskList
?.takeIf { filter !is GtasksFilter }
?.let { newChip(GtasksFilter(chipListCache.getCaldavList(it)), R.drawable.ic_list_24px) }
?.let { return it }
task.caldav
?.takeIf { filter !is CaldavFilter }
?.let { newChip(CaldavFilter(chipListCache.getCaldavList(it)), R.drawable.ic_list_24px) }

@ -5,7 +5,6 @@ import com.natpryce.makeiteasy.Property
import com.natpryce.makeiteasy.Property.newProperty
import com.natpryce.makeiteasy.PropertyValue
import com.todoroo.astrid.helper.UUIDHelper
import org.tasks.data.GoogleTask
import org.tasks.makers.Maker.make
object GoogleTaskMaker {
@ -18,7 +17,7 @@ object GoogleTaskMaker {
private val instantiator = Instantiator<GoogleTask> {
val task = GoogleTask()
task.listId = it.valueOf(LIST, "1")
task.calendar = it.valueOf(LIST, "1")
task.order = it.valueOf(ORDER, 0)
task.remoteId = it.valueOf(REMOTE_ID, UUIDHelper.newUUID())
task.task = it.valueOf(TASK, 1)

Loading…
Cancel
Save