Files
Simple-Calendar/app/src/main/kotlin/com/simplemobiletools/calendar/helpers/DBHelper.kt

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>)
}
}