Skip to content

feat: let overlapping calendar events lie over each other where no text is covered #149 - #152

Merged
rathlinus merged 1 commit into
bulwarkmail:mainfrom
wmcparla:feat/calendar-event-overlap-149
Nov 15, 2026
Merged

rathlinus merged 1 commit into
bulwarkmail:mainfrom
wmcparla:feat/calendar-event-overlap-149

Conversation

@wmcparla

Copy link
Copy Markdown
Contributor

Summary

Timed events that overlap now lie over each other where that covers no text, instead of sharing the day evenly (#149). An event keeps the room it had and takes more: the columns beside it that are free while it runs, and the room of events that start far enough from it. The later event is drawn on top and starts below the earlier one's title and time.

Week, before Week, after
Day, before Day, after

Changes

  • Layout (layoutOverlappingEvents in src/lib/calendar-utils.ts): the cluster and column packing is unchanged and is now only where an event starts from. A new step, spreadCluster, then sets each event's left and width:
    • An event spreads left and right over the columns that are free while it runs.
    • It also spreads over an event that starts far enough from it: 30 minutes, or 45 when the earlier one is long enough to show its start time. At 48 px an hour that is past the title (17 px) or past the time under it (30 px).
    • The later of the two is drawn on top, set in by a quarter of a column from the one underneath, so that one's edge still shows.
    • Events that start closer together than that stay side by side, as today.
    • No event gets narrower than its column was.
    • A block is never drawn under 20 px tall, so a short event counts for the 25 minutes it takes up on screen.
  • Grids (WeekView.tsx, TimeGridScrollView.tsx): both draw from left and width. The result is in start order, so later events are drawn last. TIME_LINE_MIN_MINUTES moved from EventBlock.tsx to calendar-utils.ts, where the layout needs it too.
  • No setting and no new strings: every event is at least as wide as before.

Two things to know:

Related issues

Closes #149

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactor / code quality improvement
  • Chore / dependency update / CI change

Checklist

  • I have read the Contributing Guide
  • My code follows the project's code style and conventions
  • I have run npm run typecheck and there are no errors (native has no lint script)
  • The build passes (no npm run build in native; an x86_64 release APK, assembleGithubRelease -PallowDebugSignedRelease=true, builds and runs)
  • I have tested my changes locally
  • I have added or updated documentation if needed (none needed)
  • I have updated translations (locales/) if my changes affect user-facing text (no new text)
  • I have included screenshots or a screen recording for UI changes

Tests:

  • npx vitest run src/lib/__tests__/calendar-utils.test.ts: 46 passed, 11 of them new. They cover a lone event, equal starts, a start that would cover the time line, one and two events over a long one, a free column, short and zero-length events, the example from the issue, and a mixed day checked for the rules above (never narrower, never outside the day, never over text). npx tsc --noEmit and npm run i18n:check are clean. The whole suite passed (7112) before the last change to the layout, which only the file above covers; CI runs it again here.
  • A separate review of the diff ran the layout against 60,000 random days. It found two cases, both about short events drawn taller than they last, and both are fixed and tested here.

On a device (Android 16 phone emulator, x86_64 release build, a test account on a self-hosted Stalwart): five events on one day, as in the screenshots: 10:00 to 14:00, 11:00 to 12:00, 11:45 to 12:45, and two at 13:00 for 30 minutes. Each block's place was read from the view hierarchy in the day and the week grid.

Check, in both grids main this PR
The long event fills the day under the others a third whole day
The 11:00 event is wider than half the day a third 92%
Each later event is set in a little from the one under it no yes
The two that start together stay side by side yes yes
No block covers the title or start time of one under it yes yes

Not tested:

  • iOS, and the paged week view (WeekView.tsx, used with free scrolling off or in a right-to-left language) on a device: it draws from the same layout through the same block component, and the run above used the scrolling grids.
  • A cluster of six or more columns in the week grid of a phone: the set-in there is a pixel or two, so the edge of an event underneath is hard to see. Its title stays clear.

🤖 Generated with Claude Code

…xt is covered bulwarkmail#149

Timed events that overlap used to share the day evenly: three in a
cluster got a third each for their whole length, which in the week grid
of a phone leaves room for no title at all.

The columns are now only where an event starts from. It spreads over
the columns beside it that are free while it runs, and over events that
start far enough from it: 30 minutes, or 45 when the earlier one shows
its start time. The later event is drawn on top and begins below the
earlier one's title and time, set in a little so the edge of the one
underneath still shows. Events that start closer together stay side by
side as before, and no event gets narrower than it was.

A block is never drawn under 20px tall, so a short event counts for the
25 minutes it takes up on screen, not only for its length.
@wmcparla
wmcparla marked this pull request as ready for review November 15, 2026 14:29
@rathlinus
rathlinus merged commit 06a61d9 into bulwarkmail:main Nov 15, 2026
1 check passed
@rathlinus

Copy link
Copy Markdown
Member

Thanks, merged. On top: a long event's title now wraps only down to where the event over it starts (with #135 it could run under it), and the room left above an overlapping event grows with the system text size, so with large text, events that start closer together stay side by side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: allow calendar events to smartly overlap for wider events

2 participants