Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b4ff90c
fix scheduleNextAlarm
Joshix-1 Oct 28, 2024
9250a9a
improve sheduling of alarms
Joshix-1 Oct 28, 2024
91474a4
extract common snoozing logic into function
Joshix-1 Oct 28, 2024
ff6f158
fix setting the hour correctly
Joshix-1 Oct 28, 2024
2f05baf
improve calender handling
Joshix-1 Oct 28, 2024
3819229
remove check
Joshix-1 Oct 29, 2024
47371ed
use getBitForCalendarDay
Joshix-1 Oct 29, 2024
20f7375
remove unused fun
Joshix-1 Oct 29, 2024
e9083ce
use getBitForCalendarDay
Joshix-1 Oct 29, 2024
29a0691
filter out alarms in the past
Joshix-1 Oct 29, 2024
0b90ef1
fix getTimeOfNextAlarm
Joshix-1 Oct 29, 2024
dabeb74
return nullable calendar in getTimeOfNextAlarm
Joshix-1 Oct 29, 2024
7aaf9db
fix code-style stuff
Joshix-1 Nov 9, 2024
dd98a74
Merge remote-tracking branch 'upstream/master'
Joshix-1 Jan 28, 2025
7005396
small changes
Joshix-1 Jan 29, 2025
651afcc
Merge remote-tracking branch 'upstream/master'
Joshix-1 Jan 29, 2025
688d241
Merge branch 'master' into master
naveensingh Mar 7, 2025
cfc7646
Merge branch 'master' into master
naveensingh Mar 7, 2025
a857d79
Merge branch 'master' into master
naveensingh Mar 9, 2025
49763b4
remove weird snoozeAlarm method
Joshix-1 Mar 9, 2025
c1fac35
update Context.setupAlarmClock
Joshix-1 Mar 9, 2025
9b3d5a0
Remove unnecessary overload for `setupAlarmClock()`
naveensingh Mar 9, 2025
f55fb2b
Remove unnecessary recursion and simplify code
naveensingh Mar 9, 2025
a3bc5da
Minor readability improvement
naveensingh Mar 9, 2025
b25ac87
Rename `snoozeTime` back to `snoozeMinutes`
naveensingh Mar 9, 2025
6297777
Avoid showing "0 minutes" as remaining time
naveensingh Mar 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.fossify.commons.helpers.MINUTE_SECONDS
import org.fossify.commons.helpers.SILENT
import org.fossify.commons.helpers.isOreoMr1Plus
import org.fossify.commons.helpers.isOreoPlus
import java.util.Calendar

