fix(edit): recurrence picker review fixes + picker unification (#42) #89

Merged
makiolaj merged 6 commits from feat/recurrence-exdate into release/v2.16.0 2026-07-20 13:29:16 +00:00
Owner

Follow-up to the custom recurrence picker redesign (#42): the review fixes, plus the family inconsistencies the review surfaced.

⚠️ Depends on floret-kit!2 — the submodule pointer currently targets that PR's branch commit. Re-point it at main once floret-kit!2 merges, before merging this.

Bug fixes

  • UNTIL showed the day after the one picked, west of UTC. toRRule deliberately writes the end of the chosen local day expressed in UTC (the provider applies UNTIL coarsely), so the read side has to convert back before taking the date. Also fixes the detail screen, which had this silently before this branch.
  • The live read-out could describe a rule different from the one OK would save — it rebuilt a parallel rule with interval ?: 1 / end ?: Never fallbacks. It now renders customResult itself, so the two cannot diverge.
  • Blank amount fields counted as errors, greying out OK with no cause. They now read as their visible placeholder (1 / 10). Backing out of the date picker no longer strands a dateless "on a date". Only a literal 0 is invalid, and it now says why.
  • remember() was called conditionally inside untilDate?.let — a slot that appears and disappears breaks positional memoisation. Hoisted.
  • Count card corners were 20dp against the rows' 22dp — a local groupedShape copy had drifted from GroupedSurface. Now delegates to the kit.
  • Cards moved onto GroupedSurface; segmented row drops its icon slot so longer unit labels fit; read-out reserves two lines so the stack stops shifting as you tap weekdays.

Refactors

  • SettingsPrefs.firstDayOfWeek(scope) replaces three copies in the Month / Agenda / EventEdit view models that had drifted onto different initialValues.
  • SelectedCheck: five app copies deleted against the kit's now-public primitive.

Unification (reaches beyond this branch)

  • The recurrence picker was the only full-screen picker whose selected row carried no check. Added to all six rows.
  • Its two AnimatedVisibility blocks were the only ones in the app not using expandEnter()/collapseExit(). Those honour rememberReduceMotion(), so the weekday and count cards were ignoring the system "remove animations" setting — an accessibility regression, now fixed.

Verification

testDebugUnitTest + lintDebug green; 7 new tests cover the UNTIL conversion across zones east/west of UTC. Installed on device — on-device visual review still owed.

Worth a look specifically: the ends-group corners; German at 360dp (whether "Monate" still ellipsises — the one thing I could not verify statically); the six new checks; the Filled→Rounded glyph change across the five other pickers; reduce-motion behaviour; and the attendee/reminder cards, which also went 20dp→22dp via the shared shape helper.

Follow-up

event_edit_recurrence_incomplete is English-only and needs the Weblate backfill.

🤖 Generated with Claude Code

Follow-up to the custom recurrence picker redesign (#42): the review fixes, plus the family inconsistencies the review surfaced. ⚠️ **Depends on [floret-kit!2](https://gitea.jeanlucmakiola.de/makiolaj/floret-kit/pulls/2)** — the submodule pointer currently targets that PR's branch commit. Re-point it at `main` once floret-kit!2 merges, before merging this. ## Bug fixes - **UNTIL showed the day after the one picked, west of UTC.** `toRRule` deliberately writes the end of the chosen *local* day expressed in UTC (the provider applies UNTIL coarsely), so the read side has to convert back before taking the date. Also fixes the detail screen, which had this silently before this branch. - **The live read-out could describe a rule different from the one OK would save** — it rebuilt a parallel rule with `interval ?: 1` / `end ?: Never` fallbacks. It now renders `customResult` itself, so the two cannot diverge. - **Blank amount fields counted as errors**, greying out OK with no cause. They now read as their visible placeholder (1 / 10). Backing out of the date picker no longer strands a dateless "on a date". Only a literal `0` is invalid, and it now says why. - **`remember()` was called conditionally** inside `untilDate?.let` — a slot that appears and disappears breaks positional memoisation. Hoisted. - **Count card corners were 20dp against the rows' 22dp** — a local `groupedShape` copy had drifted from `GroupedSurface`. Now delegates to the kit. - Cards moved onto `GroupedSurface`; segmented row drops its icon slot so longer unit labels fit; read-out reserves two lines so the stack stops shifting as you tap weekdays. ## Refactors - `SettingsPrefs.firstDayOfWeek(scope)` replaces three copies in the Month / Agenda / EventEdit view models that had drifted onto different `initialValue`s. - `SelectedCheck`: five app copies deleted against the kit's now-public primitive. ## Unification (reaches beyond this branch) - The recurrence picker was the only full-screen picker whose selected row carried no check. Added to all six rows. - **Its two `AnimatedVisibility` blocks were the only ones in the app not using `expandEnter()`/`collapseExit()`.** Those honour `rememberReduceMotion()`, so the weekday and count cards were ignoring the system "remove animations" setting — an accessibility regression, now fixed. ## Verification `testDebugUnitTest` + `lintDebug` green; 7 new tests cover the UNTIL conversion across zones east/west of UTC. Installed on device — **on-device visual review still owed.** Worth a look specifically: the ends-group corners; German at 360dp (whether "Monate" still ellipsises — the one thing I could not verify statically); the six new checks; the Filled→Rounded glyph change across the five other pickers; reduce-motion behaviour; and the attendee/reminder cards, which also went 20dp→22dp via the shared shape helper. ## Follow-up `event_edit_recurrence_incomplete` is English-only and needs the Weblate backfill. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
makiolaj added 4 commits 2026-07-20 13:21:20 +00:00
Rebuild the custom step of the recurrence picker so complex-but-supported
rules (e.g. "every 2 weeks on Mon+Tue") are discoverable and legible,
rather than buried in a ragged stack of mismatched controls.

- Add a live, human-readable summary of the rule as it is built, via the
  existing recurrenceText humanizer.
- Group interval + frequency into one tonal card; the frequency is now a
  SingleChoiceSegmentedButtonRow (all four units visible) instead of a
  dropdown.
- Reveal the weekday picks with AnimatedVisibility and house them, the
  "every" controls, and the ends group in consistent 16dp-inset grouped
  cards; the count field folds into the bottom of the ends run.

No behaviour, domain, or RRULE changes: parse/render logic and the set of
expressible rules are unchanged. The EXDATE half of #42 is deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- The weekday toggles now order by the app's "Week starts on" setting
  (via WeekStartPref.resolveFirstDay), matching the month/week/agenda
  views, instead of always following the device locale. Threaded through
  a new EventEditViewModel.firstDayOfWeek flow.
- Carry the 16dp section gaps on each block rather than a parent
  spacedBy, so the weekday card's gap collapses together with the card
  under AnimatedVisibility — removing the end-of-animation jump in the
  ends section when switching away from Weekly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review follow-ups to the picker redesign, plus the bugs it exposed.

The live read-out now renders customResult itself — the exact string OK
would save — instead of rebuilding a parallel rule with `interval ?: 1`
and `end ?: Never` fallbacks, which let it confidently describe a rule
that differed from the selected controls whenever a field was invalid.

Shrink the invalid space behind it: a blank amount field reads as its
visible placeholder (1 / 10) rather than as an error, and backing out of
the date picker falls back to "never" instead of stranding a dateless
"on a date". Only an out-of-range 0 remains invalid, and that now says so
rather than greying out OK with no cause.

UNTIL displayed the day after the one picked for zones behind UTC:
toRRule deliberately writes the end of the chosen *local* day expressed
in UTC (the provider applies UNTIL coarsely), so the read side must
convert back before taking the date. Fixes the detail screen too, and
untilLocalDate is extracted so it can be tested.

Also: hoist a remember() out of a conditional (a slot that appears and
disappears breaks positional memoisation), match GroupedSurface's 22dp
corners instead of a drifted local 20dp copy, move the cards onto
GroupedSurface, drop the segmented row's icon slot so longer unit labels
fit, and reserve two lines so the stack stops shifting as the phrase
grows with each weekday.

Extract SettingsPrefs.firstDayOfWeek(scope), replacing three copies that
had drifted onto different initialValues.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
refactor(ui): one selection check and one motion spec across the pickers
All checks were successful
Translations / check (pull_request) Successful in 6s
CI / ci (pull_request) Successful in 5m57s
463811056d
Three inconsistencies the recurrence-picker review surfaced, all of the
same kind: the redesigned picker had quietly diverged from the family.

SelectedCheck existed as five copies app-side plus a private one in the
kit, and they had drifted — the kit drew Icons.Rounded.Check, every app
copy drew Icons.Default.Check. Delete all five against the kit's now
public primitive (floret-kit!2), which settles the glyph on Rounded.

The recurrence picker was the only full-screen picker whose selected row
carried no check, relying on the tonal highlight alone. Add it to all six
rows, matching OptionPicker, reminder, agenda range, timezone, calendar
and Settings.

Its two new AnimatedVisibility blocks were the only ones in the app using
Compose's bare defaults rather than expandEnter()/collapseExit(). Those
helpers honour rememberReduceMotion(), so the weekday and count cards
were ignoring the system "remove animations" setting — an accessibility
regression, not just a style drift.

Bumps the floret-kit pointer; needs floret-kit!2 merged first.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
makiolaj added 1 commit 2026-07-20 13:24:07 +00:00
Merge remote-tracking branch 'origin/release/v2.16.0' into feat/recurrence-exdate
All checks were successful
Translations / check (pull_request) Successful in 5s
CI / ci (pull_request) Successful in 11m20s
cd6ae31d0f
# Conflicts:
#	app/src/main/java/de/jeanlucmakiola/calendula/ui/edit/EventEditScreen.kt
makiolaj added 1 commit 2026-07-20 13:28:07 +00:00
chore: point floret-kit at merged main
All checks were successful
Translations / check (pull_request) Successful in 5s
CI / ci (pull_request) Successful in 6m40s
6a454e0b33
floret-kit!2 (public SelectedCheck) is merged, so the submodule no longer
needs to track the feature branch. Same tree, so nothing rebuilds — this
only stops Calendula pinning a branch that is now deletable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
makiolaj merged commit ada6976e85 into release/v2.16.0 2026-07-20 13:29:16 +00:00
makiolaj deleted branch feat/recurrence-exdate 2026-07-20 13:29:16 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: makiolaj/calendula#89