Remove CaldavConverter

pull/1348/head
Alex Baker 5 years ago
parent e45f767c1f
commit 9ae31d5949

@ -4,7 +4,7 @@ import android.content.Context
import at.bitfire.ical4android.Task.Companion.tasksFromReader import at.bitfire.ical4android.Task.Companion.tasksFromReader
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.tasks.caldav.CaldavConverter import org.tasks.caldav.iCalendar.Companion.applyRemote
import org.tasks.data.CaldavTask import org.tasks.data.CaldavTask
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.time.DateTime import org.tasks.time.DateTime
@ -40,7 +40,7 @@ object TestUtilities {
fun vtodo(path: String): Task { fun vtodo(path: String): Task {
val task = Task() val task = Task()
CaldavConverter.apply(task, fromResource(path)) task.applyRemote(fromResource(path))
return task return task
} }
@ -48,7 +48,7 @@ object TestUtilities {
val task = Task() val task = Task()
val vtodo = readFile(path) val vtodo = readFile(path)
val remote = fromString(vtodo) val remote = fromString(vtodo)
CaldavConverter.apply(task, remote) task.applyRemote(remote)
return Triple(task, CaldavTask().apply { this.vtodo = vtodo }, remote) return Triple(task, CaldavTask().apply { this.vtodo = vtodo }, remote)
} }

@ -1,138 +0,0 @@
package org.tasks.caldav;
import static com.todoroo.andlib.utility.DateUtilities.now;
import static com.todoroo.astrid.data.Task.withoutRRULE;
import static org.tasks.caldav.iCalendar.getLocal;
import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.time.DateTime.UTC;
import static org.tasks.time.DateTimeUtils.startOfDay;
import at.bitfire.ical4android.DateUtils;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.Task.Priority;
import java.text.ParseException;
import java.util.TimeZone;
import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.property.Completed;
import net.fortuna.ical4j.model.property.DtStart;
import net.fortuna.ical4j.model.property.Due;
import net.fortuna.ical4j.model.property.RRule;
import net.fortuna.ical4j.model.property.Status;
import org.tasks.data.CaldavTask;
import timber.log.Timber;
public class CaldavConverter {
public static void apply(Task local, at.bitfire.ical4android.Task remote) {
Completed completedAt = remote.getCompletedAt();
if (completedAt != null) {
local.setCompletionDate(getLocal(completedAt));
} else if (remote.getStatus() == Status.VTODO_COMPLETED) {
if (!local.isCompleted()) {
local.setCompletionDate(now());
}
} else {
local.setCompletionDate(0L);
}
Long createdAt = remote.getCreatedAt();
if (createdAt != null) {
local.setCreationDate(newDateTime(createdAt, UTC).toLocal().getMillis());
}
local.setTitle(remote.getSummary());
local.setNotes(remote.getDescription());
local.setPriority(fromRemote(remote.getPriority()));
local.setRecurrence(remote.getRRule());
iCalendar.Companion.apply(remote.getDue(), local);
iCalendar.Companion.apply(remote.getDtStart(), local);
}
public static @Priority int fromRemote(int remotePriority) {
// https://tools.ietf.org/html/rfc5545#section-3.8.1.9
if (remotePriority == 0) {
return Priority.NONE;
}
if (remotePriority == 5) {
return Priority.MEDIUM;
}
return remotePriority < 5 ? Priority.HIGH : Priority.LOW;
}
public static int toRemote(int remotePriority, int localPriority) {
switch (localPriority) {
case Priority.NONE:
return 0;
case Priority.MEDIUM:
return 5;
case Priority.HIGH:
return remotePriority < 5 ? Math.max(1, remotePriority) : 1;
default:
return remotePriority > 5 ? Math.min(9, remotePriority) : 9;
}
}
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());
boolean allDay = !task.hasDueTime() && !task.hasStartTime();
long dueDate = task.hasDueTime() ? task.getDueDate() : startOfDay(task.getDueDate());
long startDate = task.hasStartTime() ? task.getHideUntil() : startOfDay(task.getHideUntil());
if (dueDate > 0) {
startDate = Math.min(dueDate, startDate);
remote.setDue(new Due(allDay ? getDate(dueDate) : getDateTime(dueDate)));
} else {
remote.setDue(null);
}
if (startDate > 0) {
remote.setDtStart(new DtStart(allDay ? getDate(startDate) : getDateTime(startDate)));
} else {
remote.setDtStart(null);
}
if (task.isCompleted()) {
remote.setCompletedAt(new Completed(new DateTime(task.getCompletionDate())));
remote.setStatus(Status.VTODO_COMPLETED);
remote.setPercentComplete(100);
} else if (remote.getCompletedAt() != null) {
remote.setCompletedAt(null);
remote.setStatus(null);
remote.setPercentComplete(null);
}
if (task.isRecurring()) {
try {
RRule rrule = new RRule(withoutRRULE(task.getRecurrenceWithoutFrom()));
long repeatUntil = task.getRepeatUntil();
rrule
.getRecur()
.setUntil(
repeatUntil > 0 ? new DateTime(newDateTime(repeatUntil).toUTC().getMillis()) : null);
String sanitized = Task.sanitizeRRule(rrule.getValue()); // ical4j adds COUNT=-1 if there is an UNTIL value
remote.setRRule(new RRule(sanitized));
} catch (ParseException e) {
Timber.e(e);
}
} else {
remote.setRRule(null);
}
remote.setLastModified(newDateTime(task.getModificationDate()).toUTC().getMillis());
remote.setPriority(toRemote(remote.getPriority(), task.getPriority()));
iCalendar.Companion.setParent(remote, task.getParent() == 0 ? null : caldavTask.getRemoteParent());
}
private static Date getDate(long timestamp) {
return new Date(timestamp + newDateTime(timestamp).getOffset());
}
private static DateTime getDateTime(long timestamp) {
net.fortuna.ical4j.model.TimeZone tz =
DateUtils.INSTANCE.ical4jTimeZone(TimeZone.getDefault().getID());
DateTime dateTime = new DateTime(tz != null
? timestamp
: new org.tasks.time.DateTime(timestamp).toUTC().getMillis());
dateTime.setTimeZone(tz);
return dateTime;
}
}

