263 lines
11 KiB
Markdown
263 lines
11 KiB
Markdown
# 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.
|
|
- Live event summaries, locations, URLs, and account names are never written to
|
|
shell logs, settings, fixture files, or repository content. Synthetic fixture
|
|
copy is intentionally generic.
|
|
- 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`.
|