Supported Destinations now includes Mac (Mac Catalyst) on the app and the
widget extension. Catalyst requires the iPad device family, so both targets
move to TARGETED_DEVICE_FAMILY "1,2".
The first Catalyst build failed on CalendarSelectionIntent: WidgetConfigurationIntent
requires every @Parameter to be optional, and the macOS SDK enforces that where
the iOS one lets a bare array through. selectedCalendars is now optional.
Behaviour is unchanged — the timeline provider already treated an empty
selection as "show all calendars", so nil folds into the same path.
Verified: builds for both Mac Catalyst and iOS Simulator.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The app shipped 3.5 (6) while the widget shipped 1.0.1 (2). Apple requires an
embedded appex to match its host's CFBundleShortVersionString and CFBundleVersion,
so this was a latent App Store validation failure that only surfaces at upload —
and it would surface on the Mac submission too. Both keys now live at project
level, where they cannot drift apart again.
The widget also targeted iOS 17 while the container app requires 26.0, so the
extension could never have been installed on 17 anyway. Raising it to 26.0
removes the availability skew that Mac Catalyst would otherwise inherit as
macOS 14 vs macOS 26.
Verified: app and appex Info.plists now both report 3.5 / 7 / 26.0.
Co-Authored-By: Claude Opus 5 <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>
- Move the bearer token from UserDefaults to the Keychain (accessible after
first unlock), with a one-time migration so existing logins survive.
- Replace NSAllowsArbitraryLoads=YES with NSAllowsLocalNetworking=YES so ATS
still permits cleartext to LAN/self-hosted servers but enforces TLS for
public hosts (no arbitrary cleartext/MITM).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause: mergeIntoCache() unconditionally evicted every event in the
fetched date range, even for calendars whose sync failed. Those calendars'
events were removed and never restored, so the calendar appeared to vanish.
Fix:
- SyncError now decodes calendarId from the server's "calendar_id" field
(added server-side in e0ea16f but not yet read by iOS).
- mergeIntoCache() gains a keepKeysInRange parameter: events from failed
calendars are retained (not evicted) even within the fetch window.
- loadEvents() and prefetchBackground() compute the failed keys from the
syncErrors list and pass them to mergeIntoCache.
Result: when CalDAV / Google / HA sync fails for a specific calendar, the
user sees stale-but-correct events alongside the existing error banner,
instead of a completely empty calendar with no explanation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bug fix: publishWidgetSnapshot() now guards against activeGroup != nil,
so group view events/colors never contaminate the widget cache.
Feature: widgets can now be configured via long-press → Edit Widget.
- WidgetCalendar struct + writeCalendars/readCalendars in WidgetData.swift
- calendarKey added to WidgetEvent (backward-compatible decoder)
- CalendarIntent.swift: CalendarAppEntity + CalendarEntityQuery + CalendarSelectionIntent
- CalendarrTimelineProvider migrated from TimelineProvider to AppIntentTimelineProvider
- All 13 StaticConfiguration widgets changed to AppIntentConfiguration
- publishWidgetSnapshot() builds + writes the calendar list for the intent
An empty selection (default) shows all calendars; selecting specific
calendars filters the widget events accordingly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The per-day cap of 3 made busy days collapse to "+N" so only ~6-7 events
showed total. Raise it (25) and let the total-row cap govern; extraLarge
fills up to 40 rows.
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>