fix(mobile): iOS share sheet, empty files tab, and stuck upload status

- app.json: add CFBundleDocumentTypes to iOS infoPlist so the app
  appears in the iOS Share Sheet; add ACTION_SEND/SEND_MULTIPLE
  intentFilters for Android share intent support

- src/context/ShareContext.tsx (new): React context that queues files
  received from the share sheet and delivers them to UploadScreen

- app/_layout.tsx: wrap in ShareProvider; add Linking handler
  (makeUrlHandler factory + getInitialURL cold-start + addEventListener
  warm-start) to capture file:// and content:// URLs

- src/services/api.ts: fix FileRecord interface (original_filename,
  nested ProcessingStatus, mime_type); fix UploadResponse interface;
  fix listFiles() (per_page param, unwrap data.files); add
  getFileStatus(fileId) for single-file status polling

- src/screens/FilesScreen.tsx: use file.original_filename and
  file.processing_status.status; fix statusEmoji to use actual backend
  status values (completed/pending/duplicate)

- src/screens/UploadScreen.tsx: consume ShareContext for auto-upload of
  shared files; add 5-second polling loop (search by filename → file_id
  → getFileStatus) to show real-time server processing status;
  uploadFile wrapped in useCallback; proper effect dependency arrays

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-16 15:52:54 +00:00
parent a5ef7e4903
commit 4de6b439ce
8 changed files with 341 additions and 50 deletions
+17 -2
View File
@@ -140,10 +140,24 @@ The app registers itself as a share target so any file can be sent directly to D
1. Open a file in Files, Mail, Safari, or any other app.
2. Tap the **Share** button (iOS) or **Share** (Android).
3. Find and tap **DocuElevate** in the share sheet.
4. The file is immediately uploaded.
4. The file is immediately uploaded and queued for processing.
> **Note:** The app must be installed on the device for it to appear in the share sheet.
#### iOS implementation
`app.json` declares `CFBundleDocumentTypes` (with `LSHandlerRank: Alternate`) inside the iOS `infoPlist`. This tells iOS that DocuElevate can open common document types, making it visible in the share sheet without overriding system defaults. When the user selects DocuElevate, iOS opens the app with a `file://` URL via `application:openURL:options:`.
The root layout listens for this URL via `expo-linking` (`Linking.addEventListener` for warm-start, `Linking.getInitialURL` for cold-start) and forwards it to the Upload screen through `ShareContext`.
#### Android implementation
`app.json` declares `ACTION_SEND` and `ACTION_SEND_MULTIPLE` intent filters for `mimeType: "*/*"` in the `android.intentFilters` section. Incoming content URIs are received the same way as on iOS.
#### Upload status polling
After a file is uploaded the app polls `/api/files?search=<filename>` every 5 seconds to find the corresponding `FileRecord`, then polls `/api/files/{id}` to track the processing status in real time. Polling stops automatically once the status reaches a terminal state (`completed`, `failed`, or `duplicate`).
## Mobile API Endpoints
The backend exposes a dedicated `/api/mobile/` namespace:
@@ -228,7 +242,8 @@ mobile/
├── tsconfig.json
└── src/
├── context/
── AuthContext.tsx # Auth state + SSO login flow
── AuthContext.tsx # Auth state + SSO login flow
│ └── ShareContext.tsx # Shared-file queue (iOS Share Sheet / Android Intent)
├── hooks/
│ └── usePushNotifications.ts # Push token registration
├── screens/