Commit fef93f94 authored by Ricki Hirner's avatar Ricki Hirner

Update ical4j to 2.2.3

parent e04df070
image: registry.gitlab.com/bitfireat/davdroid:latest
image: registry.gitlab.com/bitfireat/davx5-ose:latest
before_script:
- export GRADLE_USER_HOME=`pwd`/.gradle; chmod +x gradlew
......
......@@ -25,7 +25,7 @@ apply plugin: 'kotlin-android'
apply plugin: 'org.jetbrains.dokka-android'
ext {
ical4j_version = '2.2.1'
ical4j_version = '2.2.3'
}
android {
......
......@@ -80,17 +80,17 @@ class AndroidEventTest {
fun testAddEvent() {
// build and write recurring event to calendar provider
val event = Event()
event.uid = ("sample1@testAddEvent")
event.summary = ("Sample event")
event.description = ("Sample event with date/time")
event.location = ("Sample location")
event.dtStart = (DtStart("20150501T120000", tzVienna))
event.dtEnd = (DtEnd("20150501T130000", tzVienna))
event.organizer = (Organizer(URI("mailto:organizer@example.com")))
event.rRule = (RRule("FREQ=DAILY;COUNT=10"))
event.classification = (Clazz.PRIVATE)
event.status = (Status.VEVENT_CONFIRMED)
event.color = (EventColor.aliceblue)
event.uid = "sample1@testAddEvent"
event.summary = "Sample event"
event.description = "Sample event with date/time"
event.location = "Sample location"
event.dtStart = DtStart("20150501T120000", tzVienna)
event.dtEnd = DtEnd("20150501T130000", tzVienna)
event.organizer = Organizer(URI("mailto:organizer@example.com"))
event.rRule = RRule("FREQ=DAILY;COUNT=10")
event.classification = Clazz.PRIVATE
event.status = Status.VEVENT_CONFIRMED
event.color = Css3Color.aliceblue
assertFalse(event.isAllDay())
// TODO test rDates, exDate, duration
......
......@@ -50,7 +50,7 @@ abstract class AndroidCalendar<out T: AndroidEvent>(
fun insertColors(provider: ContentProviderClient, account: Account) {
provider.query(syncAdapterURI(Colors.CONTENT_URI, account), arrayOf(Colors.COLOR_KEY), null, null, null)?.use { cursor ->
if (cursor.count == EventColor.values().size)
if (cursor.count == Css3Color.values().size)
// colors already inserted and up to date
return
}
......@@ -60,9 +60,9 @@ abstract class AndroidCalendar<out T: AndroidEvent>(
values.put(CalendarContract.Colors.ACCOUNT_NAME, account.name)
values.put(CalendarContract.Colors.ACCOUNT_TYPE, account.type)
values.put(Colors.COLOR_TYPE, Colors.TYPE_EVENT)
for (color in EventColor.values()) {
for (color in Css3Color.values()) {
values.put(Colors.COLOR_KEY, color.name)
values.put(Colors.COLOR, color.rgba)
values.put(Colors.COLOR, color.argb)
provider.insert(syncAdapterURI(Colors.CONTENT_URI, account), values)
}
}
......
......@@ -53,6 +53,9 @@ abstract class AndroidEvent(
const val EXT_UNKNOWN_PROPERTY = "unknown-property"
const val MAX_UNKNOWN_PROPERTY_SIZE = 25000
// not declared in ical4j Parameters class yet
private const val PARAMETER_EMAIL = "EMAIL"
}
var id: Long? = null
......@@ -144,7 +147,7 @@ abstract class AndroidEvent(
row.getAsString(Events.EVENT_COLOR_KEY)?.let { name ->
try {
event.color = EventColor.valueOf(name)
event.color = Css3Color.valueOf(name)
} catch(e: IllegalArgumentException) {
Constants.log.warning("Ignoring unknown color $name from Calendar Provider")
}
......@@ -258,7 +261,7 @@ abstract class AndroidEvent(
if (idNS != null || id != null) {
// attendee identified by namespace and ID
attendee = Attendee(URI(idNS, id, null))
email?.let { attendee.parameters.add(ICalendar.Email(it)) }
email?.let { attendee.parameters.add(Email(it)) }
} else
// attendee identified by email address
attendee = Attendee(URI("mailto", email, null))
......@@ -581,7 +584,7 @@ abstract class AndroidEvent(
email = if (uri.scheme.equals("mailto", true))
uri.schemeSpecificPart
else {
val emailParam = organizer.getParameter(ICalendar.Email.PARAMETER_NAME) as ICalendar.Email?
val emailParam = organizer.getParameter(PARAMETER_EMAIL) as? Email
emailParam?.value
}
if (email != null)
......@@ -639,7 +642,7 @@ abstract class AndroidEvent(
// attendee identified by other URI
builder .withValue(Attendees.ATTENDEE_ID_NAMESPACE, member.scheme)
.withValue(Attendees.ATTENDEE_IDENTITY, member.schemeSpecificPart)
(attendee.getParameter(ICalendar.Email.PARAMETER_NAME) as ICalendar.Email?)?.let { email ->
(attendee.getParameter(PARAMETER_EMAIL) as? Email)?.let { email ->
builder.withValue(Attendees.ATTENDEE_EMAIL, email.value)
}
}
......@@ -649,13 +652,13 @@ abstract class AndroidEvent(
}
var type = Attendees.TYPE_NONE
val cutype = attendee.getParameter(Parameter.CUTYPE) as CuType?
val cutype = attendee.getParameter(Parameter.CUTYPE) as? CuType
if (cutype in arrayOf(CuType.RESOURCE, CuType.ROOM))
// "attendee" is a (physical) resource
type = Attendees.TYPE_RESOURCE
else {
// attendee is not a (physical) resource
val role = attendee.getParameter(Parameter.ROLE) as Role?
val role = attendee.getParameter(Parameter.ROLE) as? Role
val relationship: Int
if (role == Role.CHAIR)
relationship = Attendees.RELATIONSHIP_ORGANIZER
......@@ -669,7 +672,7 @@ abstract class AndroidEvent(
builder.withValue(Attendees.ATTENDEE_RELATIONSHIP, relationship)
}
val partStat = attendee.getParameter(Parameter.PARTSTAT) as PartStat?
val partStat = attendee.getParameter(Parameter.PARTSTAT) as? PartStat
val status = when(partStat) {
null,
PartStat.NEEDS_ACTION -> Attendees.ATTENDEE_STATUS_INVITED
......
......@@ -10,9 +10,11 @@ package at.bitfire.ical4android
/**
* Represents an RGBA COLOR value, as specified in https://tools.ietf.org/html/rfc7986#section-5.9
*
* @property argb ARGB color value (0xAARRGGBB), alpha is 0xFF for all values
*/
@Suppress("EnumEntryName")
enum class EventColor(val rgba: Int) {
enum class Css3Color(val argb: Int) {
// values taken from https://www.w3.org/TR/2011/REC-css3-color-20110607/#svg-color
aliceblue(0xfff0f8ff.toInt()),
antiquewhite(0xfffaebd7.toInt()),
......@@ -166,13 +168,29 @@ enum class EventColor(val rgba: Int) {
companion object {
/**
* Finds the best matching [EventColor] for a given RGBA value using a weighted Euclidian
* distance formula for RGB (A is being ignored).
* Returns the CSS3 color property of the given name.
*
* @param name color name
* @return [Css3Color] object or null if no match was found
*/
fun nearestMatch(rgba: Int): EventColor {
val rgb = rgba and 0xFFFFFF
fun fromString(name: String) =
try {
Css3Color.valueOf(name)
} catch (e: IllegalArgumentException) {
Constants.log.warning("Unknown color: $name")
null
}
/**
* Finds the best matching [Css3Color] for a given RGBA value using a weighted Euclidian
* distance formula for RGB.
*
* @param argb (A)RGB color (A will be ignored)
*/
fun nearestMatch(argb: Int): Css3Color {
val rgb = argb and 0xFFFFFF
val distance = values().map {
val cssColor = it.rgba and 0xFFFFFF
val cssColor = it.argb and 0xFFFFFF
val r1 = rgb shr 16
val r2 = cssColor shr 16
val r = (r1 + r2)/2.0
......
......@@ -30,7 +30,7 @@ class Event: ICalendar() {
var summary: String? = null
var location: String? = null
var description: String? = null
var color: EventColor? = null
var color: Css3Color? = null
var dtStart: DtStart? = null
var dtEnd: DtEnd? = null
......@@ -162,7 +162,7 @@ class Event: ICalendar() {
is Summary -> e.summary = prop.value
is Location -> e.location = prop.value
is Description -> e.description = prop.value
is Color -> e.color = prop.value
is Color -> e.color = Css3Color.fromString(prop.value)
is DtStart -> e.dtStart = prop
is DtEnd -> e.dtEnd = prop
is Duration -> e.duration = prop
......@@ -242,7 +242,7 @@ class Event: ICalendar() {
summary?.let { props += Summary(it) }
location?.let { props += Location(it) }
description?.let { props += Description(it) }
color?.let { props += Color(it) }
color?.let { props += Color(null, it.name) }
props += dtStart
dtEnd?.let { props += it }
......
......@@ -17,7 +17,6 @@ import net.fortuna.ical4j.model.component.*
import net.fortuna.ical4j.model.property.DateProperty
import net.fortuna.ical4j.model.property.ProdId
import net.fortuna.ical4j.model.property.TzUrl
import net.fortuna.ical4j.util.Strings
import java.io.StringReader
import java.util.*
import java.util.logging.Level
......@@ -39,16 +38,8 @@ open class ICalendar {
}
var prodId = ProdId("+//IDN bitfire.at//ical4android")
private val parameterFactoryRegistry = ParameterFactoryRegistry()
init {
parameterFactoryRegistry.register(Email.PARAMETER_NAME, Email.Factory)
}
private val propertyFactoryRegistry = PropertyFactoryRegistry()
init {
propertyFactoryRegistry.register(Color.PROPERTY_NAME, Color.Factory)
}
private val parameterFactoryRegistry = ParameterFactoryRegistry()
@JvmStatic
protected fun calendarBuilder() = CalendarBuilder(
......@@ -155,66 +146,4 @@ open class ICalendar {
override fun toString() = MiscUtils.reflectionToString(this)
// ical4j helpers and extensions
/** COLOR property for VEVENT components [RFC 7986 5.9 COLOR] */
class Color(
var value: EventColor? = null
): Property(PROPERTY_NAME, Factory) {
companion object {
const val PROPERTY_NAME = "COLOR"
}
override fun getValue() = value?.name
override fun setValue(name: String?) {
name?.let {
try {
value = EventColor.valueOf(name.toLowerCase())
} catch(e: IllegalArgumentException) {
Constants.log.warning("Ignoring unknown COLOR $name")
}
}
}
override fun validate() {
}
object Factory: PropertyFactory<Color> {
override fun createProperty() = Color()
override fun createProperty(params: ParameterList?, value: String?): Color {
val c = Color()
c.setValue(value)
return c
}
override fun supports(property: String?) = property == PROPERTY_NAME
}
}
/** EMAIL parameter for ATTENDEE properties, as used by iCloud:
ATTENDEE;EMAIL=bla@domain.tld;/path/to/principal
*/
class Email(): Parameter(PARAMETER_NAME, Factory) {
companion object {
const val PARAMETER_NAME = "EMAIL"
}
var email: String? = null
override fun getValue() = email
constructor(aValue: String): this()
{
email = Strings.unquote(aValue)
}
object Factory: ParameterFactory<Email> {
override fun createParameter(value: String) = Email(value)
override fun supports(name: String) = name == PARAMETER_NAME
}
}
}
\ No newline at end of file
......@@ -95,7 +95,7 @@ class Task: ICalendar() {
is Location -> t.location = prop.value
is Geo -> t.geoPosition = prop
is Description -> t.description = prop.value
is Color -> t.color = prop.value?.rgba
is Color -> t.color = Css3Color.fromString(prop.value)?.argb
is Url -> t.url = prop.value
is Organizer -> t.organizer = prop
is Priority -> t.priority = prop.level
......@@ -147,7 +147,7 @@ class Task: ICalendar() {
location?.let { props += Location(it) }
geoPosition?.let { props += it }
description?.let { props += Description(it) }
color?.let { props += Color(EventColor.nearestMatch(it)) }
color?.let { props += Color(null, Css3Color.nearestMatch(it).name) }
url?.let {
try {
props += Url(URI(it))
......
......@@ -11,13 +11,13 @@ package at.bitfire.ical4android
import org.junit.Assert.assertEquals
import org.junit.Test
class EventColorTest {
class Css3ColorTest {
@Test
fun testNearestMatch() {
// every color is its own nearest match
EventColor.values().forEach {
assertEquals(it.rgba, EventColor.nearestMatch(it.rgba).rgba)
Css3Color.values().forEach {
assertEquals(it.argb, Css3Color.nearestMatch(it.argb).argb)
}
}
......
......@@ -81,7 +81,8 @@ class EventTest {
assertEquals("© äö — üß", event.summary)
assertEquals("Test Description", event.description)
assertEquals("中华人民共和国", event.location)
assertEquals(EventColor.aliceblue, event.color)
assertEquals(Css3Color.aliceblue, event.color)
assertEquals("cyrus@example.com", event.attendees.first.parameters.getParameter("EMAIL").value)
}
@Test
......
......@@ -7,6 +7,7 @@ SUMMARY:© äö — üß
DESCRIPTION:Test Description
LOCATION:中华人民共和国
COLOR:aliceblue
ATTENDEE;CN=Cyrus Daboo;EMAIL=cyrus@example.com:mailto:opaque-token-1234@example.com
DTSTART:20131009T170000T
DTEND:20131009T180000T
END:VEVENT
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment