Skip to content

Commit dfbeff2

Browse files
authored
Merge pull request #200 from myxor/status_attribute
Initial support for event STATUS attribute
2 parents a5b9f00 + 997dc5c commit dfbeff2

File tree

21 files changed

+173
-22
lines changed

21 files changed

+173
-22
lines changed

app/src/main/kotlin/org/fossify/calendar/activities/EventActivity.kt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import android.net.Uri
1111
import android.os.Bundle
1212
import android.provider.CalendarContract.Attendees
1313
import android.provider.CalendarContract.Colors
14+
import android.provider.CalendarContract.Events
1415
import android.provider.ContactsContract.CommonDataKinds
1516
import android.provider.ContactsContract.CommonDataKinds.StructuredName
1617
import android.provider.ContactsContract.Data
@@ -72,6 +73,7 @@ class EventActivity : SimpleActivity() {
7273
private var mAvailableContacts = ArrayList<Attendee>()
7374
private var mSelectedContacts = ArrayList<Attendee>()
7475
private var mAvailability = Attendees.AVAILABILITY_BUSY
76+
private var mStatus = Events.STATUS_CONFIRMED
7577
private var mStoredEventTypes = ArrayList<EventType>()
7678
private var mOriginalTimeZone = DateTimeZone.getDefault().id
7779
private var mOriginalStartTS = 0L
@@ -174,6 +176,7 @@ class EventActivity : SimpleActivity() {
174176
putString(ATTENDEES, Gson().toJson(getAllAttendees(false)))
175177

176178
putInt(AVAILABILITY, mAvailability)
179+
putInt(STATUS, mStatus)
177180
putInt(EVENT_COLOR, mEventColor)
178181

179182
putLong(EVENT_TYPE_ID, mEventTypeId)
@@ -207,6 +210,7 @@ class EventActivity : SimpleActivity() {
207210
mReminder3Type = getInt(REMINDER_3_TYPE)
208211

209212
mAvailability = getInt(AVAILABILITY)
213+
mStatus = getInt(STATUS)
210214
mEventColor = getInt(EVENT_COLOR)
211215

212216
mRepeatInterval = getInt(REPEAT_INTERVAL)
@@ -337,6 +341,14 @@ class EventActivity : SimpleActivity() {
337341
}
338342
}
339343

344+
eventStatus.setOnClickListener {
345+
showStatusPicker(mStatus) {
346+
mStatus = it
347+
updateStatusText()
348+
updateStatusImage()
349+
}
350+
}
351+
340352
eventTypeHolder.setOnClickListener { showEventTypeDialog() }
341353
eventAllDay.apply {
342354
isChecked = mEvent.getIsAllDay()
@@ -458,6 +470,8 @@ class EventActivity : SimpleActivity() {
458470
updateCalDAVVisibility()
459471
updateAvailabilityText()
460472
updateAvailabilityImage()
473+
updateStatusText()
474+
updateStatusImage()
461475
}
462476

463477
private fun setupEditEvent() {
@@ -500,6 +514,7 @@ class EventActivity : SimpleActivity() {
500514
mEventTypeId = mEvent.eventType
501515
mEventCalendarId = mEvent.getCalDAVCalendarId()
502516
mAvailability = mEvent.availability
517+
mStatus = mEvent.status
503518
mEventColor = mEvent.color
504519

505520
mAttendees = mEvent.attendees.toMutableList() as ArrayList<Attendee>
@@ -576,6 +591,7 @@ class EventActivity : SimpleActivity() {
576591
reminder2Type = mReminder2Type
577592
reminder3Minutes = mReminder3Minutes
578593
reminder3Type = mReminder3Type
594+
status = mStatus
579595
eventType = mEventTypeId
580596
}
581597
}
@@ -956,6 +972,17 @@ class EventActivity : SimpleActivity() {
956972
}
957973
}
958974

975+
private fun showStatusPicker(currentValue: Int, callback: (Int) -> Unit) {
976+
val items = arrayListOf(
977+
RadioItem(Events.STATUS_TENTATIVE, getString(R.string.status_tentative)),
978+
RadioItem(Events.STATUS_CONFIRMED, getString(R.string.status_confirmed)),
979+
RadioItem(Events.STATUS_CANCELED, getString(R.string.status_canceled)),
980+
)
981+
RadioGroupDialog(this, items, currentValue) {
982+
callback(it as Int)
983+
}
984+
}
985+
959986
private fun updateReminderTypeImages() {
960987
updateReminderTypeImage(binding.eventReminder1Type, Reminder(mReminder1Minutes, mReminder1Type))
961988
updateReminderTypeImage(binding.eventReminder2Type, Reminder(mReminder2Minutes, mReminder2Type))
@@ -994,6 +1021,24 @@ class EventActivity : SimpleActivity() {
9941021
binding.eventAvailability.text = if (mAvailability == Attendees.AVAILABILITY_FREE) getString(R.string.status_free) else getString(R.string.status_busy)
9951022
}
9961023

1024+
private fun updateStatusText() {
1025+
when (mStatus) {
1026+
Events.STATUS_CONFIRMED -> binding.eventStatus.text = getString(R.string.status_confirmed)
1027+
Events.STATUS_TENTATIVE -> binding.eventStatus.text = getString(R.string.status_tentative)
1028+
Events.STATUS_CANCELED -> binding.eventStatus.text = getString(R.string.status_canceled)
1029+
}
1030+
}
1031+
1032+
private fun updateStatusImage() {
1033+
val drawable = when (mStatus) {
1034+
Events.STATUS_CONFIRMED -> R.drawable.ic_check_circle_outline_vector
1035+
Events.STATUS_CANCELED -> R.drawable.ic_cancel_circle_outline_vector
1036+
else -> R.drawable.ic_question_circle_outline_vector
1037+
}
1038+
val icon = resources.getColoredDrawableWithColor(drawable, getProperTextColor())
1039+
binding.eventStatusImage.setImageDrawable(icon)
1040+
}
1041+
9971042
private fun updateRepetitionText() {
9981043
binding.eventRepetition.text = getRepetitionText(mRepeatInterval)
9991044
}
@@ -1036,6 +1081,8 @@ class EventActivity : SimpleActivity() {
10361081
updateCalDAVVisibility()
10371082
updateAvailabilityText()
10381083
updateAvailabilityImage()
1084+
updateStatusText()
1085+
updateStatusImage()
10391086
}
10401087
}
10411088
} else {
@@ -1310,6 +1357,7 @@ class EventActivity : SimpleActivity() {
13101357
source = newSource
13111358
location = binding.eventLocation.value
13121359
availability = mAvailability
1360+
status = mStatus
13131361
color = mEventColor
13141362
}
13151363

app/src/main/kotlin/org/fossify/calendar/adapters/EventListWidgetAdapter.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.fossify.calendar.adapters
33
import android.content.Context
44
import android.content.Intent
55
import android.graphics.Paint
6+
import android.provider.CalendarContract
67
import android.widget.RemoteViews
78
import android.widget.RemoteViewsService
89
import org.fossify.calendar.R
@@ -236,7 +237,8 @@ class EventListWidgetAdapter(val context: Context, val intent: Intent) : RemoteV
236237
isRepeatable = event.repeatInterval > 0,
237238
isTask = event.isTask(),
238239
isTaskCompleted = event.isTaskCompleted(),
239-
isAttendeeInviteDeclined = event.isAttendeeInviteDeclined()
240+
isAttendeeInviteDeclined = event.isAttendeeInviteDeclined(),
241+
isEventCanceled = event.isEventCanceled()
240242
)
241243
listItems.add(listEvent)
242244
}

app/src/main/kotlin/org/fossify/calendar/databases/EventsDatabase.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import org.fossify.calendar.models.Widget
2222
import org.fossify.commons.extensions.getProperPrimaryColor
2323
import java.util.concurrent.Executors
2424

25-
@Database(entities = [Event::class, EventType::class, Widget::class, Task::class], version = 8)
25+
@Database(entities = [Event::class, EventType::class, Widget::class, Task::class], version = 9)
2626
@TypeConverters(Converters::class)
2727
abstract class EventsDatabase : RoomDatabase() {
2828

@@ -55,6 +55,7 @@ abstract class EventsDatabase : RoomDatabase() {
5555
.addMigrations(MIGRATION_5_6)
5656
.addMigrations(MIGRATION_6_7)
5757
.addMigrations(MIGRATION_7_8)
58+
.addMigrations(MIGRATION_8_9)
5859
.build()
5960
db!!.openHelper.setWriteAheadLoggingEnabled(true)
6061
}
@@ -136,5 +137,13 @@ abstract class EventsDatabase : RoomDatabase() {
136137
}
137138
}
138139
}
140+
141+
private val MIGRATION_8_9 = object : Migration(8, 9) {
142+
override fun migrate(database: SupportSQLiteDatabase) {
143+
database.apply {
144+
execSQL("ALTER TABLE events ADD COLUMN status INTEGER NOT NULL DEFAULT 1")
145+
}
146+
}
147+
}
139148
}
140149
}

