Skip to content
This repository was archived by the owner on May 26, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import android.content.ContentValues
import at.bitfire.ical4android.Task
import at.bitfire.ical4android.UnknownProperty
import at.bitfire.synctools.mapping.tasks.handler.AlarmsHandler
import at.bitfire.synctools.mapping.tasks.handler.ClassificationHandler
import at.bitfire.synctools.mapping.tasks.handler.ColorHandler
import at.bitfire.synctools.mapping.tasks.handler.CompletedHandler
import at.bitfire.synctools.mapping.tasks.handler.DescriptionHandler
import at.bitfire.synctools.mapping.tasks.handler.DmfsTaskFieldHandler
import at.bitfire.synctools.mapping.tasks.handler.DmfsTaskPropertyHandler
Expand All @@ -19,29 +21,28 @@ import at.bitfire.synctools.mapping.tasks.handler.DurationHandler
import at.bitfire.synctools.mapping.tasks.handler.GeoHandler
import at.bitfire.synctools.mapping.tasks.handler.LocationHandler
import at.bitfire.synctools.mapping.tasks.handler.OrganizerHandler
import at.bitfire.synctools.mapping.tasks.handler.PercentCompleteHandler
import at.bitfire.synctools.mapping.tasks.handler.PriorityHandler
import at.bitfire.synctools.mapping.tasks.handler.SequenceHandler
import at.bitfire.synctools.mapping.tasks.handler.StartTimeHandler
import at.bitfire.synctools.mapping.tasks.handler.StatusHandler
import at.bitfire.synctools.mapping.tasks.handler.TitleHandler
import at.bitfire.synctools.mapping.tasks.handler.UidHandler
import at.bitfire.synctools.mapping.tasks.handler.UrlHandler
import at.bitfire.synctools.storage.tasks.DmfsTask.Companion.UNKNOWN_PROPERTY_DATA
import at.bitfire.synctools.storage.tasks.DmfsTaskList
import at.bitfire.synctools.util.AndroidTimeUtils
import net.fortuna.ical4j.model.parameter.RelType
import net.fortuna.ical4j.model.property.Clazz
import net.fortuna.ical4j.model.property.Completed
import net.fortuna.ical4j.model.property.ExDate
import net.fortuna.ical4j.model.property.RDate
import net.fortuna.ical4j.model.property.RRule
import net.fortuna.ical4j.model.property.RelatedTo
import net.fortuna.ical4j.model.property.Status
import org.dmfs.tasks.contract.TaskContract.Properties
import org.dmfs.tasks.contract.TaskContract.Property.Alarm
import org.dmfs.tasks.contract.TaskContract.Property.Category
import org.dmfs.tasks.contract.TaskContract.Property.Comment
import org.dmfs.tasks.contract.TaskContract.Property.Relation
import org.dmfs.tasks.contract.TaskContract.Tasks
import java.time.Instant
import java.time.temporal.Temporal
import java.util.logging.Level
import java.util.logging.Logger
Expand All @@ -67,6 +68,11 @@ class DmfsTaskProcessor(
ColorHandler(),
UrlHandler(),
OrganizerHandler(),
PriorityHandler(),
ClassificationHandler(),
StatusHandler(),
CompletedHandler(),
PercentCompleteHandler(),
)

