Introduce an account-wide sync-flag map that is the single server-side
authority for which settings each client sends/fetches, plus value columns
for two newly-syncable device-local prefs.
- models.UserSettings: sync_flags (JSON), cache_months, month_view_paged
- main._migrate(): idempotent ALTER TABLE for the three new columns
- settings_router: DEFAULT_SYNC map + _resolve_sync_flags(); GET returns
fully-resolved sync_flags (+ cache_months, month_view_paged); PUT accepts
and merges a partial sync_flags map and the two new value fields
Rollout defaults: settings that already lived on the server sync ON; the
four newly-syncable prefs (language, share icon, cache range, month paging)
sync OFF until the user opts in.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- new BirthdaySyncDevice table + /api/birthdays/sync-report & /devices so the
web can show "birthdays come from these devices" (iOS reports its device on
each Contacts sync)
- settings: reject setting a birthday calendar as the group-visible calendar
(it can still be shared directly)
- web: Settings > Calendars > Birthdays shows the device list; exclude birthday
calendars from the group-visible picker
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Rename: Add google and homeassistant branches to the dblclick-rename
save() handler; backend already accepted name updates for both sources
- Group icon: Pass groupIconForLocalCal(cal.id) into sidebar entries so
the group's custom icon (home/heart/work/…) shows instead of always
defaulting to the people icon
- Share icon: New share_calendar_icon field in UserSettings (+ migration)
replaces the hardcoded SHARE_ICON SVG; users pick from GROUP_ICON_KEYS
in Settings → Darstellung via a new icon-picker row
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Force resp.encoding='utf-8' in _fetch_ics so umlauts (ö/ä/ü) from sources
like Ferienwiki.de are decoded correctly instead of showing as ö/ä/ü.
Add default_event_duration_minutes to UserSettings (nullable int, same pattern
as default_reminder_minutes) with DB migration, GET/PUT in settings_router.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Render event descriptions as sanitized HTML (links/line breaks) instead of
raw escaped text; no script execution
- Reminder picker: presets + custom number+unit (minutes/hours/days/weeks)
- Grey out + hint the reminder editor when a calendar's notifications are off
(reminders are kept, just not fired)
- New synced setting default_event_duration_minutes (default 60) for new events
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
local_events gains a `reminders` TEXT column (comma-separated minutes-before-
start, like exdate); EventCreate/EventUpdate accept a `reminders: [int]` list
and build_local_event_dict emits it back as a list. user_settings gains
`default_reminder_minutes` (nullable int, null = off), exposed/updatable via
/api/settings (explicit null persists as off). Migrations added in _migrate().
Clients (iOS/Android) schedule the OS notifications locally from these.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neues user_settings.group_visible_calendar_id: jedes Mitglied waehlt EINEN
lokalen Kalender, der in seinen Gruppen sichtbar ist. Die kombinierte
Ansicht ueberlagert nur diesen (statt aller) Kalender je Mitglied + den
Gruppenkalender; private Termine weiter gefiltert. Settings GET/PUT erweitert
(nullbar). Tests angepasst + ergaenzt (14 gruen).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die bisherigen Stufen-Wähler ("Dunkel/Mittel/Hell/Maximum" und
"Kaum/Subtil/Normal/Stark") für Schrift- bzw. Linienkontrast sind durch
echte Hex-Color-Picker ersetzt. Zusätzlich kann jetzt auch die
Hintergrundfarbe der Seite frei gewählt werden.
Wenn ein Override gesetzt ist:
- text_color → setzt --text-1 direkt, --text-2/--text-3 werden
daraus per shadeHex(-0.25 / -0.55) abgeleitet, damit der Hue passt
- line_color → setzt --border, --border-light wird leicht abgedunkelt
- bg_color → setzt --bg-app, daraus werden Topbar/Sidebar/Surface/
Hover/Active per shadeHex(+0.10…+0.40) konsistent hochskaliert
Per "Reset"-Knopf wird der Override geleert und die alte Stufen-Logik
(falls noch vorhanden) bzw. der Default-Theme greift wieder.
Backend:
- 3 neue nullable VARCHAR(7)-Spalten in user_settings (text_color,
line_color, bg_color) inkl. Migrationen in main.py
- settings_router nutzt model_dump(exclude_unset=True) und respektiert
explizite null-Werte nur für diese 3 Override-Felder, damit Reset
funktioniert
Auch enthalten: Auflösen der Merge-Konflikte in sw.js, index.html,
version.js (HEAD-Stand v17 behalten) und Bump auf v18.
In der rolling Monatsansicht wird jetzt am Monatswechsel:
- eine dickere Trennlinie gezeichnet (links bei Wechsel mitten in Zeile,
oben bei Zeilenstart)
- das 3-Buchstaben-Monatskürzel (z.B. JUL, AUG) groß über der "1"
angezeigt
Beide Farben (Linie und Kürzel) sind in den Einstellungen unter
"Farben" individuell anpassbar (Default: #7090c0).
Backend: neue UserSettings-Felder month_divider_color und month_label_color
mit Migration. Frontend: applyTheme setzt entsprechende CSS-Variablen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Einstellungen von Modal-Popup auf Vollbild-Seite mit Seitennavigation umgestellt
- Schriftkontrast (4 Stufen) und Linienkontrast (4 Stufen) pro Benutzer gespeichert
- Stundenhöhe (40/60/80/100px) in Wochen-/Tagesansicht per Einstellung steuerbar
- Kalenderwoche in Monats- und Wochenansicht grösser dargestellt
- CSS-Variable --hour-h für dynamische Zeitraster-Höhe in week.js und app.css
- Backend: neue Felder text_contrast, line_contrast, hour_height in UserSettings