app/src/main/kotlin/org/fossify/calendar/extensions/Context.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,8 @@ fun Context.getEventListItems(events: List<Event>, addSectionDays: Boolean = tru
675675
it.repeatInterval > 0,
676676
it.isTask(),
677677
it.isTaskCompleted(),
678-
it.isAttendeeInviteDeclined()
678+
it.isAttendeeInviteDeclined(),
679+
it.isEventCanceled()
679680
)
680681
listItems.add(listEvent)
681682
}

app/src/main/kotlin/org/fossify/calendar/extensions/Event.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ fun Event.maybeAdjustRepeatLimitCount(original: Event, occurrenceTS: Long) {
4141
}
4242
}
4343

44-
fun Event.shouldStrikeThrough() = isTaskCompleted() || isAttendeeInviteDeclined()
44+
fun Event.shouldStrikeThrough() = isTaskCompleted() || isAttendeeInviteDeclined() || isEventCanceled()

app/src/main/kotlin/org/fossify/calendar/extensions/ListEvent.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ package org.fossify.calendar.extensions
22

33
import org.fossify.calendar.models.ListEvent
44

5-
fun ListEvent.shouldStrikeThrough() = isTaskCompleted || isAttendeeInviteDeclined
5+
fun ListEvent.shouldStrikeThrough() = isTaskCompleted || isAttendeeInviteDeclined || isEventCanceled

