To-Do reminder not showing fix (#2057)

* Reminder logic updates

Check for upcoming reminder and/or if reminder is happening today.
Also - error on the side of showing a reminder

* Error on the side of showing reminder (Even if reminder time passed)

* Schedule reminders logic updates

* Fixes for reminders (Week & Year)

* Remove unused extensions

* Refactor weekly reminder scheduling logic for specific days intervals

Refactor weekly reminder scheduling logic to handle specific days and intervals correctly

* Remove alarms/reminders on task deletion

* Handle weekly same day reminder that already passed

* Handle if no days are selected for a weekly

* To-Do reminder not showing fix

Schedule single reminder instance occurrence for todo, and check if reminder is from todo when actually setting the reminder (To avoid scheduling returning early due to checking Daily reminder fields)

---------

Co-authored-by: Phillip Thelen <phillip@habitica.com>
This commit is contained in:
Fiz 2024-02-07 12:34:04 -05:00 committed by GitHub
parent afd44ab814
commit 1907d675ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 68 additions and 63 deletions

View file

@ -59,9 +59,13 @@ class TaskAlarmManager(
*/
private fun setAlarmsForTask(task: Task) {
CoroutineScope(Dispatchers.IO).launch {
val reminderOccurencesToSchedule = if (task.type == TaskType.TODO) { 1 } else {
// For dailies, we schedule multiple reminders in advance
upcomingReminderOccurrencesToSchedule
}
task.reminders?.let { reminders ->
for (reminder in reminders) {
val upcomingReminders = task.getNextReminderOccurrences(reminder, upcomingReminderOccurrencesToSchedule)
val upcomingReminders = task.getNextReminderOccurrences(reminder, reminderOccurencesToSchedule)
upcomingReminders?.forEachIndexed { index, reminderNextOccurrenceTime ->
reminder?.time = reminderNextOccurrenceTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
setAlarmForRemindersItem(task, reminder, index)

View file

@ -354,6 +354,14 @@ open class Task : RealmObject, BaseMainObject, Parcelable, BaseTask {
if (remindersItem == null) return null
val reminderTime = remindersItem.time?.parseToZonedDateTime() ?: return null
var dateTimeOccurenceToSchedule = ZonedDateTime.now().withZoneSameInstant(ZoneId.systemDefault())
val occurrencesList = mutableListOf<ZonedDateTime>()
// If the reminder is a todo, only schedule sole dueDate/time occurrence. Otherwise, schedule multiple occurrences in advance
if (this.type == TaskType.TODO) {
occurrencesList.add(this.dueDate?.toZonedDateTime()?.withHour(reminderTime.hour)?.withMinute(reminderTime.minute) ?: return null)
return occurrencesList
}
val now = ZonedDateTime.now().withZoneSameInstant(ZoneId.systemDefault())
var startDate = this.startDate?.toInstant()?.atZone(ZoneId.systemDefault()) ?: return null
val frequency = this.frequency ?: return null
@ -361,81 +369,74 @@ open class Task : RealmObject, BaseMainObject, Parcelable, BaseTask {
val repeatDays = this.repeat
startDate = startDate.withHour(reminderTime.hour).withMinute(reminderTime.minute)
var dateTimeOccurenceToSchedule = ZonedDateTime.now().withZoneSameInstant(ZoneId.systemDefault())
val occurrencesList = mutableListOf<ZonedDateTime>()
while (occurrencesList.size < occurrences) {
// Increment currentDate based on the frequency
try {
dateTimeOccurenceToSchedule = when (frequency) {
Frequency.DAILY -> {
dateTimeOccurenceToSchedule = if (dateTimeOccurenceToSchedule.isBefore(startDate)) {
startDate
} else {
dateTimeOccurenceToSchedule.plusDays(everyX.toLong()).withHour(reminderTime.hour).withMinute(reminderTime.minute)
}
dateTimeOccurenceToSchedule
dateTimeOccurenceToSchedule = when (frequency) {
Frequency.DAILY -> {
dateTimeOccurenceToSchedule = if (dateTimeOccurenceToSchedule.isBefore(startDate)) {
startDate
} else {
dateTimeOccurenceToSchedule.plusDays(everyX.toLong()).withHour(reminderTime.hour).withMinute(reminderTime.minute)
}
Frequency.WEEKLY -> {
// Set to start date if current date is earlier
if (dateTimeOccurenceToSchedule.isBefore(startDate)) {
dateTimeOccurenceToSchedule = startDate
} else if (repeatDays?.hasAnyDaySelected() == true) {
dateTimeOccurenceToSchedule
}
Frequency.WEEKLY -> {
// Set to start date if current date is earlier
if (dateTimeOccurenceToSchedule.isBefore(startDate)) {
dateTimeOccurenceToSchedule = startDate
} else if (repeatDays?.hasAnyDaySelected() == true) {
var nextDueDate = dateTimeOccurenceToSchedule.withHour(reminderTime.hour).withMinute(reminderTime.minute)
// If the next due date already happened for today, increment it by one day. Otherwise, it will be scheduled for today.
if (nextDueDate.isBefore(now) && occurrencesList.size == 0) {
nextDueDate = nextDueDate.plusDays(1)
}
var nextDueDate = dateTimeOccurenceToSchedule.withHour(reminderTime.hour).withMinute(reminderTime.minute)
// If the next due date already happened for today, increment it by one day. Otherwise, it will be scheduled for today.
if (nextDueDate.isBefore(now) && occurrencesList.size == 0) {
nextDueDate = nextDueDate.plusDays(1)
}
// If the reminder being scheduled is not the first iteration of the reminder, increment it by one day
if (occurrencesList.size > 0) {
nextDueDate = nextDueDate.plusDays(1)
}
// If the reminder being scheduled is not the first iteration of the reminder, increment it by one day
if (occurrencesList.size > 0) {
nextDueDate = nextDueDate.plusDays(1)
}
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)
}
// Calculate weeks since start and adjust for the correct interval
val weeksSinceStart = ChronoUnit.WEEKS.between(startDate.toLocalDate(), nextDueDate.toLocalDate())
if (everyX > 0 && 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)
}
}
}
dateTimeOccurenceToSchedule = nextDueDate
}
// Set time to the reminder time
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.withHour(reminderTime.hour).withMinute(reminderTime.minute)
dateTimeOccurenceToSchedule
}
Frequency.MONTHLY -> {
dateTimeOccurenceToSchedule = if (dateTimeOccurenceToSchedule.isBefore(startDate)) {
startDate
} else {
dateTimeOccurenceToSchedule.plusMonths(everyX.toLong()).withDayOfMonth(startDate.dayOfMonth).withHour(reminderTime.hour).withMinute(reminderTime.minute)
}
dateTimeOccurenceToSchedule
}
Frequency.YEARLY -> {
dateTimeOccurenceToSchedule = if (dateTimeOccurenceToSchedule.isBefore(startDate)) {
startDate
} else {
dateTimeOccurenceToSchedule.plusYears(everyX.toLong()).withDayOfMonth(startDate.dayOfMonth).withMonth(startDate.monthValue).withHour(reminderTime.hour).withMinute(reminderTime.minute)
}
dateTimeOccurenceToSchedule
dateTimeOccurenceToSchedule = nextDueDate
}
// Set time to the reminder time
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.withHour(reminderTime.hour).withMinute(reminderTime.minute)
dateTimeOccurenceToSchedule
}
Frequency.MONTHLY -> {
dateTimeOccurenceToSchedule = if (dateTimeOccurenceToSchedule.isBefore(startDate)) {
startDate
} else {
dateTimeOccurenceToSchedule.plusMonths(everyX.toLong()).withDayOfMonth(startDate.dayOfMonth).withHour(reminderTime.hour).withMinute(reminderTime.minute)
}
dateTimeOccurenceToSchedule
}
Frequency.YEARLY -> {
dateTimeOccurenceToSchedule = if (dateTimeOccurenceToSchedule.isBefore(startDate)) {
startDate
} else {
dateTimeOccurenceToSchedule.plusYears(everyX.toLong()).withDayOfMonth(startDate.dayOfMonth).withMonth(startDate.monthValue).withHour(reminderTime.hour).withMinute(reminderTime.minute)
}
dateTimeOccurenceToSchedule
}
occurrencesList.add(dateTimeOccurenceToSchedule)
} catch (_: DateTimeException) {
// Invalid date like feb 30th
}
occurrencesList.add(dateTimeOccurenceToSchedule)
}