@@ -8,7 +8,7 @@ package at.bitfire.synctools.mapping.calendar
88
99import android.content.Entity
1010import android.provider.CalendarContract.Events
11- import at.bitfire.ical4android.Event
11+ import at.bitfire.synctools.icalendar.AssociatedEvents
1212import at.bitfire.synctools.mapping.calendar.processor.AccessLevelProcessor
1313import at.bitfire.synctools.mapping.calendar.processor.AndroidEventFieldProcessor
1414import at.bitfire.synctools.mapping.calendar.processor.AttendeesProcessor
@@ -19,9 +19,9 @@ import at.bitfire.synctools.mapping.calendar.processor.DescriptionProcessor
1919import at.bitfire.synctools.mapping.calendar.processor.DurationProcessor
2020import at.bitfire.synctools.mapping.calendar.processor.EndTimeProcessor
2121import at.bitfire.synctools.mapping.calendar.processor.LocationProcessor
22- import at.bitfire.synctools.mapping.calendar.processor.MutatorsProcessor
2322import at.bitfire.synctools.mapping.calendar.processor.OrganizerProcessor
2423import at.bitfire.synctools.mapping.calendar.processor.OriginalInstanceTimeProcessor
24+ import at.bitfire.synctools.mapping.calendar.processor.ProdIdGenerator
2525import at.bitfire.synctools.mapping.calendar.processor.RecurrenceFieldsProcessor
2626import at.bitfire.synctools.mapping.calendar.processor.RemindersProcessor
2727import at.bitfire.synctools.mapping.calendar.processor.SequenceProcessor
@@ -33,29 +33,31 @@ import at.bitfire.synctools.mapping.calendar.processor.UnknownPropertiesProcesso
3333import at.bitfire.synctools.mapping.calendar.processor.UrlProcessor
3434import at.bitfire.synctools.storage.calendar.EventAndExceptions
3535import net.fortuna.ical4j.model.DateList
36+ import net.fortuna.ical4j.model.Property
3637import net.fortuna.ical4j.model.TimeZoneRegistryFactory
38+ import net.fortuna.ical4j.model.component.VEvent
3739import net.fortuna.ical4j.model.parameter.Value
3840import net.fortuna.ical4j.model.property.ExDate
41+ import net.fortuna.ical4j.model.property.RDate
42+ import net.fortuna.ical4j.model.property.RRule
3943import net.fortuna.ical4j.model.property.RecurrenceId
44+ import java.util.LinkedList
4045
4146/* *
42- * Legacy mapper from Android event main + data rows to an [Event]
43- * (former "populate..." methods).
47+ * Mapper from Android event main + data rows to [VEvent].
4448 *
45- * Important: To use recurrence exceptions, you MUST set _SYNC_ID and ORIGINAL_SYNC_ID
46- * in populateEvent() / buildEvent. Setting _ID and ORIGINAL_ID is not sufficient.
47- *
48- * @param accountName account name (used to generate self-attendee)
49+ * @param accountName account name (used to generate self-attendee)
50+ * @param prodIdGenerator generator for `PRODID`
4951 */
50- class LegacyAndroidEventProcessor (
51- private val accountName : String
52+ class AndroidEventProcessor (
53+ accountName : String ,
54+ private val prodIdGenerator : ProdIdGenerator
5255) {
5356
5457 private val tzRegistry = TimeZoneRegistryFactory .getInstance().createRegistry()
5558
5659 private val fieldProcessors: Array <AndroidEventFieldProcessor > = arrayOf(
5760 // event row fields
58- MutatorsProcessor (), // for PRODID
5961 UidProcessor (),
6062 OriginalInstanceTimeProcessor (tzRegistry),
6163 TitleProcessor (),
@@ -82,46 +84,51 @@ class LegacyAndroidEventProcessor(
8284 )
8385
8486
85- fun populate (eventAndExceptions : EventAndExceptions , to : Event ) {
87+ fun populate (eventAndExceptions : EventAndExceptions ): AssociatedEvents {
8688 // main event
87- populateEvent(
89+ val main = populateEvent(
8890 entity = eventAndExceptions.main,
89- main = eventAndExceptions.main,
90- to = to
91+ main = eventAndExceptions.main
9192 )
9293
9394 // Add exceptions of recurring main event
94- if (to.rRules.isNotEmpty() || to.rDates.isNotEmpty()) {
95+ val rRules = main.getProperties<RRule >(Property .RRULE )
96+ val rDates = main.getProperties<RDate >(Property .RDATE )
97+ val exceptions = LinkedList <VEvent >()
98+ if (rRules.isNotEmpty() || rDates.isNotEmpty()) {
9599 for (exception in eventAndExceptions.exceptions) {
96- val exceptionEvent = Event ()
97-
98100 // convert exception to Event
99- populateEvent(
101+ val exceptionEvent = populateEvent(
100102 entity = exception,
101- main = eventAndExceptions.main,
102- to = exceptionEvent
103+ main = eventAndExceptions.main
103104 )
104105
105106 // make sure that exception has a RECURRENCE-ID
106107 val recurrenceId = exceptionEvent.recurrenceId ? : continue
107108
108109 // generate EXDATE instead of VEVENT with RECURRENCE-ID for cancelled instances
109110 if (exception.entityValues.getAsInteger(Events .STATUS ) == Events .STATUS_CANCELED )
110- addAsExDate (exception, recurrenceId, to = to )
111+ main.properties + = asExDate (exception, recurrenceId)
111112 else
112- to. exceptions + = exceptionEvent
113+ exceptions + = exceptionEvent
113114 }
114115 }
116+
117+ return AssociatedEvents (
118+ main = main,
119+ exceptions = exceptions,
120+ prodId = generateProdId(eventAndExceptions.main)
121+ )
115122 }
116123
117- private fun addAsExDate (entity : Entity , recurrenceId : RecurrenceId , to : Event ) {
124+ private fun asExDate (entity : Entity , recurrenceId : RecurrenceId ): ExDate {
118125 val originalAllDay = (entity.entityValues.getAsInteger(Events .ORIGINAL_ALL_DAY ) ? : 0 ) != 0
119126 val list = DateList (
120127 if (originalAllDay) Value .DATE else Value .DATE_TIME ,
121128 recurrenceId.timeZone
122129 )
123130 list.add(recurrenceId.date)
124- to.exDates + = ExDate (list).apply {
131+ return ExDate (list).apply {
125132 // also set TZ properties of ExDate (not only the list)
126133 if (! originalAllDay) {
127134 if (recurrenceId.isUtc)
@@ -132,18 +139,35 @@ class LegacyAndroidEventProcessor(
132139 }
133140 }
134141
142+ private fun generateProdId (main : Entity ): String {
143+ val mutators: String? = main.entityValues.getAsString(Events .MUTATORS )
144+ val packages: List <String > = mutators?.split(MUTATORS_SEPARATOR )?.toList() ? : emptyList()
145+ return prodIdGenerator.generateProdId(packages)
146+ }
147+
135148 /* *
136- * Reads data of an event from the calendar provider, i.e. converts the [entity] values into
137- * an [Event] data object.
149+ * Reads data of an event from the calendar provider, i.e. converts the [entity] values into a [VEvent].
138150 *
139151 * @param entity event row as returned by the calendar provider
140152 * @param main main event row as returned by the calendar provider
141- * @param to destination data object
153+ *
154+ * @return generated data object
142155 */
143- private fun populateEvent (entity : Entity , main : Entity , to : Event ) {
144- // new processors
156+ private fun populateEvent (entity : Entity , main : Entity ): VEvent {
157+ val vEvent = VEvent ()
145158 for (processor in fieldProcessors)
146- processor.process(from = entity, main = main, to = to)
159+ processor.process(from = entity, main = main, to = vEvent)
160+ return vEvent
147161 }
148162
163+
164+ companion object {
165+
166+ /* *
167+ * The [Events.MUTATORS] field contains a list of unique package names that have modified the event,
168+ * separated by this separator.
169+ */
170+ const val MUTATORS_SEPARATOR = ' ,'
171+
172+ }
149173}
0 commit comments