Engineering notes

Porting this to native Flutter

The web MVP proves the flow. Here is the one-to-one mapping for a Flutter iOS + Android build.

Pairing / QR

Web now: qrcode + jsQR in the browser, session row in Postgres

Flutter later: qr_flutter (show) + mobile_scanner (scan); same session row via supabase_flutter

Session signalling

Web now: Postgres row + Realtime postgres_changes channel

Flutter later: supabase_flutter realtime stream, or a WebRTC data channel for LAN-only commands

Camera (iOS)

Web now: getUserMedia + MediaRecorder

Flutter later: camera plugin over AVCaptureSession; set ResolutionPreset.max for original quality

Microphone (Android)

Web now: getUserMedia audio + MediaRecorder

Flutter later: record / flutter_sound with AudioSource.unprocessed, 48 kHz, 16-bit PCM or AAC 256 kbps

Screen off while recording

Web now: Screen Wake Lock API (best effort)

Flutter later: Android foreground service (flutter_foreground_task) with microphone service type

File transfer

Web now: XHR upload to a private bucket + signed download URL

Flutter later: Same bucket via supabase_flutter, or a direct LAN HTTP transfer over TLS

Sync metadata

Web now: offsetMs / commandStartedAt / micStartedAt in audio_meta JSON

Flutter later: Identical JSON schema (schemaVersion 1); write it into the file's metadata atom

Permissions

Web now: Browser prompts on first getUserMedia call

Flutter later: permission_handler: camera, microphone, NSLocalNetworkUsageDescription, storage

Suggested Flutter structure

lib/
  main.dart
  core/session_service.dart     # create/join/patch + realtime
  core/sync_metadata.dart       # shared JSON schema
  camera/camera_screen.dart     # AVFoundation preview + record
  camera/qr_display_screen.dart
  mic/mic_recorder_service.dart # foreground service
  mic/qr_scan_screen.dart
  mic/send_audio_screen.dart
  ui/widgets.dart               # big black & white buttons