file-share/plan.md

3.6 KiB

Android → PC File Drop

Minimal Kotlin Android app that picks files/images and uploads them to a folder on a PC over the local network.

Architecture

Two pieces:

  1. PC receiver — tiny HTTP server that accepts multipart uploads and writes files into a chosen folder.
  2. Android app — one screen, one button: pick files → POST them to the PC.

No cloud, no accounts, no discovery protocol. You type (or QR-scan) the PC's LAN IP once and save it.

PC Receiver

Language: Go (single binary). Go for "double-click and forget."

Behavior:

  • Listen on 0.0.0.0:8787.
  • POST /upload accepts multipart/form-data, saves each part to DROP_DIR with its original filename.
  • Collision policy: append (1), (2), etc.
  • Optional shared-secret header (X-Auth: <token>) so randos on the same Wi-Fi can't dump files on you.
  • GET / returns "ok" for a health check.
  • Log each received file: name, size, source IP.

it is seen on the local panel so that user locally can download

Config:

  • DROP_DIR — where files land (default ~/Drops).
  • AUTH_TOKEN — shared secret (generated on first run, printed + saved to config).
  • PORT — default 8787.

Firewall: open the port on the PC's LAN profile only.

Android App

Stack: Kotlin, Jetpack Compose, single Activity, minSdk 26.

Screens: one.

UI:

  • Text field: PC address (e.g. 192.168.1.42:8787), persisted in DataStore.
  • Text field: auth token, persisted.
  • Big button: "Pick files".
  • Below: list of currently-selected files with progress bars during upload.
  • Snackbar for success/failure per file.

Flow:

  1. Tap button → ActivityResultContracts.OpenMultipleDocuments() (handles images, video, any file; no storage permission needed on modern Android).
  2. For each returned Uri: stream it as a multipart part to http://<address>/upload with the auth header.
  3. Show per-file progress; on 200, mark done; on error, show retry.

Networking: OkHttp with a MultipartBody, streaming from contentResolver.openInputStream(uri) so big videos don't OOM.

Manifest:

  • INTERNET permission.
  • usesCleartextTraffic="true" scoped to local IP ranges via network_security_config.xml (HTTP is fine on LAN; adding TLS is a stretch goal).

Share target (stretch): register as a share target so you can hit "Share → Drop to PC" from the Photos app.

Protocol

POST /upload HTTP/1.1
Host: 192.168.1.42:8787
X-Auth: <token>
Content-Type: multipart/form-data; boundary=...

--boundary
Content-Disposition: form-data; name="file"; filename="IMG_1234.jpg"
Content-Type: image/jpeg

<bytes>
--boundary--

Response: 200 OK with JSON {"saved": "IMG_1234.jpg"} or 4xx/5xx with error text.

Milestones

  1. PC receiver in ~60 lines; test with curl -F file=@foo.jpg http://localhost:8787/upload -H "X-Auth: ...".
  2. Android app scaffold: Compose UI, DataStore for settings, file picker returning URIs.
  3. Wire up OkHttp multipart upload from a URI stream.
  4. Progress + error UI.
  5. Package: PC receiver as a systemd user service (Linux) or Task Scheduler entry (Windows) so it autostarts. Android side sideload the APK.

Stretch

  • QR code on PC receiver's GET / page encoding address + token so first-time setup is scan-once.
  • mDNS advertisement (_filedrop._tcp.local) so the app can discover the PC without typing IPs.
  • TLS with a self-signed cert pinned in the app.
  • Share-target intent filter.
  • Resume interrupted uploads (Content-Range).

Non-goals

  • PC → Android direction (use MTP or a second app instance later).
  • Internet / NAT traversal.
  • Multiple PCs at once (one address at a time is fine).