mirror of
https://github.com/FossifyOrg/Clock.git
synced 2026-04-18 13:26:58 -04:00
Merge pull request #147 from FossifyOrg/fix_onetime_alarms
Fix issue with re-enabling alarms for current day
This commit is contained in:
@@ -188,7 +188,7 @@ class AlarmActivity : SimpleActivity() {
|
||||
} else if (config.useSameSnooze) {
|
||||
dismissAlarmAndFinish(config.snoozeTime)
|
||||
} else {
|
||||
alarmController.stopAlarm(alarmId = alarm!!.id, disable = false)
|
||||
alarmController.silenceAlarm()
|
||||
showPickSecondsDialog(
|
||||
curSeconds = config.snoozeTime * MINUTE_SECONDS,
|
||||
isSnoozePicker = true,
|
||||
|
||||
@@ -11,8 +11,9 @@ import org.fossify.commons.helpers.MINUTE_SECONDS
|
||||
class SnoozeReminderActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
alarmController.silenceAlarm()
|
||||
|
||||
val alarmId = intent.getIntExtra(ALARM_ID, -1)
|
||||
alarmController.stopAlarm(alarmId = alarmId, disable = false)
|
||||
showPickSecondsDialog(
|
||||
curSeconds = config.snoozeTime * MINUTE_SECONDS,
|
||||
isSnoozePicker = true,
|
||||
|
||||
@@ -12,11 +12,8 @@ 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.getAlarmSelectedDaysString
|
||||
import org.fossify.clock.extensions.getFormattedTime
|
||||
import org.fossify.clock.extensions.swap
|
||||
import org.fossify.clock.helpers.TOMORROW_BIT
|
||||
import org.fossify.clock.helpers.getCurrentDayMinutes
|
||||
import org.fossify.clock.helpers.updateNonRecurringAlarmDay
|
||||
import org.fossify.clock.interfaces.ToggleAlarmInterface
|
||||
import org.fossify.clock.models.Alarm
|
||||
import org.fossify.clock.models.AlarmEvent
|
||||
@@ -24,7 +21,9 @@ import org.fossify.commons.adapters.MyRecyclerViewAdapter
|
||||
import org.fossify.commons.dialogs.ConfirmationDialog
|
||||
import org.fossify.commons.extensions.applyColorFilter
|
||||
import org.fossify.commons.extensions.beVisibleIf
|
||||
import org.fossify.commons.extensions.toast
|
||||
import org.fossify.commons.extensions.getSelectedDaysString
|
||||
import org.fossify.commons.extensions.move
|
||||
import org.fossify.commons.helpers.EVERY_DAY_BIT
|
||||
import org.fossify.commons.helpers.SORT_BY_CUSTOM
|
||||
import org.fossify.commons.interfaces.ItemMoveCallback
|
||||
import org.fossify.commons.interfaces.ItemTouchHelperContract
|
||||
@@ -152,7 +151,7 @@ class AlarmsAdapter(
|
||||
)
|
||||
alarmTime.setTextColor(textColor)
|
||||
|
||||
alarmDays.text = activity.getAlarmSelectedDaysString(alarm.days)
|
||||
alarmDays.text = getAlarmSelectedDaysString(alarm)
|
||||
alarmDays.setTextColor(textColor)
|
||||
|
||||
alarmLabel.text = alarm.label
|
||||
@@ -185,34 +184,38 @@ class AlarmsAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
alarm.isToday() -> {
|
||||
if (alarm.timeInMinutes <= getCurrentDayMinutes()) {
|
||||
alarm.days = TOMORROW_BIT
|
||||
binding.alarmDays.text =
|
||||
resources.getString(org.fossify.commons.R.string.tomorrow)
|
||||
}
|
||||
activity.dbHelper.updateAlarm(alarm)
|
||||
toggleAlarmInterface.alarmToggled(alarm.id, binding.alarmSwitch.isChecked)
|
||||
}
|
||||
|
||||
alarm.isTomorrow() -> {
|
||||
toggleAlarmInterface.alarmToggled(alarm.id, binding.alarmSwitch.isChecked)
|
||||
}
|
||||
|
||||
// Unreachable zombie branch. Days are always set to a non-zero value.
|
||||
binding.alarmSwitch.isChecked -> {
|
||||
activity.toast(R.string.no_days_selected)
|
||||
binding.alarmSwitch.isChecked = false
|
||||
}
|
||||
|
||||
else -> {
|
||||
updateNonRecurringAlarmDay(alarm)
|
||||
activity.dbHelper.updateAlarm(alarm)
|
||||
binding.alarmDays.text = getAlarmSelectedDaysString(
|
||||
alarm = alarm, isEnabled = binding.alarmSwitch.isChecked
|
||||
)
|
||||
toggleAlarmInterface.alarmToggled(alarm.id, binding.alarmSwitch.isChecked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAlarmSelectedDaysString(
|
||||
alarm: Alarm, isEnabled: Boolean = alarm.isEnabled,
|
||||
): String {
|
||||
if (alarm.isRecurring()) {
|
||||
return if (alarm.days == EVERY_DAY_BIT) {
|
||||
activity.getString(org.fossify.commons.R.string.every_day)
|
||||
} else {
|
||||
// TODO: This does not respect config.firstDayOfWeek
|
||||
activity.getSelectedDaysString(alarm.days)
|
||||
}
|
||||
}
|
||||
|
||||
return when {
|
||||
!isEnabled -> resources.getString(R.string.not_scheduled)
|
||||
alarm.isToday() -> resources.getString(org.fossify.commons.R.string.today)
|
||||
else -> resources.getString(org.fossify.commons.R.string.tomorrow)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRowMoved(fromPosition: Int, toPosition: Int) {
|
||||
alarms.swap(fromPosition, toPosition)
|
||||
alarms.move(fromPosition, toPosition)
|
||||
notifyItemMoved(fromPosition, toPosition)
|
||||
saveAlarmsCustomOrder(alarms)
|
||||
if (activity.config.alarmSort != SORT_BY_CUSTOM) {
|
||||
|
||||
@@ -15,7 +15,6 @@ import org.fossify.clock.extensions.config
|
||||
import org.fossify.clock.extensions.getFormattedDuration
|
||||
import org.fossify.clock.extensions.hideTimerNotification
|
||||
import org.fossify.clock.extensions.secondsToMillis
|
||||
import org.fossify.clock.extensions.swap
|
||||
import org.fossify.clock.models.Timer
|
||||
import org.fossify.clock.models.TimerEvent
|
||||
import org.fossify.clock.models.TimerState.Finished
|
||||
@@ -31,6 +30,7 @@ import org.fossify.commons.extensions.beInvisibleIf
|
||||
import org.fossify.commons.extensions.beVisibleIf
|
||||
import org.fossify.commons.extensions.getColoredDrawableWithColor
|
||||
import org.fossify.commons.extensions.getFormattedDuration
|
||||
import org.fossify.commons.extensions.move
|
||||
import org.fossify.commons.extensions.openNotificationSettings
|
||||
import org.fossify.commons.helpers.SORT_BY_CUSTOM
|
||||
import org.fossify.commons.interfaces.ItemMoveCallback
|
||||
@@ -260,7 +260,7 @@ class TimerAdapter(
|
||||
|
||||
override fun onRowMoved(fromPosition: Int, toPosition: Int) {
|
||||
val timers = currentList.toMutableList()
|
||||
timers.swap(fromPosition, toPosition)
|
||||
timers.move(fromPosition, toPosition)
|
||||
submitList(timers)
|
||||
saveAlarmsCustomOrder(ArrayList(timers))
|
||||
if (simpleActivity.config.timerSort != SORT_BY_CUSTOM) {
|
||||
|
||||
@@ -19,9 +19,8 @@ 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.TODAY_BIT
|
||||
import org.fossify.clock.helpers.TOMORROW_BIT
|
||||
import org.fossify.clock.helpers.getCurrentDayMinutes
|
||||
import org.fossify.clock.helpers.updateNonRecurringAlarmDay
|
||||
import org.fossify.clock.models.Alarm
|
||||
import org.fossify.commons.dialogs.ConfirmationDialog
|
||||
import org.fossify.commons.dialogs.SelectAlarmSoundDialog
|
||||
@@ -178,13 +177,7 @@ class EditAlarmDialog(
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
if (alarm.days <= 0) {
|
||||
alarm.days = if (alarm.timeInMinutes > getCurrentDayMinutes()) {
|
||||
TODAY_BIT
|
||||
} else {
|
||||
TOMORROW_BIT
|
||||
}
|
||||
}
|
||||
updateNonRecurringAlarmDay(alarm)
|
||||
|
||||
alarm.label = binding.editAlarm.value
|
||||
alarm.isEnabled = true
|
||||
|
||||
@@ -66,14 +66,12 @@ import org.fossify.commons.extensions.formatSecondsToTimeString
|
||||
import org.fossify.commons.extensions.getDefaultAlarmSound
|
||||
import org.fossify.commons.extensions.getLaunchIntent
|
||||
import org.fossify.commons.extensions.getProperPrimaryColor
|
||||
import org.fossify.commons.extensions.getSelectedDaysString
|
||||
import org.fossify.commons.extensions.grantReadUriPermission
|
||||
import org.fossify.commons.extensions.notificationManager
|
||||
import org.fossify.commons.extensions.rotateLeft
|
||||
import org.fossify.commons.extensions.showErrorToast
|
||||
import org.fossify.commons.extensions.toInt
|
||||
import org.fossify.commons.extensions.toast
|
||||
import org.fossify.commons.helpers.EVERY_DAY_BIT
|
||||
import org.fossify.commons.helpers.FRIDAY_BIT
|
||||
import org.fossify.commons.helpers.MINUTE_SECONDS
|
||||
import org.fossify.commons.helpers.MONDAY_BIT
|
||||
@@ -562,15 +560,6 @@ fun Context.checkAlarmsWithDeletedSoundUri(uri: String) {
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.getAlarmSelectedDaysString(bitMask: Int): String {
|
||||
return when (bitMask) {
|
||||
TODAY_BIT -> getString(org.fossify.commons.R.string.today)
|
||||
TOMORROW_BIT -> getString(org.fossify.commons.R.string.tomorrow)
|
||||
EVERY_DAY_BIT -> getString(org.fossify.commons.R.string.every_day)
|
||||
else -> getSelectedDaysString(bitMask) // TODO: This does not respect config.firstDayOfWeek
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.rotateWeekdays(days: List<Int>) = days.rotateLeft(config.firstDayOfWeek - 1)
|
||||
|
||||
fun Context.firstDayOrder(bitMask: Int): Int {
|
||||
@@ -608,12 +597,3 @@ fun Context.startAlarmService(alarmId: Int) {
|
||||
showErrorToast(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.stopAlarmService() {
|
||||
try {
|
||||
val serviceIntent = Intent(this, AlarmService::class.java)
|
||||
stopService(serviceIntent)
|
||||
} catch (e: Exception) {
|
||||
showErrorToast(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package org.fossify.clock.extensions
|
||||
|
||||
@Deprecated(
|
||||
message = "Use the `move` extension function from commons",
|
||||
replaceWith = ReplaceWith(
|
||||
expression = "this.move(index1, index2)",
|
||||
imports = ["org.fossify.commons.extensions.move"]
|
||||
)
|
||||
)
|
||||
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
|
||||
this[index1] = this[index2].also {
|
||||
this[index2] = this[index1]
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,18 @@ package org.fossify.clock.helpers
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import org.fossify.clock.extensions.cancelAlarmClock
|
||||
import org.fossify.clock.extensions.dbHelper
|
||||
import org.fossify.clock.extensions.setupAlarmClock
|
||||
import org.fossify.clock.extensions.showRemainingTimeMessage
|
||||
import org.fossify.clock.extensions.startAlarmService
|
||||
import org.fossify.clock.extensions.stopAlarmService
|
||||
import org.fossify.clock.extensions.updateWidgets
|
||||
import org.fossify.clock.models.Alarm
|
||||
import org.fossify.clock.models.AlarmEvent
|
||||
import org.fossify.clock.services.AlarmService
|
||||
import org.fossify.commons.extensions.removeBit
|
||||
import org.fossify.commons.extensions.showErrorToast
|
||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.util.Calendar
|
||||
@@ -26,8 +28,10 @@ class AlarmController(
|
||||
private val bus: EventBus,
|
||||
) {
|
||||
/**
|
||||
* Reschedules all enabled alarms with the exception of one-time alarms that were scheduled
|
||||
* for today (to avoid rescheduling skipped upcoming alarms, yeah).
|
||||
* 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`.
|
||||
* NOTE: The handling of skipped upcoming alarms for today needs refinement.
|
||||
*/
|
||||
fun rescheduleEnabledAlarms() {
|
||||
db.getEnabledAlarms().forEach {
|
||||
@@ -40,7 +44,7 @@ class AlarmController(
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the next occurrence of a repeating alarm based on its repetition rules.
|
||||
* Schedules the next occurrence of the given alarm based on its properties (time, repetition).
|
||||
*
|
||||
* @param alarm The alarm to schedule.
|
||||
* @param showToasts If true, a remaining time toast will be shown for the alarm.
|
||||
@@ -92,8 +96,9 @@ class AlarmController(
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the triggering of an alarm, scheduling the next occurrence and starting the service
|
||||
* for sounding the alarm.
|
||||
* Handles the triggering of an alarm.
|
||||
* If the alarm is repeating, it schedules the next occurrence immediately.
|
||||
* Then, it starts the service for sounding the alarm.
|
||||
*
|
||||
* @param alarmId The ID of the alarm that was triggered.
|
||||
*/
|
||||
@@ -109,26 +114,31 @@ class AlarmController(
|
||||
context.startAlarmService(alarmId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Silences the currently ringing alarm by stopping the alarm service.
|
||||
*/
|
||||
fun silenceAlarm() {
|
||||
stopAlarmService()
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses an alarm that is currently ringing or has just finished ringing.
|
||||
*
|
||||
* - Stops the alarm sound/vibration service ([stopAlarmService]).
|
||||
* - If the alarm is *not* repeating and the `disable` parameter is true, the alarm is
|
||||
* disabled or deleted via [disableOrDeleteOneTimeAlarm].
|
||||
* - If the alarm is *not* repeating, it is cancelled in the system scheduler and then
|
||||
* disabled or deleted via [disableOrDeleteOneTimeAlarm].
|
||||
*
|
||||
* @param alarmId The ID of the alarm to dismiss.
|
||||
* @param disable If true and the alarm is a one-time alarm, it will be disabled or deleted.
|
||||
* This parameter has no effect on repeating alarms.
|
||||
*/
|
||||
fun stopAlarm(alarmId: Int, disable: Boolean = true) {
|
||||
context.stopAlarmService()
|
||||
fun stopAlarm(alarmId: Int) {
|
||||
stopAlarmService()
|
||||
bus.post(AlarmEvent.Stopped(alarmId))
|
||||
|
||||
ensureBackgroundThread {
|
||||
val alarm = db.getAlarmWithId(alarmId)
|
||||
|
||||
// We don't reschedule alarms here.
|
||||
if (alarm != null && !alarm.isRecurring() && disable) {
|
||||
if (alarm != null && !alarm.isRecurring()) {
|
||||
context.cancelAlarmClock(alarm)
|
||||
disableOrDeleteOneTimeAlarm(alarm)
|
||||
}
|
||||
@@ -144,24 +154,22 @@ class AlarmController(
|
||||
* - Schedules the alarm to ring again after [snoozeMinutes] using [setupAlarmClock]
|
||||
* with a calculated future trigger time.
|
||||
*
|
||||
* TODO: This works but it is very rudimentary. Snoozed alarms should be tracked properly.
|
||||
*
|
||||
* @param alarmId The ID of the alarm to snooze.
|
||||
* @param snoozeMinutes The number of minutes from now until the alarm should ring again.
|
||||
*/
|
||||
fun snoozeAlarm(alarmId: Int, snoozeMinutes: Int) {
|
||||
context.stopAlarmService()
|
||||
stopAlarmService()
|
||||
bus.post(AlarmEvent.Stopped(alarmId))
|
||||
|
||||
ensureBackgroundThread {
|
||||
val alarm = db.getAlarmWithId(alarmId)
|
||||
// TODO: This works but it is very rudimentary. Snoozed alarms are not being tracked.
|
||||
if (alarm != null) {
|
||||
context.setupAlarmClock(
|
||||
alarm = alarm,
|
||||
triggerTimeMillis = Calendar.getInstance()
|
||||
.apply { add(Calendar.MINUTE, snoozeMinutes) }
|
||||
.timeInMillis
|
||||
)
|
||||
val triggerTimeMillis = Calendar.getInstance()
|
||||
.apply { add(Calendar.MINUTE, snoozeMinutes) }
|
||||
.timeInMillis
|
||||
|
||||
context.setupAlarmClock(alarm = alarm, triggerTimeMillis = triggerTimeMillis)
|
||||
}
|
||||
|
||||
notifyObservers()
|
||||
@@ -204,6 +212,15 @@ class AlarmController(
|
||||
bus.post(AlarmEvent.Refresh)
|
||||
}
|
||||
|
||||
private fun stopAlarmService() {
|
||||
try {
|
||||
val serviceIntent = Intent(context, AlarmService::class.java)
|
||||
context.stopService(serviceIntent)
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Volatile
|
||||
private var instance: AlarmController? = null
|
||||
|
||||
@@ -287,7 +287,7 @@ fun getTimeOfNextAlarm(alarmTimeInMinutes: Int, days: Int): Calendar? {
|
||||
else -> {
|
||||
val now = Calendar.getInstance()
|
||||
repeat(8) {
|
||||
val currentDay = (nextAlarmTime.get(Calendar.DAY_OF_WEEK) + 5) % 7
|
||||
val currentDay = getDayNumber(nextAlarmTime.get(Calendar.DAY_OF_WEEK))
|
||||
if (days.isBitSet(currentDay) && now < nextAlarmTime) {
|
||||
return nextAlarmTime
|
||||
} else {
|
||||
@@ -298,3 +298,12 @@ fun getTimeOfNextAlarm(alarmTimeInMinutes: Int, days: Int): Calendar? {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateNonRecurringAlarmDay(alarm: Alarm) {
|
||||
if (alarm.isRecurring()) return
|
||||
alarm.days = if (alarm.timeInMinutes > getCurrentDayMinutes()) {
|
||||
TODAY_BIT
|
||||
} else {
|
||||
TOMORROW_BIT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
<string name="no_timers_found">No timers found</string>
|
||||
<string name="add_timer">Add timer</string>
|
||||
<string name="upcoming_alarm">Upcoming alarm</string>
|
||||
<string name="not_scheduled">Not scheduled</string>
|
||||
|
||||
<!-- Timer -->
|
||||
<string name="timers_notification_msg">Timers are running</string>
|
||||
|
||||
Reference in New Issue
Block a user