From 0f70ac0f5d1b50d8ab9101c48129616333d42995 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Thu, 14 Jan 2021 17:06:12 -0600 Subject: [PATCH] Use AndroidTask to read OpenTask data --- app/build.gradle.kts | 2 +- .../main/java/org/tasks/caldav/iCalendar.kt | 24 ++--- .../main/java/org/tasks/data/OpenTaskDao.kt | 74 ++++++-------- .../tasks/opentasks/OpenTasksSynchronizer.kt | 98 +------------------ deps_fdroid.txt | 2 +- deps_googleplay.txt | 2 +- 6 files changed, 46 insertions(+), 156 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 70a0fad1e..08704939d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -142,7 +142,7 @@ val googleplayImplementation by configurations dependencies { coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.1") implementation("com.gitlab.bitfireAT:dav4jvm:2.1.1") - implementation("com.gitlab.abaker:ical4android:6ccdb1a") + implementation("com.gitlab.abaker:ical4android:007f7751d5") implementation("com.gitlab.bitfireAT:cert4android:0710fb57c1") implementation("com.github.dmfs.opentasks:opentasks-provider:1.2.4") { exclude("com.github.dmfs.opentasks", "opentasks-contract") diff --git a/app/src/main/java/org/tasks/caldav/iCalendar.kt b/app/src/main/java/org/tasks/caldav/iCalendar.kt index ca998f06f..f0f3718fc 100644 --- a/app/src/main/java/org/tasks/caldav/iCalendar.kt +++ b/app/src/main/java/org/tasks/caldav/iCalendar.kt @@ -115,25 +115,16 @@ class iCalendar @Inject constructor( calendar: CaldavCalendar, existing: CaldavTask?, remote: Task, - vtodo: String, + vtodo: String?, obj: String? = null, eTag: String? = null) { - val task: com.todoroo.astrid.data.Task - val caldavTask: CaldavTask - if (existing == null) { - task = taskCreator.createWithValues("") - taskDao.createNew(task) - caldavTask = CaldavTask(task.id, calendar.uuid, remote.uid, obj) - } else { - caldavTask = existing - task = taskDao.fetch(existing.task) - ?: taskCreator.createWithValues("").apply { - taskDao.createNew(this) - caldavTask.task = id - } - } + val task = existing?.task?.let { taskDao.fetch(it) } + ?: taskCreator.createWithValues("").apply { + taskDao.createNew(this) + existing?.task = id + } + val caldavTask = existing ?: CaldavTask(task.id, calendar.uuid, remote.uid, obj) CaldavConverter.apply(task, remote) - caldavTask.order = remote.order setPlace(task.id, remote.geoPosition) tagDao.applyTags(task, tagDataDao, getTags(remote.categories)) task.suppressSync() @@ -143,6 +134,7 @@ class iCalendar @Inject constructor( caldavTask.etag = eTag caldavTask.lastSync = task.modificationDate caldavTask.remoteParent = remote.getParent() + caldavTask.order = remote.order if (caldavTask.id == com.todoroo.astrid.data.Task.NO_ID) { caldavTask.id = caldavDao.insert(caldavTask) Timber.d("NEW %s", caldavTask) diff --git a/app/src/main/java/org/tasks/data/OpenTaskDao.kt b/app/src/main/java/org/tasks/data/OpenTaskDao.kt index e94225a58..ced3c125b 100644 --- a/app/src/main/java/org/tasks/data/OpenTaskDao.kt +++ b/app/src/main/java/org/tasks/data/OpenTaskDao.kt @@ -5,6 +5,9 @@ import android.content.ContentProviderOperation.* import android.content.ContentValues import android.content.Context import android.database.Cursor +import at.bitfire.ical4android.AndroidTask +import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues +import at.bitfire.ical4android.Task import at.bitfire.ical4android.UnknownProperty import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers @@ -127,22 +130,6 @@ class OpenTaskDao @Inject constructor( } } - suspend fun getTags(listId: Long, caldavTask: CaldavTask): List = withContext(Dispatchers.IO) { - val id = getId(listId, caldavTask.remoteId) - val tags = ArrayList() - cr.query( - properties, - arrayOf(Properties.DATA1), - "${Properties.TASK_ID} = $id AND ${Properties.MIMETYPE} = '${Category.CONTENT_ITEM_TYPE}'", - null, - null)?.use { - while (it.moveToNext()) { - it.getString(Properties.DATA1)?.let(tags::add) - } - } - return@withContext tags - } - fun setTags(id: Long, tags: List): List { val delete = listOf( newDelete(properties) @@ -162,26 +149,6 @@ class OpenTaskDao @Inject constructor( return delete + inserts } - suspend fun getRemoteOrder(listId: Long, caldavTask: CaldavTask): Long? = withContext(Dispatchers.IO) { - val id = getId(listId, caldavTask.remoteId) ?: return@withContext null - cr.query( - properties, - arrayOf(Properties.DATA0), - "${Properties.TASK_ID} = $id AND ${Properties.MIMETYPE} = '${UnknownProperty.CONTENT_ITEM_TYPE}' AND ${Properties.DATA0} LIKE '%$APPLE_SORT_ORDER%'", - null, - null)?.use { - while (it.moveToNext()) { - it.getString(Properties.DATA0) - ?.let(UnknownProperty::fromJsonString) - ?.takeIf { xprop -> xprop.name.equals(APPLE_SORT_ORDER, true) } - ?.let { xprop -> - return@withContext xprop.value.toLong() - } - } - } - return@withContext null - } - fun setRemoteOrder(id: Long, caldavTask: CaldavTask): List { val operations = ArrayList() operations.add( @@ -226,15 +193,18 @@ class OpenTaskDao @Inject constructor( return operations } - suspend fun getParent(id: Long): String? = withContext(Dispatchers.IO) { + suspend fun getTask(listId: Long, uid: String): Task? = withContext(Dispatchers.IO) { cr.query( - properties, - arrayOf(Relation.RELATED_UID), - "${Relation.TASK_ID} = $id AND ${Properties.MIMETYPE} = '${Relation.CONTENT_ITEM_TYPE}' AND ${Relation.RELATED_TYPE} = ${Relation.RELTYPE_PARENT}", + Tasks.getContentUri(authority) + .buildUpon() + .appendQueryParameter(LOAD_PROPERTIES, "1") + .build(), + null, + "${Tasks.LIST_ID} = $listId AND ${Tasks._UID} = '$uid'", null, null)?.use { if (it.moveToFirst()) { - it.getString(Relation.RELATED_UID) + MyAndroidTask(it).task } else { null } @@ -264,13 +234,31 @@ class OpenTaskDao @Inject constructor( fun String?.isDecSync(): Boolean = this?.startsWith(ACCOUNT_TYPE_DECSYNC) == true - fun Cursor.getString(columnName: String): String? = + private fun Cursor.getString(columnName: String): String? = getString(getColumnIndex(columnName)) fun Cursor.getInt(columnName: String): Int = getInt(getColumnIndex(columnName)) - fun Cursor.getLong(columnName: String): Long = + private fun Cursor.getLong(columnName: String): Long = getLong(getColumnIndex(columnName)) + + private class MyAndroidTask(cursor: Cursor) : AndroidTask(null) { + init { + val values = cursor.toValues() + task = Task() + populateTask(values) + populateRelatedTo(values) + if (values.containsKey(Properties.PROPERTY_ID)) { + // process the first property, which is combined with the task row + populateProperty(values) + + while (cursor.moveToNext()) { + // process the other properties + populateProperty(cursor.toValues(true)) + } + } + } + } } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/opentasks/OpenTasksSynchronizer.kt b/app/src/main/java/org/tasks/opentasks/OpenTasksSynchronizer.kt index 68b8393f4..8eb63e4e7 100644 --- a/app/src/main/java/org/tasks/opentasks/OpenTasksSynchronizer.kt +++ b/app/src/main/java/org/tasks/opentasks/OpenTasksSynchronizer.kt @@ -3,19 +3,11 @@ package org.tasks.opentasks import android.content.ContentProviderOperation import android.content.ContentValues import android.content.Context -import android.database.Cursor -import com.todoroo.andlib.utility.DateUtilities.now import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.data.Task -import com.todoroo.astrid.data.Task.Companion.HIDE_UNTIL_SPECIFIC_DAY -import com.todoroo.astrid.data.Task.Companion.HIDE_UNTIL_SPECIFIC_DAY_TIME -import com.todoroo.astrid.data.Task.Companion.URGENCY_SPECIFIC_DAY -import com.todoroo.astrid.data.Task.Companion.URGENCY_SPECIFIC_DAY_TIME import com.todoroo.astrid.data.Task.Companion.sanitizeRRule -import com.todoroo.astrid.service.TaskCreator import com.todoroo.astrid.service.TaskDeleter import dagger.hilt.android.qualifiers.ApplicationContext -import net.fortuna.ical4j.model.property.Geo import net.fortuna.ical4j.model.property.RRule import org.dmfs.tasks.contract.TaskContract.Tasks import org.tasks.LocalBroadcastManager @@ -23,20 +15,16 @@ import org.tasks.R import org.tasks.analytics.Constants import org.tasks.analytics.Firebase import org.tasks.billing.Inventory -import org.tasks.caldav.CaldavConverter import org.tasks.caldav.CaldavConverter.toRemote import org.tasks.caldav.iCalendar import org.tasks.data.* import org.tasks.data.CaldavAccount.Companion.openTaskType import org.tasks.data.OpenTaskDao.Companion.getInt -import org.tasks.data.OpenTaskDao.Companion.getLong -import org.tasks.data.OpenTaskDao.Companion.getString import org.tasks.data.OpenTaskDao.Companion.isDavx5 import org.tasks.data.OpenTaskDao.Companion.isDecSync import org.tasks.data.OpenTaskDao.Companion.isEteSync import org.tasks.data.OpenTaskDao.Companion.newAccounts import org.tasks.time.DateTime -import org.tasks.time.DateTimeUtils.currentTimeMillis import org.tasks.time.DateTimeUtils.startOfDay import timber.log.Timber import java.util.* @@ -49,13 +37,11 @@ class OpenTasksSynchronizer @Inject constructor( private val caldavDao: CaldavDao, private val taskDeleter: TaskDeleter, private val localBroadcastManager: LocalBroadcastManager, - private val taskCreator: TaskCreator, private val taskDao: TaskDao, private val firebase: Firebase, private val iCalendar: iCalendar, private val locationDao: LocationDao, private val openTaskDao: OpenTaskDao, - private val tagDao: TagDao, private val tagDataDao: TagDataDao, private val inventory: Inventory) { @@ -293,90 +279,14 @@ class OpenTasksSynchronizer @Inject constructor( listId: Long, uid: String, etag: String?, - existing: CaldavTask?) { - cr.query( - Tasks.getContentUri(openTaskDao.authority), - null, - "${Tasks.LIST_ID} = $listId AND ${Tasks._UID} = '$uid'", - null, - null)?.use { - if (!it.moveToFirst()) { - return - } - val task = existing?.task - ?.let { task -> taskDao.fetch(task) } - ?: taskCreator - .createWithValues("") - .apply { taskDao.createNew(this) } - val caldavTask = existing - ?: CaldavTask(task.id, calendar.uuid, it.getString(Tasks._UID), null) - task.title = it.getString(Tasks.TITLE) - task.priority = CaldavConverter.fromRemote(it.getInt(Tasks.PRIORITY)) - val completedAt = it.getLong(Tasks.COMPLETED) - task.completionDate = when { - completedAt > 0 -> completedAt - it.getInt(Tasks.STATUS) == Tasks.STATUS_COMPLETED -> - if (task.isCompleted) task.completionDate else now() - else -> 0L - } - task.notes = it.getString(Tasks.DESCRIPTION) - task.modificationDate = currentTimeMillis() - task.creationDate = it.getLong(Tasks.CREATED).toLocal() - val allDay = it.getBoolean(Tasks.IS_ALLDAY) - val due = it.getLong(Tasks.DUE) - task.dueDate = when { - due == 0L -> 0 - allDay -> Task.createDueDate(URGENCY_SPECIFIC_DAY, due - DateTime(due).offset) - else -> Task.createDueDate(URGENCY_SPECIFIC_DAY_TIME, due) - } - val start = it.getLong(Tasks.DTSTART) - task.hideUntil = when { - start == 0L -> 0 - allDay -> task.createHideUntil(HIDE_UNTIL_SPECIFIC_DAY, start - DateTime(start).offset) - else -> task.createHideUntil(HIDE_UNTIL_SPECIFIC_DAY_TIME, start) - } - iCalendar.setPlace(task.id, it.getString(Tasks.GEO).toGeo()) - task.setRecurrence(it.getString(Tasks.RRULE).toRRule()) - val tagNames = openTaskDao.getTags(listId, caldavTask) - val tags = iCalendar.getTags(tagNames) - caldavTask.etag = etag - caldavTask.order = openTaskDao.getRemoteOrder(listId, caldavTask) - caldavTask.remoteParent = openTaskDao.getParent(it.getLong(Tasks._ID)) - task.suppressSync() - task.suppressRefresh() - taskDao.save(task) - tagDao.applyTags(task, tagDataDao, tags) - caldavTask.lastSync = task.modificationDate - if (caldavTask.id == Task.NO_ID) { - caldavTask.id = caldavDao.insert(caldavTask) - Timber.d("NEW $caldavTask") - } else { - caldavDao.update(caldavTask) - Timber.d("UPDATE $caldavTask") - } + existing: CaldavTask? + ) { + openTaskDao.getTask(listId, uid)?.let { + iCalendar.fromVtodo(calendar, existing, it, null, null, etag) } } companion object { private fun Location?.toGeoString(): String? = this?.let { "$longitude,$latitude" } - - private fun String?.toGeo(): Geo? = - this - ?.takeIf { it.isNotBlank() } - ?.split(",") - ?.takeIf { - it.size == 2 - && it[0].toDoubleOrNull() != null - && it[1].toDoubleOrNull() != null } - ?.let { Geo("${it[1]};${it[0]}") } - - private fun String?.toRRule(): RRule? = - this?.takeIf { it.isNotBlank() }?.let(::RRule) - - private fun Cursor.getBoolean(columnName: String): Boolean = - getInt(getColumnIndex(columnName)) != 0 - - private fun Long.toLocal(): Long = - DateTime(this).toLocal().millis } } \ No newline at end of file diff --git a/deps_fdroid.txt b/deps_fdroid.txt index 99d76e2ec..3a76e0941 100644 --- a/deps_fdroid.txt +++ b/deps_fdroid.txt @@ -97,7 +97,7 @@ ++--- com.gitlab.bitfireAT:dav4jvm:2.1.1 +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.72 -> 1.4.21 (*) +| \--- org.apache.commons:commons-lang3:3.9 -++--- com.gitlab.abaker:ical4android:6ccdb1a +++--- com.gitlab.abaker:ical4android:007f7751d5 +| +--- org.mnode.ical4j:ical4j:3.0.21 +| | +--- org.slf4j:slf4j-api:1.7.25 -> 1.7.30 +| | +--- commons-codec:commons-codec:1.11 diff --git a/deps_googleplay.txt b/deps_googleplay.txt index 6cf962be3..e11d89a98 100644 --- a/deps_googleplay.txt +++ b/deps_googleplay.txt @@ -249,7 +249,7 @@ ++--- com.gitlab.bitfireAT:dav4jvm:2.1.1 +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.72 -> 1.4.21 (*) +| \--- org.apache.commons:commons-lang3:3.9 -++--- com.gitlab.abaker:ical4android:6ccdb1a +++--- com.gitlab.abaker:ical4android:007f7751d5 +| +--- org.mnode.ical4j:ical4j:3.0.21 +| | +--- org.slf4j:slf4j-api:1.7.25 -> 1.7.30 +| | +--- commons-codec:commons-codec:1.11