Add six draft posts drawn from Calendula issues
Technical, journey, and philosophy posts sourced from the Calendula issue threads, reviewed for source-accuracy, standards, ethics, and voice. All draft:true with staggered future pubDates; they stay hidden in prod until approved (draft:false) and due. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
79
src/content/blog/caldav-colors.md
Normal file
79
src/content/blog/caldav-colors.md
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: Why your CalDAV events show sixty shades of the same blue
|
||||
description: >-
|
||||
Two open colour reports on Calendula come from one root — an overstuffed picker
|
||||
on CalDAV calendars and hard-to-read dark event titles — and both trace back to
|
||||
how event colour flows through Android's calendar provider.
|
||||
pubDate: 2026-07-08
|
||||
tags: [android, calendula, caldav, accessibility]
|
||||
draft: true
|
||||
---
|
||||
|
||||
Two colour reports landed on Calendula in the same week, and both are still open.
|
||||
One is a bug: the colour picker on a CalDAV calendar shows a full screen of
|
||||
colours, many of them near-duplicates ([#22]). The other is a request: make
|
||||
event titles readable on dark backgrounds so busy weeks don't turn into a smear
|
||||
([#21]). They look unrelated. They come from the same place — how event colour
|
||||
actually flows through Android's calendar provider — which is why I'm writing up
|
||||
the diagnosis before I write the fix.
|
||||
|
||||
## Palette vs. free-for-all
|
||||
|
||||
Android's
|
||||
[`CalendarContract`](https://developer.android.com/reference/android/provider/CalendarContract)
|
||||
has two ways to colour an event, and which one you get depends on the account.
|
||||
|
||||
Google and local calendars expose a **palette**: a small, indexed set of colours
|
||||
through
|
||||
[`CalendarContract.Colors`](https://developer.android.com/reference/android/provider/CalendarContract.Colors).
|
||||
An event stores a `color_key`, the provider maps it to a swatch, and a picker can
|
||||
show exactly those choices — a tidy dozen.
|
||||
|
||||
CalDAV is different. The iCalendar
|
||||
[`COLOR`](https://datatracker.ietf.org/doc/html/rfc7986#section-5.9) property is
|
||||
defined as a CSS3 colour *name* — a set of about 150, already far bigger than a
|
||||
palette — and in practice clients push arbitrary hex through vendor extensions
|
||||
like `X-APPLE-CALENDAR-COLOR`. Either way, by the time it reaches the provider
|
||||
there's no `color_key` and no shared index: the event just carries a raw
|
||||
`EVENT_COLOR`. So a picker that tries to *build* a palette from what it finds
|
||||
ends up gathering every distinct value that ever appeared, including a dozen
|
||||
blues that differ by a rounding error you can't see. That's the "too many
|
||||
colours" bug: it isn't showing junk, it's faithfully showing an *unbounded* space
|
||||
as though it were a fixed menu. The fix is to stop pretending CalDAV has a
|
||||
palette — offer a sane curated set and map to the nearest real colour, rather
|
||||
than enumerating every ghost.
|
||||
|
||||
## The contrast problem is the same problem
|
||||
|
||||
Once an event can be *any* colour, you can no longer assume the text on top is
|
||||
readable. A pale event with dark text is fine; a deep navy block with the same
|
||||
dark text is a smear. Right now Calendula draws event titles in a fixed near-
|
||||
black — which is exactly the assumption that breaks. Google Calendar flips to
|
||||
white text on dark fills, and [#21] asks for the same.
|
||||
|
||||
The rule for "is this colour dark" isn't the average of its channels — the eye
|
||||
isn't equally sensitive to red, green and blue. The
|
||||
[WCAG relative luminance](https://www.w3.org/TR/WCAG21/#dfn-relative-luminance)
|
||||
formula weights them the way perception does (green counts far more than blue),
|
||||
linearises each channel, and yields a single brightness figure. Pick a threshold,
|
||||
and below it the title renders white (or off-white), above it near-black. It's a
|
||||
few lines of maths applied to the same event colour the picker just handed you —
|
||||
which is the point. The overstuffed picker and the unreadable title are two ends
|
||||
of one pipe: *the moment colour stops being a fixed palette and becomes
|
||||
arbitrary, both the input and the output need taming.* One end is a bug to close;
|
||||
the other is a threshold to add. Same pipe.
|
||||
|
||||
## Standard first, taste second
|
||||
|
||||
The tidy path would be to store my own colour for every event and never touch the
|
||||
provider's mess. I don't — for the same reason Calendula owns no other part of
|
||||
your data. The `COLOR` on a CalDAV event belongs to the event, and the sync
|
||||
adapter carries it out to every other client that reads your calendar; if I
|
||||
overwrote it with a private value, that portability would be gone. My job isn't
|
||||
to replace the colour. It's to present a bounded, readable *view* of it — a
|
||||
curated picker on the way in, a luminance-aware title on the way out — while the
|
||||
value itself stays yours and portable. Two open issues, one fix: let you read
|
||||
your own calendar without taking it over.
|
||||
|
||||
[#21]: https://codeberg.org/jlmakiola/calendula/issues/21
|
||||
[#22]: https://codeberg.org/jlmakiola/calendula/issues/22
|
||||
Reference in New Issue
Block a user