Design the Panama calendar agenda
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
# Calendar Agenda design
|
||||
|
||||
## Summary
|
||||
|
||||
Panama will use Evolution Data Server (EDS), the same calendar backend already
|
||||
used by GNOME Calendar, to turn the existing date menu into a live Daybook. The
|
||||
shell will display synchronized Google, iCloud/CalDAV, Nextcloud, local, and ICS
|
||||
subscription events without owning account credentials or implementing calendar
|
||||
sync.
|
||||
|
||||
The approved visual direction is **A · Daybook**: a 760-pixel Prism panel with a
|
||||
month calendar on the left and the selected day's agenda on the right. GNOME
|
||||
Calendar remains the account-management and event-editing application.
|
||||
|
||||
## Goals
|
||||
|
||||
- Show events from every enabled EDS calendar already visible to GNOME Calendar.
|
||||
- Keep month context and the selected day's schedule visible together.
|
||||
- Represent all-day, timed, recurring, and multi-day events correctly.
|
||||
- Preserve the complete notification center, weather, and conditional media
|
||||
controls in the date menu.
|
||||
- Open events in GNOME Calendar and expose a Join action for recognized meeting
|
||||
links.
|
||||
- Surface upcoming events globally only when they are timely and actionable.
|
||||
- Continue working from EDS's local cache while account providers are offline.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Panama will not store account passwords, OAuth tokens, or CalDAV credentials.
|
||||
- Panama will not add, remove, or reconfigure calendar accounts.
|
||||
- Panama will not create or edit events in the first release. Those actions open
|
||||
GNOME Calendar.
|
||||
- Panama will not implement reminders, alarms, tasks, or email invitations.
|
||||
- Panama will not parse remote ICS URLs or synchronize calendar data itself.
|
||||
- Wi-Fi QR sharing is no longer planned.
|
||||
|
||||
## Existing system
|
||||
|
||||
The workstation runs Evolution Data Server 3.60.2 and GNOME Calendar 50. EDS
|
||||
currently reports ten enabled event sources backed by CalDAV, contacts, and a
|
||||
local calendar. The GNOME Shell calendar service also works in the Hyprland
|
||||
session and reports that calendars are available.
|
||||
|
||||
Panama can therefore integrate below the GNOME Calendar user interface:
|
||||
|
||||
```text
|
||||
Google / iCloud / Nextcloud / ICS subscriptions
|
||||
│
|
||||
▼
|
||||
Evolution Data Server
|
||||
┌──────┴──────┐
|
||||
▼ ▼
|
||||
GNOME Calendar Panama Daybook
|
||||
manage + edit glance + launch
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Calendar bridge
|
||||
|
||||
Add `config/dot/quickshell/scripts/calendar-agenda`, a small Python/GObject
|
||||
bridge using the installed `EDataServer` and `ECal` introspection libraries. A
|
||||
native EDS client is preferred over scraping GNOME Calendar or reading source
|
||||
files because it preserves recurrence, time-zone, source, and cached-sync
|
||||
semantics.
|
||||
|
||||
The bridge exposes three commands:
|
||||
|
||||
- `probe` reports whether EDS, the source registry, and at least one enabled
|
||||
event source are available. It never emits account names or event contents.
|
||||
- `query START END` returns one normalized JSON snapshot and exits. It is used by
|
||||
tests and as a recovery path.
|
||||
- `watch START END` emits newline-delimited JSON snapshots. It refreshes when a
|
||||
source changes and periodically as a defensive fallback. Restarting `watch`
|
||||
with a new range is how the shell follows month navigation.
|
||||
|
||||
`watch` queries enabled `E_SOURCE_EXTENSION_CALENDAR` sources, connects an
|
||||
`ECal.Client` for each one, and expands recurrence instances for the requested
|
||||
time range. One unavailable source does not suppress healthy sources. Refreshes
|
||||
are debounced so a provider sync produces one shell update rather than a burst.
|
||||
|
||||
Each snapshot has one stable contract:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"generatedAt": 1786978200,
|
||||
"sources": [
|
||||
{
|
||||
"id": "source-id",
|
||||
"name": "Calendar name",
|
||||
"color": "#82aaff"
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"id": "source-id:event-id:instance",
|
||||
"sourceId": "source-id",
|
||||
"uid": "event-id",
|
||||
"summary": "Event title",
|
||||
"start": 1786978200,
|
||||
"end": 1786980000,
|
||||
"allDay": false,
|
||||
"location": "",
|
||||
"joinUrl": ""
|
||||
}
|
||||
],
|
||||
"errors": []
|
||||
}
|
||||
```
|
||||
|
||||
Source and event identifiers remain local. Descriptions and attendee lists are
|
||||
not sent to Quickshell. The bridge inspects the component URL, location, and
|
||||
description only to extract an HTTPS Google Meet, Zoom, Microsoft Teams, Webex,
|
||||
or Jitsi URL; it does not include the original description in its output.
|
||||
|
||||
### Quickshell service
|
||||
|
||||
Add `services/CalendarAgenda.qml` as the single shell-facing calendar state
|
||||
owner. It will:
|
||||
|
||||
- Start and supervise the bridge.
|
||||
- Hold normalized source and event arrays.
|
||||
- Track loading, ready, degraded, and unavailable states.
|
||||
- Expose events and colored day markers for a requested date or month.
|
||||
- Calculate the next timed event and its relative start text.
|
||||
- Open GNOME Calendar by event UUID, or by date when no event UUID exists.
|
||||
- Open recognized meeting links through `xdg-open`.
|
||||
- Restart the bridge when the visible month leaves the current loaded range.
|
||||
|
||||
The normal range begins seven days before the visible month and ends seven days
|
||||
after it. This covers all 42 calendar cells and the near-future bar capsule with
|
||||
one query.
|
||||
|
||||
The service refreshes when the Daybook opens, after a bridge change event, at
|
||||
midnight, and every ten minutes as a fallback. It never writes event data to
|
||||
Panama configuration or logs.
|
||||
|
||||
## Daybook interface
|
||||
|
||||
### Panel structure
|
||||
|
||||
The date menu grows from 480 to 760 logical pixels and keeps the current Prism
|
||||
surface, top-center anchor, type system, and open motion.
|
||||
|
||||
```text
|
||||
┌ Monday, August 17 ─────────────── DND · Open Calendar ┐
|
||||
│ August 2026 │ Up next · in 24 minutes │
|
||||
│ S M T W T F S │ Command Center standup Join │
|
||||
│ month grid │─────────────────────────────│
|
||||
│ colored markers │ Today · Your schedule │
|
||||
│ │ 1:00 Release planning │
|
||||
│ weather / media │ 2:30 Focus time │
|
||||
│ │ 6:30 Dinner │
|
||||
│ │ 2 notifications View │
|
||||
└─────────────────────────┴─────────────────────────────┘
|
||||
```
|
||||
|
||||
The left column is 310 pixels wide. It contains the month grid followed by the
|
||||
conditional media card and weather. The right column owns either the agenda or
|
||||
the full notification list. Its content scrolls independently when necessary;
|
||||
the panel itself does not grow beyond the usable monitor height.
|
||||
|
||||
### Calendar interaction
|
||||
|
||||
- Opening from the clock selects today and shows the agenda.
|
||||
- Clicking a current-month day selects it and updates the right column.
|
||||
- Clicking an adjacent-month day navigates to that month and selects the day.
|
||||
- Month arrows retain the selected day where possible and request a new range.
|
||||
- Today uses the solid blue accent. The selected non-today date uses a restrained
|
||||
accent surface.
|
||||
- A day shows up to three source-colored dots. Additional events do not add more
|
||||
dots.
|
||||
- Calendar source names appear beside events rather than in a permanent legend,
|
||||
which remains usable when more than three calendars are enabled.
|
||||
|
||||
### Agenda interaction
|
||||
|
||||
- The first future timed event on the selected day becomes the Up Next card.
|
||||
- Up Next shows a Join action only for a recognized meeting URL.
|
||||
- All-day events appear before timed events and do not become Up Next.
|
||||
- Timed events are sorted by start time. Past events remain visible but dimmed.
|
||||
- Each event shows its source color, time, summary, source name, and concise
|
||||
location when present.
|
||||
- Clicking an event opens it in GNOME Calendar with `--uuid`.
|
||||
- An empty day says `Nothing scheduled` and keeps an `Open Calendar` action.
|
||||
- Event titles are single-line and elide; full details belong in GNOME Calendar.
|
||||
|
||||
### Notifications, media, and weather
|
||||
|
||||
The notification summary appears at the bottom of the agenda only when history
|
||||
is non-empty. Clicking it replaces the right column with the existing grouped
|
||||
notification list. Opening the panel from the notification indicator starts in
|
||||
that notification view; opening it from the clock starts in Agenda.
|
||||
|
||||
Notification view keeps DND and Clear All. A `Back to agenda` action restores
|
||||
the selected day without resetting the month. Existing inline replies remain
|
||||
keyboard-accessible.
|
||||
|
||||
The media card stays conditional and moves beneath the calendar. Weather remains
|
||||
the quiet final item in the left column. Neither competes with Up Next.
|
||||
|
||||
## Quiet global event capsule
|
||||
|
||||
The bar does not permanently display calendar content and Panama does not emit
|
||||
calendar toasts or sounds.
|
||||
|
||||
A compact event capsule appears only for the next timed event:
|
||||
|
||||
- fifteen minutes before its start;
|
||||
- through five minutes after its start; and
|
||||
- only when the event is not marked all-day.
|
||||
|
||||
The capsule shows a calendar glyph and relative time, such as `12m` or `Now`.
|
||||
The title stays in a tooltip to avoid exposing work details across the bar.
|
||||
Clicking opens the Daybook on today. If a meeting URL exists, a small secondary
|
||||
Join affordance is available inside the Daybook, not on the bar.
|
||||
|
||||
The capsule uses event-driven transitions only. It has no pulse, shimmer, or
|
||||
continuous animation.
|
||||
|
||||
## Failure and privacy behavior
|
||||
|
||||
- If one account is offline, cached events from that source remain visible when
|
||||
EDS provides them; healthy sources continue normally.
|
||||
- If the bridge fails, the calendar grid, notifications, media, and weather
|
||||
remain usable. The agenda says `Calendar data is unavailable` and offers
|
||||
`Open Calendar`.
|
||||
- Malformed event fields are omitted individually rather than crashing the
|
||||
service.
|
||||
- Event summaries, locations, URLs, and account names are never written to shell
|
||||
logs, settings, fixture files, or repository content.
|
||||
- The bridge does not access EDS authentication extensions or credential stores.
|
||||
- URL actions require a user click and only allow `https://` links.
|
||||
|
||||
## Testing
|
||||
|
||||
Focused tests will cover:
|
||||
|
||||
1. The bridge's probe and normalized JSON contract without printing live event
|
||||
contents.
|
||||
2. Time-range filtering, ordering, all-day handling, recurrence identifiers,
|
||||
meeting-link allowlisting, and malformed component handling through synthetic
|
||||
local fixtures.
|
||||
3. CalendarAgenda state, selected-date filtering, month marker aggregation, and
|
||||
next-event timing through a deterministic fixture mode.
|
||||
4. Daybook panel structure, date activation, notification-view routing, and
|
||||
GNOME Calendar launch commands through contract tests.
|
||||
5. A live read-only EDS smoke test that asserts enabled source and event counts
|
||||
while redacting names and summaries.
|
||||
6. Fresh Quickshell compilation, Hyprland configuration verification, visual
|
||||
fixture screenshots, and a live panel check against the current EDS cache.
|
||||
|
||||
No test creates, modifies, or deletes a real calendar event.
|
||||
|
||||
## Documentation updates
|
||||
|
||||
- Mark Calendar Agenda live in `config/dot/hypr/DESKTOP-PARITY.md`.
|
||||
- Remove Wi-Fi QR sharing from the remaining roadmap and package guidance.
|
||||
- Document GNOME Calendar as the account/editing handoff and the quiet capsule
|
||||
behavior in `config/dot/hypr/README.md`.
|
||||
Reference in New Issue
Block a user