private val propertyHandlers: Map<String, DmfsTaskPropertyHandler> = mapOf(
Expand All @@ -82,27 +88,8 @@ class DmfsTaskProcessor(

to.userAgents += taskList.providerName.packageName

values.getAsInteger(Tasks.PRIORITY)?.let { to.priority = it }

// Note: big method – maybe split? Depends on how we want to proceed with refactoring.

to.classification = when (values.getAsInteger(Tasks.CLASSIFICATION)) {
Tasks.CLASSIFICATION_PUBLIC -> Clazz(Clazz.VALUE_PUBLIC)
Tasks.CLASSIFICATION_PRIVATE -> Clazz(Clazz.VALUE_PRIVATE)
Tasks.CLASSIFICATION_CONFIDENTIAL -> Clazz(Clazz.VALUE_CONFIDENTIAL)
else -> null
}

values.getAsLong(Tasks.COMPLETED)?.let { to.completedAt = Completed(Instant.ofEpochMilli(it)) }
values.getAsInteger(Tasks.PERCENT_COMPLETE)?.let { to.percentComplete = it }

to.status = when (values.getAsInteger(Tasks.STATUS)) {
Tasks.STATUS_IN_PROCESS -> Status(Status.VALUE_IN_PROCESS)
Tasks.STATUS_COMPLETED -> Status(Status.VALUE_COMPLETED)
Tasks.STATUS_CANCELLED -> Status(Status.VALUE_CANCELLED)
else -> Status(Status.VALUE_NEEDS_ACTION)
}

val allDay = (values.getAsInteger(Tasks.IS_ALLDAY) ?: 0) != 0

values.getAsLong(Tasks.CREATED)?.let { to.createdAt = it }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* This file is part of bitfireAT/synctools which is released under GPLv3.
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package at.bitfire.synctools.mapping.tasks.handler

import android.content.ContentValues
import at.bitfire.ical4android.Task
import net.fortuna.ical4j.model.property.Clazz
import org.dmfs.tasks.contract.TaskContract.Tasks

class ClassificationHandler : DmfsTaskFieldHandler {

override fun process(from: ContentValues, to: Task) {
to.classification = when (from.getAsInteger(Tasks.CLASSIFICATION)) {
Tasks.CLASSIFICATION_PUBLIC -> Clazz(Clazz.VALUE_PUBLIC)
Tasks.CLASSIFICATION_PRIVATE -> Clazz(Clazz.VALUE_PRIVATE)
Tasks.CLASSIFICATION_CONFIDENTIAL -> Clazz(Clazz.VALUE_CONFIDENTIAL)
else -> null
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* This file is part of bitfireAT/synctools which is released under GPLv3.
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package at.bitfire.synctools.mapping.tasks.handler

import android.content.ContentValues
import at.bitfire.ical4android.Task
import net.fortuna.ical4j.model.property.Completed
import org.dmfs.tasks.contract.TaskContract.Tasks
import java.time.Instant

class CompletedHandler : DmfsTaskFieldHandler {

override fun process(from: ContentValues, to: Task) {
from.getAsLong(Tasks.COMPLETED)?.let { epochMillis ->
to.completedAt = Completed(Instant.ofEpochMilli(epochMillis))
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* This file is part of bitfireAT/synctools which is released under GPLv3.
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package at.bitfire.synctools.mapping.tasks.handler

import android.content.ContentValues
import at.bitfire.ical4android.Task
import org.dmfs.tasks.contract.TaskContract.Tasks

class PercentCompleteHandler : DmfsTaskFieldHandler {

override fun process(from: ContentValues, to: Task) {
from.getAsInteger(Tasks.PERCENT_COMPLETE)?.let { percent ->
to.percentComplete = percent
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* This file is part of bitfireAT/synctools which is released under GPLv3.
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package at.bitfire.synctools.mapping.tasks.handler

import android.content.ContentValues
import at.bitfire.ical4android.Task
import org.dmfs.tasks.contract.TaskContract.Tasks

class PriorityHandler : DmfsTaskFieldHandler {

override fun process(from: ContentValues, to: Task) {
from.getAsInteger(Tasks.PRIORITY)?.let { to.priority = it }
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* This file is part of bitfireAT/synctools which is released under GPLv3.
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package at.bitfire.synctools.mapping.tasks.handler

import android.content.ContentValues
import at.bitfire.ical4android.Task
import net.fortuna.ical4j.model.property.Status
import org.dmfs.tasks.contract.TaskContract.Tasks

class StatusHandler : DmfsTaskFieldHandler {

override fun process(from: ContentValues, to: Task) {
to.status = when (from.getAsInteger(Tasks.STATUS)) {
Tasks.STATUS_IN_PROCESS -> Status(Status.VALUE_IN_PROCESS)
Tasks.STATUS_COMPLETED -> Status(Status.VALUE_COMPLETED)
Tasks.STATUS_CANCELLED -> Status(Status.VALUE_CANCELLED)
else -> Status(Status.VALUE_NEEDS_ACTION)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* This file is part of bitfireAT/synctools which is released under GPLv3.
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package at.bitfire.synctools.mapping.tasks.handler

import android.content.ContentValues
import androidx.core.content.contentValuesOf
import at.bitfire.ical4android.Task
import net.fortuna.ical4j.model.property.Clazz
import org.dmfs.tasks.contract.TaskContract.Tasks
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
class ClassificationHandlerTest {

private val handler = ClassificationHandler()

@Test
fun `No CLASSIFICATION`() {
val task = Task()
handler.process(ContentValues(), task)
assertNull(task.classification)
}

@Test
fun `CLASSIFICATION_PUBLIC maps to CLASS PUBLIC`() {
val task = Task()
handler.process(contentValuesOf(Tasks.CLASSIFICATION to Tasks.CLASSIFICATION_PUBLIC), task)
assertEquals(Clazz(Clazz.VALUE_PUBLIC), task.classification)
}

@Test
fun `CLASSIFICATION_PRIVATE maps to CLASS PRIVATE`() {
val task = Task()
handler.process(contentValuesOf(Tasks.CLASSIFICATION to Tasks.CLASSIFICATION_PRIVATE), task)
assertEquals(Clazz(Clazz.VALUE_PRIVATE), task.classification)
}

@Test
fun `CLASSIFICATION_CONFIDENTIAL maps to CLASS CONFIDENTIAL`() {
val task = Task()
handler.process(contentValuesOf(Tasks.CLASSIFICATION to Tasks.CLASSIFICATION_CONFIDENTIAL), task)
assertEquals(Clazz(Clazz.VALUE_CONFIDENTIAL), task.classification)
}

@Test
fun `Unknown CLASSIFICATION maps to null`() {
val task = Task()
handler.process(contentValuesOf(Tasks.CLASSIFICATION to 99), task)
assertNull(task.classification)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* This file is part of bitfireAT/synctools which is released under GPLv3.
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package at.bitfire.synctools.mapping.tasks.handler

import android.content.ContentValues
import androidx.core.content.contentValuesOf
import at.bitfire.ical4android.Task
import net.fortuna.ical4j.model.property.Completed
import org.dmfs.tasks.contract.TaskContract.Tasks
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import java.time.Instant

@RunWith(RobolectricTestRunner::class)
class CompletedHandlerTest {

private val handler = CompletedHandler()

@Test
fun `No COMPLETED leaves completedAt null`() {
val task = Task()
handler.process(ContentValues(), task)
assertNull(task.completedAt)
}

@Test
fun `COMPLETED epoch millis is mapped correctly`() {
val task = Task()
val epochMillis = 1_700_000_000_000L
handler.process(contentValuesOf(Tasks.COMPLETED to epochMillis), task)
assertEquals(Completed(Instant.ofEpochMilli(epochMillis)), task.completedAt)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* This file is part of bitfireAT/synctools which is released under GPLv3.
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
* SPDX-License-Identifier: GPL-3.0-or-later
*/

package at.bitfire.synctools.mapping.tasks.handler

import android.content.ContentValues
import androidx.core.content.contentValuesOf
import at.bitfire.ical4android.Task
import org.dmfs.tasks.contract.TaskContract.Tasks
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
class PercentCompleteHandlerTest {

private val handler = PercentCompleteHandler()

@Test
fun `No PERCENT_COMPLETE leaves percentComplete null`() {
val task = Task()
handler.process(ContentValues(), task)
assertNull(task.percentComplete)
}

@Test
fun `PERCENT_COMPLETE 0 is mapped correctly`() {
val task = Task()
handler.process(contentValuesOf(Tasks.PERCENT_COMPLETE to 0), task)
assertEquals(0, task.percentComplete)
}

@Test
fun `PERCENT_COMPLETE 100 is mapped correctly`() {
val task = Task()
handler.process(contentValuesOf(Tasks.PERCENT_COMPLETE to 100), task)
assertEquals(100, task.percentComplete)
}

}
Loading
Loading