diff --git a/app/src/main/kotlin/org/fossify/clock/activities/IntentHandlerActivity.kt b/app/src/main/kotlin/org/fossify/clock/activities/IntentHandlerActivity.kt index 7e457b52c..80d697593 100644 --- a/app/src/main/kotlin/org/fossify/clock/activities/IntentHandlerActivity.kt +++ b/app/src/main/kotlin/org/fossify/clock/activities/IntentHandlerActivity.kt @@ -22,11 +22,11 @@ import org.fossify.clock.extensions.isBitSet import org.fossify.clock.extensions.secondsToMillis import org.fossify.clock.extensions.timerHelper import org.fossify.clock.helpers.DEFAULT_ALARM_MINUTES -import org.fossify.clock.helpers.TODAY_BIT -import org.fossify.clock.helpers.TOMORROW_BIT import org.fossify.clock.helpers.UPCOMING_ALARM_NOTIFICATION_ID import org.fossify.clock.helpers.getBitForCalendarDay import org.fossify.clock.helpers.getCurrentDayMinutes +import org.fossify.clock.helpers.getDateFromTimeInMinutes +import org.fossify.clock.helpers.getEpochDayFromMillis import org.fossify.clock.helpers.getTodayBit import org.fossify.clock.helpers.getTomorrowBit import org.fossify.clock.models.Alarm @@ -42,7 +42,6 @@ import org.fossify.commons.helpers.SILENT import org.fossify.commons.helpers.ensureBackgroundThread import org.fossify.commons.models.AlarmSound import org.greenrobot.eventbus.EventBus -import java.util.concurrent.TimeUnit class IntentHandlerActivity : SimpleActivity() { companion object { @@ -114,22 +113,21 @@ class IntentHandlerActivity : SimpleActivity() { // We don't want to accidentally edit existing alarm, so allow reuse only when skipping UI if (hasExtra(AlarmClock.EXTRA_HOUR) && skipUi) { - var daysToCompare = weekDays val timeInMinutes = hour * 60 + minute - if (weekDays <= 0) { - daysToCompare = if (timeInMinutes > getCurrentDayMinutes()) { - TODAY_BIT + val scheduledDateToCompare = if (weekDays <= 0) getDateFromTimeInMinutes(timeInMinutes) else 0L + val existingAlarm = dbHelper.getAlarms().firstOrNull { + val sameScheduling = if (weekDays > 0) { + it.days == weekDays } else { - TOMORROW_BIT + !it.isRecurring() && it.getScheduledDateEpochDay() == scheduledDateToCompare } - } - val existingAlarm = dbHelper.getAlarms().firstOrNull { - it.days == daysToCompare - && it.vibrate == vibrate - && it.soundTitle == soundToUse.title - && it.soundUri == soundToUse.uri - && it.label == (message ?: "") - && it.timeInMinutes == timeInMinutes + + sameScheduling + && it.vibrate == vibrate + && it.soundTitle == soundToUse.title + && it.soundUri == soundToUse.uri + && it.label == (message ?: "") + && it.timeInMinutes == timeInMinutes } if (existingAlarm != null && !existingAlarm.isEnabled) { @@ -156,11 +154,8 @@ class IntentHandlerActivity : SimpleActivity() { } else { newAlarm.timeInMinutes = hour * 60 + minute if (newAlarm.days <= 0) { - newAlarm.days = if (newAlarm.timeInMinutes > getCurrentDayMinutes()) { - TODAY_BIT - } else { - TOMORROW_BIT - } + newAlarm.days = 0 + newAlarm.scheduledDate = getDateFromTimeInMinutes(newAlarm.timeInMinutes) newAlarm.oneShot = true } @@ -269,20 +264,23 @@ class IntentHandlerActivity : SimpleActivity() { AlarmClock.ALARM_SEARCH_MODE_NEXT -> { val next = alarmManager.nextAlarmClock + val calendar = java.util.Calendar.getInstance().apply { + timeInMillis = next.triggerTime + } val timeInMinutes = - TimeUnit.MILLISECONDS.toMinutes(next.triggerTime).toInt() + calendar.get(java.util.Calendar.HOUR_OF_DAY) * 60 + + calendar.get(java.util.Calendar.MINUTE) + val nextEpochDay = getEpochDayFromMillis(next.triggerTime) val dayBitToLookFor = if (timeInMinutes <= getCurrentDayMinutes()) { getTomorrowBit() } else { getTodayBit() } - val dayToLookFor = if (timeInMinutes <= getCurrentDayMinutes()) { - TOMORROW_BIT - } else { - TODAY_BIT - } alarms = alarms.filter { - it.timeInMinutes == timeInMinutes && (it.days.isBitSet(dayBitToLookFor) || it.days == dayToLookFor) + it.timeInMinutes == timeInMinutes && ( + (it.isRecurring() && it.days.isBitSet(dayBitToLookFor)) + || (!it.isRecurring() && it.getScheduledDateEpochDay() == nextEpochDay) + ) } } diff --git a/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt b/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt index c29d72fe6..b670d31ee 100644 --- a/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt +++ b/app/src/main/kotlin/org/fossify/clock/adapters/AlarmsAdapter.kt @@ -12,7 +12,9 @@ import org.fossify.clock.activities.SimpleActivity import org.fossify.clock.databinding.ItemAlarmBinding import org.fossify.clock.extensions.config import org.fossify.clock.extensions.dbHelper +import org.fossify.clock.extensions.getFormattedDate import org.fossify.clock.extensions.getFormattedTime +import org.fossify.clock.helpers.getCalendarFromEpochDay import org.fossify.clock.helpers.updateNonRecurringAlarmDay import org.fossify.clock.interfaces.ToggleAlarmInterface import org.fossify.clock.models.Alarm @@ -209,6 +211,10 @@ class AlarmsAdapter( return when { !isEnabled -> resources.getString(R.string.not_scheduled) + alarm.getScheduledDateEpochDay() > 0L -> { + activity.getFormattedDate(getCalendarFromEpochDay(alarm.getScheduledDateEpochDay())) + } + alarm.isToday() -> resources.getString(org.fossify.commons.R.string.today) else -> resources.getString(org.fossify.commons.R.string.tomorrow) } diff --git a/app/src/main/kotlin/org/fossify/clock/dialogs/EditAlarmDialog.kt b/app/src/main/kotlin/org/fossify/clock/dialogs/EditAlarmDialog.kt index 06a992637..d4ce09461 100644 --- a/app/src/main/kotlin/org/fossify/clock/dialogs/EditAlarmDialog.kt +++ b/app/src/main/kotlin/org/fossify/clock/dialogs/EditAlarmDialog.kt @@ -15,11 +15,13 @@ import org.fossify.clock.extensions.checkAlarmsWithDeletedSoundUri import org.fossify.clock.extensions.colorCompoundDrawable import org.fossify.clock.extensions.config import org.fossify.clock.extensions.dbHelper +import org.fossify.clock.extensions.getFormattedDate import org.fossify.clock.extensions.getFormattedTime import org.fossify.clock.extensions.handleFullScreenNotificationsPermission import org.fossify.clock.extensions.rotateWeekdays import org.fossify.clock.helpers.PICK_AUDIO_FILE_INTENT_ID -import org.fossify.clock.helpers.getCurrentDayMinutes +import org.fossify.clock.helpers.getCalendarFromEpochDay +import org.fossify.clock.helpers.getDateFromTimeInMinutes import org.fossify.clock.helpers.updateNonRecurringAlarmDay import org.fossify.clock.models.Alarm import org.fossify.commons.dialogs.ConfirmationDialog @@ -139,6 +141,7 @@ class EditAlarmDialog( day.setOnClickListener { if (!alarm.isRecurring()) { alarm.days = 0 + alarm.scheduledDate = 0L } val selectDay = alarm.days and bitmask == 0 @@ -216,6 +219,7 @@ class EditAlarmDialog( alarm.soundUri = lastConfig.soundUri alarm.timeInMinutes = lastConfig.timeInMinutes alarm.vibrate = lastConfig.vibrate + alarm.scheduledDate = lastConfig.scheduledDate } } } @@ -226,6 +230,9 @@ class EditAlarmDialog( private fun timePicked(hours: Int, minutes: Int) { alarm.timeInMinutes = hours * 60 + minutes + if (!alarm.isRecurring()) { + alarm.scheduledDate = 0L + } updateAlarmTime() } @@ -240,13 +247,9 @@ class EditAlarmDialog( private fun checkDaylessAlarm() { if (!alarm.isRecurring()) { - val textId = if (alarm.timeInMinutes > getCurrentDayMinutes()) { - org.fossify.commons.R.string.today - } else { - org.fossify.commons.R.string.tomorrow - } - - binding.editAlarmDaylessLabel.text = "(${activity.getString(textId)})" + val epochDay = alarm.scheduledDate.takeIf { it > 0L } ?: getDateFromTimeInMinutes(alarm.timeInMinutes) + val calendar = getCalendarFromEpochDay(epochDay) + binding.editAlarmDaylessLabel.text = "(${activity.getFormattedDate(calendar)})" } binding.editAlarmDaylessLabel.beVisibleIf(!alarm.isRecurring()) } diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt index 7eb52fc9e..f09202e45 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt @@ -16,13 +16,13 @@ import org.fossify.clock.extensions.cancelAlarmClock import org.fossify.clock.extensions.config import org.fossify.clock.extensions.createNewAlarm import org.fossify.clock.extensions.dbHelper -import org.fossify.clock.extensions.firstDayOrder import org.fossify.clock.extensions.handleFullScreenNotificationsPermission import org.fossify.clock.extensions.updateWidgets import org.fossify.clock.helpers.DEFAULT_ALARM_MINUTES import org.fossify.clock.helpers.SORT_BY_ALARM_TIME import org.fossify.clock.helpers.SORT_BY_DATE_AND_TIME -import org.fossify.clock.helpers.getTomorrowBit +import org.fossify.clock.helpers.getTimeOfNextAlarm +import org.fossify.clock.helpers.getTomorrowEpochDay import org.fossify.clock.interfaces.ToggleAlarmInterface import org.fossify.clock.models.Alarm import org.fossify.clock.models.AlarmEvent @@ -81,7 +81,8 @@ class AlarmFragment : Fragment(), ToggleAlarmInterface { alarmFab.setOnClickListener { val newAlarm = root.context.createNewAlarm(DEFAULT_ALARM_MINUTES, 0) newAlarm.isEnabled = true - newAlarm.days = getTomorrowBit() + newAlarm.days = 0 + newAlarm.scheduledDate = getTomorrowEpochDay() openEditAlarm(newAlarm) } } @@ -103,11 +104,7 @@ class AlarmFragment : Fragment(), ToggleAlarmInterface { when (safeContext.config.alarmSort) { SORT_BY_ALARM_TIME -> newAlarms.sortBy { it.timeInMinutes } SORT_BY_DATE_CREATED -> newAlarms.sortBy { it.id } - SORT_BY_DATE_AND_TIME -> newAlarms.sortWith(compareBy { - safeContext.firstDayOrder(it.days) - }.thenBy { - it.timeInMinutes - }) + SORT_BY_DATE_AND_TIME -> newAlarms.sortBy { getTimeOfNextAlarm(it)?.timeInMillis ?: Long.MAX_VALUE } SORT_BY_CUSTOM -> { val customAlarmsSortOrderString = activity?.config?.alarmsCustomSorting diff --git a/app/src/main/kotlin/org/fossify/clock/helpers/AlarmController.kt b/app/src/main/kotlin/org/fossify/clock/helpers/AlarmController.kt index eb887cf90..98c7c3f2d 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/AlarmController.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/AlarmController.kt @@ -28,14 +28,15 @@ class AlarmController( ) { /** * Reschedules all enabled alarms. - * Skips rescheduling one-time alarms that were set for today but whose time has already passed, - * and potentially upcoming alarms for today depending on the logic in `scheduleNextOccurrence`. + * For one-time alarms, "today" / "tomorrow" are stored as relative sentinels. + * Normalize them against the current clock before rescheduling so a saved + * "tomorrow" alarm does not get pushed out by another full day after boot, + * package replacement, or a manual time change. */ fun rescheduleEnabledAlarms() { db.getEnabledAlarms().forEach { - // TODO: Skipped upcoming alarms are being *rescheduled* here. - if (!it.isToday() || it.timeInMinutes > getCurrentDayMinutes()) { - scheduleNextOccurrence(it, false) + normalizeRescheduledAlarm(it)?.let { normalizedAlarm -> + scheduleNextOccurrence(normalizedAlarm, false) } } } @@ -193,6 +194,33 @@ class AlarmController( } } + private fun normalizeRescheduledAlarm(alarm: Alarm): Alarm? { + if (alarm.isRecurring()) { + return alarm + } + + if (alarm.hasAbsoluteDate()) { + return alarm.takeIf { getTimeOfNextAlarm(it) != null } + } + + val currentMinutes = getCurrentDayMinutes() + return when { + alarm.days == TODAY_BIT && alarm.timeInMinutes > currentMinutes -> { + alarm.copy(days = 0, scheduledDate = getCurrentEpochDay()) + } + + alarm.days == TOMORROW_BIT && alarm.timeInMinutes > currentMinutes -> { + alarm.copy(days = 0, scheduledDate = getTomorrowEpochDay()) + } + + alarm.days == TOMORROW_BIT -> { + alarm.copy(days = 0, scheduledDate = getCurrentEpochDay()) + } + + else -> null + } + } + private fun scheduleNextAlarm(alarm: Alarm, showToast: Boolean = false) { val triggerTimeMillis = getTimeOfNextAlarm(alarm)?.timeInMillis ?: return context.setupAlarmClock(alarm = alarm, triggerTimeMillis = triggerTimeMillis) diff --git a/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt b/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt index 2d812c03d..14adcfb40 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt @@ -11,6 +11,9 @@ import org.fossify.commons.helpers.THURSDAY_BIT import org.fossify.commons.helpers.TUESDAY_BIT import org.fossify.commons.helpers.WEDNESDAY_BIT import org.fossify.commons.helpers.isPiePlus +import java.time.Instant +import java.time.LocalDate +import java.time.ZoneId import java.util.Calendar import java.util.Date import java.util.TimeZone @@ -164,6 +167,33 @@ fun getTomorrowBit(): Int { return 1 shl dayOfWeek } +fun getCurrentEpochDay(): Long = LocalDate.now().toEpochDay() + +fun getTomorrowEpochDay(): Long = LocalDate.now().plusDays(1).toEpochDay() + +fun getEpochDayFromMillis(timeInMillis: Long): Long { + return Instant.ofEpochMilli(timeInMillis).atZone(ZoneId.systemDefault()).toLocalDate().toEpochDay() +} + +fun getDateFromTimeInMinutes(timeInMinutes: Int): Long { + return if (timeInMinutes > getCurrentDayMinutes()) { + getCurrentEpochDay() + } else { + getTomorrowEpochDay() + } +} + +fun getCalendarFromEpochDay(epochDay: Long): Calendar { + val timeInMillis = LocalDate.ofEpochDay(epochDay) + .atStartOfDay(ZoneId.systemDefault()) + .toInstant() + .toEpochMilli() + + return Calendar.getInstance().apply { + this.timeInMillis = timeInMillis + } +} + fun getTodayBit(): Int { val calendar = Calendar.getInstance() val dayOfWeek = getDayNumber(calendar.get(Calendar.DAY_OF_WEEK)) @@ -274,7 +304,14 @@ fun getAllTimeZones() = arrayListOf( ) fun getTimeOfNextAlarm(alarm: Alarm): Calendar? { - return getTimeOfNextAlarm(alarm.timeInMinutes, alarm.days) + return if (alarm.isRecurring()) { + getTimeOfNextAlarm(alarm.timeInMinutes, alarm.days) + } else { + when { + alarm.hasAbsoluteDate() -> getTimeOfNextAlarm(alarm.timeInMinutes, alarm.scheduledDate) + else -> getTimeOfNextAlarm(alarm.timeInMinutes, alarm.days) + } + } } fun getTimeOfNextAlarm(alarmTimeInMinutes: Int, days: Int): Calendar? { @@ -303,11 +340,27 @@ fun getTimeOfNextAlarm(alarmTimeInMinutes: Int, days: Int): Calendar? { } } +fun getTimeOfNextAlarm(alarmTimeInMinutes: Int, epochDay: Long): Calendar? { + if (epochDay <= 0L) { + return null + } + + val nextAlarmTime = getCalendarFromEpochDay(epochDay).apply { + set(Calendar.HOUR_OF_DAY, alarmTimeInMinutes / 60) + set(Calendar.MINUTE, alarmTimeInMinutes % 60) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + } + + return nextAlarmTime.takeIf { Calendar.getInstance() < it } +} + fun updateNonRecurringAlarmDay(alarm: Alarm) { - if (alarm.isRecurring()) return - alarm.days = if (alarm.timeInMinutes > getCurrentDayMinutes()) { - TODAY_BIT - } else { - TOMORROW_BIT + if (alarm.isRecurring()) { + alarm.scheduledDate = 0L + return } + + alarm.days = 0 + alarm.scheduledDate = getDateFromTimeInMinutes(alarm.timeInMinutes) } diff --git a/app/src/main/kotlin/org/fossify/clock/helpers/DBHelper.kt b/app/src/main/kotlin/org/fossify/clock/helpers/DBHelper.kt index b40975992..c9869a603 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/DBHelper.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/DBHelper.kt @@ -24,22 +24,24 @@ class DBHelper private constructor( val context: Context, ) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { - private val ALARMS_TABLE_NAME = "contacts" // wrong table name, ignore it - private val COL_ID = "id" - private val COL_TIME_IN_MINUTES = "time_in_minutes" - private val COL_DAYS = "days" - private val COL_IS_ENABLED = "is_enabled" - private val COL_VIBRATE = "vibrate" - private val COL_SOUND_TITLE = "sound_title" - private val COL_SOUND_URI = "sound_uri" - private val COL_LABEL = "label" - private val COL_ONE_SHOT = "one_shot" + private val alarmsTableName = "contacts" // wrong table name, ignore it + private val colId = "id" + private val colTimeInMinutes = "time_in_minutes" + private val colDays = "days" + private val colIsEnabled = "is_enabled" + private val colVibrate = "vibrate" + private val colSoundTitle = "sound_title" + private val colSoundUri = "sound_uri" + private val colLabel = "label" + private val colOneShot = "one_shot" + private val colScheduledDate = "scheduled_date" private val mDb = writableDatabase companion object { - private const val DB_VERSION = 2 + private const val DB_VERSION = 3 const val DB_NAME = "alarms.db" + private const val VERSION_WITH_SCHEDULED_DATE = 3 @SuppressLint("StaticFieldLeak") @Volatile @@ -55,15 +57,31 @@ class DBHelper private constructor( override fun onCreate(db: SQLiteDatabase) { db.execSQL( - "CREATE TABLE IF NOT EXISTS $ALARMS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_TIME_IN_MINUTES INTEGER, $COL_DAYS INTEGER, " + - "$COL_IS_ENABLED INTEGER, $COL_VIBRATE INTEGER, $COL_SOUND_TITLE TEXT, $COL_SOUND_URI TEXT, $COL_LABEL TEXT, $COL_ONE_SHOT INTEGER)" + "CREATE TABLE IF NOT EXISTS $alarmsTableName (" + + "$colId INTEGER PRIMARY KEY AUTOINCREMENT, " + + "$colTimeInMinutes INTEGER, " + + "$colDays INTEGER, " + + "$colIsEnabled INTEGER, " + + "$colVibrate INTEGER, " + + "$colSoundTitle TEXT, " + + "$colSoundUri TEXT, " + + "$colLabel TEXT, " + + "$colOneShot INTEGER, " + + "$colScheduledDate INTEGER NOT NULL DEFAULT 0)" ) insertInitialAlarms(db) } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { if (oldVersion == 1 && newVersion > oldVersion) { - db.execSQL("ALTER TABLE $ALARMS_TABLE_NAME ADD COLUMN $COL_ONE_SHOT INTEGER NOT NULL DEFAULT 0") + db.execSQL("ALTER TABLE $alarmsTableName ADD COLUMN $colOneShot INTEGER NOT NULL DEFAULT 0") + } + + if (oldVersion < VERSION_WITH_SCHEDULED_DATE) { + db.execSQL( + "ALTER TABLE $alarmsTableName " + + "ADD COLUMN $colScheduledDate INTEGER NOT NULL DEFAULT 0" + ) } } @@ -79,22 +97,22 @@ class DBHelper private constructor( fun insertAlarm(alarm: Alarm, db: SQLiteDatabase = mDb): Int { val values = fillAlarmContentValues(alarm) - return db.insert(ALARMS_TABLE_NAME, null, values).toInt() + return db.insert(alarmsTableName, null, values).toInt() } fun updateAlarm(alarm: Alarm): Boolean { val selectionArgs = arrayOf(alarm.id.toString()) val values = fillAlarmContentValues(alarm) - val selection = "$COL_ID = ?" - return mDb.update(ALARMS_TABLE_NAME, values, selection, selectionArgs) == 1 + val selection = "$colId = ?" + return mDb.update(alarmsTableName, values, selection, selectionArgs) == 1 } fun updateAlarmEnabledState(id: Int, isEnabled: Boolean): Boolean { val selectionArgs = arrayOf(id.toString()) val values = ContentValues() - values.put(COL_IS_ENABLED, isEnabled) - val selection = "$COL_ID = ?" - return mDb.update(ALARMS_TABLE_NAME, values, selection, selectionArgs) == 1 + values.put(colIsEnabled, isEnabled) + val selection = "$colId = ?" + return mDb.update(alarmsTableName, values, selection, selectionArgs) == 1 } fun deleteAlarms(alarms: ArrayList) { @@ -103,8 +121,8 @@ class DBHelper private constructor( } val args = TextUtils.join(", ", alarms.map { it.id.toString() }) - val selection = "$ALARMS_TABLE_NAME.$COL_ID IN ($args)" - mDb.delete(ALARMS_TABLE_NAME, selection, null) + val selection = "$alarmsTableName.$colId IN ($args)" + mDb.delete(alarmsTableName, selection, null) } fun getAlarmWithId(id: Int) = getAlarms().firstOrNull { it.id == id } @@ -113,14 +131,15 @@ class DBHelper private constructor( private fun fillAlarmContentValues(alarm: Alarm): ContentValues { return ContentValues().apply { - put(COL_TIME_IN_MINUTES, alarm.timeInMinutes) - put(COL_DAYS, alarm.days) - put(COL_IS_ENABLED, alarm.isEnabled) - put(COL_VIBRATE, alarm.vibrate) - put(COL_SOUND_TITLE, alarm.soundTitle) - put(COL_SOUND_URI, alarm.soundUri) - put(COL_LABEL, alarm.label) - put(COL_ONE_SHOT, alarm.oneShot) + put(colTimeInMinutes, alarm.timeInMinutes) + put(colDays, alarm.days) + put(colIsEnabled, alarm.isEnabled) + put(colVibrate, alarm.vibrate) + put(colSoundTitle, alarm.soundTitle) + put(colSoundUri, alarm.soundUri) + put(colLabel, alarm.label) + put(colOneShot, alarm.oneShot) + put(colScheduledDate, alarm.scheduledDate) } } @@ -129,31 +148,34 @@ class DBHelper private constructor( fun getAlarms(): ArrayList { val alarms = ArrayList() val cols = arrayOf( - COL_ID, - COL_TIME_IN_MINUTES, - COL_DAYS, - COL_IS_ENABLED, - COL_VIBRATE, - COL_SOUND_TITLE, - COL_SOUND_URI, - COL_LABEL, - COL_ONE_SHOT + colId, + colTimeInMinutes, + colDays, + colIsEnabled, + colVibrate, + colSoundTitle, + colSoundUri, + colLabel, + colOneShot, + colScheduledDate ) var cursor: Cursor? = null try { - cursor = mDb.query(ALARMS_TABLE_NAME, cols, null, null, null, null, null) + cursor = mDb.query(alarmsTableName, cols, null, null, null, null, null) if (cursor?.moveToFirst() == true) { do { try { - val id = cursor.getIntValue(COL_ID) - val timeInMinutes = cursor.getIntValue(COL_TIME_IN_MINUTES) - val days = cursor.getIntValue(COL_DAYS) - val isEnabled = cursor.getIntValue(COL_IS_ENABLED) == 1 - val vibrate = cursor.getIntValue(COL_VIBRATE) == 1 - val soundTitle = cursor.getStringValue(COL_SOUND_TITLE) - val soundUri = cursor.getStringValue(COL_SOUND_URI) - val label = cursor.getStringValue(COL_LABEL) - val oneShot = cursor.getIntValue(COL_ONE_SHOT) == 1 + val id = cursor.getIntValue(colId) + val timeInMinutes = cursor.getIntValue(colTimeInMinutes) + val days = cursor.getIntValue(colDays) + val isEnabled = cursor.getIntValue(colIsEnabled) == 1 + val vibrate = cursor.getIntValue(colVibrate) == 1 + val soundTitle = cursor.getStringValue(colSoundTitle) + val soundUri = cursor.getStringValue(colSoundUri) + val label = cursor.getStringValue(colLabel) + val oneShot = cursor.getIntValue(colOneShot) == 1 + val scheduledDateIndex = cursor.getColumnIndex(colScheduledDate) + val scheduledDate = if (scheduledDateIndex == -1) 0L else cursor.getLong(scheduledDateIndex) val alarm = Alarm( id = id, @@ -164,7 +186,8 @@ class DBHelper private constructor( soundTitle = soundTitle, soundUri = soundUri, label = label, - oneShot = oneShot + oneShot = oneShot, + scheduledDate = scheduledDate ) alarms.add(alarm) } catch (e: Exception) { diff --git a/app/src/main/kotlin/org/fossify/clock/models/Alarm.kt b/app/src/main/kotlin/org/fossify/clock/models/Alarm.kt index 263ca1fac..5a8a4d277 100644 --- a/app/src/main/kotlin/org/fossify/clock/models/Alarm.kt +++ b/app/src/main/kotlin/org/fossify/clock/models/Alarm.kt @@ -1,6 +1,8 @@ package org.fossify.clock.models import androidx.annotation.Keep +import org.fossify.clock.helpers.getCurrentEpochDay +import org.fossify.clock.helpers.getTomorrowEpochDay import org.fossify.clock.helpers.TODAY_BIT import org.fossify.clock.helpers.TOMORROW_BIT @@ -16,12 +18,27 @@ data class Alarm( var soundUri: String, var label: String, var oneShot: Boolean = false, + var scheduledDate: Long = 0L, ) { fun isRecurring() = days > 0 - fun isToday() = days == TODAY_BIT + fun hasAbsoluteDate() = scheduledDate > 0L - fun isTomorrow() = days == TOMORROW_BIT + fun getScheduledDateEpochDay(): Long { + if (scheduledDate > 0L) { + return scheduledDate + } + + return when (days) { + TODAY_BIT -> getCurrentEpochDay() + TOMORROW_BIT -> getTomorrowEpochDay() + else -> 0L + } + } + + fun isToday() = !isRecurring() && getScheduledDateEpochDay() == getCurrentEpochDay() + + fun isTomorrow() = !isRecurring() && getScheduledDateEpochDay() == getTomorrowEpochDay() } @Keep @@ -35,6 +52,7 @@ data class ObfuscatedAlarm( var g: String, var h: String, var i: Boolean = false, + var j: Long = 0L, ) { - fun toAlarm() = Alarm(a, b, c, d, e, f, g, h, i) + fun toAlarm() = Alarm(a, b, c, d, e, f, g, h, i, j) }