mirror of
https://github.com/SimpleMobileTools/Simple-Calendar.git
synced 2025-06-05 21:59:17 +02:00
623 lines
24 KiB
Kotlin
623 lines
24 KiB
Kotlin
package com.simplemobiletools.calendar.helpers
|
|
|
|
import android.content.ContentValues
|
|
import android.content.Context
|
|
import android.database.Cursor
|
|
import android.database.sqlite.SQLiteDatabase
|
|
import android.database.sqlite.SQLiteException
|
|
import android.database.sqlite.SQLiteOpenHelper
|
|
import android.database.sqlite.SQLiteQueryBuilder
|
|
import android.text.TextUtils
|
|
import com.simplemobiletools.calendar.R
|
|
import com.simplemobiletools.calendar.extensions.config
|
|
import com.simplemobiletools.calendar.extensions.scheduleReminder
|
|
import com.simplemobiletools.calendar.extensions.seconds
|
|
import com.simplemobiletools.calendar.extensions.updateWidgets
|
|
import com.simplemobiletools.calendar.models.Event
|
|
import com.simplemobiletools.calendar.models.EventType
|
|
import com.simplemobiletools.commons.extensions.getIntValue
|
|
import com.simplemobiletools.commons.extensions.getStringValue
|
|
import org.joda.time.DateTime
|
|
import java.util.*
|
|
|
|
class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
|
|
private val MAIN_TABLE_NAME = "events"
|
|
private val COL_ID = "id"
|
|
private val COL_START_TS = "start_ts"
|
|
private val COL_END_TS = "end_ts"
|
|
private val COL_TITLE = "title"
|
|
private val COL_DESCRIPTION = "description"
|
|
private val COL_REMINDER_MINUTES = "reminder_minutes"
|
|
private val COL_REMINDER_MINUTES_2 = "reminder_minutes_2"
|
|
private val COL_REMINDER_MINUTES_3 = "reminder_minutes_3"
|
|
private val COL_IMPORT_ID = "import_id"
|
|
private val COL_FLAGS = "flags"
|
|
private val COL_EVENT_TYPE = "event_type"
|
|
|
|
private val META_TABLE_NAME = "events_meta"
|
|
private val COL_EVENT_ID = "event_id"
|
|
private val COL_REPEAT_START = "repeat_start"
|
|
private val COL_REPEAT_INTERVAL = "repeat_interval"
|
|
private val COL_REPEAT_RULE = "repeat_rule"
|
|
private val COL_REPEAT_LIMIT = "repeat_limit"
|
|
|
|
private val TYPES_TABLE_NAME = "event_types"
|
|
private val COL_TYPE_ID = "event_type_id"
|
|
private val COL_TYPE_TITLE = "event_type_title"
|
|
private val COL_TYPE_COLOR = "event_type_color"
|
|
|
|
private val EXCEPTIONS_TABLE_NAME = "event_repeat_exceptions"
|
|
private val COL_EXCEPTION_ID = "event_exception_id"
|
|
private val COL_OCCURRENCE_TIMESTAMP = "event_occurrence_timestamp"
|
|
private val COL_OCCURRENCE_DAYCODE = "event_occurrence_daycode"
|
|
private val COL_PARENT_EVENT_ID = "event_parent_id"
|
|
|
|
private val mDb: SQLiteDatabase = writableDatabase
|
|
|
|
companion object {
|
|
private val DB_VERSION = 11
|
|
val DB_NAME = "events.db"
|
|
val REGULAR_EVENT_TYPE_ID = 1
|
|
|
|
private var mEventsListener: EventUpdateListener? = null
|
|
|
|
fun newInstance(context: Context, callback: EventUpdateListener? = null): DBHelper {
|
|
mEventsListener = callback
|
|
return DBHelper(context)
|
|
}
|
|
}
|
|
|
|
override fun onCreate(db: SQLiteDatabase) {
|
|
db.execSQL("CREATE TABLE $MAIN_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY, $COL_START_TS INTEGER, $COL_END_TS INTEGER, $COL_TITLE TEXT, " +
|
|
"$COL_DESCRIPTION TEXT, $COL_REMINDER_MINUTES INTEGER, $COL_REMINDER_MINUTES_2 INTEGER, $COL_REMINDER_MINUTES_3 INTEGER, " +
|
|
"$COL_IMPORT_ID TEXT, $COL_FLAGS INTEGER, $COL_EVENT_TYPE INTEGER NOT NULL DEFAULT $REGULAR_EVENT_TYPE_ID, " +
|
|
"$COL_PARENT_EVENT_ID INTEGER)")
|
|
|
|
createMetaTable(db)
|
|
createTypesTable(db)
|
|
createExceptionsTable(db)
|
|
}
|
|
|
|
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
|
if (oldVersion == 1) {
|
|
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_REMINDER_MINUTES INTEGER DEFAULT -1")
|
|
}
|
|
|
|
if (oldVersion < 3) {
|
|
createMetaTable(db)
|
|
}
|
|
|
|
if (oldVersion < 4) {
|
|
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_IMPORT_ID TEXT DEFAULT ''")
|
|
}
|
|
|
|
if (oldVersion < 5) {
|
|
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_FLAGS INTEGER NOT NULL DEFAULT 0")
|
|
db.execSQL("ALTER TABLE $META_TABLE_NAME ADD COLUMN $COL_REPEAT_LIMIT INTEGER NOT NULL DEFAULT 0")
|
|
}
|
|
|
|
if (oldVersion < 6) {
|
|
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_REMINDER_MINUTES_2 INTEGER NOT NULL DEFAULT -1")
|
|
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_REMINDER_MINUTES_3 INTEGER NOT NULL DEFAULT -1")
|
|
}
|
|
|
|
if (oldVersion < 7) {
|
|
createTypesTable(db)
|
|
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_EVENT_TYPE INTEGER NOT NULL DEFAULT $REGULAR_EVENT_TYPE_ID")
|
|
}
|
|
|
|
if (oldVersion < 8) {
|
|
db.execSQL("ALTER TABLE $MAIN_TABLE_NAME ADD COLUMN $COL_PARENT_EVENT_ID INTEGER NOT NULL DEFAULT 0")
|
|
createExceptionsTable(db)
|
|
}
|
|
|
|
if (oldVersion < 9) {
|
|
try {
|
|
db.execSQL("ALTER TABLE $EXCEPTIONS_TABLE_NAME ADD COLUMN $COL_OCCURRENCE_DAYCODE INTEGER NOT NULL DEFAULT 0")
|
|
} catch (e: SQLiteException) {
|
|
}
|
|
convertExceptionTimestampToDaycode(db)
|
|
}
|
|
|
|
if (oldVersion < 11) {
|
|
db.execSQL("ALTER TABLE $META_TABLE_NAME ADD COLUMN $COL_REPEAT_RULE INTEGER NOT NULL DEFAULT 0")
|
|
setupRepeatRules(db)
|
|
}
|
|
}
|
|
|
|
private fun createMetaTable(db: SQLiteDatabase) {
|
|
db.execSQL("CREATE TABLE $META_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY, $COL_EVENT_ID INTEGER UNIQUE, $COL_REPEAT_START INTEGER, " +
|
|
"$COL_REPEAT_INTERVAL INTEGER, $COL_REPEAT_LIMIT INTEGER, $COL_REPEAT_RULE INTEGER)")
|
|
}
|
|
|
|
private fun createTypesTable(db: SQLiteDatabase) {
|
|
db.execSQL("CREATE TABLE $TYPES_TABLE_NAME ($COL_TYPE_ID INTEGER PRIMARY KEY, $COL_TYPE_TITLE TEXT, $COL_TYPE_COLOR INTEGER)")
|
|
addRegularEventType(db)
|
|
}
|
|
|
|
private fun createExceptionsTable(db: SQLiteDatabase) {
|
|
db.execSQL("CREATE TABLE $EXCEPTIONS_TABLE_NAME ($COL_EXCEPTION_ID INTEGER PRIMARY KEY, $COL_PARENT_EVENT_ID INTEGER, $COL_OCCURRENCE_TIMESTAMP INTEGER, " +
|
|
"$COL_OCCURRENCE_DAYCODE INTEGER)")
|
|
}
|
|
|
|
private fun addRegularEventType(db: SQLiteDatabase) {
|
|
val regularEvent = context.resources.getString(R.string.regular_event)
|
|
val eventType = EventType(REGULAR_EVENT_TYPE_ID, regularEvent, context.config.primaryColor)
|
|
addEventType(eventType, db)
|
|
}
|
|
|
|
fun insert(event: Event): Int {
|
|
if (event.startTS > event.endTS || event.title.trim().isEmpty())
|
|
return 0
|
|
|
|
val eventValues = fillEventValues(event)
|
|
val id = mDb.insert(MAIN_TABLE_NAME, null, eventValues)
|
|
event.id = id.toInt()
|
|
|
|
if (event.repeatInterval != 0) {
|
|
val metaValues = fillMetaValues(event)
|
|
mDb.insert(META_TABLE_NAME, null, metaValues)
|
|
}
|
|
|
|
context.updateWidgets()
|
|
context.scheduleReminder(event)
|
|
mEventsListener?.eventInserted(event)
|
|
return event.id
|
|
}
|
|
|
|
fun update(event: Event) {
|
|
val selectionArgs = arrayOf(event.id.toString())
|
|
val values = fillEventValues(event)
|
|
val selection = "$COL_ID = ?"
|
|
mDb.update(MAIN_TABLE_NAME, values, selection, selectionArgs)
|
|
|
|
if (event.repeatInterval == 0) {
|
|
val metaSelection = "$COL_EVENT_ID = ?"
|
|
mDb.delete(META_TABLE_NAME, metaSelection, selectionArgs)
|
|
} else {
|
|
val metaValues = fillMetaValues(event)
|
|
mDb.insertWithOnConflict(META_TABLE_NAME, null, metaValues, SQLiteDatabase.CONFLICT_REPLACE)
|
|
}
|
|
|
|
context.updateWidgets()
|
|
context.scheduleReminder(event)
|
|
mEventsListener?.eventUpdated(event)
|
|
}
|
|
|
|
private fun fillEventValues(event: Event): ContentValues {
|
|
return ContentValues().apply {
|
|
put(COL_START_TS, event.startTS)
|
|
put(COL_END_TS, event.endTS)
|
|
put(COL_TITLE, event.title)
|
|
put(COL_DESCRIPTION, event.description)
|
|
put(COL_REMINDER_MINUTES, event.reminder1Minutes)
|
|
put(COL_REMINDER_MINUTES_2, event.reminder2Minutes)
|
|
put(COL_REMINDER_MINUTES_3, event.reminder3Minutes)
|
|
put(COL_IMPORT_ID, event.importId)
|
|
put(COL_FLAGS, event.flags)
|
|
put(COL_EVENT_TYPE, event.eventType)
|
|
put(COL_PARENT_EVENT_ID, 0)
|
|
}
|
|
}
|
|
|
|
private fun fillMetaValues(event: Event): ContentValues {
|
|
return ContentValues().apply {
|
|
put(COL_EVENT_ID, event.id)
|
|
put(COL_REPEAT_START, event.startTS)
|
|
put(COL_REPEAT_INTERVAL, event.repeatInterval)
|
|
put(COL_REPEAT_LIMIT, event.repeatLimit)
|
|
put(COL_REPEAT_RULE, event.repeatRule)
|
|
}
|
|
}
|
|
|
|
private fun addEventType(eventType: EventType, db: SQLiteDatabase) {
|
|
insertEventType(eventType, db)
|
|
}
|
|
|
|
fun insertEventType(eventType: EventType, db: SQLiteDatabase = mDb): Int {
|
|
val values = fillEventTypeValues(eventType)
|
|
val insertedId = db.insert(TYPES_TABLE_NAME, null, values).toInt()
|
|
context.config.addDisplayEventType(insertedId.toString())
|
|
return insertedId
|
|
}
|
|
|
|
fun updateEventType(eventType: EventType): Int {
|
|
val selectionArgs = arrayOf(eventType.id.toString())
|
|
val values = fillEventTypeValues(eventType)
|
|
val selection = "$COL_TYPE_ID = ?"
|
|
return mDb.update(TYPES_TABLE_NAME, values, selection, selectionArgs)
|
|
}
|
|
|
|
private fun fillEventTypeValues(eventType: EventType): ContentValues {
|
|
return ContentValues().apply {
|
|
put(COL_TYPE_TITLE, eventType.title)
|
|
put(COL_TYPE_COLOR, eventType.color)
|
|
}
|
|
}
|
|
|
|
private fun fillExceptionValues(parentEventId: Int, occurrenceTS: Int): ContentValues {
|
|
return ContentValues().apply {
|
|
put(COL_PARENT_EVENT_ID, parentEventId)
|
|
put(COL_OCCURRENCE_DAYCODE, Formatter.getDayCodeFromTS(occurrenceTS))
|
|
}
|
|
}
|
|
|
|
fun getEventTypeIdWithTitle(title: String): Int {
|
|
val cols = arrayOf(COL_TYPE_ID)
|
|
val selection = "$COL_TYPE_TITLE = ? COLLATE NOCASE"
|
|
val selectionArgs = arrayOf(title)
|
|
var cursor: Cursor? = null
|
|
try {
|
|
cursor = mDb.query(TYPES_TABLE_NAME, cols, selection, selectionArgs, null, null, null)
|
|
if (cursor?.moveToFirst() == true) {
|
|
return cursor.getIntValue(COL_TYPE_ID)
|
|
}
|
|
} finally {
|
|
cursor?.close()
|
|
}
|
|
return -1
|
|
}
|
|
|
|
fun getEventType(id: Int): EventType? {
|
|
val cols = arrayOf(COL_TYPE_TITLE, COL_TYPE_COLOR)
|
|
val selection = "$COL_TYPE_ID = ?"
|
|
val selectionArgs = arrayOf(id.toString())
|
|
var cursor: Cursor? = null
|
|
try {
|
|
cursor = mDb.query(TYPES_TABLE_NAME, cols, selection, selectionArgs, null, null, null)
|
|
if (cursor?.moveToFirst() == true) {
|
|
val title = cursor.getStringValue(COL_TYPE_TITLE)
|
|
val color = cursor.getIntValue(COL_TYPE_COLOR)
|
|
return EventType(id, title, color)
|
|
}
|
|
} finally {
|
|
cursor?.close()
|
|
}
|
|
return null
|
|
}
|
|
|
|
fun deleteEvents(ids: Array<String>) {
|
|
val args = TextUtils.join(", ", ids)
|
|
val selection = "$COL_ID IN ($args)"
|
|
mDb.delete(MAIN_TABLE_NAME, selection, null)
|
|
|
|
val metaSelection = "$COL_EVENT_ID IN ($args)"
|
|
mDb.delete(META_TABLE_NAME, metaSelection, null)
|
|
|
|
val exceptionSelection = "$COL_PARENT_EVENT_ID IN ($args)"
|
|
mDb.delete(EXCEPTIONS_TABLE_NAME, exceptionSelection, null)
|
|
|
|
context.updateWidgets()
|
|
mEventsListener?.eventsDeleted(ids.size)
|
|
}
|
|
|
|
fun addEventRepeatException(parentEventId: Int, occurrenceTS: Int) {
|
|
val values = fillExceptionValues(parentEventId, occurrenceTS)
|
|
mDb.insert(EXCEPTIONS_TABLE_NAME, null, values)
|
|
}
|
|
|
|
fun deleteEventTypes(ids: ArrayList<Int>, callback: (deletedCnt: Int) -> Unit) {
|
|
var deleteIds = ids
|
|
if (ids.contains(DBHelper.REGULAR_EVENT_TYPE_ID))
|
|
deleteIds = ids.filter { it != DBHelper.REGULAR_EVENT_TYPE_ID } as ArrayList<Int>
|
|
|
|
val deletedSet = HashSet<String>()
|
|
deleteIds.map { deletedSet.add(it.toString()) }
|
|
context.config.removeDisplayEventTypes(deletedSet)
|
|
if (deleteIds.isEmpty())
|
|
return
|
|
|
|
for (eventTypeId in deleteIds) {
|
|
resetEventsWithType(eventTypeId)
|
|
}
|
|
|
|
val args = TextUtils.join(", ", deleteIds)
|
|
val selection = "$COL_TYPE_ID IN ($args)"
|
|
callback.invoke(mDb.delete(TYPES_TABLE_NAME, selection, null))
|
|
}
|
|
|
|
private fun resetEventsWithType(eventTypeId: Int) {
|
|
val values = ContentValues()
|
|
values.put(COL_EVENT_TYPE, REGULAR_EVENT_TYPE_ID)
|
|
|
|
val selection = "$COL_EVENT_TYPE = ?"
|
|
val selectionArgs = arrayOf(eventTypeId.toString())
|
|
mDb.update(MAIN_TABLE_NAME, values, selection, selectionArgs)
|
|
}
|
|
|
|
fun getImportIds(): ArrayList<String> {
|
|
val ids = ArrayList<String>()
|
|
val columns = arrayOf(COL_IMPORT_ID)
|
|
val selection = "$COL_IMPORT_ID IS NOT NULL"
|
|
var cursor: Cursor? = null
|
|
try {
|
|
cursor = mDb.query(MAIN_TABLE_NAME, columns, selection, null, null, null, null)
|
|
if (cursor != null && cursor.moveToFirst()) {
|
|
do {
|
|
val id = cursor.getStringValue(COL_IMPORT_ID)
|
|
ids.add(id)
|
|
} while (cursor.moveToNext())
|
|
}
|
|
} finally {
|
|
cursor?.close()
|
|
}
|
|
return ids
|
|
}
|
|
|
|
fun getEvent(id: Int): Event? {
|
|
val selection = "$MAIN_TABLE_NAME.$COL_ID = ?"
|
|
val selectionArgs = arrayOf(id.toString())
|
|
val cursor = getEventsCursor(selection, selectionArgs)
|
|
val events = fillEvents(cursor)
|
|
return if (!events.isEmpty())
|
|
events[0]
|
|
else
|
|
null
|
|
}
|
|
|
|
fun getEvents(fromTS: Int, toTS: Int, callback: (events: MutableList<Event>) -> Unit) {
|
|
Thread({
|
|
getEventsInBackground(fromTS, toTS, callback)
|
|
}).start()
|
|
}
|
|
|
|
fun getEventsInBackground(fromTS: Int, toTS: Int, callback: (events: MutableList<Event>) -> Unit) {
|
|
val events = ArrayList<Event>()
|
|
|
|
val selection = "$COL_START_TS <= ? AND $COL_END_TS >= ? AND $COL_REPEAT_INTERVAL IS NULL"
|
|
val selectionArgs = arrayOf(toTS.toString(), fromTS.toString())
|
|
val cursor = getEventsCursor(selection, selectionArgs)
|
|
events.addAll(fillEvents(cursor))
|
|
|
|
events.addAll(getRepeatableEventsFor(fromTS, toTS))
|
|
|
|
val filtered = events.filterNot { it.ignoreEventOccurrences.contains(Formatter.getDayCodeFromTS(it.startTS).toInt()) } as MutableList<Event>
|
|
callback(filtered)
|
|
}
|
|
|
|
private fun getRepeatableEventsFor(fromTS: Int, toTS: Int, getRunningEvents: Boolean = false): List<Event> {
|
|
val newEvents = ArrayList<Event>()
|
|
|
|
// get repeatable events
|
|
val selection = "$COL_REPEAT_INTERVAL != 0 AND $COL_START_TS < $toTS"
|
|
val events = getEvents(selection)
|
|
for (event in events) {
|
|
while (event.startTS < toTS && (event.repeatLimit == 0 || event.repeatLimit >= event.startTS)) {
|
|
if (event.startTS >= fromTS) {
|
|
newEvents.add(event.copy())
|
|
} else if (getRunningEvents && (event.startTS <= fromTS && event.endTS >= toTS)) {
|
|
newEvents.add(event.copy())
|
|
}
|
|
event.addIntervalTime()
|
|
}
|
|
}
|
|
|
|
return newEvents
|
|
}
|
|
|
|
fun getRunningEvents(): List<Event> {
|
|
val events = ArrayList<Event>()
|
|
val ts = (System.currentTimeMillis() / 1000).toInt()
|
|
|
|
val selection = "$COL_START_TS <= ? AND $COL_END_TS >= ?"
|
|
val selectionArgs = arrayOf(ts.toString(), ts.toString())
|
|
val cursor = getEventsCursor(selection, selectionArgs)
|
|
events.addAll(fillEvents(cursor))
|
|
|
|
events.addAll(getRepeatableEventsFor(ts, ts, true))
|
|
return events
|
|
}
|
|
|
|
private fun getEvents(selection: String): List<Event> {
|
|
val events = ArrayList<Event>()
|
|
var cursor: Cursor? = null
|
|
try {
|
|
cursor = getEventsCursor(selection)
|
|
if (cursor != null) {
|
|
val currEvents = fillEvents(cursor)
|
|
events.addAll(currEvents)
|
|
}
|
|
} finally {
|
|
cursor?.close()
|
|
}
|
|
|
|
return events
|
|
}
|
|
|
|
fun getEventsWithIds(ids: List<Int>): List<Event> {
|
|
val args = TextUtils.join(", ", ids)
|
|
val selection = "$MAIN_TABLE_NAME.$COL_ID IN ($args)"
|
|
return getEvents(selection)
|
|
}
|
|
|
|
fun getEventsAtReboot(): List<Event> {
|
|
val selection = "$COL_REMINDER_MINUTES != -1 AND ($COL_START_TS > ? OR $COL_REPEAT_INTERVAL != 0)"
|
|
val selectionArgs = arrayOf(DateTime.now().seconds().toString())
|
|
val cursor = getEventsCursor(selection, selectionArgs)
|
|
return fillEvents(cursor)
|
|
}
|
|
|
|
fun getEventsToExport(includePast: Boolean): ArrayList<Event> {
|
|
val currTime = (System.currentTimeMillis() / 1000).toString()
|
|
var events = ArrayList<Event>()
|
|
|
|
// non repeating events
|
|
var cursor = if (includePast) {
|
|
getEventsCursor()
|
|
} else {
|
|
val selection = "$COL_END_TS > ?"
|
|
val selectionArgs = arrayOf(currTime)
|
|
getEventsCursor(selection, selectionArgs)
|
|
}
|
|
events.addAll(fillEvents(cursor))
|
|
|
|
// repeating events
|
|
if (!includePast) {
|
|
val selection = "$COL_REPEAT_INTERVAL != 0 AND ($COL_REPEAT_LIMIT == 0 OR $COL_REPEAT_LIMIT > ?)"
|
|
val selectionArgs = arrayOf(currTime)
|
|
cursor = getEventsCursor(selection, selectionArgs)
|
|
events.addAll(fillEvents(cursor))
|
|
}
|
|
|
|
events = events.distinctBy { it.id } as ArrayList<Event>
|
|
return events
|
|
}
|
|
|
|
private fun getEventsCursor(selection: String = "", selectionArgs: Array<String>? = null): Cursor? {
|
|
val builder = SQLiteQueryBuilder()
|
|
builder.tables = "$MAIN_TABLE_NAME LEFT OUTER JOIN $META_TABLE_NAME ON $COL_EVENT_ID = $MAIN_TABLE_NAME.$COL_ID"
|
|
val projection = allColumns
|
|
return builder.query(mDb, projection, selection, selectionArgs, "$MAIN_TABLE_NAME.$COL_ID", null, COL_START_TS)
|
|
}
|
|
|
|
private val allColumns: Array<String>
|
|
get() = arrayOf("$MAIN_TABLE_NAME.$COL_ID", COL_START_TS, COL_END_TS, COL_TITLE, COL_DESCRIPTION, COL_REMINDER_MINUTES, COL_REMINDER_MINUTES_2,
|
|
COL_REMINDER_MINUTES_3, COL_REPEAT_INTERVAL, COL_REPEAT_RULE, COL_IMPORT_ID, COL_FLAGS, COL_REPEAT_LIMIT, COL_EVENT_TYPE)
|
|
|
|
private fun fillEvents(cursor: Cursor?): List<Event> {
|
|
val events = ArrayList<Event>()
|
|
try {
|
|
if (cursor != null && cursor.moveToFirst()) {
|
|
do {
|
|
val id = cursor.getIntValue(COL_ID)
|
|
val startTS = cursor.getIntValue(COL_START_TS)
|
|
var endTS = cursor.getIntValue(COL_END_TS)
|
|
val reminder1Minutes = cursor.getIntValue(COL_REMINDER_MINUTES)
|
|
val reminder2Minutes = cursor.getIntValue(COL_REMINDER_MINUTES_2)
|
|
val reminder3Minutes = cursor.getIntValue(COL_REMINDER_MINUTES_3)
|
|
val repeatInterval = cursor.getIntValue(COL_REPEAT_INTERVAL)
|
|
val repeatRule = cursor.getIntValue(COL_REPEAT_RULE)
|
|
val title = cursor.getStringValue(COL_TITLE)
|
|
val description = cursor.getStringValue(COL_DESCRIPTION)
|
|
val importId = cursor.getStringValue(COL_IMPORT_ID)
|
|
val flags = cursor.getIntValue(COL_FLAGS)
|
|
val repeatLimit = cursor.getIntValue(COL_REPEAT_LIMIT)
|
|
val eventType = cursor.getIntValue(COL_EVENT_TYPE)
|
|
if (flags and FLAG_ALL_DAY != 0)
|
|
endTS -= 1
|
|
|
|
val ignoreEventOccurrences = if (repeatInterval != 0) {
|
|
getIgnoredOccurrences(id)
|
|
} else {
|
|
ArrayList<Int>()
|
|
}
|
|
|
|
val event = Event(id, startTS, endTS, title, description, reminder1Minutes, reminder2Minutes, reminder3Minutes,
|
|
repeatInterval, importId, flags, repeatLimit, repeatRule, eventType, ignoreEventOccurrences)
|
|
events.add(event)
|
|
} while (cursor.moveToNext())
|
|
}
|
|
} finally {
|
|
cursor?.close()
|
|
}
|
|
return events
|
|
}
|
|
|
|
fun getEventTypes(callback: (types: ArrayList<EventType>) -> Unit) {
|
|
Thread({
|
|
fetchEventTypes(callback)
|
|
}).start()
|
|
}
|
|
|
|
fun fetchEventTypes(callback: (types: ArrayList<EventType>) -> Unit) {
|
|
val eventTypes = ArrayList<EventType>(3)
|
|
val cols = arrayOf(COL_TYPE_ID, COL_TYPE_TITLE, COL_TYPE_COLOR)
|
|
var cursor: Cursor? = null
|
|
try {
|
|
cursor = mDb.query(TYPES_TABLE_NAME, cols, null, null, null, null, "$COL_TYPE_TITLE ASC")
|
|
if (cursor?.moveToFirst() == true) {
|
|
do {
|
|
val id = cursor.getIntValue(COL_TYPE_ID)
|
|
val title = cursor.getStringValue(COL_TYPE_TITLE)
|
|
val color = cursor.getIntValue(COL_TYPE_COLOR)
|
|
val eventType = EventType(id, title, color)
|
|
eventTypes.add(eventType)
|
|
} while (cursor.moveToNext())
|
|
}
|
|
} finally {
|
|
cursor?.close()
|
|
}
|
|
callback.invoke(eventTypes)
|
|
}
|
|
|
|
private fun getIgnoredOccurrences(eventId: Int): ArrayList<Int> {
|
|
val projection = arrayOf(COL_OCCURRENCE_DAYCODE)
|
|
val selection = "$COL_PARENT_EVENT_ID = ?"
|
|
val selectionArgs = arrayOf(eventId.toString())
|
|
val daycodes = ArrayList<Int>()
|
|
|
|
var cursor: Cursor? = null
|
|
try {
|
|
cursor = mDb.query(EXCEPTIONS_TABLE_NAME, projection, selection, selectionArgs, null, null, COL_OCCURRENCE_DAYCODE)
|
|
if (cursor?.moveToFirst() == true) {
|
|
do {
|
|
daycodes.add(cursor.getIntValue(COL_OCCURRENCE_DAYCODE))
|
|
} while (cursor.moveToNext())
|
|
}
|
|
} finally {
|
|
cursor?.close()
|
|
}
|
|
return daycodes
|
|
}
|
|
|
|
private fun convertExceptionTimestampToDaycode(db: SQLiteDatabase) {
|
|
val projection = arrayOf(COL_EXCEPTION_ID, COL_OCCURRENCE_TIMESTAMP)
|
|
var cursor: Cursor? = null
|
|
try {
|
|
cursor = db.query(EXCEPTIONS_TABLE_NAME, projection, null, null, null, null, null)
|
|
if (cursor?.moveToFirst() == true) {
|
|
do {
|
|
val id = cursor.getIntValue(COL_EXCEPTION_ID)
|
|
val ts = cursor.getIntValue(COL_OCCURRENCE_TIMESTAMP)
|
|
val values = ContentValues()
|
|
values.put(COL_OCCURRENCE_DAYCODE, Formatter.getDayCodeFromTS(ts))
|
|
|
|
val selection = "$COL_EXCEPTION_ID = ?"
|
|
val selectionArgs = arrayOf(id.toString())
|
|
db.update(EXCEPTIONS_TABLE_NAME, values, selection, selectionArgs)
|
|
} while (cursor.moveToNext())
|
|
}
|
|
} finally {
|
|
cursor?.close()
|
|
}
|
|
}
|
|
|
|
private fun setupRepeatRules(db: SQLiteDatabase) {
|
|
val projection = arrayOf(COL_EVENT_ID, COL_REPEAT_INTERVAL)
|
|
val selection = "$COL_REPEAT_INTERVAL = ? OR $COL_REPEAT_INTERVAL = ?"
|
|
val selectionArgs = arrayOf(DAY.toString(), MONTH.toString())
|
|
var cursor: Cursor? = null
|
|
try {
|
|
cursor = db.query(META_TABLE_NAME, projection, selection, selectionArgs, null, null, null)
|
|
if (cursor?.moveToFirst() == true) {
|
|
do {
|
|
val eventId = cursor.getIntValue(COL_EVENT_ID)
|
|
val interval = cursor.getIntValue(COL_REPEAT_INTERVAL)
|
|
var rule = EVERY_DAY
|
|
if (interval == MONTH) {
|
|
rule = REPEAT_MONTH_SAME_DAY
|
|
}
|
|
|
|
val values = ContentValues()
|
|
values.put(COL_REPEAT_RULE, rule)
|
|
val curSelection = "$COL_EVENT_ID = ?"
|
|
val curSelectionArgs = arrayOf(eventId.toString())
|
|
db.update(META_TABLE_NAME, values, curSelection, curSelectionArgs)
|
|
} while (cursor.moveToNext())
|
|
}
|
|
} finally {
|
|
cursor?.close()
|
|
}
|
|
}
|
|
|
|
interface EventUpdateListener {
|
|
fun eventInserted(event: Event)
|
|
|
|
fun eventUpdated(event: Event)
|
|
|
|
fun eventsDeleted(cnt: Int)
|
|
|
|
fun gotEvents(events: MutableList<Event>)
|
|
}
|
|
}
|