class ReminderActivity : SimpleActivity() {
companion object {
Expand Down Expand Up @@ -273,23 +274,29 @@ class ReminderActivity : SimpleActivity() {
private fun snoozeAlarm(overrideSnoozeDuration: Int? = null) {
destroyEffects()
if (overrideSnoozeDuration != null) {
setupAlarmClock(alarm!!, overrideSnoozeDuration * MINUTE_SECONDS)
wasAlarmSnoozed = true
finishActivity()
scheduleSnoozedAlarm(overrideSnoozeDuration)
} else if (config.useSameSnooze) {
setupAlarmClock(alarm!!, config.snoozeTime * MINUTE_SECONDS)
wasAlarmSnoozed = true
finishActivity()
scheduleSnoozedAlarm(config.snoozeTime)
} else {
showPickSecondsDialog(config.snoozeTime * MINUTE_SECONDS, true, cancelCallback = { finishActivity() }) {
config.snoozeTime = it / MINUTE_SECONDS
setupAlarmClock(alarm!!, it)
wasAlarmSnoozed = true
finishActivity()
scheduleSnoozedAlarm(config.snoozeTime)
}
}
}

private fun scheduleSnoozedAlarm(snoozeMinutes: Int) {
setupAlarmClock(
alarm = alarm!!,
triggerTimeMillis = Calendar.getInstance()
.apply { add(Calendar.MINUTE, snoozeMinutes) }
.timeInMillis
)

wasAlarmSnoozed = true
finishActivity()
}

private fun finishActivity() {
if (!wasAlarmSnoozed && alarm != null) {
cancelAlarmClock(alarm!!)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.fossify.clock.extensions.setupAlarmClock
import org.fossify.clock.helpers.ALARM_ID
import org.fossify.commons.extensions.showPickSecondsDialog
import org.fossify.commons.helpers.MINUTE_SECONDS
import java.util.Calendar

class SnoozeReminderActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -18,7 +19,12 @@ class SnoozeReminderActivity : AppCompatActivity() {
hideNotification(id)
showPickSecondsDialog(config.snoozeTime * MINUTE_SECONDS, true, cancelCallback = { dialogCancelled() }) {
config.snoozeTime = it / MINUTE_SECONDS
setupAlarmClock(alarm, it)
setupAlarmClock(
alarm = alarm,
triggerTimeMillis = Calendar.getInstance()
.apply { add(Calendar.SECOND, it) }
.timeInMillis
)
finishActivity()
}
}
Expand Down
100 changes: 37 additions & 63 deletions app/src/main/kotlin/org/fossify/clock/extensions/Context.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import android.os.Handler
import android.os.Looper
import android.os.PowerManager
import android.text.SpannableString
import android.text.format.DateFormat
import android.text.style.RelativeSizeSpan
import android.widget.Toast
import androidx.core.app.AlarmManagerCompat
Expand All @@ -36,7 +35,8 @@ import org.fossify.commons.helpers.*
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import kotlin.math.pow
import kotlin.math.ceil
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.minutes

val Context.config: Config get() = Config.newInstance(applicationContext)
Expand Down Expand Up @@ -100,59 +100,44 @@ fun Context.createNewTimer(): Timer {
}

fun Context.scheduleNextAlarm(alarm: Alarm, showToast: Boolean) {
val calendar = Calendar.getInstance()
calendar.firstDayOfWeek = Calendar.MONDAY
val currentTimeInMinutes = getCurrentDayMinutes()
val triggerTimeMillis = getTimeOfNextAlarm(alarm)?.timeInMillis ?: return
setupAlarmClock(alarm = alarm, triggerTimeMillis = triggerTimeMillis)

if (alarm.days == TODAY_BIT) {
val triggerInMinutes = alarm.timeInMinutes - currentTimeInMinutes
setupAlarmClock(alarm, triggerInMinutes * 60 - calendar.get(Calendar.SECOND))

if (showToast) {
showRemainingTimeMessage(triggerInMinutes)
}
} else if (alarm.days == TOMORROW_BIT) {
val triggerInMinutes = alarm.timeInMinutes - currentTimeInMinutes + DAY_MINUTES
setupAlarmClock(alarm, triggerInMinutes * 60 - calendar.get(Calendar.SECOND))
if (showToast) {
val now = Calendar.getInstance()
val triggerInMillis = triggerTimeMillis - now.timeInMillis
showRemainingTimeMessage(triggerInMillis)
}
}

if (showToast) {
showRemainingTimeMessage(triggerInMinutes)
}
fun Context.showRemainingTimeMessage(triggerInMillis: Long) {
val totalSeconds = triggerInMillis.milliseconds.inWholeSeconds.toInt()
val remainingTime = if (totalSeconds >= MINUTE_SECONDS) {
val roundedMinutes = ceil(totalSeconds / MINUTE_SECONDS.toFloat()).toInt()
formatMinutesToTimeString(roundedMinutes)
} else {
for (i in 0..7) {
val currentDay = (calendar.get(Calendar.DAY_OF_WEEK) + 5) % 7
val isCorrectDay = alarm.days and 2.0.pow(currentDay).toInt() != 0
if (isCorrectDay && (alarm.timeInMinutes > currentTimeInMinutes || i > 0)) {
val triggerInMinutes = alarm.timeInMinutes - currentTimeInMinutes + (i * DAY_MINUTES)
setupAlarmClock(alarm, triggerInMinutes * 60 - calendar.get(Calendar.SECOND))

if (showToast) {
showRemainingTimeMessage(triggerInMinutes)
}
break
} else {
calendar.add(Calendar.DAY_OF_MONTH, 1)
}
}
formatSecondsToTimeString(totalSeconds)
}
}

fun Context.showRemainingTimeMessage(totalMinutes: Int) {
val fullString = String.format(getString(org.fossify.commons.R.string.time_remaining), formatMinutesToTimeString(totalMinutes))
toast(fullString, Toast.LENGTH_LONG)
toast(
msg = String.format(
getString(org.fossify.commons.R.string.time_remaining), remainingTime
),
length = Toast.LENGTH_LONG
)
}

fun Context.setupAlarmClock(alarm: Alarm, triggerInSeconds: Int) {
fun Context.setupAlarmClock(alarm: Alarm, triggerTimeMillis: Long) {
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val targetMS = System.currentTimeMillis() + triggerInSeconds * 1000

try {
AlarmManagerCompat.setAlarmClock(alarmManager, targetMS, getOpenAlarmTabIntent(), getAlarmIntent(alarm))
AlarmManagerCompat.setAlarmClock(alarmManager, triggerTimeMillis, getOpenAlarmTabIntent(), getAlarmIntent(alarm))

// show a notification to allow dismissing the alarm 10 minutes before it actually triggers
val dismissalTriggerTime = if (targetMS - System.currentTimeMillis() < 10.minutes.inWholeMilliseconds) {
val dismissalTriggerTime = if (triggerTimeMillis - System.currentTimeMillis() < 10.minutes.inWholeMilliseconds) {
System.currentTimeMillis() + 500
} else {
targetMS - 10.minutes.inWholeMilliseconds
triggerTimeMillis - 10.minutes.inWholeMilliseconds
}
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, 0, dismissalTriggerTime, getEarlyAlarmDismissalIntent(alarm))
} catch (e: Exception) {
Expand Down Expand Up @@ -277,35 +262,26 @@ fun Context.getClosestEnabledAlarmString(callback: (result: String) -> Unit) {
return@getEnabledAlarms
}

val now = Calendar.getInstance()
val nextAlarmList = enabledAlarms
.mapNotNull { getTimeUntilNextAlarm(it.timeInMinutes, it.days) }
.mapNotNull(::getTimeOfNextAlarm)
.filter { it > now }

if (nextAlarmList.isEmpty()) {
callback("")
}

var closestAlarmTime = Int.MAX_VALUE
nextAlarmList.forEach { time ->
if (time < closestAlarmTime) {
closestAlarmTime = time
}
}

if (closestAlarmTime == Int.MAX_VALUE) {
val closestAlarmTime = nextAlarmList.minOrNull()
if (closestAlarmTime == null) {
callback("")
return@getEnabledAlarms
}

val calendar = Calendar.getInstance().apply { firstDayOfWeek = Calendar.MONDAY }
calendar.add(Calendar.MINUTE, closestAlarmTime)
val dayOfWeekIndex = (calendar.get(Calendar.DAY_OF_WEEK) + 5) % 7
val dayOfWeekIndex = (closestAlarmTime.get(Calendar.DAY_OF_WEEK) + 5) % 7
val dayOfWeek = resources.getStringArray(org.fossify.commons.R.array.week_days_short)[dayOfWeekIndex]
val pattern = if (config.use24HourFormat) {
FORMAT_24H
} else {
FORMAT_12H
}

val formattedTime = SimpleDateFormat(pattern, Locale.getDefault()).format(calendar.time)
val formattedTime = SimpleDateFormat(pattern, Locale.getDefault()).format(closestAlarmTime.time)
callback("$dayOfWeek $formattedTime")
}
}
Expand Down Expand Up @@ -359,7 +335,7 @@ fun Context.getTimerNotification(timer: Timer, pendingIntent: PendingIntent, add
if (isOreoPlus()) {
try {
notificationManager.deleteNotificationChannel(channelId)
} catch (e: Exception) {
} catch (_: Exception) {
}

val audioAttributes = AudioAttributes.Builder()
Expand All @@ -385,10 +361,8 @@ fun Context.getTimerNotification(timer: Timer, pendingIntent: PendingIntent, add
}
}

val title = if (timer.label.isEmpty()) {
val title = timer.label.ifEmpty {
getString(R.string.timer)
} else {
timer.label
}

val reminderActivityIntent = getReminderActivityIntent()
Expand Down
72 changes: 40 additions & 32 deletions app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
package org.fossify.clock.helpers

import org.fossify.clock.extensions.isBitSet
import org.fossify.clock.models.Alarm
import org.fossify.clock.models.MyTimeZone
import org.fossify.commons.helpers.*
import org.fossify.commons.helpers.FRIDAY_BIT
import org.fossify.commons.helpers.MONDAY_BIT
import org.fossify.commons.helpers.SATURDAY_BIT
import org.fossify.commons.helpers.SUNDAY_BIT
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.util.Calendar
import java.util.Date
import java.util.TimeZone
Expand Down Expand Up @@ -125,7 +133,13 @@ fun getPassedSeconds(): Int {
return ((calendar.timeInMillis + offset) / 1000).toInt()
}

fun formatTime(showSeconds: Boolean, use24HourFormat: Boolean, hours: Int, minutes: Int, seconds: Int): String {
fun formatTime(
showSeconds: Boolean,
use24HourFormat: Boolean,
hours: Int,
minutes: Int,
seconds: Int,
): String {
val hoursFormat = if (use24HourFormat) "%02d" else "%01d"
var format = "$hoursFormat:%02d"

Expand Down Expand Up @@ -254,39 +268,33 @@ fun getAllTimeZones() = arrayListOf(
MyTimeZone(89, "GMT+13:00 Tongatapu", "Pacific/Tongatapu")
)

fun getTimeUntilNextAlarm(alarmTimeInMinutes: Int, days: Int): Int? {
val calendar = Calendar.getInstance()
calendar.firstDayOfWeek = Calendar.MONDAY
val currentTimeInMinutes = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE)
val currentDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY
fun getTimeOfNextAlarm(alarm: Alarm): Calendar? {
return getTimeOfNextAlarm(alarm.timeInMinutes, alarm.days)
}

var minTimeDifferenceInMinutes = Int.MAX_VALUE
fun getTimeOfNextAlarm(alarmTimeInMinutes: Int, days: Int): Calendar? {
val nextAlarmTime = Calendar.getInstance().apply {
firstDayOfWeek = Calendar.MONDAY // why is this here? seems unnecessary
set(Calendar.HOUR_OF_DAY, alarmTimeInMinutes / 60)
set(Calendar.MINUTE, alarmTimeInMinutes % 60)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}

for (i in 0..6) {
val alarmDayOfWeek = (currentDayOfWeek + i) % 7
if (isAlarmEnabledForDay(alarmDayOfWeek, days)) {
val timeDifferenceInMinutes = getTimeDifferenceInMinutes(currentTimeInMinutes, alarmTimeInMinutes, i)
if (timeDifferenceInMinutes < minTimeDifferenceInMinutes) {
minTimeDifferenceInMinutes = timeDifferenceInMinutes
return when (days) {
TODAY_BIT -> nextAlarmTime // do nothing, alarm is today
TOMORROW_BIT -> nextAlarmTime.apply { add(Calendar.DAY_OF_MONTH, 1) }
else -> {
val now = Calendar.getInstance()
repeat(8) {
val currentDay = (nextAlarmTime.get(Calendar.DAY_OF_WEEK) + 5) % 7
if (days.isBitSet(currentDay) && now < nextAlarmTime) {
return nextAlarmTime
} else {
nextAlarmTime.add(Calendar.DAY_OF_MONTH, 1)
}
}
null
}
}

return if (minTimeDifferenceInMinutes != Int.MAX_VALUE) {
minTimeDifferenceInMinutes
} else {
null
}
}

fun isAlarmEnabledForDay(day: Int, alarmDays: Int) = alarmDays.isBitSet(day)

fun getTimeDifferenceInMinutes(currentTimeInMinutes: Int, alarmTimeInMinutes: Int, daysUntilAlarm: Int): Int {
val minutesInADay = 24 * 60
val minutesUntilAlarm = daysUntilAlarm * minutesInADay + alarmTimeInMinutes
return if (minutesUntilAlarm > currentTimeInMinutes) {
minutesUntilAlarm - currentTimeInMinutes
} else {
minutesInADay - (currentTimeInMinutes - minutesUntilAlarm)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ import org.fossify.clock.extensions.dbHelper
import org.fossify.clock.extensions.hideNotification
import org.fossify.clock.extensions.setupAlarmClock
import org.fossify.clock.helpers.ALARM_ID
import org.fossify.commons.helpers.MINUTE_SECONDS
import java.util.Calendar

class SnoozeService : IntentService("Snooze") {
override fun onHandleIntent(intent: Intent?) {
val id = intent!!.getIntExtra(ALARM_ID, -1)
val alarm = dbHelper.getAlarmWithId(id) ?: return
hideNotification(id)
setupAlarmClock(alarm, config.snoozeTime * MINUTE_SECONDS)
setupAlarmClock(
alarm = alarm,
triggerTimeMillis = Calendar.getInstance()
.apply { add(Calendar.MINUTE, config.snoozeTime) }
.timeInMillis
)
}
}
Loading