@ -1,14 +1,19 @@
package org.tasks.caldav package org.tasks.caldav
import at.bitfire.ical4android.DateUtils.ical4jTimeZone
import at.bitfire.ical4android.Task import at.bitfire.ical4android.Task
import at.bitfire.ical4android.Task.Companion.tasksFromReader import at.bitfire.ical4android.Task.Companion.tasksFromReader
import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task.Companion.HIDE_UNTIL_SPECIFIC_DAY 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.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
import com.todoroo.astrid.data.Task.Companion.URGENCY_SPECIFIC_DAY_TIME import com.todoroo.astrid.data.Task.Companion.URGENCY_SPECIFIC_DAY_TIME
import com.todoroo.astrid.data.Task.Companion.sanitizeRRule
import com.todoroo.astrid.data.Task.Companion.withoutRRULE
import com.todoroo.astrid.helper.UUIDHelper import com.todoroo.astrid.helper.UUIDHelper
import com.todoroo.astrid.service.TaskCreator import com.todoroo.astrid.service.TaskCreator
import net.fortuna.ical4j.model.Date
import net.fortuna.ical4j.model.DateTime import net.fortuna.ical4j.model.DateTime
import net.fortuna.ical4j.model.Parameter import net.fortuna.ical4j.model.Parameter
import net.fortuna.ical4j.model.Property import net.fortuna.ical4j.model.Property
@ -19,15 +24,20 @@ import org.tasks.caldav.GeoUtils.equalish
import org.tasks.caldav.GeoUtils.toGeo import org.tasks.caldav.GeoUtils.toGeo
import org.tasks.caldav.GeoUtils.toLikeString import org.tasks.caldav.GeoUtils.toLikeString
import org.tasks.data.* import org.tasks.data.*
import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.jobs.WorkManager import org.tasks.jobs.WorkManager
import org.tasks.location.GeofenceApi import org.tasks.location.GeofenceApi
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.time.DateTime.UTC import org.tasks.time.DateTime.UTC
import org.tasks.time.DateTimeUtils.startOfDay
import timber.log.Timber import timber.log.Timber
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.StringReader import java.io.StringReader
import java.text.ParseException
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.max
import kotlin.math.min
@Suppress("ClassName") @Suppress("ClassName")
class iCalendar @Inject constructor( class iCalendar @Inject constructor(
@ -107,7 +117,7 @@ class iCalendar @Inject constructor(
} }
suspend fun toVtodo(caldavTask: CaldavTask, task: com.todoroo.astrid.data.Task, remoteModel: Task) { suspend fun toVtodo(caldavTask: CaldavTask, task: com.todoroo.astrid.data.Task, remoteModel: Task) {
CaldavConverter.toCaldav(caldavTask, task, remoteModel) remoteModel.applyLocal(caldavTask, task)
remoteModel.order = caldavTask.order remoteModel.order = caldavTask.order
val categories = remoteModel.categories val categories = remoteModel.categories
categories.clear() categories.clear()
@ -139,7 +149,7 @@ class iCalendar @Inject constructor(
existing?.task = id existing?.task = id
} }
val caldavTask = existing ?: CaldavTask(task.id, calendar.uuid, remote.uid, obj) val caldavTask = existing ?: CaldavTask(task.id, calendar.uuid, remote.uid, obj)
CaldavConverter.apply(task, remote) task.applyRemote(remote)
setPlace(task.id, remote.geoPosition) setPlace(task.id, remote.geoPosition)
tagDao.applyTags(task, tagDataDao, getTags(remote.categories)) tagDao.applyTags(task, tagDataDao, getTags(remote.categories))
task.suppressSync() task.suppressSync()
@ -260,5 +270,97 @@ class iCalendar @Inject constructor(
} }
} }
} }
fun com.todoroo.astrid.data.Task.applyRemote(remote: Task) {
val completedAt = remote.completedAt
if (completedAt != null) {
completionDate = getLocal(completedAt)
} else if (remote.status === Status.VTODO_COMPLETED) {
if (!isCompleted) {
completionDate = DateUtilities.now()
}
} else {
completionDate = 0L
}
remote.createdAt?.let {
creationDate = newDateTime(it, UTC).toLocal().millis
}
title = remote.summary
notes = remote.description
priority = when (remote.priority) {
// https://tools.ietf.org/html/rfc5545#section-3.8.1.9
in 1..4 -> com.todoroo.astrid.data.Task.Priority.HIGH
5 -> com.todoroo.astrid.data.Task.Priority.MEDIUM
in 6..9 -> com.todoroo.astrid.data.Task.Priority.LOW
else -> com.todoroo.astrid.data.Task.Priority.NONE
}
setRecurrence(remote.rRule)
remote.due.apply(this)
remote.dtStart.apply(this)
}
fun Task.applyLocal(caldavTask: CaldavTask, task: com.todoroo.astrid.data.Task) {
createdAt = newDateTime(task.creationDate).toUTC().millis
summary = task.title
description = task.notes
val allDay = !task.hasDueTime() && !task.hasStartTime()
val dueDate = if (task.hasDueTime()) task.dueDate else task.dueDate.startOfDay()
var startDate = if (task.hasStartTime()) task.hideUntil else task.hideUntil.startOfDay()
due = if (dueDate > 0) {
startDate = min(dueDate, startDate)
Due(if (allDay) getDate(dueDate) else getDateTime(dueDate))
} else {
null
}
dtStart = if (startDate > 0) {
DtStart(if (allDay) getDate(startDate) else getDateTime(startDate))
} else {
null
}
if (task.isCompleted) {
completedAt = Completed(DateTime(task.completionDate))
status = Status.VTODO_COMPLETED
percentComplete = 100
} else if (completedAt != null) {
completedAt = null
status = null
percentComplete = null
}
rRule = if (task.isRecurring) {
try {
val rrule = RRule(task.getRecurrenceWithoutFrom().withoutRRULE())
val repeatUntil = task.repeatUntil
rrule
.recur.until = if (repeatUntil > 0) DateTime(newDateTime(repeatUntil).toUTC().millis) else null
val sanitized: String = rrule.value.sanitizeRRule()!! // ical4j adds COUNT=-1 if there is an UNTIL value
RRule(sanitized)
} catch (e: ParseException) {
Timber.e(e)
null
}
} else {
null
}
lastModified = newDateTime(task.modificationDate).toUTC().millis
priority = when (task.priority) {
com.todoroo.astrid.data.Task.Priority.NONE -> 0
com.todoroo.astrid.data.Task.Priority.MEDIUM -> 5
com.todoroo.astrid.data.Task.Priority.HIGH ->
if (priority < 5) max(1, priority) else 1
else -> if (priority > 5) min(9, priority) else 9
}
setParent(if (task.parent == 0L) null else caldavTask.remoteParent)
}
private fun getDate(timestamp: Long): Date {
return Date(timestamp + newDateTime(timestamp).offset)
}
private fun getDateTime(timestamp: Long): DateTime {
val tz = ical4jTimeZone(TimeZone.getDefault().id)
val dateTime = DateTime(if (tz != null) timestamp else org.tasks.time.DateTime(timestamp).toUTC().millis)
dateTime.timeZone = tz
return dateTime
}
} }
} }

