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