app/src/main/kotlin/org/fossify/calendar/extensions/MonthViewEvent.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ package org.fossify.calendar.extensions
22

33
import org.fossify.calendar.models.MonthViewEvent
44

5-
fun MonthViewEvent.shouldStrikeThrough() = isTaskCompleted || isAttendeeInviteDeclined
5+
fun MonthViewEvent.shouldStrikeThrough() = isTaskCompleted || isAttendeeInviteDeclined || isEventCanceled

app/src/main/kotlin/org/fossify/calendar/helpers/CalDAVHelper.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.content.ContentUris
55
import android.content.ContentValues
66
import android.content.Context
77
import android.graphics.Color
8+
import android.provider.CalendarContract
89
import android.provider.CalendarContract.*
910
import android.widget.Toast
1011
import org.fossify.calendar.R
@@ -242,7 +243,7 @@ class CalDAVHelper(val context: Context) {
242243
reminder1?.type ?: REMINDER_NOTIFICATION, reminder2?.type ?: REMINDER_NOTIFICATION,
243244
reminder3?.type ?: REMINDER_NOTIFICATION, repeatRule.repeatInterval, repeatRule.repeatRule,
244245
repeatRule.repeatLimit, ArrayList(), attendees, importId, eventTimeZone, allDay, eventTypeId,
245-
source = source, availability = availability, color = displayColor
246+
source = source, availability = availability, color = displayColor, status = status
246247
)
247248

