3.4 KiB
Share Intake
Share intake is the app's highest-friction capture path. It should be reliable, reviewable, and conservative about identity matching.
Entry Points
Flutter listener:
lib/features/share_intake/presentation/incoming_share_listener.dart
Native iOS:
ios/Share Extension/ShareViewController.swiftios/Save Action/SaveActionViewController.swiftios/Share Extension/Info.plistios/Save Action/Info.plistios/Runner.xcodeproj/project.pbxproj
Android:
android/app/src/main/AndroidManifest.xmlreceive_sharing_intentplugin integration
Developer simulation:
- Settings ->
Simulate Share Capture
Pipeline
native share / simulation
-> IncomingShareListener
-> SharePayloadParser
-> startShareCaptureReview
-> capture to existing profile, create profile, or save to inbox
-> LocalRepositoryShareOperations
-> LocalDataState + sync queue + optional facts/dates/signals
Payload Normalization
SharePayloadParser normalizes:
- source app labels
- text vs URL vs text-with-URL payloads
- WhatsApp sender prefixes
- Signal sender prefixes
- source-message timestamp evidence
SharedPayload keeps both app-side timestamps and source-message timestamps:
createdAt: normalized payload creation timereceivedAt: app receive/import timesharedMessageDateTime: best-effort original message time, nullable
Source Message Timestamp Extraction
Source: lib/features/share_intake/domain/shared_message_datetime_extractor.dart
The extractor tries multiple metadata-like patterns:
- bracketed chat prefixes such as
[19/05/2026, 14:30] Sender: text - exported chat prefixes such as
5/19/26, 2:30 PM - Sender: text - labelled lines such as
Received at: 19 May 2026 at 14:30 - ISO-like timestamps
today at HH:mmandyesterday at HH:mm- numeric and month-name date variants
It returns null instead of throwing. It intentionally avoids arbitrary content
dates, for example birthday is May 20, because those are not message receive
times.
Identity Matching
Matching order:
- Existing
SourceProfileLinkby source fingerprint/user/thread metadata. - Exact normalized display name when exactly one profile matches.
- Near-name conflict detection.
- Inbox when missing, ambiguous, or risky.
Do not auto-link when evidence is weak. The inbox is the safety valve.
Inbox Resolution
Share Inbox supports:
- resolving to an existing person
- creating a person
- editing structured draft type/text/date
- reviewing conflict candidates
- saving provenance for facts and source links
Relevant files:
lib/features/share_intake/presentation/share_inbox_view.dartlib/features/share_intake/presentation/share_capture_review_sheet.dartlib/app/data/relationship_repository_share.dart
Native iOS Notes
The repository currently contains Share Extension and Save Action target entries
in the Xcode project. The iOS Podfile still only has the Runner target, so
verify extension build behavior after plugin updates or Pod changes.
Physical iPhone testing is required for real chat apps. Simulators are useful for Notes/Safari-style text and URL sharing, but not enough for WhatsApp, iMessage, or app-specific metadata behavior.
Tests
Useful focused tests:
flutter test test/features/share_intake
flutter test test/features/local/local_repository_test.dart
Add parser tests for every new source format. Add repository tests when matching, inbox, source links, facts, or signals change.