The agenda widget loaded and sliced its data in the provideGlance preamble
and captured it as a non-reactive local. updateAll() reliably recomposes a
live Glance session but does not reliably re-run that preamble, so a range
change was redrawn against the stale slice (intermittently — only when no
session was alive did it pick up the new range). This is the same platform
limitation the month widget already works around.
Mirror that pattern: load the widest selectable window once, store the range
in per-instance Glance state (AGENDA_RANGE_KEY), read it reactively via
currentState, and slice in the composition. The settings setter writes the
state into each instance and recomposes, so a range change now reflects via
plain recomposition regardless of session lifecycle.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The debounced observer was unreliable: drop(1) plus the ViewModel lifecycle
could swallow a change after re-entering the app, so a single range change
sometimes didn't refresh the widget. Refresh directly from the settings
setters instead (always fires on a real change), serialized through a mutex
so a rapid flip-and-flip-back can't run two updateAll calls at once and
strand the widget on the intermediate value.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refreshing the widget directly from the setter raced when a setting was
flipped and flipped back quickly: two concurrent updateAll calls could
coalesce around a stale read and leave the widget on the intermediate value.
Observe the agenda-widget-range and week-start prefs instead and push a
single debounced updateAll once changes settle, so the widget always
converges to the final value.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The agenda widget only re-read agendaWidgetRange on the next data-change /
midnight / periodic refresh (or re-placement), so a settings change appeared
to do nothing until then. Push an updateAll from the settings setters:
the agenda widget on an agenda-widget-range change, and both widgets on a
week-start change (month weekday header + the agenda widget's "this week").
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Consolidate the separate "range title" and "range button" settings into a
single "Range bar" toggle, now that the header and switcher live on one bar.
On by default.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the session range pill from the bottom-left corner onto the same top
bar as the "Showing all upcoming events for …" header — header on the left,
pill on the right, each still independently toggleable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reword the range header to "Showing all upcoming events for". Replace the
dry empty state ("Nothing scheduled" + subtitle) with a single warmer line
("You're all caught up"), drop the subtitle, and switch the icon to a
coffee cup. The empty title is shared with the agenda widget.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the "Showing all events for <window>" line out of the picker and into
the agenda view as an always-visible header above the list. Add two
settings (Agenda group, both ON by default) to toggle the range header
banner and the bottom-left range pill independently. The picker keeps its
two-list grouping but no longer carries the header.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Group the range options into calendar-aligned (today / this week / this
month) and rolling (next 7 / 30 days / custom) lists. Add a header showing
the concrete span currently in effect — a single date for Today, the month
and year for This month, otherwise a start–end span — so it's clear what
the agenda is showing. The header appears only where a window is supplied
(the agenda pill), not in Settings.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a tonal pill in the agenda's bottom-left corner showing the current
range; tapping it opens the existing AgendaRangePicker as a session-only
override. The override lives in AgendaViewModel (in-memory), so it survives
view switches and rotation but resets to the saved default when the app is
relaunched. The pill fills with the primary container while an override is
active, and a hint in the picker spells out the temporary nature.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the uniform two-per-card grouping for meaningful sections: theme &
colour (2), calendar — default view, week start, time format, hour lines
(4), and agenda (2).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Integrate #3/#5/#6 (week-start, time-format, hour-lines) into the agenda
range branch. SettingsViewModel folds all five view prefs into one combine;
WidgetData keeps the range-based window and adds the resolved is24Hour.
Also, in the same Appearance section:
- regroup the rows into four titled-by-spacing groups (theme & colour /
calendar layout / timeline display / agenda) instead of one long card.
- add an explanatory description line under the title of each agenda-range
picker (PickerDescription).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend AgendaRange with calendar-aligned windows alongside the rolling
ones: ThisWeek runs through the end of the current week (respecting the
week-start preference — a Monday start means everything before next
Monday), ThisMonth through the last day of the current month. dayCount now
takes the anchor day and week-start; the agenda screen and widget resolve
the week-start preference and pass it through. Rolling options relabelled
("Today", "Next 7 days", "Next 30 days") to read distinctly from the new
calendar-aligned ones.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add independent agendaScreenRange and agendaWidgetRange preferences, each a
rolling window: 1 day / 1 week / 1 month / custom 1–365 days (default Month).
Rolling (not calendar-aligned) so the span never degenerates near a period
boundary. The in-app Agenda screen and the agenda widget each read their own
setting, configured via a new AgendaRangePicker with an inline custom-days
editor.
Closes #4 (Codeberg)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>