Skip to content

Feature: Mobile Share-Sheet for Reel Imports

ID: 0010
Status: In progress
Owner: @satya
Created: 2026-05-14
Updated: 2026-05-14
Related ADRs: 0001 (Flutter mobile)
Depends on: 0008 (reel video imports), 0009 (reel extraction cache)

Instagram / TikTok / YouTube share-sheets pass a URL (not the video bytes) to the host app. Today users have to copy the URL out, switch apps, and paste it into Treeper. With this slice they tap Share → Treeper, pick a trip, and the global reel cache (spec 0009) serves the draft in <1s on cache hits or queues a worker run on misses.

P1 — Solo planner. Reels and TikToks are how they collect “must visit” ideas during commutes.

  • F0010.1 Accept shared text URLs from the OS share-sheet on both iOS and Android.
  • F0010.2 Filter incoming URLs to the reel allowlist (instagram, tiktok, youtube, youtu.be); silently ignore other shares.
  • F0010.3 Trip-picker bottom sheet — pick from the user’s existing trips, or “Create new trip” pre-filled with the URL.
  • F0010.4 Single API call to existing POST /trips/:id/imports with source_type='video' and the shared URL as source_uri.
  • F0010.5 Show progress / cache-hit feedback inline — when the imports row comes back status='ready' immediately (cache hit), jump straight to the existing review screen.
  • F0010.6 ImportSourceType.video in the Flutter domain model + repository.
  • Sharing files (mp4/mov) — only URLs from share-sheet for now.
  • Background reel pre-fetch — share opens app foreground.
  • Authenticated share when user isn’t signed in — gate behind a “log in to continue” screen.
  • iOS Share Extension full setup (requires Xcode UI; documented in apps/mobile/ios/README.md but not scripted).
  • “Imported by N others” badge — comes after global cache UI lands.
  • As P1, when I’m watching a travel reel on Instagram, I can tap Share → Treeper, pick the trip, and see the draft populate in the review screen without re-typing anything.
[User on Instagram]
tap Share → grid → Treeper
[Treeper opens → cold or warm start]
┌─────────────────────────────┐
│ Save reel to which trip? │
│ ─────────────────────────── │
│ ▢ Bali Aug 2026 │
│ ▢ Vietnam – planning │
│ + Create new trip… │
└─────────────────────────────┘
↓ (pick)
[POST /trips/:id/imports]
- cache HIT → review screen instantly
- cache MISS → review screen with "parsing…" → realtime updates
AC-1 F0010.1 On Android, sharing https://www.instagram.com/p/X/
from Instagram launches Treeper with the URL.
AC-2 F0010.2 Sharing https://example.com/foo (not on allowlist)
is silently ignored — Treeper opens but no sheet.
AC-3 F0010.3 Trip-picker shows all user's non-archived trips +
"Create new trip" affordance.
AC-4 F0010.4 Confirming a trip POSTs to /trips/:id/imports with
source_type='video', source_uri=<shared URL>.
AC-5 F0010.5 If the returned import is status='ready' on first
read, navigate directly to /imports/:id/review.
Otherwise navigate and the existing realtime cubit
handles progress.
AC-6 F0010.6 ImportSourceType.video round-trips through
TripImport.fromJson without loss.

No new endpoints. Reuses:

POST /trips/:id/imports { source_type: "video", source_uri: <url> }
GET /imports/:id
  • pubspec.yaml: receive_sharing_intent: ^1.8.0
  • lib/features/trips/domain/trip_import.dart: add video to ImportSourceType enum + PendingImport.video factory.
  • lib/core/share_intake/share_intake_service.dart (new):
    • subscribes to both cold + warm shared-text streams,
    • validates the host allowlist (same list as backend / worker),
    • emits a SharedReel event with the canonical URL.
  • lib/features/share_intake/view/pick_trip_sheet.dart (new):
    • bottom sheet listing user’s trips + “new trip” CTA,
    • on submit calls ImportsRepository.create(sourceType: video, …),
    • on status='ready' navigates to review screen.
  • lib/app/app.dart: wire ShareIntakeService.start(router) next to DeepLinkHandler.start(router).
  • android/app/src/main/AndroidManifest.xml: intent filter for android.intent.action.SEND + text/plain.
  • ios/Runner/Info.plist + new ShareExtension/ target: documented in ios/README.md. Xcode UI is the canonical path.
  • No iOS Share Extension boilerplate change visible in IDE diff: reviewer should be able to read this PR without touching Xcode.
  • Cold-start latency: app launches and shows the trip picker in < 1.5s on warm cache (Flutter engine already loaded).
  • R1 — iOS Share Extension setup is mostly Xcode UI clicks; if a contributor skips them, share from iOS won’t work. Mitigation: CI smoke job for iOS later, plus a README.
  • R2receive_sharing_intent v1.x had a major redesign; pinned to ^1.8.0. Watch for v2 API changes.
  • Q1 — Should a share into a new trip pre-fill the trip title with “Inspired by ”? Deferred — keep first slice minimal, just open the editor with the URL pending.

Plain feature ship. No flag — when the OS share-sheet shows Treeper, sharing into it Just Works. Old build still ignores share intents until updated.