Skip to content
This repository was archived by the owner on May 26, 2026. It is now read-only.

Commit 7c4abc5

Browse files
authored
[DmfsTask] implement status field handlers (#436)
* Implement PriorityHandler with unit test * Implement ClassificationHandler with unit test * Implement StatusHandler with unit test * Implement CompletedHandler with unit test * Implement PercentCompleteHandler with unit test * Fix PriorityHandlerTest and restore Instant import in DmfsTaskProcessor
1 parent c7b9fba commit 7c4abc5

11 files changed

Lines changed: 393 additions & 23 deletions

File tree

lib/src/main/kotlin/at/bitfire/synctools/mapping/tasks/DmfsTaskProcessor.kt

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import android.content.ContentValues
1010
import at.bitfire.ical4android.Task
1111
import at.bitfire.ical4android.UnknownProperty
1212
import at.bitfire.synctools.mapping.tasks.handler.AlarmsHandler
13+
import at.bitfire.synctools.mapping.tasks.handler.ClassificationHandler
1314
import at.bitfire.synctools.mapping.tasks.handler.ColorHandler
15+
import at.bitfire.synctools.mapping.tasks.handler.CompletedHandler
1416
import at.bitfire.synctools.mapping.tasks.handler.DescriptionHandler
1517
import at.bitfire.synctools.mapping.tasks.handler.DmfsTaskFieldHandler
1618
import at.bitfire.synctools.mapping.tasks.handler.DmfsTaskPropertyHandler
@@ -19,29 +21,28 @@ import at.bitfire.synctools.mapping.tasks.handler.DurationHandler
1921
import at.bitfire.synctools.mapping.tasks.handler.GeoHandler
2022
import at.bitfire.synctools.mapping.tasks.handler.LocationHandler
2123
import at.bitfire.synctools.mapping.tasks.handler.OrganizerHandler
24+
import at.bitfire.synctools.mapping.tasks.handler.PercentCompleteHandler
25+
import at.bitfire.synctools.mapping.tasks.handler.PriorityHandler
2226
import at.bitfire.synctools.mapping.tasks.handler.SequenceHandler
2327
import at.bitfire.synctools.mapping.tasks.handler.StartTimeHandler
28+
import at.bitfire.synctools.mapping.tasks.handler.StatusHandler
2429
import at.bitfire.synctools.mapping.tasks.handler.TitleHandler
2530
import at.bitfire.synctools.mapping.tasks.handler.UidHandler
2631
import at.bitfire.synctools.mapping.tasks.handler.UrlHandler
2732
import at.bitfire.synctools.storage.tasks.DmfsTask.Companion.UNKNOWN_PROPERTY_DATA
2833
import at.bitfire.synctools.storage.tasks.DmfsTaskList
2934
import at.bitfire.synctools.util.AndroidTimeUtils
3035
import net.fortuna.ical4j.model.parameter.RelType
31-
import net.fortuna.ical4j.model.property.Clazz
32-
import net.fortuna.ical4j.model.property.Completed
3336
import net.fortuna.ical4j.model.property.ExDate
3437
import net.fortuna.ical4j.model.property.RDate
3538
import net.fortuna.ical4j.model.property.RRule
3639
import net.fortuna.ical4j.model.property.RelatedTo
37-
import net.fortuna.ical4j.model.property.Status
3840
import org.dmfs.tasks.contract.TaskContract.Properties
3941
import org.dmfs.tasks.contract.TaskContract.Property.Alarm
4042
import org.dmfs.tasks.contract.TaskContract.Property.Category
4143
import org.dmfs.tasks.contract.TaskContract.Property.Comment
4244
import org.dmfs.tasks.contract.TaskContract.Property.Relation
4345
import org.dmfs.tasks.contract.TaskContract.Tasks
44-
import java.time.Instant
4546
import java.time.temporal.Temporal
4647
import java.util.logging.Level
4748
import java.util.logging.Logger
@@ -67,6 +68,11 @@ class DmfsTaskProcessor(
6768
ColorHandler(),
6869
UrlHandler(),
6970
OrganizerHandler(),
71+
PriorityHandler(),
72+
ClassificationHandler(),
73+
StatusHandler(),
74+
CompletedHandler(),
75+
PercentCompleteHandler(),
7076
)
7177

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

8389
to.userAgents += taskList.providerName.packageName
8490

85-
values.getAsInteger(Tasks.PRIORITY)?.let { to.priority = it }
86-
8791
// Note: big method – maybe split? Depends on how we want to proceed with refactoring.
8892

89-
to.classification = when (values.getAsInteger(Tasks.CLASSIFICATION)) {
90-
Tasks.CLASSIFICATION_PUBLIC -> Clazz(Clazz.VALUE_PUBLIC)
91-
Tasks.CLASSIFICATION_PRIVATE -> Clazz(Clazz.VALUE_PRIVATE)
92-
Tasks.CLASSIFICATION_CONFIDENTIAL -> Clazz(Clazz.VALUE_CONFIDENTIAL)
93-
else -> null
94-
}
95-
96-
values.getAsLong(Tasks.COMPLETED)?.let { to.completedAt = Completed(Instant.ofEpochMilli(it)) }
97-
values.getAsInteger(Tasks.PERCENT_COMPLETE)?.let { to.percentComplete = it }
98-
99-
to.status = when (values.getAsInteger(Tasks.STATUS)) {
100-
Tasks.STATUS_IN_PROCESS -> Status(Status.VALUE_IN_PROCESS)
101-
Tasks.STATUS_COMPLETED -> Status(Status.VALUE_COMPLETED)
102-
Tasks.STATUS_CANCELLED -> Status(Status.VALUE_CANCELLED)
103-
else -> Status(Status.VALUE_NEEDS_ACTION)
104-
}
105-
10693
val allDay = (values.getAsInteger(Tasks.IS_ALLDAY) ?: 0) != 0
10794

10895
values.getAsLong(Tasks.CREATED)?.let { to.createdAt = it }
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* This file is part of bitfireAT/synctools which is released under GPLv3.
3+
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
4+
* SPDX-License-Identifier: GPL-3.0-or-later
5+
*/
6+
7+
package at.bitfire.synctools.mapping.tasks.handler
8+
9+
import android.content.ContentValues
10+
import at.bitfire.ical4android.Task
11+
import net.fortuna.ical4j.model.property.Clazz
12+
import org.dmfs.tasks.contract.TaskContract.Tasks
13+
14+
class ClassificationHandler : DmfsTaskFieldHandler {
15+
16+
override fun process(from: ContentValues, to: Task) {
17+
to.classification = when (from.getAsInteger(Tasks.CLASSIFICATION)) {
18+
Tasks.CLASSIFICATION_PUBLIC -> Clazz(Clazz.VALUE_PUBLIC)
19+
Tasks.CLASSIFICATION_PRIVATE -> Clazz(Clazz.VALUE_PRIVATE)
20+
Tasks.CLASSIFICATION_CONFIDENTIAL -> Clazz(Clazz.VALUE_CONFIDENTIAL)
21+
else -> null
22+
}
23+
}
24+
25+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* This file is part of bitfireAT/synctools which is released under GPLv3.
3+
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
4+
* SPDX-License-Identifier: GPL-3.0-or-later
5+
*/
6+
7+
package at.bitfire.synctools.mapping.tasks.handler
8+
9+
import android.content.ContentValues
10+
import at.bitfire.ical4android.Task
11+
import net.fortuna.ical4j.model.property.Completed
12+
import org.dmfs.tasks.contract.TaskContract.Tasks
13+
import java.time.Instant
14+
15+
class CompletedHandler : DmfsTaskFieldHandler {
16+
17+
override fun process(from: ContentValues, to: Task) {
18+
from.getAsLong(Tasks.COMPLETED)?.let { epochMillis ->
19+
to.completedAt = Completed(Instant.ofEpochMilli(epochMillis))
20+
}
21+
}
22+
23+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* This file is part of bitfireAT/synctools which is released under GPLv3.
3+
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
4+
* SPDX-License-Identifier: GPL-3.0-or-later
5+
*/
6+
7+
package at.bitfire.synctools.mapping.tasks.handler
8+
9+
import android.content.ContentValues
10+
import at.bitfire.ical4android.Task
11+
import org.dmfs.tasks.contract.TaskContract.Tasks
12+
13+
class PercentCompleteHandler : DmfsTaskFieldHandler {
14+
15+
override fun process(from: ContentValues, to: Task) {
16+
from.getAsInteger(Tasks.PERCENT_COMPLETE)?.let { percent ->
17+
to.percentComplete = percent
18+
}
19+
}
20+
21+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* This file is part of bitfireAT/synctools which is released under GPLv3.
3+
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
4+
* SPDX-License-Identifier: GPL-3.0-or-later
5+
*/
6+
7+
package at.bitfire.synctools.mapping.tasks.handler
8+
9+
import android.content.ContentValues
10+
import at.bitfire.ical4android.Task
11+
import org.dmfs.tasks.contract.TaskContract.Tasks
12+
13+
class PriorityHandler : DmfsTaskFieldHandler {
14+
15+
override fun process(from: ContentValues, to: Task) {
16+
from.getAsInteger(Tasks.PRIORITY)?.let { to.priority = it }
17+
}
18+
19+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* This file is part of bitfireAT/synctools which is released under GPLv3.
3+
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
4+
* SPDX-License-Identifier: GPL-3.0-or-later
5+
*/
6+
7+
package at.bitfire.synctools.mapping.tasks.handler
8+
9+
import android.content.ContentValues
10+
import at.bitfire.ical4android.Task
11+
import net.fortuna.ical4j.model.property.Status
12+
import org.dmfs.tasks.contract.TaskContract.Tasks
13+
14+
class StatusHandler : DmfsTaskFieldHandler {
15+
16+
override fun process(from: ContentValues, to: Task) {
17+
to.status = when (from.getAsInteger(Tasks.STATUS)) {
18+
Tasks.STATUS_IN_PROCESS -> Status(Status.VALUE_IN_PROCESS)
19+
Tasks.STATUS_COMPLETED -> Status(Status.VALUE_COMPLETED)
20+
Tasks.STATUS_CANCELLED -> Status(Status.VALUE_CANCELLED)
21+
else -> Status(Status.VALUE_NEEDS_ACTION)
22+
}
23+
}
24+
25+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* This file is part of bitfireAT/synctools which is released under GPLv3.
3+
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
4+
* SPDX-License-Identifier: GPL-3.0-or-later
5+
*/
6+
7+
package at.bitfire.synctools.mapping.tasks.handler
8+
9+
import android.content.ContentValues
10+
import androidx.core.content.contentValuesOf
11+
import at.bitfire.ical4android.Task
12+
import net.fortuna.ical4j.model.property.Clazz
13+
import org.dmfs.tasks.contract.TaskContract.Tasks
14+
import org.junit.Assert.assertEquals
15+
import org.junit.Assert.assertNull
16+
import org.junit.Test
17+
import org.junit.runner.RunWith
18+
import org.robolectric.RobolectricTestRunner
19+
20+
@RunWith(RobolectricTestRunner::class)
21+
class ClassificationHandlerTest {
22+
23+
private val handler = ClassificationHandler()
24+
25+
@Test
26+
fun `No CLASSIFICATION`() {
27+
val task = Task()
28+
handler.process(ContentValues(), task)
29+
assertNull(task.classification)
30+
}
31+
32+
@Test
33+
fun `CLASSIFICATION_PUBLIC maps to CLASS PUBLIC`() {
34+
val task = Task()
35+
handler.process(contentValuesOf(Tasks.CLASSIFICATION to Tasks.CLASSIFICATION_PUBLIC), task)
36+
assertEquals(Clazz(Clazz.VALUE_PUBLIC), task.classification)
37+
}
38+
39+
@Test
40+
fun `CLASSIFICATION_PRIVATE maps to CLASS PRIVATE`() {
41+
val task = Task()
42+
handler.process(contentValuesOf(Tasks.CLASSIFICATION to Tasks.CLASSIFICATION_PRIVATE), task)
43+
assertEquals(Clazz(Clazz.VALUE_PRIVATE), task.classification)
44+
}
45+
46+
@Test
47+
fun `CLASSIFICATION_CONFIDENTIAL maps to CLASS CONFIDENTIAL`() {
48+
val task = Task()
49+
handler.process(contentValuesOf(Tasks.CLASSIFICATION to Tasks.CLASSIFICATION_CONFIDENTIAL), task)
50+
assertEquals(Clazz(Clazz.VALUE_CONFIDENTIAL), task.classification)
51+
}
52+
53+
@Test
54+
fun `Unknown CLASSIFICATION maps to null`() {
55+
val task = Task()
56+
handler.process(contentValuesOf(Tasks.CLASSIFICATION to 99), task)
57+
assertNull(task.classification)
58+
}
59+
60+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* This file is part of bitfireAT/synctools which is released under GPLv3.
3+
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
4+
* SPDX-License-Identifier: GPL-3.0-or-later
5+
*/
6+
7+
package at.bitfire.synctools.mapping.tasks.handler
8+
9+
import android.content.ContentValues
10+
import androidx.core.content.contentValuesOf
11+
import at.bitfire.ical4android.Task
12+
import net.fortuna.ical4j.model.property.Completed
13+
import org.dmfs.tasks.contract.TaskContract.Tasks
14+
import org.junit.Assert.assertEquals
15+
import org.junit.Assert.assertNull
16+
import org.junit.Test
17+
import org.junit.runner.RunWith
18+
import org.robolectric.RobolectricTestRunner
19+
import java.time.Instant
20+
21+
@RunWith(RobolectricTestRunner::class)
22+
class CompletedHandlerTest {
23+
24+
private val handler = CompletedHandler()
25+
26+
@Test
27+
fun `No COMPLETED leaves completedAt null`() {
28+
val task = Task()
29+
handler.process(ContentValues(), task)
30+
assertNull(task.completedAt)
31+
}
32+
33+
@Test
34+
fun `COMPLETED epoch millis is mapped correctly`() {
35+
val task = Task()
36+
val epochMillis = 1_700_000_000_000L
37+
handler.process(contentValuesOf(Tasks.COMPLETED to epochMillis), task)
38+
assertEquals(Completed(Instant.ofEpochMilli(epochMillis)), task.completedAt)
39+
}
40+
41+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* This file is part of bitfireAT/synctools which is released under GPLv3.
3+
* Copyright © All Contributors. See the LICENSE and AUTHOR files in the root directory for details.
4+
* SPDX-License-Identifier: GPL-3.0-or-later
5+
*/
6+
7+
package at.bitfire.synctools.mapping.tasks.handler
8+
9+
import android.content.ContentValues
10+
import androidx.core.content.contentValuesOf
11+
import at.bitfire.ical4android.Task
12+
import org.dmfs.tasks.contract.TaskContract.Tasks
13+
import org.junit.Assert.assertEquals
14+
import org.junit.Assert.assertNull
15+
import org.junit.Test
16+
import org.junit.runner.RunWith
17+
import org.robolectric.RobolectricTestRunner
18+
19+
@RunWith(RobolectricTestRunner::class)
20+
class PercentCompleteHandlerTest {
21+
22+
private val handler = PercentCompleteHandler()
23+
24+
@Test
25+
fun `No PERCENT_COMPLETE leaves percentComplete null`() {
26+
val task = Task()
27+
handler.process(ContentValues(), task)
28+
assertNull(task.percentComplete)
29+
}
30+
31+
@Test
32+
fun `PERCENT_COMPLETE 0 is mapped correctly`() {
33+
val task = Task()
34+
handler.process(contentValuesOf(Tasks.PERCENT_COMPLETE to 0), task)
35+
assertEquals(0, task.percentComplete)
36+
}
37+
38+
@Test
39+
fun `PERCENT_COMPLETE 100 is mapped correctly`() {
40+
val task = Task()
41+
handler.process(contentValuesOf(Tasks.PERCENT_COMPLETE to 100), task)
42+
assertEquals(100, task.percentComplete)
43+
}
44+
45+
}

0 commit comments

Comments
 (0)