diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SettingsActivity.kt index 286d9224d..50f8d0ea3 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/activities/SettingsActivity.kt @@ -14,6 +14,7 @@ import com.simplemobiletools.calendar.dialogs.CustomEventReminderDialog import com.simplemobiletools.calendar.dialogs.SelectCalendarsDialog import com.simplemobiletools.calendar.dialogs.SnoozePickerDialog import com.simplemobiletools.calendar.extensions.* +import com.simplemobiletools.calendar.helpers.CalDAVEventsHandler import com.simplemobiletools.calendar.helpers.FONT_SIZE_LARGE import com.simplemobiletools.calendar.helpers.FONT_SIZE_MEDIUM import com.simplemobiletools.calendar.helpers.FONT_SIZE_SMALL @@ -137,7 +138,7 @@ class SettingsActivity : SimpleActivity() { Thread({ if (ids.isNotEmpty()) { val eventTypeNames = dbHelper.fetchEventTypes().map { it.title.toLowerCase() } as ArrayList - val calendars = getCalDAVCalendars(config.caldavSyncedCalendarIDs) + val calendars = CalDAVEventsHandler(applicationContext).getCalDAVCalendars(config.caldavSyncedCalendarIDs) calendars.forEach { if (!eventTypeNames.contains(it.displayName.toLowerCase())) { val eventType = EventType(0, it.displayName, it.color) @@ -148,7 +149,7 @@ class SettingsActivity : SimpleActivity() { calendars.forEach { val eventTypeId = dbHelper.getEventTypeIdWithTitle(it.displayName) - fetchCalDAVCalendarEvents(it.id, eventTypeId) + CalDAVEventsHandler(applicationContext).fetchCalDAVCalendarEvents(it.id, eventTypeId) } } }).start() diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectCalendarsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectCalendarsDialog.kt index d5e3753b5..607afac4b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectCalendarsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/dialogs/SelectCalendarsDialog.kt @@ -8,7 +8,7 @@ import android.view.ViewGroup import android.widget.RelativeLayout import com.simplemobiletools.calendar.R import com.simplemobiletools.calendar.extensions.config -import com.simplemobiletools.calendar.extensions.getCalDAVCalendars +import com.simplemobiletools.calendar.helpers.CalDAVEventsHandler import com.simplemobiletools.commons.extensions.setupDialogStuff import kotlinx.android.synthetic.main.calendar_item_account.view.* import kotlinx.android.synthetic.main.calendar_item_calendar.view.* @@ -21,7 +21,7 @@ class SelectCalendarsDialog(val activity: Activity, val callback: () -> Unit) : init { val ids = activity.config.caldavSyncedCalendarIDs.split(",").filter { it.trim().isNotEmpty() } as ArrayList - val calendars = activity.getCalDAVCalendars() + val calendars = CalDAVEventsHandler(activity).getCalDAVCalendars() val sorted = calendars.sortedWith(compareBy({ it.accountName }, { it.displayName })) sorted.forEach { if (prevAccount != it.accountName) { diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Context.kt index 0a0967f67..fdf1ff621 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/extensions/Context.kt @@ -8,26 +8,24 @@ import android.app.NotificationManager import android.app.PendingIntent import android.appwidget.AppWidgetManager import android.content.ComponentName -import android.content.ContentValues import android.content.Context import android.content.Intent import android.content.pm.PackageManager -import android.database.Cursor import android.graphics.Color import android.net.Uri import android.os.Build -import android.provider.CalendarContract import android.support.v4.content.ContextCompat import android.support.v7.app.NotificationCompat import com.simplemobiletools.calendar.R import com.simplemobiletools.calendar.activities.EventActivity import com.simplemobiletools.calendar.helpers.* import com.simplemobiletools.calendar.helpers.Formatter -import com.simplemobiletools.calendar.models.CalDAVCalendar import com.simplemobiletools.calendar.models.Event import com.simplemobiletools.calendar.receivers.NotificationReceiver import com.simplemobiletools.calendar.services.SnoozeService -import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.extensions.getContrastColor +import com.simplemobiletools.commons.extensions.isKitkatPlus +import com.simplemobiletools.commons.extensions.isLollipopPlus import org.joda.time.DateTime import org.joda.time.DateTimeZone import java.text.SimpleDateFormat @@ -232,167 +230,6 @@ fun Context.launchNewEventIntent(startNewTask: Boolean = false, today: Boolean = } } -fun Context.getCalDAVCalendars(ids: String = ""): List { - val calendars = ArrayList() - if (!hasCalendarPermission()) { - return calendars - } - - dbHelper.fetchEventTypes() - val uri = CalendarContract.Calendars.CONTENT_URI - val projection = arrayOf( - CalendarContract.Calendars._ID, - CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, - CalendarContract.Calendars.ACCOUNT_NAME, - CalendarContract.Calendars.OWNER_ACCOUNT, - CalendarContract.Calendars.CALENDAR_COLOR) - val selection = if (ids.trim().isNotEmpty()) "${CalendarContract.Calendars._ID} IN ($ids)" else null - - var cursor: Cursor? = null - try { - cursor = contentResolver.query(uri, projection, selection, null, null) - if (cursor != null && cursor.moveToFirst()) { - do { - val id = cursor.getLongValue(CalendarContract.Calendars._ID) - val displayName = cursor.getStringValue(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME) - val accountName = cursor.getStringValue(CalendarContract.Calendars.ACCOUNT_NAME) - val ownerName = cursor.getStringValue(CalendarContract.Calendars.OWNER_ACCOUNT) - val color = cursor.getIntValue(CalendarContract.Calendars.CALENDAR_COLOR) - val calendar = CalDAVCalendar(id, displayName, accountName, ownerName, color) - calendars.add(calendar) - } while (cursor.moveToNext()) - } - } finally { - cursor?.close() - } - return calendars -} - -fun Context.fetchCalDAVCalendarEvents(calendarId: Long, eventTypeId: Int) { - val importIdsMap = HashMap() - val existingEvents = dbHelper.getEventsFromCalDAVCalendar(calendarId) - existingEvents.forEach { - importIdsMap.put(it.importId, it) - } - - val uri = CalendarContract.Events.CONTENT_URI - val projection = arrayOf( - CalendarContract.Events._ID, - CalendarContract.Events.TITLE, - CalendarContract.Events.DESCRIPTION, - CalendarContract.Events.DTSTART, - CalendarContract.Events.DTEND, - CalendarContract.Events.DURATION, - CalendarContract.Events.ALL_DAY, - CalendarContract.Events.RRULE) - val selection = "${CalendarContract.Events.CALENDAR_ID} = $calendarId" - - var cursor: Cursor? = null - try { - cursor = contentResolver.query(uri, projection, selection, null, null) - if (cursor != null && cursor.moveToFirst()) { - do { - val id = cursor.getLongValue(CalendarContract.Events._ID) - val title = cursor.getStringValue(CalendarContract.Events.TITLE) ?: continue - val description = cursor.getStringValue(CalendarContract.Events.DESCRIPTION) - val startTS = (cursor.getLongValue(CalendarContract.Events.DTSTART) / 1000).toInt() - var endTS = (cursor.getLongValue(CalendarContract.Events.DTEND) / 1000).toInt() - val allDay = cursor.getIntValue(CalendarContract.Events.ALL_DAY) - val rrule = cursor.getStringValue(CalendarContract.Events.RRULE) ?: "" - val reminders = getCalDAVEventReminders(id) - - if (endTS == 0) { - val duration = cursor.getStringValue(CalendarContract.Events.DURATION) - endTS = startTS + Parser().parseDuration(duration) - } - - val importId = getCalDAVEventImportId(calendarId, id) - val repeatRule = Parser().parseRepeatInterval(rrule, startTS) - val event = Event(0, startTS, endTS, title, description, reminders.getOrElse(0, { -1 }), - reminders.getOrElse(1, { -1 }), reminders.getOrElse(2, { -1 }), repeatRule.repeatInterval, - importId, allDay, repeatRule.repeatLimit, repeatRule.repeatRule, eventTypeId, source = "$CALDAV-$calendarId") - - if (event.getIsAllDay() && endTS > startTS) { - event.endTS -= DAY - } - - if (importIdsMap.containsKey(event.importId)) { - val existingEvent = importIdsMap[importId] - val originalEventId = existingEvent!!.id - existingEvent.id = 0 - if (existingEvent.hashCode() != event.hashCode()) { - event.id = originalEventId - dbHelper.update(event) { - } - } - } else { - dbHelper.insert(event, false) { - importIdsMap.put(event.importId, event) - } - } - } while (cursor.moveToNext()) - } - } finally { - cursor?.close() - } -} - -fun Context.addCalDAVEvent(event: Event, calendarId: Long) { - val durationMinutes = (event.endTS - event.startTS) / 1000 / 60 - val uri = CalendarContract.Events.CONTENT_URI - val values = ContentValues().apply { - put(CalendarContract.Events.CALENDAR_ID, calendarId) - put(CalendarContract.Events.TITLE, event.title) - put(CalendarContract.Events.DESCRIPTION, event.description) - put(CalendarContract.Events.DTSTART, event.startTS * 1000L) - put(CalendarContract.Events.ALL_DAY, if (event.getIsAllDay()) 1 else 0) - put(CalendarContract.Events.RRULE, Parser().getShortRepeatInterval(event)) - put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().toString()) - - if (event.getIsAllDay() && event.endTS > event.startTS) - event.endTS += DAY - - if (event.repeatInterval > 0) { - put(CalendarContract.Events.DURATION, Parser().getDurationString(durationMinutes)) - } else { - put(CalendarContract.Events.DTEND, event.endTS * 1000L) - } - } - - val newUri = contentResolver.insert(uri, values) - val eventRemoteID = java.lang.Long.parseLong(newUri.lastPathSegment) - - val importId = getCalDAVEventImportId(calendarId, eventRemoteID) - dbHelper.updateEventImportIdAndSource(event.id, importId, "$CALDAV-$calendarId") -} - -fun Context.getCalDAVEventReminders(eventId: Long): List { - val reminders = ArrayList() - val uri = CalendarContract.Reminders.CONTENT_URI - val projection = arrayOf( - CalendarContract.Reminders.MINUTES, - CalendarContract.Reminders.METHOD) - val selection = "${CalendarContract.Reminders.EVENT_ID} = $eventId" - var cursor: Cursor? = null - try { - cursor = contentResolver.query(uri, projection, selection, null, null) - if (cursor != null && cursor.moveToFirst()) { - do { - val minutes = cursor.getIntValue(CalendarContract.Reminders.MINUTES) - val method = cursor.getIntValue(CalendarContract.Reminders.METHOD) - if (method == CalendarContract.Reminders.METHOD_ALERT) { - reminders.add(minutes) - } - } while (cursor.moveToNext()) - } - } finally { - cursor?.close() - } - return reminders -} - -fun Context.getCalDAVEventImportId(calendarId: Long, eventId: Long) = "$CALDAV-$calendarId-$eventId" - fun Context.getNewEventTimestampFromCode(dayCode: String) = Formatter.getLocalDateTimeFromCode(dayCode).withTime(13, 0, 0, 0).seconds() fun Context.getCurrentOffset() = SimpleDateFormat("Z", Locale.getDefault()).format(Date()) diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/CalDAVEventsHandler.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/CalDAVEventsHandler.kt new file mode 100644 index 000000000..5715fe97c --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/CalDAVEventsHandler.kt @@ -0,0 +1,177 @@ +package com.simplemobiletools.calendar.helpers + +import android.content.ContentValues +import android.content.Context +import android.database.Cursor +import android.provider.CalendarContract +import com.simplemobiletools.calendar.extensions.dbHelper +import com.simplemobiletools.calendar.extensions.hasCalendarPermission +import com.simplemobiletools.calendar.models.CalDAVCalendar +import com.simplemobiletools.calendar.models.Event +import com.simplemobiletools.commons.extensions.getIntValue +import com.simplemobiletools.commons.extensions.getLongValue +import com.simplemobiletools.commons.extensions.getStringValue +import java.util.* + +class CalDAVEventsHandler(val context: Context) { + fun getCalDAVCalendars(ids: String = ""): List { + val calendars = ArrayList() + if (!context.hasCalendarPermission()) { + return calendars + } + + context.dbHelper.fetchEventTypes() + val uri = CalendarContract.Calendars.CONTENT_URI + val projection = arrayOf( + CalendarContract.Calendars._ID, + CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, + CalendarContract.Calendars.ACCOUNT_NAME, + CalendarContract.Calendars.OWNER_ACCOUNT, + CalendarContract.Calendars.CALENDAR_COLOR) + val selection = if (ids.trim().isNotEmpty()) "${CalendarContract.Calendars._ID} IN ($ids)" else null + + var cursor: Cursor? = null + try { + cursor = context.contentResolver.query(uri, projection, selection, null, null) + if (cursor != null && cursor.moveToFirst()) { + do { + val id = cursor.getLongValue(CalendarContract.Calendars._ID) + val displayName = cursor.getStringValue(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME) + val accountName = cursor.getStringValue(CalendarContract.Calendars.ACCOUNT_NAME) + val ownerName = cursor.getStringValue(CalendarContract.Calendars.OWNER_ACCOUNT) + val color = cursor.getIntValue(CalendarContract.Calendars.CALENDAR_COLOR) + val calendar = CalDAVCalendar(id, displayName, accountName, ownerName, color) + calendars.add(calendar) + } while (cursor.moveToNext()) + } + } finally { + cursor?.close() + } + return calendars + } + + fun fetchCalDAVCalendarEvents(calendarId: Long, eventTypeId: Int) { + val importIdsMap = HashMap() + val existingEvents = context.dbHelper.getEventsFromCalDAVCalendar(calendarId) + existingEvents.forEach { + importIdsMap.put(it.importId, it) + } + + val uri = CalendarContract.Events.CONTENT_URI + val projection = arrayOf( + CalendarContract.Events._ID, + CalendarContract.Events.TITLE, + CalendarContract.Events.DESCRIPTION, + CalendarContract.Events.DTSTART, + CalendarContract.Events.DTEND, + CalendarContract.Events.DURATION, + CalendarContract.Events.ALL_DAY, + CalendarContract.Events.RRULE) + val selection = "${CalendarContract.Events.CALENDAR_ID} = $calendarId" + + var cursor: Cursor? = null + try { + cursor = context.contentResolver.query(uri, projection, selection, null, null) + if (cursor != null && cursor.moveToFirst()) { + do { + val id = cursor.getLongValue(CalendarContract.Events._ID) + val title = cursor.getStringValue(CalendarContract.Events.TITLE) ?: continue + val description = cursor.getStringValue(CalendarContract.Events.DESCRIPTION) + val startTS = (cursor.getLongValue(CalendarContract.Events.DTSTART) / 1000).toInt() + var endTS = (cursor.getLongValue(CalendarContract.Events.DTEND) / 1000).toInt() + val allDay = cursor.getIntValue(CalendarContract.Events.ALL_DAY) + val rrule = cursor.getStringValue(CalendarContract.Events.RRULE) ?: "" + val reminders = getCalDAVEventReminders(id) + + if (endTS == 0) { + val duration = cursor.getStringValue(CalendarContract.Events.DURATION) + endTS = startTS + Parser().parseDuration(duration) + } + + val importId = getCalDAVEventImportId(calendarId, id) + val repeatRule = Parser().parseRepeatInterval(rrule, startTS) + val event = Event(0, startTS, endTS, title, description, reminders.getOrElse(0, { -1 }), + reminders.getOrElse(1, { -1 }), reminders.getOrElse(2, { -1 }), repeatRule.repeatInterval, + importId, allDay, repeatRule.repeatLimit, repeatRule.repeatRule, eventTypeId, source = "$CALDAV-$calendarId") + + if (event.getIsAllDay() && endTS > startTS) { + event.endTS -= DAY + } + + if (importIdsMap.containsKey(event.importId)) { + val existingEvent = importIdsMap[importId] + val originalEventId = existingEvent!!.id + existingEvent.id = 0 + if (existingEvent.hashCode() != event.hashCode()) { + event.id = originalEventId + context.dbHelper.update(event) { + } + } + } else { + context.dbHelper.insert(event, false) { + importIdsMap.put(event.importId, event) + } + } + } while (cursor.moveToNext()) + } + } finally { + cursor?.close() + } + } + + fun addCalDAVEvent(event: Event, calendarId: Long) { + val durationMinutes = (event.endTS - event.startTS) / 1000 / 60 + val uri = CalendarContract.Events.CONTENT_URI + val values = ContentValues().apply { + put(CalendarContract.Events.CALENDAR_ID, calendarId) + put(CalendarContract.Events.TITLE, event.title) + put(CalendarContract.Events.DESCRIPTION, event.description) + put(CalendarContract.Events.DTSTART, event.startTS * 1000L) + put(CalendarContract.Events.ALL_DAY, if (event.getIsAllDay()) 1 else 0) + put(CalendarContract.Events.RRULE, Parser().getShortRepeatInterval(event)) + put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().toString()) + + if (event.getIsAllDay() && event.endTS > event.startTS) + event.endTS += DAY + + if (event.repeatInterval > 0) { + put(CalendarContract.Events.DURATION, Parser().getDurationString(durationMinutes)) + } else { + put(CalendarContract.Events.DTEND, event.endTS * 1000L) + } + } + + val newUri = context.contentResolver.insert(uri, values) + val eventRemoteID = java.lang.Long.parseLong(newUri.lastPathSegment) + + val importId = getCalDAVEventImportId(calendarId, eventRemoteID) + context.dbHelper.updateEventImportIdAndSource(event.id, importId, "$CALDAV-$calendarId") + } + + fun getCalDAVEventReminders(eventId: Long): List { + val reminders = ArrayList() + val uri = CalendarContract.Reminders.CONTENT_URI + val projection = arrayOf( + CalendarContract.Reminders.MINUTES, + CalendarContract.Reminders.METHOD) + val selection = "${CalendarContract.Reminders.EVENT_ID} = $eventId" + var cursor: Cursor? = null + try { + cursor = context.contentResolver.query(uri, projection, selection, null, null) + if (cursor != null && cursor.moveToFirst()) { + do { + val minutes = cursor.getIntValue(CalendarContract.Reminders.MINUTES) + val method = cursor.getIntValue(CalendarContract.Reminders.METHOD) + if (method == CalendarContract.Reminders.METHOD_ALERT) { + reminders.add(minutes) + } + } while (cursor.moveToNext()) + } + } finally { + cursor?.close() + } + return reminders + } + + fun getCalDAVEventImportId(calendarId: Long, eventId: Long) = "$CALDAV-$calendarId-$eventId" +}