248249
if (event.getIsAllDay()) {
@@ -421,7 +422,7 @@ class CalDAVHelper(val context: Context) {
421422
put(Events.TITLE, event.title)
422423
put(Events.DESCRIPTION, event.description)
423424
put(Events.EVENT_LOCATION, event.location)
424-
put(Events.STATUS, Events.STATUS_CONFIRMED)
425+
put(Events.STATUS, event.status)
425426
put(Events.AVAILABILITY, event.availability)
426427

427428
if (event.color == 0) {

app/src/main/kotlin/org/fossify/calendar/helpers/Constants.kt

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.fossify.calendar.helpers
22

3+
import android.provider.CalendarContract
4+
import android.provider.CalendarContract.Events
35
import org.fossify.calendar.activities.EventActivity
46
import org.fossify.calendar.activities.TaskActivity
57
import org.fossify.commons.helpers.MONTH_SECONDS
@@ -14,7 +16,8 @@ const val COLUMN_COUNT = 7
1416
const val SCHEDULE_CALDAV_REQUEST_CODE = 10000
1517
const val AUTOMATIC_BACKUP_REQUEST_CODE = 10001
1618
const val FETCH_INTERVAL = 3 * MONTH_SECONDS
17-
const val MAX_SEARCH_YEAR = 2051218800L // 2035, limit search results for events repeating indefinitely
19+
const val MAX_SEARCH_YEAR =
20+
2051218800L // 2035, limit search results for events repeating indefinitely
1821

1922
// endless scrolling updating
2023
const val MIN_EVENTS_TRESHOLD = 30
@@ -71,7 +74,8 @@ const val TYPE_TASK = 1
7174
const val TWELVE_HOURS = 43200
7275
const val DAY = 86400
7376
const val WEEK = 604800
74-
const val MONTH = 2592001 // exact value not taken into account, Joda is used for adding months and years
77+
const val MONTH =
78+
2592001 // exact value not taken into account, Joda is used for adding months and years
7579
const val YEAR = 31536000
7680

7781
const val EVENT_PERIOD_TODAY = -1
@@ -148,10 +152,13 @@ const val AUTO_BACKUP_PAST_ENTRIES = "auto_backup_past_entries"
148152
const val LAST_AUTO_BACKUP_TIME = "last_auto_backup_time"
149153

150154
// repeat_rule for monthly and yearly repetition
151-
const val REPEAT_SAME_DAY = 1 // i.e. 25th every month, or 3rd june (if yearly repetition)
152-
const val REPEAT_ORDER_WEEKDAY_USE_LAST = 2 // i.e. every last sunday. 4th if a month has 4 sundays, 5th if 5 (or last sunday in june, if yearly)
155+
const val REPEAT_SAME_DAY =
156+
1 // i.e. 25th every month, or 3rd june (if yearly repetition)
157+
const val REPEAT_ORDER_WEEKDAY_USE_LAST =
158+
2 // i.e. every last sunday. 4th if a month has 4 sundays, 5th if 5 (or last sunday in june, if yearly)
153159
const val REPEAT_LAST_DAY = 3 // i.e. every last day of the month
154-
const val REPEAT_ORDER_WEEKDAY = 4 // i.e. every 4th sunday, even if a month has 4 sundays only (will stay 4th even at months with 5)
160+
const val REPEAT_ORDER_WEEKDAY =
161+
4 // i.e. every 4th sunday, even if a month has 4 sundays only (will stay 4th even at months with 5)
155162

156163
// special event and task flags
157164
const val FLAG_ALL_DAY = 1
@@ -178,7 +185,8 @@ const val DURATION = "DURATION:"
178185
const val SUMMARY = "SUMMARY"
179186
const val DESCRIPTION = "DESCRIPTION"
180187
const val DESCRIPTION_EXPORT = "DESCRIPTION:"
181-
val DESCRIPTION_REGEX = Regex("""DESCRIPTION(?:(?:;[^:;]*="[^"]*")*;?(?:;LANGUAGE=[^:;]*)?(?:;[^:;]*="[^"]*")*)*:(.*(?:\r?\n\s+.*)*)""")
188+
val DESCRIPTION_REGEX =
189+
Regex("""DESCRIPTION(?:(?:;[^:;]*="[^"]*")*;?(?:;LANGUAGE=[^:;]*)?(?:;[^:;]*="[^"]*")*)*:(.*(?:\r?\n\s+.*)*)""")
182190
const val UID = "UID:"
183191
const val ACTION = "ACTION:"
184192
const val TRANSP = "TRANSP:"
@@ -269,6 +277,10 @@ const val EVENT_CALENDAR_ID = "EVENT_CALENDAR_ID"
269277
const val IS_NEW_EVENT = "IS_NEW_EVENT"
270278
const val EVENT_COLOR = "EVENT_COLOR"
271279

280+
// From Status attribute (RFC 5545 3.8.1.11)
281+
const val CANCELLED = "CANCELLED"
282+
const val TENTATIVE = "TENTATIVE"
283+
272284
// actions
273285
const val ACTION_MARK_COMPLETED = "ACTION_MARK_COMPLETED"
274286

@@ -330,3 +342,11 @@ fun getJavaDayOfWeekFromJoda(dayOfWeek: Int): Int {
330342
else -> throw IllegalArgumentException("Invalid day: $dayOfWeek")
331343
}
332344
}
345+
346+
fun getStatusStringFromEventStatus(statusCode: Int): String {
347+
return when (statusCode) {
348+
Events.STATUS_CONFIRMED -> CONFIRMED
349+
Events.STATUS_CANCELED -> CANCELLED
350+
else -> TENTATIVE
351+
}
352+
}

app/src/main/kotlin/org/fossify/calendar/helpers/IcsExporter.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class IcsExporter(private val context: Context) {
2828
private var calendars = ArrayList<CalDAVCalendar>()
2929
private val reminderLabel = context.getString(R.string.reminder)
3030
private val exportTime = Formatter.getExportedTime(System.currentTimeMillis())
31+
private val status = 1
3132

3233
fun exportEvents(
3334
outputStream: OutputStream?,
@@ -149,7 +150,7 @@ class IcsExporter(private val context: Context) {
149150
writeLn("$MISSING_YEAR${if (event.hasMissingYear()) 1 else 0}")
150151

151152
writeLn("$DTSTAMP$exportTime")
152-
writeLn("$STATUS$CONFIRMED")
153+
writeLn("$STATUS${getStatusStringFromEventStatus(event.status)}")
153154
Parser().getRepeatCode(event).let { if (it.isNotEmpty()) writeLn("$RRULE$it") }
154155

155156
fillDescription(event.description.replace("\n", "\\n"), writer)

0 commit comments

Comments
 (0)