Move mode picker below device status bar; fix invisible calendar lines; add CalDAV calendar support
Build and push server image / build-and-push (push) Successful in 50s

Calendar rule/grid lines were light gray, which dithers away to
near-invisible on the 6-color e-ink palette -- now black.

CalDAV accounts (Nextcloud, Fastmail, iCloud, ...) can now be linked
alongside the existing single ICS subscription, since one account can
expose several calendars. A frame's Calendar tab now lists calendars
per person rather than one opt-in per person: your own row shows every
calendar you have available with a full add/remove toggle, while other
linked users' rows show only calendars they've included, toggleable
off (mute) but not on -- only a calendar's owner can add it to a
shared frame. FrameCalendar replaces the old single-boolean
UserFrame.calendar_included; existing opt-ins are migrated forward.
This commit is contained in:
2026-07-22 22:01:05 -04:00
parent 95d69a5512
commit acdb929a99
21 changed files with 525 additions and 109 deletions
+36
View File
@@ -110,6 +110,41 @@ def _migration_8(conn) -> None:
def _migration_9(conn) -> None:
"""CalDAV support alongside the plain ICS subscription (see
caldav_client.py), and the frame_calendars table that replaces
user_frames.calendar_included now that one account (CalDAV) can
expose more than one calendar -- see models.py's FrameCalendar.
Existing single-calendar opt-ins are carried forward as "ics" rows
before the old column is dropped, so nobody's frame goes silently
calendar-less after this migration."""
conn.execute(text("ALTER TABLE users ADD COLUMN calendar_caldav_url TEXT NOT NULL DEFAULT ''"))
conn.execute(text("ALTER TABLE users ADD COLUMN calendar_caldav_username TEXT NOT NULL DEFAULT ''"))
conn.execute(text("ALTER TABLE users ADD COLUMN calendar_caldav_password TEXT NOT NULL DEFAULT ''"))
conn.execute(text("ALTER TABLE users ADD COLUMN calendar_caldav_calendars TEXT"))
conn.execute(text("ALTER TABLE users ADD COLUMN calendar_caldav_checked_at REAL NOT NULL DEFAULT 0.0"))
conn.execute(text(
"CREATE TABLE frame_calendars ("
"id INTEGER PRIMARY KEY, "
"frame_id INTEGER NOT NULL REFERENCES frames(id) ON DELETE CASCADE, "
"user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, "
"calendar_key TEXT NOT NULL, "
"calendar_label TEXT NOT NULL DEFAULT '', "
"included INTEGER NOT NULL DEFAULT 1)"
))
conn.execute(text(
"CREATE UNIQUE INDEX ix_frame_calendars_unique ON frame_calendars (frame_id, user_id, calendar_key)"
))
conn.execute(text(
"INSERT INTO frame_calendars (frame_id, user_id, calendar_key, calendar_label, included) "
"SELECT uf.frame_id, uf.user_id, 'ics', 'My calendar', 1 "
"FROM user_frames uf JOIN users u ON u.id = uf.user_id "
"WHERE uf.calendar_included = 1 AND u.calendar_ics_url != ''"
))
conn.execute(text("ALTER TABLE user_frames DROP COLUMN calendar_included"))
MIGRATIONS = [
(1, _migration_1),
(2, _migration_2),
@@ -119,6 +154,7 @@ MIGRATIONS = [
(6, _migration_6),
(7, _migration_7),
(8, _migration_8),
(9, _migration_9),
]