Skip to content

feat(media-store): backends, phase 4 (dropbox, google drive, icloud)#559

Merged
ericgriffin merged 9 commits into
worktree-media-store-phase3from
worktree-media-store-phase4
Jul 11, 2026
Merged

feat(media-store): backends, phase 4 (dropbox, google drive, icloud)#559
ericgriffin merged 9 commits into
worktree-media-store-phase3from
worktree-media-store-phase4

Conversation

@ericgriffin

@ericgriffin ericgriffin commented Jul 11, 2026

Copy link
Copy Markdown
Member

Summary

Phase 4 of the Media Store program (design spec, section 17): the three managed backends. Dropbox, Google Drive, and iCloud now implement the same MediaObjectStore interface the S3 adapter shipped in Phase 1, so the upload pipeline, worker, queue, resolver, and cache from Phases 1-3 run unchanged over all four providers.

Stacked PR: targets worktree-media-store-phase3 (#557), which targets worktree-media-store-phase2 (#556), which targets worktree-s3-media-store (#550). Merge bottom-up: #550, then #556, then #557, then this.

Changes

  • Dropbox adapter (dropbox_media_object_store.dart): path-native keys under /submersion-media/<key> in the app folder; single-shot upload below the chunk threshold, upload sessions above it with {sessionId, offset} resume state; incorrect_offset restarts fresh; chunked getFile via Range on /files/download. New public session primitives + ranged download + recursive listFolder on DropboxApiClient.
  • Google Drive adapter (google_drive_media_object_store.dart): raw REST over the provider's authenticated client; always-resumable upload sessions with a Content-Range: bytes */total probe to recover the confirmed offset after interruption; file NAME = full store key inside a single appDataFolder folder; chunks are 256 KiB multiples.
  • iCloud adapter (icloud_media_object_store.dart + icloud_media_platform.dart): filesystem operations over the ubiquity container behind an injectable ICloudMediaPlatform (native implementation + directory-backed test/dev implementation); small writes copy, large writes move; reads call downloadIfNeeded for evict-from-local files. Resume is OS-managed (documented deviation: the OS transfer daemon owns partial-transfer state, so resumeStateJson stays unused).
  • Provider-typed attach state: MediaStoreAttachState records which provider a device attached with; pre-phase-4 attachments without a stored type read back as S3, so existing S3 attachments migrate for free.
  • Runtime wiring: mediaStoreRuntimeProvider builds the adapter for the attached provider via shared buildMediaObjectStore(); an unavailable provider (no Dropbox link, no silent Google session, iCloud off) yields a null runtime without clearing the attachment.
  • Per-provider connect flows on MediaStoreService (connectDropbox/connectGoogleDrive/connectICloud): marker ensure/adopt, attach, synced descriptor row; managed providers never touch the S3 keychain entry; unavailable providers throw MediaStoreErrorKind.auth.
  • Provider chooser UI on the Media Storage settings page: SegmentedButton (S3 / Dropbox / Google Drive / iCloud, the latter only on Apple platforms) with hint + connect panels for managed providers; the existing S3 form shows only when S3 is selected. 5 new l10n keys across all 11 locales.
  • Exit e2e: the Phase 3 cross-device video flow re-run over the Dropbox adapter against a protocol-level fake (upload sessions up, ranged downloads back), byte-identical on device B.

Testing

  • New protocol fakes: FakeDropboxServer, FakeDriveServer (MockClient-based, exercising real auth headers, session endpoints, Range requests, and error shapes).
  • All four adapters run the shared media_object_store_contract.dart behavioral suite; per-adapter tests cover large-object session paths, kill-and-resume by request counting (Dropbox appends resume mid-session; Drive probes bytes */total then resumes; S3 unchanged), stale-resume restart, and chunked ranged downloads.
  • Suites: test/features/media_store/ + test/core/services/media_store/ + test/core/services/cloud_storage/ (328), test/features/media/ (566), test/features/backup/ + test/core/data/ + test/features/settings/ (865). dart format . clean, flutter analyze clean.

Manual verification pending

  • Dropbox and Google Drive live smoke against real accounts (fakes cover the protocol; auth flows need real credentials).
  • iCloud two-device hardware smoke (simulator/CI cannot exercise the ubiquity daemon).
  • Carried from earlier phases: MinIO smoke for S3, macOS UI walkthrough/screenshots.

@ericgriffin ericgriffin self-assigned this Jul 11, 2026
@ericgriffin ericgriffin moved this from Backlog to In review in Submersion Release Tracker Jul 11, 2026
@ericgriffin ericgriffin merged commit d570c02 into worktree-media-store-phase3 Jul 11, 2026
@ericgriffin ericgriffin deleted the worktree-media-store-phase4 branch July 11, 2026 04:28
@github-project-automation github-project-automation Bot moved this from In review to Done in Submersion Release Tracker Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant