Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion PROPOSAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Phones get taken and unlocked — sometimes by force. Instant local wipe, aggres

**5. iOS background.**
The killer. iOS aggressively suspends BLE in background. A relay only helps if it works with the phone in a pocket and the screen off. Does anyone have real-world numbers on background Nearby Connections / Core Bluetooth state-restoration behaviour on current iOS?

`
**6. Should this even be an app?**
Honest question. An app store listing is a chokepoint and a "possession = intent" artifact. Sideloaded APK? PWA (no, WebBluetooth can't do this)? Meshtastic + LoRa gets kilometres of range and totally sidesteps cellular, but needs hardware nobody has in their pocket. Is phone-only the right call, or is it just the *convenient* one?

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@ Row 4 is the real proof — it is the difference between a mesh and a Bluetooth

The channel test worth doing deliberately: join `gate4` on two phones with the same passphrase and on a third with the *wrong* one. The third should see nothing while still relaying the traffic — that demonstrates confidentiality and relaying are genuinely independent, which is the core claim of the design.

## Recent Features (Emergency & Quick Chat)

- **Hold and Chat**: Added support for hold-and-chat interactions.
- **Quick Replies**: Added 5 predefined messages to avoid manual typing during critical situations: "I'm safe", "Medical", "Need help", "Unsafe situation", and "Lost my group".
- **Enhanced UI and UX**: Upgraded the overall user interface and experience for faster, more intuitive access during emergencies.

## What is not built yet

- Background relaying (iOS suspends BLE aggressively — the biggest open problem)
Expand Down
Binary file modified docs/banner.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"expo-font": "~57.0.1",
"expo-glass-effect": "~57.0.1",
"expo-image": "~57.0.1",
"expo-linear-gradient": "~57.0.1",
"expo-linking": "~57.0.3",
"expo-localization": "~57.0.1",
"expo-router": "~57.0.7",
Expand Down
67 changes: 67 additions & 0 deletions setupfile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# ProtestChat: Emergency Coordination System Testing Guide

This document explains how to set up, run, and test the new offline emergency coordination features.

## 1. Prerequisites for Testing

Because this is a Bluetooth mesh communication app, **you cannot fully test it on a single simulator**. You need at least two instances running.

**Best testing setup:**
- Two physical iOS/Android devices.
- Bluetooth enabled on both.

**Alternative (Simulators):**
- Some limited mesh testing can be done with two simulators if the transport layer has a local mock/TCP fallback (depending on the `expo-mesh` implementation), but Bluetooth strictly requires physical devices for real-world verification.

## 2. Running the App

Start the Expo development server:
```bash
npm install
npx expo start
```
Scan the QR code with the Expo Go app on two different physical phones.

## 3. Testing the Emergency Flow End-to-End

### Test A: Sending a Medical Emergency
1. On **Phone A** and **Phone B**, open the app. Accept Bluetooth permissions if prompted.
2. Verify both phones show the green "Connected" or "Radio Active" status in the top Status Banner.
3. On **Phone A**, look at the new **EMERGENCY** grid on the Home screen.
4. Tap the red **Medical** (🏥) button.
5. A modal (`/emergency/sos`) will slide up. It says "Send Emergency Alert" and "Medical emergency".
6. **Press and hold** the large SOS button in the center. A ring will expand. Hold for **1.5 seconds** until it turns green and says "Alert sent".
7. The modal will auto-close after 2 seconds.
8. On **Phone A**, the Medical button on the home screen will now be grayed out (rate-limited for 5 minutes).

### Test B: Receiving the Alert
1. Look at **Phone B**.
2. At the top of the Home screen, a red alert should appear in the **NEARBY ALERTS** feed:
- Icon: 🏥
- Title: "Medical emergency"
- Subtitle: "1 person nearby · just now"
- Trust note: "Reported by nearby user — not verified"
3. (Optional) On **Phone B**, tap the "✕" (Dismiss) button. The alert will disappear from the UI.

### Test C: Deduplication and Merging (Anti-Spam)
1. Restart the app on **Phone A** (this clears the in-memory rate limiter).
2. On **Phone A**, send another **Medical** alert.
3. Look at **Phone B** (if you didn't dismiss it) or **Phone C** (a third device).
4. The alert feed should now say: **"2 people nearby"** instead of showing two separate medical alerts. This verifies the `window_bucket` SQLite constraint is merging reports for the same incident in the same 5-minute window.

### Test D: Safe Heartbeat
1. On **Phone B**, tap the wide green **I'm Safe (🟢)** button.
2. Hold the button for 1.5 seconds.
3. On **Phone A**, check the Contacts list. You should see a status indicating that the peer is "Safe" (heartbeat received).

### Test E: Panic Wipe
1. On **Phone B**, tap **SETTINGS** at the top right.
2. Find the panic wipe / delete everything button and trigger it.
3. Return to the Home screen on Phone B.
4. Verify that the Alert Feed is completely empty. The atomic database wipe destroys `emergency_alerts` and `heartbeats` alongside chat messages.

## 4. Expected Background Behaviors

- **15-Minute Expiry:** Leave an alert on the screen. After 15 minutes, the database `sweepExpired()` function runs. The alert will automatically vanish from the feed because 15-minute-old emergencies are no longer actionable.
- **Silent Discarding:** If an older version of the app (without this code) receives these messages, it will silently drop them (`return null` in `decodeBody`), ensuring no crashes on legacy clients.
- **No Chat Pollution:** Emergency messages will **never** appear inside the `#public` chat channel or direct messages. They are routed exclusively to the Alert Feed.
9 changes: 8 additions & 1 deletion src/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,14 @@ function LocalizedLayout() {
options={{ title: copy('nav.newGroup'), presentation: 'modal', animation: 'slide_from_bottom' }}
/>
<Stack.Screen name="settings" options={{ title: copy('nav.settings') }} />
</Stack>
<Stack.Screen
name="emergency/sos"
options={{
presentation: 'modal',
headerShown: false,
}}
/>
</Stack>
</AppProvider>
</KeyboardProvider>
</SafeAreaProvider>
Expand Down
Loading