Skip to content

Commit

Permalink
To-Do reminder not showing fix (#2057)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
Hafizzle and phillipthelen authored Feb 7, 2024
1 parent afd44ab commit 1907d67
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,88 +354,89 @@ 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
val everyX = this.everyX ?: 1
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) {

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)
}
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)
}

// 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

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.MONTHLY -> {
dateTimeOccurenceToSchedule = if (dateTimeOccurenceToSchedule.isBefore(startDate)) {
startDate
} else {
dateTimeOccurenceToSchedule.plusMonths(everyX.toLong()).withDayOfMonth(startDate.dayOfMonth).withHour(reminderTime.hour).withMinute(reminderTime.minute)
}
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
}
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)
}


Expand Down

0 comments on commit 1907d67

Please sign in to comment.