Short events near midnight keep their minimum height flush against midnight and get their own lane, and the timeline scrolls far enough past midnight to clear the + button.
New Start times switch under Settings → Views → Month, and the time on a month chip now only shows when the whole title or its first 12 characters still fit beside it.
Combines #470 and #471 into one PR.
## Midnight-to-midnight events (#296)
A timed event that starts and ends on local midnight now displays as an all-day event:
- Day/week: in the all-day strip instead of the time grid.
- Month and month widget: a bar with no start time.
- Agenda and agenda widget: "All day".
- Sorting: with the all-day events.
- Countdown widget: skipped in next-event mode like other all-day events, with the all-day label when pinned.
- Reminder notification: the text names the day(s) instead of 00:00 – 00:00.
The event itself stays timed. The detail sheet still shows 00:00 – 00:00, and reminders still fire at their own lead time before 00:00, since that is what the stored reminder says. Midnight is checked in the device zone, so a feed event stored as 22:00Z only counts as whole-day at UTC+2. Search results are left as they are.
Dragging or resizing a block in the timeline so it lands exactly on midnight to midnight moves it to the all-day strip. The floating copy and the selection are dropped right away. Display priority is now computed once per event, not on every sort comparison.
## Event status (#388)
The calendar views now use the event's own status (Events.STATUS), not just your reply to an invite:
- Cancelled events are struck through and sorted last, the same as declined invites. This applies to day/week, month, agenda, search and the widgets. The countdown widget skips them in both modes, and the week-strip widget leaves them out of its count and dots.
- Tentative events get the outline used for unanswered invites (in-app grids). An event that is both cancelled and an open invite is struck through, not outlined.
- Cancelled standalone events and cancelled series are no longer hidden. Cancelled exception rows (a single occurrence deleted from a series) are still filtered out, matched by ORIGINAL_ID or ORIGINAL_SYNC_ID.
- The editor has a new optional Status field after Availability, built on floret-kit's new `SegmentedChoiceCard` (Availability uses it too). A new event writes STATUS only when it isn't Confirmed, an edit writes it only when it changed.
- `isDeclined` was renamed to `isCrossedOut`, and a new `isOutlined` covers both cases.
Deviations from the issue:
- The editor offers Confirmed and Tentative only. Cancelled is offered only for an event that's already cancelled, so it can be put back. Google treats a cancelled event as deleted, so letting people pick it would silently delete Google events.
- A cancelled series can't be edited or moved one occurrence at a time. "Only this event" is left out of the scope prompts, because Android saves a cancelled single occurrence as a deleted one. A drag that could only move the single occurrence is refused.
- The widgets don't draw outlines for unanswered invites either, so tentative events look filled there.
Depends on jlmakiola/floret-kit#27. The submodule is pinned to its branch, so that PR has to land on floret-kit main and the pin has to be moved before release.
Closes#296Closes#388
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/472
With no day selected, the split agenda always added its start day, so in any month other than the current one an empty 1st showed a "Nothing scheduled" block above the first events.
The list now only holds days with events. A free today is kept only when the Agenda view's "show today" setting is on, using the same helper as the Agenda view. A month with nothing in it shows a single "Nothing scheduled this month" row instead of a date header ("Nothing else scheduled this month" for the rest of the current one); these are two new strings. A fixed first item keeps a newly added earlier day in view instead of above the scroll position.
Closes#142
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/469
Switching back to month view after going before 1 Jan 1900 in day or week view crashed with `IndexOutOfBoundsException: index: -1, size: 12`. Each view had its own range: the month grid and the date picker covered 1900–2100, while the week and day pagers reached roughly 1808–2191. The month view took the date it was handed without checking it.
- A new `CalendarSpan` (1 Jan 1600 – 31 Dec 2399) is used by the month and dense-week grids, the week, multi-day and day pagers, and the date picker's `yearRange`. No view can hand another a date it can't show, and you can now go past 2100 and before 1900 everywhere.
- Every write to the month view's current month goes through one clamp, and `yearMonthForIndex` can't throw on any index. This is a safety net for dates arriving from outside, such as another app opening Calendula via the time intent.
- Tapping a greyed-out day past either end of the grid is ignored.
The timeline pagers now number pages from the span's first day rather than around a fixed middle page, so page numbers change once. `PageNumberingTest` pins the new numbering.
Closes#457
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/466
A month page could stop updating for good. `PageStateCache` cancelled a month's query when the requested month moved far enough away, but the pager keeps pages composed further out than that window. Even a small drag that snaps back loads two months ahead (it prefetches), so the neighbouring month was dropped while still on screen. That page then never showed new or edited events until you swiped two months away and back.
This explains both reports. In split mode the day pane reads from the same stale page, and opening an event from it handed the editor the old start and end times.
`PageStateCache` now runs a page's query only while something collects it, stops it 5 s after the last collector leaves, and starts it again when it's collected again. Letting an entry go only removes it from the cache; it never stops a state a page still holds. A dropped entry nobody collects holds no coroutine. Week and day views use the same cache and get the same behaviour.
Widening the month window was tried first and wasn't enough, since how far the pager composes depends on drag and prefetch.
Closes#440Closes#454
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/467
An event with several reminders posted a separate notification for each one. Each occurrence now has one notification, and every later reminder replaces the earlier one in place.
- The notification tag and the snooze alarm are keyed on the occurrence. Snooze, dismiss and open actions stay per reminder, so tapping them on an outdated notification can't remove the newer one.
- A different reminder alerts again; the same reminder posted twice stays silent.
- If several reminders of one occurrence are due in the same scan (e.g. after the phone was off), only the latest is posted.
- A newly due reminder cancels a pending snooze for its occurrence, and a snoozed reminder doesn't re-show over a newer one.
- Notifications posted before this change still dismiss and snooze, and a newer reminder for the same event replaces them.
- Reminder and occurrence keys share one hash in `ReminderPlan`.
Closes#463
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/468
Follow-up to the #142 feedback in the split month view:
- With a day selected, the filter chip now stands in for the day's header, so the date isn't shown twice. Tapping the chip opens the Day view; its ✕ clears the filter.
- The day headers in the agenda pane below the grid use less vertical space.
- Event dots no longer drop on days that show a "+N".
Closes#142
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/453
Feedback on 2.24.0-beta.1 from #90, #376 and #71. floret-kit is pinned to its main after floret-kit#24, which carries the shared parts.
- Transparent background: switching to or from it now shows right away on Date, Countdown, Week strip, Quick add, Upcoming and Today (and the Month and day grid). Their backings always set a fill, so a reapplied rendering can't keep the old one.
- App language: changing it in Settings redraws every widget, which now render in the app language. Below Android 13 the choice is mirrored for the widget process, since AppCompat only applies it inside an activity.
- Picker previews: Countdown and Week strip previews inflate on Android 14 and below (they used View/Space, which RemoteViews refuses).
- Month widget: days outside the month take a 40% lighter shade, in the widget and its XML preview.
- Add button: the filled header action is 44dp instead of 36dp wide (floret-kit).
- Tinted background: the tonal header and weekday pills had the same tone as the fill and disappeared; they now use inversePrimary there (floret-kit). Not in the issues, found while testing.
- Dimmed past events (Month and day, Today, Agenda): the fill fades to 30% and the text to 65% instead of both to 40%, so the title stays readable.
- Widget picker: names drop the Calendula prefix, and each widget gets its own description instead of repeating its name (#71).
The config screen stalling until touched (#90, item 2) is not addressed: it didn't reproduce on an Android 12 emulator.
Closes#376Closes#71
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/449
Glance's 499 view ids forced busy months down to one or two lanes. The week rows are now one embedded RemoteViews tree, so every event that fits the height gets its bar and only the rest folds into +N. The on-device test now checks the payload instead of the view count.
Drops the agenda refresh button (redraws are automatic since #420). Caps the config preview at Glance's 10-row Column limit, which made it fail with busy agendas (#292).
Stable 2.23.0 after four betas. It adds long-press select, move, resize and drafting in the timeline, tap-to-call phone numbers, formatted HTML descriptions, scrolling back in the agenda, events from shared text, the option to open the editor on tap, the black theme, Liberapay and more haptics. It also fixes the daylight saving and recurring-move bugs. CHANGELOG.md has the full list, and every store locale has its own What's New.
I merged main into the release branch to pick up Liberapay (#430) and Weblate #421. The Czech and Japanese string conflicts were lines added at the end of each file on both sides, so I kept main's.
Closes#116, closes#141, closes#153, closes#178, closes#181, closes#271, closes#306, closes#339, closes#367, closes#387, closes#413
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Co-authored-by: Tritra002 <tritratrulala002@outlook.com>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/433
Adds Liberapay as a second donation option next to Ko-fi.
- Settings: "Support development" now opens a full-screen picker with Ko-fi (one-off tips) and Liberapay (recurring donations) instead of linking straight to Ko-fi.
- README: Liberapay badge next to the Ko-fi badge, plus a short Support section.
No issue for this one.
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/430