Reminders: Ability to explicitly set the date of a reminder and have it handle recurrence based on that date
Some checks failed
CI / test (push) Failing after 6m31s
Lint / test (push) Successful in 35s
Trivy / test (push) Successful in 23s

This commit is contained in:
Miguel Jacq 2025-12-06 10:47:06 +11:00
parent 778d988ebd
commit f5c52eaf3b
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
2 changed files with 39 additions and 25 deletions

View file

@ -2,6 +2,7 @@
* Time reports: Fix report 'group by' logic to not show ambiguous 'note' data. * Time reports: Fix report 'group by' logic to not show ambiguous 'note' data.
* Time reports: Add default option to 'don't group'. This gives every individual time log row (and so the 'note' is shown in this case) * Time reports: Add default option to 'don't group'. This gives every individual time log row (and so the 'note' is shown in this case)
* Reminders: Ability to explicitly set the date of a reminder and have it handle recurrence based on that date
# 0.6.3 # 0.6.3

View file

@ -27,6 +27,7 @@ from PySide6.QtWidgets import (
QAbstractItemView, QAbstractItemView,
QHeaderView, QHeaderView,
QSpinBox, QSpinBox,
QDateEdit,
) )
from . import strings from . import strings
@ -76,6 +77,22 @@ class ReminderDialog(QDialog):
self.text_edit.setText(reminder.text) self.text_edit.setText(reminder.text)
self.form.addRow("&" + strings._("reminder") + ":", self.text_edit) self.form.addRow("&" + strings._("reminder") + ":", self.text_edit)
# Date
self.date_edit = QDateEdit()
self.date_edit.setCalendarPopup(True)
self.date_edit.setDisplayFormat("yyyy-MM-dd")
if reminder and reminder.date_iso:
d = QDate.fromString(reminder.date_iso, "yyyy-MM-dd")
if d.isValid():
self.date_edit.setDate(d)
else:
self.date_edit.setDate(QDate.currentDate())
else:
self.date_edit.setDate(QDate.currentDate())
self.form.addRow("&" + strings._("date") + ":", self.date_edit)
# Time # Time
self.time_edit = QTimeEdit() self.time_edit = QTimeEdit()
self.time_edit.setDisplayFormat("HH:mm") self.time_edit.setDisplayFormat("HH:mm")
@ -126,7 +143,7 @@ class ReminderDialog(QDialog):
if reminder and reminder.weekday is not None: if reminder and reminder.weekday is not None:
self.weekday_combo.setCurrentIndex(reminder.weekday) self.weekday_combo.setCurrentIndex(reminder.weekday)
else: else:
self.weekday_combo.setCurrentIndex(QDate.currentDate().dayOfWeek() - 1) self.weekday_combo.setCurrentIndex(self.date_edit.date().dayOfWeek() - 1)
self.form.addRow("&" + strings._("day") + ":", self.weekday_combo) self.form.addRow("&" + strings._("day") + ":", self.weekday_combo)
day_label = self.form.labelForField(self.weekday_combo) day_label = self.form.labelForField(self.weekday_combo)
@ -187,6 +204,16 @@ class ReminderDialog(QDialog):
self.nth_spin.setVisible(show_nth) self.nth_spin.setVisible(show_nth)
nth_label.setVisible(show_nth) nth_label.setVisible(show_nth)
# For new reminders, when switching to a type that uses a weekday,
# snap the weekday to match the currently selected date.
if reminder_type in (
ReminderType.WEEKLY,
ReminderType.MONTHLY_NTH_WEEKDAY,
) and (self._reminder is None or self._reminder.reminder_type != reminder_type):
dow = self.date_edit.date().dayOfWeek() - 1 # 0..6 (Mon..Sun)
if 0 <= dow < self.weekday_combo.count():
self.weekday_combo.setCurrentIndex(dow)
def get_reminder(self) -> Reminder: def get_reminder(self) -> Reminder:
"""Get the configured reminder.""" """Get the configured reminder."""
reminder_type = self.type_combo.currentData() reminder_type = self.type_combo.currentData()
@ -198,46 +225,32 @@ class ReminderDialog(QDialog):
weekday = self.weekday_combo.currentData() weekday = self.weekday_combo.currentData()
date_iso = None date_iso = None
today = QDate.currentDate() anchor_date = self.date_edit.date()
if reminder_type == ReminderType.ONCE: if reminder_type == ReminderType.ONCE:
# Fire once, today, at the chosen time # Fire once, on the chosen calendar date at the chosen time
date_iso = today.toString("yyyy-MM-dd") date_iso = anchor_date.toString("yyyy-MM-dd")
elif reminder_type == ReminderType.FORTNIGHTLY: elif reminder_type == ReminderType.FORTNIGHTLY:
# Anchor: today. Every 14 days from this date. # Anchor: the chosen calendar date. Every 14 days from this date.
if ( date_iso = anchor_date.toString("yyyy-MM-dd")
self._reminder
and self._reminder.reminder_type == ReminderType.FORTNIGHTLY
and self._reminder.date_iso
):
date_iso = self._reminder.date_iso
else:
date_iso = today.toString("yyyy-MM-dd")
elif reminder_type == ReminderType.MONTHLY_DATE: elif reminder_type == ReminderType.MONTHLY_DATE:
# Anchor: today's calendar date. "Same date each month" # Anchor: the chosen calendar date. "Same date each month"
if ( date_iso = anchor_date.toString("yyyy-MM-dd")
self._reminder
and self._reminder.reminder_type == ReminderType.MONTHLY_DATE
and self._reminder.date_iso
):
date_iso = self._reminder.date_iso
else:
date_iso = today.toString("yyyy-MM-dd")
elif reminder_type == ReminderType.MONTHLY_NTH_WEEKDAY: elif reminder_type == ReminderType.MONTHLY_NTH_WEEKDAY:
# Anchor: the nth weekday for this month (gives us “3rd Monday” etc.) # Anchor: the nth weekday for the chosen month (gives us “3rd Monday” etc.)
weekday = self.weekday_combo.currentData() weekday = self.weekday_combo.currentData()
nth_index = self.nth_spin.value() - 1 # 0-based nth_index = self.nth_spin.value() - 1 # 0-based
first = QDate(today.year(), today.month(), 1) first = QDate(anchor_date.year(), anchor_date.month(), 1)
target_dow = weekday + 1 # Qt: Monday=1 target_dow = weekday + 1 # Qt: Monday=1
offset = (target_dow - first.dayOfWeek() + 7) % 7 offset = (target_dow - first.dayOfWeek() + 7) % 7
anchor = first.addDays(offset + nth_index * 7) anchor = first.addDays(offset + nth_index * 7)
# If nth weekday doesn't exist in this month, fall back to the last such weekday # If nth weekday doesn't exist in this month, fall back to the last such weekday
if anchor.month() != today.month(): if anchor.month() != anchor_date.month():
anchor = anchor.addDays(-7) anchor = anchor.addDays(-7)
date_iso = anchor.toString("yyyy-MM-dd") date_iso = anchor.toString("yyyy-MM-dd")