Reminders can count from a task's start as well as its due date (#72), and each reminder on an all-day task can have its own time (#78). ## Changes - A reminder counts from the start or the due date. Tasks with only a start date get reminders. Defaults in Settings can mix both, globally and per list. - Each reminder on an all-day task can have its own time of day. Reminders without one ring at the all-day time set in Settings. 00:00 can't be stored, so it becomes 00:01. - The editor shows the defaults a new task, or a newly added date, will get, and keeps them in step with dates, list and all-day until you change a reminder. What it shows is what gets saved. Removing the shown defaults now leaves the task without a reminder (Room store only; OpenTasks mode still falls back to the default). - Switching between timed and all-day converts the reminders right away in the editor. Switching straight back restores them. - Labels name the date when a task has both: "15 minutes before the start", "On the due date at 09:00". New reminders preselect the start. - Defaults that have already passed don't ring when the task is saved. - Sync: reminders rounded to whole days by builds before 1.2 pick up their real time of day on the next download. ## Deviations from the issues - The start/due anchor lives in floret-kit (`ReminderLead`, floret-kit#19) rather than being packed into minute values. That PR is additive, so Calendula is unaffected. - `error_reminder_without_due` was renamed to `error_reminder_without_date`, and the "(before start)/(before due)" strings were replaced by full sentences. The stale keys were deleted from the translation files so lint passes, and Weblate needs to offer the new strings to translators. - The dead single-reminder API (`setAlarm`, `alarms()`, `editable()`, `reminderFor`) was removed. - `AlarmLift` is back to its frozen 2→3 migration state. ## Release branch `release/v1.2.0` is merged into this branch. Through it, this PR also brings main's commits the release branch was missing, including the reminder sync from #81 that this work builds on. I resolved conflicts in the data source interface, `TaskAlarmDao`, CHANGELOG, PRIVACY.md and the floret-kit pointer by keeping both sides. Closes #72 Closes #78 Co-authored-by: Weblate <noreply-mt-weblate@weblate.org> Co-authored-by: Sup99999 <alelmnour1o234@proton.me> Co-authored-by: Robin Schanbacher <robin@schanbros.de> Co-authored-by: Knee8811 <mk-weby@protonmail.com> Co-authored-by: Sonja Kraus <klein.felix@pm.me> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de> Reviewed-on: https://codeberg.org/jlmakiola/agendula/pulls/88
3.8 KiB
3.8 KiB
VTODO fixture corpus
The mapper's specification, not its regression net. Every file here is a shape that was found in the wild and that a plausible implementation gets wrong. A clean, server-generated VTODO catches nothing and is deliberately absent.
RoundTripTest asserts every fixture survives parse → map → write → serialise
with no property lost, compared as a canonical multiset modulo an allowlist
(PRODID, DTSTAMP, LAST-MODIFIED, SEQUENCE,
VTIMEZONE bodies, fold positions, parameter quoting).
| File | What it is for |
|---|---|
nextcloud-shared-confidential.ics |
A CLASS:CONFIDENTIAL task as Nextcloud rewrites it on GET from a shared calendar — DUE, STATUS, COMPLETED, PERCENT-COMPLETE, PRIORITY and RELATED-TO already stripped, ETag left untouched. Re-PUTting this destroys the owner's task |
recurring-master-overrides.ics |
Master plus two RECURRENCE-ID overrides in one resource, sharing a UID |
valarm-unknown-nested.ics |
Unknown properties inside a VALARM — the case a flat property-per-row model cannot represent. An Apple default alarm, so it stays in the residue |
valarm-claimed-apple.ics |
The same Apple alarm without X-APPLE-DEFAULT-ALARM, so it is claimed as a reminder: RELATED=START on a task with only DUE (Apple's non-conformant shape) reads as a before-due lead, and the original must come back verbatim through the row's raw |
unknown-component.ics |
An entirely unknown sub-component |
unknown-tzid.ics |
A TZID no device tzdb knows, with its own VTIMEZONE |
uid-special-chars.ics |
A UID containing / and @ — the href sanitiser must not assume it is filename-safe |
rrule-due-no-dtstart.ics |
RRULE + DUE and no DTSTART: no well-defined RECURRENCE-ID, undefined in RFC 5545, ubiquitous in the wild |
moz-alarm-props.ics |
X-MOZ-LASTACK / X-MOZ-SNOOZE-TIME. Dropping them causes documented Thunderbird alarm storms |
apple-sort-order.ics |
X-APPLE-SORT-ORDER — preserve, never interpret |
floating-time.ics |
DTSTART with neither Z nor TZID. Readable, not reproducible: it must round-trip from the residue, not be rewritten as a guess |
completion-model-a.ics |
Completion as a RECURRENCE-ID override, master stays open — jtx Board, Thunderbird. The model we write |
completion-model-b.ics |
Master's DUE advanced in place, completion cleared — tasks.org, Evolution, Nextcloud in practice |
completion-model-c.ics |
STATUS:COMPLETED on the master, killing the series — Nextcloud Tasks ≤ 0.17. Always a bug; we read it, we never write it |
completion-model-d.ics |
The completed occurrence detached as a new task with a new UID — OpenTasks |
quoted-param-colon.ics |
A quoted parameter value containing a colon and a comma. The value separator is the first colon outside quotes |
mixed-value-types.ics |
DTSTART;VALUE=DATE with a timed DUE. One is_all_day flag cannot author both, so the odd one out must stay in the residue rather than be flattened to a date |
malformed-scalars.ics |
PRIORITY:11, PERCENT-COMPLETE:150, SEQUENCE:x, STATUS:X-DEFERRED, CLASS:X-INTERNAL — values no spec allows. Clamping or defaulting any of them is a silent rewrite of somebody's data |
two-timezones.ics |
DTSTART and DUE in different zones. One timezone column cannot author both |
folded-utf8.ics |
A line folded mid-emoji-adjacent, to prove folding counts octets and splits on character boundaries |
categories-shapes.ics |
One CATEGORIES line with an escaped comma inside a value — the one shape the column claims, so it is re-authored and must come out identical |
categories-split.ics |
One line per tag, a LANGUAGE parameter and a space after a comma. Read for display, but none of it is ours to rewrite |