Use AndroidTask to read OpenTask data

pull/1297/head
Alex Baker 3 years ago
parent e9c0bcfff3
commit 0f70ac0f5d

@ -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")

@ -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)

@ -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<String> = withContext(Dispatchers.IO) {
val id = getId(listId, caldavTask.remoteId)
val tags = ArrayList<String>()
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<String>): List<ContentProviderOperation> {
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<ContentProviderOperation> {
val operations = ArrayList<ContentProviderOperation>()
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))
}
}
}
}
}
}

@ -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
}
}

@ -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

@ -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

Loading…
Cancel
Save