Skip to content

Commit 5569e1a

Browse files
authored
Add new Android event builder logic (#65)
* Split legacy Android event builder logic into separate builders - Introduce `AndroidEventFieldBuilder` interface - Create `TitleBuilder` for handling event titles - Refactor `LegacyAndroidEventBuilder2` to use both new and legacy builders * KDoc * KDoc: null
1 parent fda79a4 commit 5569e1a

File tree

4 files changed

+133
-1
lines changed

4 files changed

+133
-1
lines changed

lib/src/main/kotlin/at/bitfire/synctools/mapping/calendar/LegacyAndroidEventBuilder2.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import at.bitfire.ical4android.util.TimeApiExtensions.toLocalTime
2828
import at.bitfire.ical4android.util.TimeApiExtensions.toRfc5545Duration
2929
import at.bitfire.ical4android.util.TimeApiExtensions.toZonedDateTime
3030
import at.bitfire.synctools.exception.InvalidLocalResourceException
31+
import at.bitfire.synctools.mapping.calendar.builder.AndroidEventFieldBuilder
32+
import at.bitfire.synctools.mapping.calendar.builder.TitleBuilder
3133
import at.bitfire.synctools.storage.calendar.AndroidCalendar
3234
import at.bitfire.synctools.storage.calendar.AndroidEvent2
3335
import at.bitfire.synctools.storage.calendar.EventAndExceptions
@@ -59,6 +61,9 @@ import java.util.logging.Logger
5961
*
6062
* Important: To use recurrence exceptions, you MUST set _SYNC_ID and ORIGINAL_SYNC_ID
6163
* in populateEvent() / buildEvent. Setting _ID and ORIGINAL_ID is not sufficient.
64+
*
65+
* Note: "Legacy" will be removed from the class name as soon as the [Event] dependency is
66+
* replaced by [at.bitfire.synctools.icalendar.AssociatedEvents].
6267
*/
6368
class LegacyAndroidEventBuilder2(
6469
private val calendar: AndroidCalendar,
@@ -92,6 +97,13 @@ class LegacyAndroidEventBuilder2(
9297
val entity = Entity(row)
9398
val from = recurrence ?: event
9499

100+
// new builders
101+
102+
for (builder in fieldBuilders())
103+
builder.build(from = from, main = event, to = entity)
104+
105+
// legacy fields
106+
95107
for (reminder in from.alarms)
96108
entity.addSubValue(Reminders.CONTENT_URI, buildReminder(reminder))
97109

@@ -328,7 +340,6 @@ class LegacyAndroidEventBuilder2(
328340
}
329341

330342
// text fields
331-
row.put(Events.TITLE, from.summary)
332343
row.put(Events.EVENT_LOCATION, from.location)
333344
row.put(Events.DESCRIPTION, from.description)
334345

@@ -498,4 +509,9 @@ class LegacyAndroidEventBuilder2(
498509
ExtendedProperties.VALUE to url
499510
)
500511

512+
513+
private fun fieldBuilders(): Array<AndroidEventFieldBuilder> = arrayOf(
514+
TitleBuilder()
515+
)
516+
501517
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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.calendar.builder
8+
9+
import android.content.Entity
10+
import at.bitfire.ical4android.Event
11+
12+
interface AndroidEventFieldBuilder {
13+
14+
/**
15+
* Maps the given event into the provided [Entity].
16+
*
17+
* If [from] references the same object as [main], this method is called for a main event (not an exception).
18+
* If [from] references another object as [main], this method is called for an exception (not a main event).
19+
*
20+
* So you can use (note the referential equality operator):
21+
*
22+
* ```
23+
* val buildsMainEvent = from === main
24+
* ```
25+
*
26+
* Note: The result of the mapping is used to either create or update the event row in the content provider.
27+
* For updates, explicit `null` values are required for fields that should be `null` (otherwise the value
28+
* wouldn't be updated to `null` in case of an event update).
29+
*
30+
* @param from event to map
31+
* @param main main event
32+
* @param to destination object where built values are stored (set `null` values, see note)
33+
*/
34+
fun build(from: Event, main: Event, to: Entity)
35+
36+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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.calendar.builder
8+
9+
import android.content.Entity
10+
import android.provider.CalendarContract.Events
11+
import at.bitfire.ical4android.Event
12+
import at.bitfire.vcard4android.Utils.trimToNull
13+
14+
class TitleBuilder: AndroidEventFieldBuilder {
15+
16+
override fun build(from: Event, main: Event, to: Entity) {
17+
to.entityValues.put(Events.TITLE, from.summary.trimToNull())
18+
}
19+
20+
}
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.calendar.builder
8+
9+
import android.content.ContentValues
10+
import android.content.Entity
11+
import android.provider.CalendarContract.Events
12+
import at.bitfire.ical4android.Event
13+
import org.junit.Assert.assertEquals
14+
import org.junit.Assert.assertNull
15+
import org.junit.Assert.assertTrue
16+
import org.junit.Test
17+
import org.junit.runner.RunWith
18+
import org.robolectric.RobolectricTestRunner
19+
20+
@RunWith(RobolectricTestRunner::class)
21+
class TitleBuilderTest {
22+
23+
private val builder = TitleBuilder()
24+
25+
@Test
26+
fun `No SUMMARY`() {
27+
val result = Entity(ContentValues())
28+
builder.build(
29+
from = Event(),
30+
main = Event(),
31+
to = result
32+
)
33+
assertTrue(result.entityValues.containsKey(Events.TITLE))
34+
assertNull(result.entityValues.get(Events.TITLE))
35+
}
36+
37+
@Test
38+
fun `SUMMARY is blank`() {
39+
val result = Entity(ContentValues())
40+
builder.build(
41+
from = Event(summary = ""),
42+
main = Event(),
43+
to = result
44+
)
45+
assertTrue(result.entityValues.containsKey(Events.TITLE))
46+
assertNull(result.entityValues.get(Events.TITLE))
47+
}
48+
49+
@Test
50+
fun `SUMMARY is text`() {
51+
val result = Entity(ContentValues())
52+
builder.build(
53+
from = Event(summary = "Event Summary"),
54+
main = Event(),
55+
to = result
56+
)
57+
assertEquals("Event Summary", result.entityValues.getAsString(Events.TITLE))
58+
}
59+
60+
}

0 commit comments

Comments
 (0)