diff options
author | Patrick Lang <72232737+patrickunterwegs@users.noreply.github.com> | 2022-02-15 21:34:47 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-15 21:34:47 +0300 |
commit | 9d57f4c3c454bc0dc2779fa39d61a667a7a383bc (patch) | |
tree | 2418403e1741652964a4dc671605051717cbd3b8 | |
parent | 37f0216b1ce2f586750e048b8473a25443192e03 (diff) |
Add option to export collections as .ics (#9)
* Refactored ics-generation, using ical4android now
Closes #15
* Added option to export collections as .ics
Fixed issue for exporting entries with attachments (affected also sync!)
* Added test for getICSForCollection()
* Closes #13 jtx: ICS generation always contains ORGANIZER although it is empty
3 files changed, 63 insertions, 6 deletions
diff --git a/src/androidTest/java/at/bitfire/ical4android/JtxCollectionTest.kt b/src/androidTest/java/at/bitfire/ical4android/JtxCollectionTest.kt index e1478fe..807f1bc 100644 --- a/src/androidTest/java/at/bitfire/ical4android/JtxCollectionTest.kt +++ b/src/androidTest/java/at/bitfire/ical4android/JtxCollectionTest.kt @@ -14,8 +14,7 @@ import at.bitfire.ical4android.MiscUtils.ContentProviderClientHelper.closeCompat import at.bitfire.ical4android.impl.TestJtxCollection import at.techbee.jtx.JtxContract import at.techbee.jtx.JtxContract.asSyncAdapter -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNotNull +import junit.framework.TestCase.* import org.junit.After import org.junit.Before import org.junit.Test @@ -25,7 +24,6 @@ class JtxCollectionTest { private val testAccount = Account("TEST", JtxContract.JtxCollection.TEST_ACCOUNT_TYPE) private lateinit var contentResolver: ContentResolver private lateinit var client: ContentProviderClient - var collection: JtxCollection<JtxICalObject>? = null lateinit var context: Context private val url = "https://jtx.techbee.at" @@ -93,4 +91,36 @@ class JtxCollectionTest { assertEquals(1, icalobjects.size) } + + @Test + fun getICSForCollection_test() { + val collectionUri = JtxCollection.create(testAccount, client, cv) + assertNotNull(collectionUri) + + val collections = JtxCollection.find(testAccount, client, context, TestJtxCollection.Factory, null, null) + val items = collections[0].queryICalObjects(null, null) + assertEquals(0, items.size) + + val cv1 = ContentValues().apply { + put(JtxContract.JtxICalObject.SUMMARY, "summary") + put(JtxContract.JtxICalObject.COMPONENT, JtxContract.JtxICalObject.Component.VJOURNAL.name) + put(JtxContract.JtxICalObject.ICALOBJECT_COLLECTIONID, collections[0].id) + } + val cv2 = ContentValues().apply { + put(JtxContract.JtxICalObject.SUMMARY, "entry2") + put(JtxContract.JtxICalObject.COMPONENT, JtxContract.JtxICalObject.Component.VTODO.name) + put(JtxContract.JtxICalObject.ICALOBJECT_COLLECTIONID, collections[0].id) + } + client.insert(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(testAccount), cv1) + client.insert(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(testAccount), cv2) + + val ics = collections[0].getICSForCollection() + + assertTrue(ics.contains(Regex("BEGIN:VCALENDAR(\\n*|\\r*|\\t*|.*)*END:VCALENDAR"))) + assertTrue(ics.contains("PRODID:+//IDN bitfire.at//ical4android")) + assertTrue(ics.contains("SUMMARY:summary")) + assertTrue(ics.contains("SUMMARY:entry2")) + assertTrue(ics.contains(Regex("BEGIN:VJOURNAL(\\n*|\\r*|\\t*|.*)*END:VJOURNAL"))) + assertTrue(ics.contains(Regex("BEGIN:VTODO(\\n*|\\r*|\\t*|.*)*END:VTODO"))) + } } diff --git a/src/main/java/at/bitfire/ical4android/JtxCollection.kt b/src/main/java/at/bitfire/ical4android/JtxCollection.kt index a10ee42..25277b9 100644 --- a/src/main/java/at/bitfire/ical4android/JtxCollection.kt +++ b/src/main/java/at/bitfire/ical4android/JtxCollection.kt @@ -13,6 +13,10 @@ import android.net.Uri import at.bitfire.ical4android.MiscUtils.CursorHelper.toValues import at.techbee.jtx.JtxContract import at.techbee.jtx.JtxContract.asSyncAdapter +import net.fortuna.ical4j.model.Calendar +import net.fortuna.ical4j.model.component.VJournal +import net.fortuna.ical4j.model.component.VToDo +import net.fortuna.ical4j.model.property.Version import java.util.* open class JtxCollection<out T: JtxICalObject>(val account: Account, @@ -262,4 +266,28 @@ open class JtxCollection<out T: JtxICalObject>(val account: Account, } } + + /** + * @return a string with all JtxICalObjects within the collection as iCalendar + */ + fun getICSForCollection(): String { + client.query(JtxContract.JtxICalObject.CONTENT_URI.asSyncAdapter(account), null, "${JtxContract.JtxICalObject.ICALOBJECT_COLLECTIONID} = ? AND ${JtxContract.JtxICalObject.DELETED} = ?", arrayOf(id.toString(), "0"), null).use { cursor -> + Ical4Android.log.fine("getICSForCollection: found ${cursor?.count} records in ${account.name}") + + val ical = Calendar() + ical.properties += Version.VERSION_2_0 + ical.properties += ICalendar.prodId + + while (cursor?.moveToNext() == true) { + val jtxIcalObject = JtxICalObject(this) + jtxIcalObject.populateFromContentValues(cursor.toValues()) + val singleICS = jtxIcalObject.getICalendarFormat() + singleICS?.components?.forEach { component -> + if(component is VToDo || component is VJournal) + ical.components += component + } + } + return ical.toString() + } + } }
\ No newline at end of file diff --git a/src/main/java/at/bitfire/ical4android/JtxICalObject.kt b/src/main/java/at/bitfire/ical4android/JtxICalObject.kt index 7a9218c..087ca00 100644 --- a/src/main/java/at/bitfire/ical4android/JtxICalObject.kt +++ b/src/main/java/at/bitfire/ical4android/JtxICalObject.kt @@ -675,8 +675,6 @@ open class JtxICalObject( Ical4Android.log.log(Level.WARNING, "Ignoring invalid task URL: $url", e) } } - //organizer?.let { props += it } - classification?.let { props += Clazz(it) } status?.let { props += Status(it) } @@ -1518,7 +1516,8 @@ duration?.let(props::add) language = organizerContentValues?.getAsString(JtxContract.JtxOrganizer.LANGUAGE) other = organizerContentValues?.getAsString(JtxContract.JtxOrganizer.OTHER) } - organizer = orgnzr + if(orgnzr.caladdress?.isNotEmpty() == true) // we only take the organizer if there was a caladdress (otherwise an empty ORGANIZER is created) + organizer = orgnzr // Take care of attachments val attachmentContentValues = getAttachmentsContentValues() |