Completes v2.7 Branch 2. Wires the import core into the app:
- Manifest ACTION_VIEW/SEND for text/calendar; MainActivity parses the
incoming Uri (content/file only, so calendula:// deep-links don't match)
and routes it through RootScreen → CalendarHost like the other one-shot
intents.
- ImportViewModel reads + parses the file and routes by count: one event →
the prefilled create form for review (EventEditViewModel.openImported,
which freezes the reminder default so the file's reminders win); many →
ImportScreen with a writable-calendar picker, then a bulk import (UID
dedup) and a result summary.
- ImportScreen also surfaces parser warnings (skipped recurrence overrides,
ignored attendees, unknown-timezone fallback). Strings EN+DE.
Package is ui.imports (not ui.import — Java keyword). lint + test +
assembleDebug green. No v2.7 tag until on-device review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v2.7 Branch 2 (core, no UI yet). The read side of the .ics engine:
- domain/ics: IcsParser (inverse of IcsWriter) — unfold/unescape/param
parsing, VALUE=DATE / UTC-Z / TZID date handling resolved against the OS
tz db, VEVENT walk → ParsedIcsEvent + typed warnings. Liberal-in/
strict-out: a malformed VEVENT is skipped, RECURRENCE-ID overrides /
attendees / unresolved TZIDs are reported, not silently dropped.
- Promoted parseRfc2445DurationMillis into domain/ics (shared by writer-
side mapper and parser); IcsDuration + test.
- Datasource existingUids()/insertImportedEvent(); repository
importEvents() with UID dedup (skip known UIDs → idempotent restore) →
IcsImportSummary. IcsImporter reads a Uri's text.
- ParsedIcsEvent.toEventForm() for the single-event "open into the create
form" path.
Parser round-trips against IcsWriter; dedup + form-adapter unit-tested.
Intent filter, routing and import UI land in the next commit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>