Add birthday feature (iOS)

- 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>
This commit is contained in:
Scarriffle
2026-07-12 21:58:31 +02:00
parent e55e6c7c92
commit cf990e4279
15 changed files with 527 additions and 19 deletions

View File

@@ -345,6 +345,29 @@ private let strings: [String: [String: String]] = [
"local.color": "Farbe",
"local.create": "Erstellen",
// Birthdays
"birthday.new": "Neuer Geburtstag",
"birthday.person": "Name",
"birthday.person_placeholder": "Name der Person",
"birthday.date": "Geburtstag",
"birthday.year_unknown": "Jahr unbekannt",
"birthday.no_calendars": "Kein Geburtstagskalender vorhanden. Erstelle zuerst einen unter „Konten & Kalender“.",
"birthday.is_calendar": "Geburtstagskalender",
"birthday.is_calendar.desc": "Ganztägige, jährliche Termine mit Alter und Geburtstags-Icon.",
"birthday.notify": "Erinnerung",
"birthday.notify.off": "Aus",
"birthday.notify.same_day": "Am Tag",
"birthday.notify.one_day": "1 Tag vorher",
"birthday.notify.days": "%d Tage vorher",
"birthday.contacts.header": "Geburtstage aus Kontakten",
"birthday.contacts.sync": "Aus Kontakten synchronisieren",
"birthday.contacts.target": "Zielkalender",
"birthday.contacts.sync_now": "Jetzt synchronisieren",
"birthday.contacts.synced": "Geburtstage synchronisiert",
"birthday.contacts.hint": "Überträgt Geburtstage aus deinen Kontakten in den gewählten Geburtstagskalender sichtbar auf allen Geräten.",
"birthday.contacts.denied": "Kein Zugriff auf Kontakte. Bitte in den iOS-Einstellungen erlauben.",
"birthday.contacts.need_calendar": "Erstelle zuerst einen Geburtstagskalender.",
// iCal add sheet
"ical.title": "iCal abonnieren",
"ical.subscription": "Abonnement",
@@ -677,6 +700,29 @@ private let strings: [String: [String: String]] = [
"local.color": "Color",
"local.create": "Create",
// Birthdays
"birthday.new": "New birthday",
"birthday.person": "Name",
"birthday.person_placeholder": "Person's name",
"birthday.date": "Birthday",
"birthday.year_unknown": "Year unknown",
"birthday.no_calendars": "No birthday calendar yet. Create one first under “Accounts & Calendars”.",
"birthday.is_calendar": "Birthday calendar",
"birthday.is_calendar.desc": "All-day, yearly events with age and a birthday icon.",
"birthday.notify": "Reminder",
"birthday.notify.off": "Off",
"birthday.notify.same_day": "On the day",
"birthday.notify.one_day": "1 day before",
"birthday.notify.days": "%d days before",
"birthday.contacts.header": "Birthdays from Contacts",
"birthday.contacts.sync": "Sync from Contacts",
"birthday.contacts.target": "Target calendar",
"birthday.contacts.sync_now": "Sync now",
"birthday.contacts.synced": "Birthdays synced",
"birthday.contacts.hint": "Copies birthdays from your contacts into the chosen birthday calendar visible on all devices.",
"birthday.contacts.denied": "No access to Contacts. Please allow it in iOS Settings.",
"birthday.contacts.need_calendar": "Create a birthday calendar first.",
// iCal add sheet
"ical.title": "Subscribe to iCal",
"ical.subscription": "Subscription",