# Mobile App — Social Proximity ## Technology Choice: Flutter We chose **Flutter** over React Native for this project because BLE scanning requires close hardware access. Flutter compiles to native ARM code and communicates with the platform via direct platform channels — no JavaScript bridge between the app logic and the BLE hardware. | | Flutter (chosen) | React Native | |---|---|---| | Language | Dart | TypeScript | | BLE access | Platform channels — native | Via JS bridge | | Performance | Compiles to native | JS runtime overhead | | BLE library | `flutter_blue_plus` | `react-native-ble-plx` | | Platforms | Android + iOS from one codebase | Same | **Dart** is straightforward to learn if you know TypeScript: strongly typed, OOP, async/await, null safety built in. ## BLE Library: `flutter_blue_plus` `flutter_blue_plus` is the most actively maintained Flutter BLE library. It supports: - Scanning for nearby BLE peripherals - Advertising as a BLE peripheral (Android 5+, iOS limited) - Reading/writing GATT characteristics - Connection state management **Required permissions:** _Android (`AndroidManifest.xml`):_ ```xml ``` _iOS (`Info.plist`):_ ```xml NSBluetoothAlwaysUsageDescription Used to detect nearby people with shared interests. ``` ## BLE Flow ``` App starts └─► Check BLE permissions (request if missing) └─► Generate ephemeral BLE token (UUID v4, per-session) └─► Register token + interests with backend (POST /session) User enables "Open to talk" └─► Start BLE advertising (token in manufacturer data) └─► Start BLE scanning for other tokens └─► Open WebSocket to backend (/ws/{token}) Nearby token detected └─► Send detected token to backend (POST /match) └─► If match: WebSocket nudge received └─► Display nudge card to user User disables "Open to talk" or closes app └─► Stop advertising + scanning └─► Close WebSocket └─► Session expires on backend (Redis TTL) ``` ## Project Structure ``` app/ ├── lib/ │ ├── main.dart │ ├── screens/ │ │ ├── onboarding_screen.dart ← Interest selection on first launch │ │ ├── home_screen.dart ← "Open to talk" toggle + nudge display │ │ └── settings_screen.dart ← Manage interests, reset session │ ├── widgets/ │ │ ├── nudge_card.dart ← The nudge notification UI │ │ ├── interest_chip.dart ← Selectable interest tag │ │ └── open_toggle.dart ← Big friendly on/off toggle │ ├── services/ │ │ ├── ble_service.dart ← BLE scan/advertise logic │ │ ├── api_service.dart ← HTTP client (register, match) │ │ └── ws_service.dart ← WebSocket client (nudge receiver) │ └── models/ │ ├── interest.dart │ ├── session.dart │ └── nudge.dart ├── android/ ├── ios/ └── pubspec.yaml ``` ## Screens ### Onboarding (first launch) - Choose interest categories (multi-select chips) - Brief explanation of how the app works - Consent acknowledgement ### Home - Large "Open to talk" toggle — the primary interaction - When active: scanning indicator - Nudge card appears when a match is found - Shows shared interests (no name, no face, no location) - "Say hello" is just a reminder — no in-app chat ### Settings - Manage interest categories - Reset ephemeral identity - Privacy information ## State Management For MVP simplicity: use Flutter's built-in `Provider` or `Riverpod`. Avoid complex state management (no BLoC in MVP). ## Running Locally ```bash cd app flutter pub get flutter run # runs on connected device or emulator flutter run -d android flutter run -d ios ``` **Prerequisites:** - Flutter SDK ≥ 3.x - Android Studio (for Android emulator) or Xcode (for iOS simulator) - Physical device recommended for BLE testing — emulators do not support BLE scanning