From 503271c440029129f5c860c888687ea9ac897194 Mon Sep 17 00:00:00 2001 From: Hafiz Date: Mon, 1 Jan 2024 10:33:22 -0500 Subject: [PATCH] Refactor weekly reminder scheduling logic for specific days intervals Refactor weekly reminder scheduling logic to handle specific days and intervals correctly --- .../habitica/helpers/TaskAlarmManager.kt | 3 +- .../android/habitica/models/tasks/Task.kt | 56 +++++++++---------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt index c1ef83615..2da0d9ac0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt @@ -5,6 +5,7 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent import android.os.Build +import android.util.Log import androidx.preference.PreferenceManager import com.habitrpg.android.habitica.data.TaskRepository import com.habitrpg.android.habitica.extensions.withImmutableFlag @@ -128,7 +129,6 @@ class TaskAlarmManager( val now = ZonedDateTime.now().withZoneSameLocal(ZoneId.systemDefault())?.toInstant() val reminderZonedTime = remindersItem.getLocalZonedDateTimeInstant() - if (reminderZonedTime == null || reminderZonedTime.isBefore(now)) { return } @@ -253,6 +253,7 @@ class TaskAlarmManager( // For SDK >= Android 12, allows batching of reminders try { alarmManager?.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pendingIntent) + Log.d("TaskAlarmManager", "setAlarm: Scheduling for $time using setAndAllowWhileIdle") } catch (ex: Exception) { when (ex) { is IllegalStateException, is SecurityException -> { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt index 30fac0383..62f14f928 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt @@ -375,40 +375,38 @@ open class Task : RealmObject, BaseMainObject, Parcelable, BaseTask { dateTimeOccurenceToSchedule } Frequency.WEEKLY -> { + // Set to start date if current date is earlier if (dateTimeOccurenceToSchedule.isBefore(startDate)) { dateTimeOccurenceToSchedule = startDate } else { - // Check if all days are selected - if (repeatDays?.hasAnyDaySelected() == true) { - // Simply increment by one day - dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.plusDays(1) - } else { - // Logic for specific days selected - var nextDueDate = dateTimeOccurenceToSchedule - while (!nextDueDate.matchesRepeatDays(repeatDays)) { - nextDueDate = nextDueDate.plusDays(1) - } - - val weeksSinceStart = ChronoUnit.WEEKS.between(startDate.toLocalDate(), nextDueDate.toLocalDate()) - if (weeksSinceStart % everyX != 0L) { - val weeksToNextValidInterval = everyX - (weeksSinceStart % everyX) - nextDueDate = nextDueDate.plusWeeks(weeksToNextValidInterval) - while (!nextDueDate.matchesRepeatDays(repeatDays)) { - nextDueDate = nextDueDate.plusDays(1) - } - } - - val now = ZonedDateTime.now().withZoneSameInstant(ZoneId.systemDefault()) - if (nextDueDate.isBefore(now)) { - nextDueDate = nextDueDate.plusWeeks(everyX.toLong()) - while (!nextDueDate.matchesRepeatDays(repeatDays)) { - nextDueDate = nextDueDate.plusDays(1) - } - } - - dateTimeOccurenceToSchedule = nextDueDate + var nextDueDate = dateTimeOccurenceToSchedule.withHour(reminderTime.hour).withMinute(reminderTime.minute) + while (!nextDueDate.matchesRepeatDays(repeatDays)) { + nextDueDate = nextDueDate.plusDays(1).withHour(reminderTime.hour).withMinute(reminderTime.minute) } + // Calculate weeks since start and adjust for the correct interval + val weeksSinceStart = ChronoUnit.WEEKS.between(startDate.toLocalDate(), nextDueDate.toLocalDate()) + if (weeksSinceStart % everyX != 0L) { + val weeksToNextValidInterval = everyX - (weeksSinceStart % everyX) + nextDueDate = nextDueDate.plusWeeks(weeksToNextValidInterval) + // Find the exact next due day within the valid interval + while (!nextDueDate.matchesRepeatDays(repeatDays)) { + nextDueDate = nextDueDate.plusDays(1).withHour(reminderTime.hour).withMinute(reminderTime.minute) + } + } + + // Ensure the next due date is in the future + val now = ZonedDateTime.now().withZoneSameInstant(ZoneId.systemDefault()) + if (nextDueDate.isBefore(now)) { + nextDueDate = nextDueDate.plusWeeks(everyX.toLong()) + // Find the next due day in the future + while (!nextDueDate.matchesRepeatDays(repeatDays)) { + nextDueDate = nextDueDate.plusDays(1).withHour(reminderTime.hour).withMinute(reminderTime.minute) + } + } + + dateTimeOccurenceToSchedule = nextDueDate } + // Set time to the reminder time dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.withHour(reminderTime.hour).withMinute(reminderTime.minute) dateTimeOccurenceToSchedule }