@ -8,6 +8,7 @@ import org.junit.Ignore
import org.junit.Test import org.junit.Test
import org.tasks.TestUtilities.setup import org.tasks.TestUtilities.setup
import org.tasks.TestUtilities.vtodo import org.tasks.TestUtilities.vtodo
import org.tasks.caldav.iCalendar.Companion.applyLocal
import org.tasks.time.DateTime import org.tasks.time.DateTime
import java.util.* import java.util.*
@ -96,7 +97,7 @@ class ThunderbirdTests {
@Test @Test
fun dontTruncateTimeFromUntil() { fun dontTruncateTimeFromUntil() {
val (task, caldavTask, remote) = setup("thunderbird/repeat_until_date_time.txt") val (task, caldavTask, remote) = setup("thunderbird/repeat_until_date_time.txt")
CaldavConverter.toCaldav(caldavTask, task, remote) remote.applyLocal(caldavTask, task)
assertEquals( assertEquals(
"FREQ=WEEKLY;UNTIL=20200731T160000Z;BYDAY=MO,TU,WE,TH,FR", "FREQ=WEEKLY;UNTIL=20200731T160000Z;BYDAY=MO,TU,WE,TH,FR",
remote.rRule!!.value) remote.rRule!!.value)

Loading…
Cancel
Save