Generalise the two-tier SettingsSync into a server-driven flag map: each
syncable key has an account-wide flag (fetched from the server); pull applies
only on-flagged keys, push (read-modify-write) sends only on-flagged keys plus
the flag map. Per-row link icon toggles a setting's sync; a global switch flips
all. Enabling a flag adopts this device's current value as the shared one.
- AppSettings: fix bg_color mapping (was background_color), add cache_months,
month_view_paged, sync_flags
- SettingsView: uniform rows (sync icon | name | value), ContrastSelector and
the button pickers replaced by menu dropdowns, every colour gets a reset to a
canonical default, global "sync all" toggle; account settings (privacy,
group calendar, hide profile) kept in their own block; language and text/line
contrast kept device-local (iOS-specific)
- unify default line colour to #3A3A52 across views
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- LocalCalendar/CalEvent gain is_birthday + birthday fields; API sends
rrule/external_uid/birth_year and can create/update birthday calendars
- BirthdaysImporter: mirrors Contacts birthdays into a chosen birthday
calendar, reconciling by external_uid (leaves manual entries untouched)
- AccountsView: "birthday calendar" toggle + notify-days when creating a
calendar, and a "Birthdays from Contacts" section (enable + target + sync now)
- FAB long-press menu -> "New birthday" opens a minimal name+date mask
(BirthdayEditorSheet) targeting birthday calendars, with year-unknown option
- Event bars render display_title (age) and a cake icon via EventLabel
- NSContactsUsageDescription added to both app build configs
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- UserProfile decodes directory_hidden; updateProfile() sends it; Settings has
a "hide my profile" toggle (excludes you from share/group pickers).
- GroupMember decodes shares_calendar; the group filter list now only shows
members who actually share a calendar (no phantom empty rows).
- Robust custom decoders (decodeIfPresent) for the new fields.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Reminder editor: presets + custom number+unit (minutes/hours/days/weeks)
- Grey out + footer hint when the selected calendar's reminders are muted;
reminders are kept, scheduler already skips them
- New synced setting defaultEventDurationMinutes for new events
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
C1 — Localization: route the remaining hardcoded German strings through
L10n (LoginView, ServerSetupView, SettingsView email, EventDetailSheet) so
"System Default" + English device language shows fully English text.
C2 — Per-calendar reminders: parse the new reminders_enabled flag on every
calendar type; CalendarStore persists a reminderDisabledKeys set and passes
it to NotificationScheduler, which skips events of muted calendars (default
and per-event reminders). Filter sheet gains a per-calendar reminder toggle
(leading swipe + bell.slash indicator), reconciled from the server and
synced back via PUT.
C3 — Widgets:
- Shared WidgetTime.range helper; Today / Today & Tomorrow / Three Days /
Up Next now show start–end instead of only the start time.
- This Week: show up to 6 events per day (was 3) to use the height.
- Two Weeks: mini event-title pills instead of bare dots.
- Two Months: weeks expand to fill the column (no more empty lower third).
- Day & Events: smaller header/strip/rows so content stops clipping.
- Next 5 days → Next 7 days (range + labels), higher row cap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per-event reminders (multiple, local calendars only) in the editor, prefilled
from a new "default reminder" setting that applies to all events otherwise.
CalEvent gains `reminders`; AppSettings/SettingsSync sync default_reminder_minutes
(always group). New NotificationScheduler requests permission and schedules the
soonest ≤60 upcoming reminders via UNUserNotificationCenter, rescheduling on
load/sync/edit and when the default changes (skipped in group overlay).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add two-way settings sync (SettingsSync) with toggle, app-start/foreground/
10-min pull and debounced push; server wins; view/week-start/dim-past always
sync. Wire previously-ignored settings (hour height, contrasts, week start,
default view, dim past) into the actual UI.
- Make AppSettings decoding resilient (decodeIfPresent) so getSettings no longer
fails on iOS-only fields the server omits; keep text/bg/line colors local-only;
month divider/label colors now sync.
- Auto-refresh after create/edit (cache-busting) and optimistic removal on
delete; switch delete confirm to a centered alert. Add HA event deletion.
- Calendar visibility: fix inverted hide/show toggle; normalize calendar keys so
local filtering works for all sources; sync banish with server sidebar_hidden
(CalDAV/Google/HA), refetch on un-banish.
- Manual "sync with server" button in the menu.
- Upcoming widget shows next 5 days (renamed).
- Week/Day view: route multi-day timed events to the all-day strip so they no
longer render as a full-height block.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Vertical-scroll month view with multi-day event spans, zig-zag month
divider, CW number per week, on-demand event loading while scrolling
- Top bar redesign: icon-only view picker on right, month title centered
- Long-press context menus on day cells (month) and hour slots (week/day)
for "New event", "Open in week view", "Open in day view", "Open in month view"
- Localization system with system/de/en switch covering top bar, view picker,
settings, menu, profile, server, accounts, event editor, agenda
- Three new color pickers (text/background/line) + today-marker color
applied in calendar views; current-time line now uses today color
- App icon: removed alpha channel, accent color set to icon green (#20A050)
- TestFlight: ITSAppUsesNonExemptEncryption=NO baked into Info.plist keys
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>