Use ical4android to build content provider ops

pull/1309/head
Alex Baker 3 years ago
parent ebbd4ec365
commit d1d076a3d7

@ -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:007f7751d5")
implementation("com.gitlab.abaker:ical4android:0e928b567c")
implementation("com.gitlab.bitfireAT:cert4android:26a91a729f")
implementation("com.github.dmfs.opentasks:opentasks-provider:1.2.4") {
exclude("com.github.dmfs.opentasks", "opentasks-contract")

@ -21,11 +21,12 @@ object TestUtilities {
return task
}
fun setup(path: String): Pair<Task, CaldavTask> {
fun setup(path: String): Triple<Task, CaldavTask, at.bitfire.ical4android.Task> {
val task = Task()
val vtodo = readFile(path)
CaldavConverter.apply(task, fromString(vtodo))
return Pair(task, CaldavTask().apply { this.vtodo = vtodo })
val remote = fromString(vtodo)
CaldavConverter.apply(task, remote)
return Triple(task, CaldavTask().apply { this.vtodo = vtodo }, remote)
}
private fun fromResource(path: String): at.bitfire.ical4android.Task =

@ -3,7 +3,6 @@ package org.tasks.caldav;
import static com.todoroo.andlib.utility.DateUtilities.now;
import static com.todoroo.astrid.data.Task.URGENCY_SPECIFIC_DAY;
import static com.todoroo.astrid.data.Task.URGENCY_SPECIFIC_DAY_TIME;
import static org.tasks.Strings.isNullOrEmpty;
import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.time.DateTimeUtils.startOfDay;
@ -96,18 +95,7 @@ public class CaldavConverter {
}
}
public static at.bitfire.ical4android.Task toCaldav(CaldavTask caldavTask, Task task) {
at.bitfire.ical4android.Task remote = null;
try {
if (!isNullOrEmpty(caldavTask.getVtodo())) {
remote = iCalendar.Companion.fromVtodo(caldavTask.getVtodo());
}
} catch (Exception e) {
Timber.e(e);
}
if (remote == null) {
remote = new at.bitfire.ical4android.Task();
}
public static void toCaldav(CaldavTask caldavTask, Task task, at.bitfire.ical4android.Task remote) {
remote.setCreatedAt(newDateTime(task.getCreationDate()).toUTC().getMillis());
remote.setSummary(task.getTitle());
remote.setDescription(task.getNotes());
@ -153,8 +141,6 @@ public class CaldavConverter {
remote.setLastModified(newDateTime(task.getModificationDate()).toUTC().getMillis());
remote.setPriority(toRemote(remote.getPriority(), task.getPriority()));
iCalendar.Companion.setParent(remote, task.getParent() == 0 ? null : caldavTask.getRemoteParent());
return remote;
}
private static DateTime getDateTime(long timestamp) {

@ -88,7 +88,27 @@ class iCalendar @Inject constructor(
}
suspend fun toVtodo(caldavTask: CaldavTask, task: com.todoroo.astrid.data.Task): ByteArray {
val remoteModel = CaldavConverter.toCaldav(caldavTask, task)
var remoteModel: Task? = null
try {
if (!isNullOrEmpty(caldavTask.vtodo)) {
remoteModel = fromVtodo(caldavTask.vtodo!!)
}
} catch (e: java.lang.Exception) {
Timber.e(e)
}
if (remoteModel == null) {
remoteModel = Task()
}
toVtodo(caldavTask, task, remoteModel)
val os = ByteArrayOutputStream()
remoteModel.write(os)
return os.toByteArray()
}
suspend fun toVtodo(caldavTask: CaldavTask, task: com.todoroo.astrid.data.Task, remoteModel: Task) {
CaldavConverter.toCaldav(caldavTask, task, remoteModel)
remoteModel.order = caldavTask.order
val categories = remoteModel.categories
categories.clear()
@ -105,10 +125,6 @@ class iCalendar @Inject constructor(
if (localGeo == null || !localGeo.equalish(remoteModel.geoPosition)) {
remoteModel.geoPosition = localGeo
}
val os = ByteArrayOutputStream()
remoteModel.write(os)
return os.toByteArray()
}
suspend fun fromVtodo(

@ -1,7 +1,11 @@
package org.tasks.data
import android.database.Cursor
import android.net.Uri
import at.bitfire.ical4android.AndroidTask
import at.bitfire.ical4android.BatchOperation
import at.bitfire.ical4android.BatchOperation.CpoBuilder.Companion.newInsert
import at.bitfire.ical4android.BatchOperation.CpoBuilder.Companion.newUpdate
import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues
import at.bitfire.ical4android.Task
import org.dmfs.tasks.contract.TaskContract
@ -23,4 +27,21 @@ class MyAndroidTask() : AndroidTask(null) {
}
}
}
constructor(task: Task) : this() {
this.task = task
}
fun toBuilder(uri: Uri, isNew: Boolean): BatchOperation.CpoBuilder {
val builder = if (isNew) newInsert(uri) else newUpdate(uri)
buildTask(builder, true)
if (!isNew) {
builder.remove(TaskContract.Tasks._UID)
}
return builder
.remove(TaskContract.Tasks.CREATED)
.remove(TaskContract.Tasks.LAST_MODIFIED)
.remove(TaskContract.Tasks._DIRTY)
.remove(TaskContract.Tasks.SYNC_VERSION)
}
}

@ -1,10 +1,12 @@
package org.tasks.data
import android.content.ContentProviderOperation
import android.content.ContentProviderOperation.*
import android.content.ContentProviderOperation.newDelete
import android.content.ContentProviderOperation.newInsert
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import at.bitfire.ical4android.BatchOperation
import at.bitfire.ical4android.Task
import at.bitfire.ical4android.UnknownProperty
import dagger.hilt.android.qualifiers.ApplicationContext
@ -26,7 +28,7 @@ class OpenTaskDao @Inject constructor(
) {
private val cr = context.contentResolver
val authority = context.getString(R.string.opentasks_authority)
private val tasks = Tasks.getContentUri(authority)
val tasks = Tasks.getContentUri(authority)
private val properties = Properties.getContentUri(authority)
suspend fun newAccounts(): List<String> = getListsByAccount().newAccounts(caldavDao)
@ -85,17 +87,14 @@ class OpenTaskDao @Inject constructor(
null)
.build()
fun insert(values: ContentValues): ContentProviderOperation =
newInsert(tasks)
.withValues(values)
.build()
fun insert(builder: BatchOperation.CpoBuilder): ContentProviderOperation = builder.build()
fun update(listId: Long, uid: String, values: ContentValues): ContentProviderOperation =
newUpdate(tasks)
fun update(listId: Long, uid: String, builder: BatchOperation.CpoBuilder): ContentProviderOperation =
builder
.withSelection(
"${Tasks.LIST_ID} = $listId AND ${Tasks._UID} = '$uid'",
null)
.withValues(values)
emptyArray()
)
.build()
suspend fun getId(listId: Long, uid: String?): Long? =
@ -235,7 +234,7 @@ class OpenTaskDao @Inject constructor(
private fun Cursor.getString(columnName: String): String? =
getString(getColumnIndex(columnName))
fun Cursor.getInt(columnName: String): Int =
private fun Cursor.getInt(columnName: String): Int =
getInt(getColumnIndex(columnName))
private fun Cursor.getLong(columnName: String): Long =

@ -1,31 +1,24 @@
package org.tasks.opentasks
import android.content.ContentProviderOperation
import android.content.ContentValues
import android.content.Context
import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task
import com.todoroo.astrid.data.Task.Companion.sanitizeRRule
import com.todoroo.astrid.service.TaskDeleter
import dagger.hilt.android.qualifiers.ApplicationContext
import net.fortuna.ical4j.model.property.RRule
import org.dmfs.tasks.contract.TaskContract.Tasks
import org.tasks.LocalBroadcastManager
import org.tasks.R
import org.tasks.analytics.Constants
import org.tasks.analytics.Firebase
import org.tasks.billing.Inventory
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.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.startOfDay
import timber.log.Timber
import java.util.*
import javax.inject.Inject
@ -40,13 +33,10 @@ class OpenTasksSynchronizer @Inject constructor(
private val taskDao: TaskDao,
private val firebase: Firebase,
private val iCalendar: iCalendar,
private val locationDao: LocationDao,
private val openTaskDao: OpenTaskDao,
private val tagDataDao: TagDataDao,
private val inventory: Inventory) {
private val cr = context.contentResolver
suspend fun sync() {
val lists = openTaskDao.getListsByAccount()
lists.newAccounts(caldavDao)
@ -212,60 +202,21 @@ class OpenTasksSynchronizer @Inject constructor(
): Pair<CaldavTask, ContentProviderOperation>? {
val caldavTask = caldavDao.getTask(task.id) ?: return null
caldavTask.lastSync = task.modificationDate
val values = ContentValues()
values.put(Tasks.LIST_ID, listId)
values.put(Tasks.TITLE, task.title)
values.put(Tasks.DESCRIPTION, task.notes)
values.put(Tasks.GEO, locationDao.getGeofences(task.id).toGeoString())
values.put(Tasks.RRULE, if (task.isRecurring) {
val rrule = RRule(task.getRecurrenceWithoutFrom()!!.replace("RRULE:", ""))
if (task.repeatUntil > 0) {
rrule.recur.until = DateTime(task.repeatUntil).toUTC().toDateTime()
}
RRule(rrule.value.sanitizeRRule()).value
} else null)
val allDay = !task.hasDueTime() && !task.hasStartTime()
values.put(Tasks.IS_ALLDAY, if (allDay) 1 else 0)
values.put(Tasks.DUE, when {
task.hasDueTime() -> task.dueDate
task.hasDueDate() -> task.dueDate.startOfDay()
else -> null
})
values.put(Tasks.DTSTART, when {
task.hasStartTime() -> task.hideUntil
task.hasStartDate() -> task.hideUntil.startOfDay()
else -> null
})
values.put(Tasks.COMPLETED_IS_ALLDAY, 0)
values.put(Tasks.COMPLETED, if (task.isCompleted) task.completionDate else null)
values.put(Tasks.STATUS, if (task.isCompleted) Tasks.STATUS_COMPLETED else null)
values.put(Tasks.PERCENT_COMPLETE, if (task.isCompleted) 100 else null)
if (!allDay || task.isCompleted) {
values.put(Tasks.TZ, TimeZone.getDefault().id)
}
values.put(Tasks.PARENT_ID, null as Long?)
val existing = cr.query(
Tasks.getContentUri(openTaskDao.authority),
arrayOf(Tasks.PRIORITY),
"${Tasks.LIST_ID} = $listId AND ${Tasks._UID} = '${caldavTask.remoteId}'",
null,
null)?.use {
if (!it.moveToFirst()) {
return@use false
}
values.put(Tasks.PRIORITY, toRemote(it.getInt(Tasks.PRIORITY), task.priority))
true
} ?: false
val remoteModel = openTaskDao.getTask(listId, caldavTask.remoteId!!)
?: at.bitfire.ical4android.Task()
val isNew = remoteModel.uid.isNullOrBlank()
iCalendar.toVtodo(caldavTask, task, remoteModel)
val builder = MyAndroidTask(remoteModel).toBuilder(openTaskDao.tasks, isNew)
val operation = try {
if (existing) {
openTaskDao.update(listId, caldavTask.remoteId!!, values)
} else {
if (isNew) {
if (isEteSync) {
values.put(Tasks.SYNC2, caldavTask.remoteId)
builder.withValue(Tasks.SYNC2, caldavTask.remoteId)
}
values.put(Tasks._UID, caldavTask.remoteId)
values.put(Tasks.PRIORITY, toRemote(task.priority, task.priority))
openTaskDao.insert(values)
builder.withValue(Tasks.LIST_ID, listId)
openTaskDao.insert(builder)
} else {
openTaskDao.update(listId, caldavTask.remoteId!!, builder)
}
} catch (e: Exception) {
firebase.reportException(e)
@ -285,8 +236,4 @@ class OpenTasksSynchronizer @Inject constructor(
iCalendar.fromVtodo(calendar, existing, it, null, null, etag)
}
}
companion object {
private fun Location?.toGeoString(): String? = this?.let { "$longitude,$latitude" }
}
}

@ -95,8 +95,8 @@ class ThunderbirdTests {
@Test
fun dontTruncateTimeFromUntil() {
val (task, caldavTask) = setup("thunderbird/repeat_until_date_time.txt")
val remote = CaldavConverter.toCaldav(caldavTask, task)
val (task, caldavTask, remote) = setup("thunderbird/repeat_until_date_time.txt")
CaldavConverter.toCaldav(caldavTask, task, remote)
assertEquals(
"FREQ=WEEKLY;UNTIL=20200731T160000Z;BYDAY=MO,TU,WE,TH,FR",
remote.rRule!!.value)

@ -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:007f7751d5
++--- com.gitlab.abaker:ical4android:0e928b567c
+| +--- 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:007f7751d5
++--- com.gitlab.abaker:ical4android:0e928b567c
+| +--- 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