From cb63b48b7831a5f2f971aeed2efd9e6dfeb8d443 Mon Sep 17 00:00:00 2001 From: zjs81 Date: Fri, 20 Mar 2026 02:24:02 -0700 Subject: [PATCH] Add comprehensive documentation for various app features - Introduced "Contacts" documentation detailing the contact management system, types, list, search, and tap actions. - Added "Map & Location" documentation covering map features, interactions, path tracing, and line-of-sight analysis. - Created "Navigation" documentation outlining app flow, QuickSwitchBar, and device screen interactions. - Developed "Notifications" documentation explaining notification types, in-app badges, settings, and rate limiting. - Established "Repeater Management" documentation for managing repeaters and room servers, including CLI access and telemetry. - Compiled "Scanner & Connection" documentation detailing BLE, USB, and TCP connection processes. - Formulated "Settings" documentation outlining access, layout, device info, app settings, node settings, actions, debug options, export features, and about section. --- documentation/README.md | 30 +++ documentation/additional-features.md | 187 ++++++++++++++++++ documentation/ble-protocol.md | 249 ++++++++++++++++++++++++ documentation/channels.md | 164 ++++++++++++++++ documentation/chat-and-messaging.md | 120 ++++++++++++ documentation/contacts.md | 118 +++++++++++ documentation/map-and-location.md | 186 ++++++++++++++++++ documentation/navigation.md | 87 +++++++++ documentation/notifications.md | 92 +++++++++ documentation/repeater-management.md | 186 ++++++++++++++++++ documentation/scanner-and-connection.md | 124 ++++++++++++ documentation/settings.md | 169 ++++++++++++++++ 12 files changed, 1712 insertions(+) create mode 100644 documentation/README.md create mode 100644 documentation/additional-features.md create mode 100644 documentation/ble-protocol.md create mode 100644 documentation/channels.md create mode 100644 documentation/chat-and-messaging.md create mode 100644 documentation/contacts.md create mode 100644 documentation/map-and-location.md create mode 100644 documentation/navigation.md create mode 100644 documentation/notifications.md create mode 100644 documentation/repeater-management.md create mode 100644 documentation/scanner-and-connection.md create mode 100644 documentation/settings.md diff --git a/documentation/README.md b/documentation/README.md new file mode 100644 index 0000000..1367013 --- /dev/null +++ b/documentation/README.md @@ -0,0 +1,30 @@ +# MeshCore Open - Feature Documentation + +MeshCore Open is an open-source Flutter client for MeshCore LoRa mesh networking devices. This documentation covers every user-facing feature, how to access it, and what it does. + +## Table of Contents + +1. [Scanner & Connection](scanner-and-connection.md) - BLE scanning, USB serial, and TCP connection +2. [Navigation](navigation.md) - App flow, device screen, and quick-switch navigation +3. [Contacts](contacts.md) - Contact management, groups, discovery, and sharing +4. [Chat & Messaging](chat-and-messaging.md) - Direct messages, message status, reactions, and retries +5. [Channels](channels.md) - Broadcast channels, communities, and channel chat +6. [Map & Location](map-and-location.md) - Node map, path tracing, line-of-sight, and offline caching +7. [Settings](settings.md) - Device settings, app settings, radio configuration, and exports +8. [Notifications](notifications.md) - System notifications, unread badges, and notification preferences +9. [Repeater Management](repeater-management.md) - Repeater hub, status, CLI, telemetry, and neighbors +10. [Additional Features](additional-features.md) - GIF picker, localization, debug logs, SMAZ compression, and more +11. [BLE Protocol & Data Layer](ble-protocol.md) - Technical reference for the communication protocol and data architecture + +## App Overview + +MeshCore Open connects to MeshCore LoRa mesh radios over BLE, USB, or TCP. Once connected, users can: + +- **Chat** with other mesh nodes via encrypted direct messages +- **Broadcast** on shared channels (public, hashtag, private, or community-scoped) +- **View nodes on a map** with GPS locations, predicted positions, and path traces +- **Manage repeaters** with CLI access, telemetry, neighbor info, and settings +- **Share contacts** via `meshcore://` URIs and QR codes +- **Configure radio settings** including frequency, power, bandwidth, and spreading factor +- **Cache offline maps** for use without internet connectivity +- **Analyze line-of-sight** between nodes with terrain elevation profiles diff --git a/documentation/additional-features.md b/documentation/additional-features.md new file mode 100644 index 0000000..f7b8319 --- /dev/null +++ b/documentation/additional-features.md @@ -0,0 +1,187 @@ +# Additional Features + +## GIF Picker (Giphy Integration) + +### How to Access +In any chat screen (direct or channel), tap the GIF button in the message input bar. + +### What the User Sees +A bottom sheet with a search field and a grid of GIF thumbnails. + +### Key Interactions +- On open, loads trending GIFs (G-rated, 25 results) +- Type to search and press the keyboard submit button (search triggers on submit, not on each keystroke). Clearing the search field reloads trending GIFs +- On network/API errors, a "Retry" button is shown in-place +- Tap a GIF to select it — the chat input shows an inline preview with an X button to dismiss +- Send the message to transmit the GIF reference (`g:`) +- Recipients see the GIF rendered inline via Giphy CDN +- "Powered by Giphy" attribution is always shown at the bottom of the picker +- The bottom sheet occupies 70% of screen height + +--- + +## Localization / Multi-Language Support + +### How to Access +App Settings → Appearance → Language + +### Supported Languages (15) +English, French, Spanish, German, Polish, Slovenian, Portuguese, Italian, Chinese, Swedish, Dutch, Slovak, Bulgarian, Russian, Ukrainian + +### How It Works +- All UI strings go through Flutter's ARB localization system +- Language can follow the system locale or be explicitly overridden +- Changes take effect immediately + +--- + +## Discovered Contacts Screen + +### How to Access +From Contacts screen → overflow menu → "Discovered Contacts" + +### What the User Sees +A list of nodes heard passively over the air but not yet added as contacts. Each shows: +- Color-coded avatar (by type) +- Name +- Short public key +- Last-seen time + +### Key Interactions +- Search bar with debounced filtering +- Sort by last seen or name; filter by type +- **Tap**: Import the contact (adds to your contact list) +- **Long-press**: Add Contact, Copy `meshcore://` URI to clipboard, or Delete +- Overflow menu → "Delete All" (with confirmation) +- Already-known contacts and your own node are filtered out + +--- + +## SMAZ Compression + +### What It Is +An optional per-contact and per-channel text compression feature using the SMAZ algorithm (optimized for short English text). + +### How to Enable +- **Per contact**: Chat screen → info button → toggle "SMAZ compression" +- **Per channel**: Long-press channel → Edit → toggle "SMAZ compression" + +### How It Works +- When enabled, compression is applied using a "compress only if smaller" strategy — the message is only transmitted compressed if the encoded result is actually shorter than the original. Otherwise, the original text is sent uncompressed +- Compressed messages are transmitted with a `s:` prefix followed by base64-encoded data +- Recipients using MeshCore Open will decompress automatically. **Recipients using other software** that is not SMAZ-aware will see garbled `s:...` text +- The codec operates on ASCII. Non-ASCII / non-English text generally does not benefit from compression and may even expand. Best suited for short English messages +- Disabled by default + +--- + +## Community QR Scanner + +### How to Access +From Channels screen → "+" FAB → "Scan Community QR" + +### What the User Sees +A live QR scanner view with instruction text overlay. + +### Key Interactions +- Scan a community QR code shared by another member +- On valid scan: confirmation dialog showing community name and ID +- Option to "Add public channel to device" on join +- If already a member: shows an "Already a member" dialog +- Invalid QR: shows an orange error snackbar + +--- + +## Channel Message Path Viewing + +### How to Access +In a channel chat, tap a message bubble (mobile) or use the "Path" action (desktop). + +### What the User Sees +- Summary card: sender, time, repeat count, path type, observed hops +- "Other Observed Paths" section (if multiple paths detected) +- "Repeater Hops" section listing each hop with hex prefix, resolved name, and GPS coordinates + +### Actions +- **Radar icon**: Opens path trace map for live trace +- **Map icon**: Opens a map with hop markers and polyline +- **Path dropdown**: Switch between observed path variants (if multiple) + +--- + +## Debug Logging + +### BLE Debug Log +**Access**: Settings → BLE Debug Log + +Two views: +- **Frames**: Each BLE frame with direction, description, hex preview, timestamp. Long-press to copy hex. +- **Raw Log RX**: Decoded LoRa packets with route type, payload type, path bytes, and summary. + +### App Debug Log +**Access**: Settings → App Debug Log (must be enabled first in App Settings → Debug) + +Structured log entries with level (Info/Warning/Error), tag, message, and timestamp. + +Both logs support copy-all and clear operations. + +--- + +## Chrome Required Screen + +### When It Appears +Automatically shown on web platforms when a non-Chromium browser is detected. + +### What the User Sees +A full-screen informational page explaining that Web Bluetooth requires a Chromium-based browser. No interactive elements — purely informational. + +--- + +## Path History Service + +### What It Does (Background Service) +Maintains an in-memory LRU cache of up to 50 contacts, each with up to 100 route history entries, tracking: +- Hop count and trip time +- Success/failure counts and route weights +- Flood vs. direct discovery + +### Path Scoring +Paths are scored using a weighted formula: reliability (45%), route weight (20%), latency (25%), and freshness (10%). These weights are internal and not user-configurable. Paths whose weight drops to zero or below are automatically deleted. Flood deliveries that receive an ACK give a weight boost (+0.5) to the specific return path. + +Used internally for: +- **Auto route rotation**: Cycles through known paths using configurable weights on retries, with a diversity window to avoid re-using recently tried paths +- **Path selection**: Picks the best-scored path for each retry attempt +- **Flood statistics**: Tracks flood vs. direct discovery ratios + +--- + +## Message Retry Service + +### What It Does (Background Service) +Handles reliable delivery of outgoing direct messages: +1. Assigns a UUID and sends immediately. Only one message per contact can be in-flight at a time (avoids overflowing the firmware's 8-entry ACK table); subsequent messages are queued +2. Listens for ACK frames matched via SHA-256 hash of `[timestamp][attempt][text][sender_pubkey]` +3. On timeout, retries with exponential backoff: `1000 × 2^retryCount` ms (1s, 2s, 4s, 8s...) +4. Each retry may use a different path (via path history diversity window) +5. After max retries: marks failed but keeps a **30-second grace window** during which a late ACK can still resolve the message to "delivered". Optionally clears the contact's path +6. Reports RTT and path data for quality learning +7. Maintains an ACK hash history (last 50 entries) to handle duplicate ACKs + +### Configurable Settings (App Settings → Messaging) +- Max retries (2–10, default 5) +- Clear path on max retry (on/off) +- Auto route rotation with weight parameters + +--- + +## Timeout Prediction (ML) + +### What It Does (Background Service) +An ML-based service that predicts expected delivery timeouts: +- Collects delivery observations (path length, message size, time since last RX, delivery time) in a sliding window of up to 100 observations (oldest evicted first) +- Requires **10 minimum observations** before first training. After that, retrains every 5 new observations +- Applies a **1.5x safety margin** to raw predictions (the actual timeout issued is 1.5× the model's predicted delivery time) +- Features with zero variance are automatically excluded from training +- Blends per-contact statistics with ML predictions +- Falls back to `3000 + 3000 × pathLength` ms when insufficient data +- Observations are persisted to storage via a 2-second debounced timer (observations within 2s of app termination may be lost) diff --git a/documentation/ble-protocol.md b/documentation/ble-protocol.md new file mode 100644 index 0000000..9f4c1d7 --- /dev/null +++ b/documentation/ble-protocol.md @@ -0,0 +1,249 @@ +# BLE Protocol & Data Layer + +This is a technical reference for the communication protocol and data architecture. + +## Transport Layer + +The app supports three transports, all sharing the same command/response protocol: + +| Transport | Method | Implementation | +|---|---|---| +| Bluetooth LE | Nordic UART Service (NUS) GATT | `flutter_blue_plus` | +| USB Serial | Packet-framed serial | `MeshCoreUsbManager` | +| TCP | Packet-framed socket | `MeshCoreTcpConnector` | + +### BLE (Nordic UART Service) + +- **Service UUID**: `6e400001-b5a3-f393-e0a9-e50e24dcca9e` +- **RX Characteristic** (write to device): `6e400002-b5a3-f393-e0a9-e50e24dcca9e` +- **TX Characteristic** (notify from device): `6e400003-b5a3-f393-e0a9-e50e24dcca9e` + +Raw `Uint8List` payloads are written directly to the RX characteristic. Writes use "write without response" if supported, falling back to "write with response". + +### USB and TCP Framing + +Both use a lightweight packet framing codec: + +``` +TX (host → device): [0x3C][len_lo][len_hi][payload...] +RX (device → host): [0x3E][len_lo][len_hi][payload...] +``` + +- Frame start: `0x3C` (`<`) for outgoing, `0x3E` (`>`) for incoming +- Length: 2-byte little-endian, payload only +- Max payload: 172 bytes +- TCP: `tcpNoDelay: true` (Nagle disabled), writes serialized to prevent interleaving +- USB: 10ms post-write delay between frames + +## Connection State Machine + +``` +enum MeshCoreConnectionState { + disconnected, + scanning, + connecting, + connected, + disconnecting, +} +``` + +## BLE Connection Lifecycle + +1. **Scan** with keyword filters `["MeshCore-", "Whisper-"]` +2. **Connect** with 15-second timeout +3. **Request MTU** 185 bytes (non-web only) +4. **Discover services** and locate NUS +5. **Enable TX notifications** (up to 3 attempts on native) +6. **Subscribe** to TX characteristic for incoming frames +7. **Initial sync**: device info query, time sync, channel sync + +## Auto-Reconnect (BLE Only) + +On unexpected disconnection, auto-reconnect with exponential backoff: +- Delays: 1s, 2s, 4s, 8s, 16s, 30s, 30s... +- Resets on successful connection +- Disabled for manual disconnects +- Not available for USB or TCP + +## Protocol Constants + +| Constant | Value | Description | +|---|---|---| +| Max frame size | 172 bytes | BLE/USB/TCP payload limit | +| Public key size | 32 bytes | Ed25519 public key | +| Max path size | 64 bytes | Maximum path data | +| Max name size | 32 bytes | Maximum node name | +| Max text payload | 160 bytes | Firmware `MAX_TEXT_LEN` | +| App protocol version | 3 | Sent in device query | +| Contact frame size | 148 bytes | Fixed-size contact record | + +## Command Codes (App → Device) + +| Code | Name | Description | +|------|------|-------------| +| 1 | CMD_APP_START | Announce app connection | +| 2 | CMD_SEND_TXT_MSG | Send direct text message | +| 3 | CMD_SEND_CHANNEL_TXT_MSG | Send channel text message | +| 4 | CMD_GET_CONTACTS | Request contact list | +| 5 | CMD_GET_DEVICE_TIME | Query device clock | +| 6 | CMD_SET_DEVICE_TIME | Set device clock | +| 7 | CMD_SEND_SELF_ADVERT | Broadcast own advertisement | +| 8 | CMD_SET_ADVERT_NAME | Set node name | +| 9 | CMD_ADD_UPDATE_CONTACT | Add or update a contact | +| 10 | CMD_SYNC_NEXT_MESSAGE | Request next queued message | +| 11 | CMD_SET_RADIO_PARAMS | Set radio parameters | +| 12 | CMD_SET_RADIO_TX_POWER | Set TX power | +| 13 | CMD_RESET_PATH | Reset contact path | +| 14 | CMD_SET_ADVERT_LATLON | Set advertised location | +| 15 | CMD_REMOVE_CONTACT | Remove a contact | +| 16 | CMD_SHARE_CONTACT | Share contact to mesh | +| 17 | CMD_EXPORT_CONTACT | Export contact as bytes | +| 18 | CMD_IMPORT_CONTACT | Import contact from bytes | +| 19 | CMD_REBOOT | Reboot device | +| 20 | CMD_GET_BATT_AND_STORAGE | Query battery and storage | +| 22 | CMD_DEVICE_QUERY | Query device info | +| 26 | CMD_SEND_LOGIN | Login to repeater/room | +| 27 | CMD_SEND_STATUS_REQ | Request repeater status | +| 30 | CMD_GET_CONTACT_BY_KEY | Get contact by public key | +| 31 | CMD_GET_CHANNEL | Get channel definition | +| 32 | CMD_SET_CHANNEL | Set channel name and PSK | +| 36 | CMD_SEND_TRACE_PATH | Request path trace | +| 38 | CMD_SET_OTHER_PARAMS | Set misc parameters | +| 39 | CMD_GET_TELEMETRY_REQ | Request sensor telemetry | +| 40 | CMD_GET_CUSTOM_VAR | Get custom variables | +| 41 | CMD_SET_CUSTOM_VAR | Set a custom variable | +| 50 | CMD_SEND_BINARY_REQ | Send binary request | +| 57 | CMD_SEND_ANON_REQ | Send anonymous request | +| 58 | CMD_SET_AUTO_ADD_CONFIG | Set auto-add configuration | +| 59 | CMD_GET_AUTO_ADD_CONFIG | Get auto-add configuration | + +## Response / Push Codes (Device → App) + +| Code | Name | Description | +|------|------|-------------| +| 0 | RESP_CODE_OK | Generic success | +| 1 | RESP_CODE_ERR | Generic error | +| 2 | RESP_CODE_CONTACTS_START | Contact list begins | +| 3 | RESP_CODE_CONTACT | Single contact data | +| 4 | RESP_CODE_END_OF_CONTACTS | Contact list complete | +| 5 | RESP_CODE_SELF_INFO | Device self-info response | +| 6 | RESP_CODE_SENT | Message transmitted; carries `[1]=is_flood, [2–5]=ack_hash, [6–9]=estimated_timeout_ms` | +| 7 | RESP_CODE_CONTACT_MSG_RECV | Incoming direct message (v2) | +| 8 | RESP_CODE_CHANNEL_MSG_RECV | Incoming channel message (v2) | +| 10 | RESP_CODE_NO_MORE_MESSAGES | No more queued messages | +| 11 | RESP_CODE_EXPORT_CONTACT | Exported contact data | +| 9 | RESP_CODE_CURR_TIME | Current device time | +| 12 | RESP_CODE_BATT_AND_STORAGE | Battery mV (uint16 LE) + storage used/total (uint32 LE each) | +| 13 | RESP_CODE_DEVICE_INFO | Firmware info | +| 16 | RESP_CODE_CONTACT_MSG_RECV_V3 | Incoming direct message (v3) | +| 17 | RESP_CODE_CHANNEL_MSG_RECV_V3 | Incoming channel message (v3) | +| 18 | RESP_CODE_CHANNEL_INFO | Channel definition | +| 21 | RESP_CODE_CUSTOM_VARS | Custom variables | +| 25 | RESP_CODE_AUTO_ADD_CONFIG | Auto-add flags | +| 0x80 | PUSH_CODE_ADVERT | Known contact re-seen | +| 0x81 | PUSH_CODE_PATH_UPDATED | Better path found; carries the 32-byte public key of the updated contact | +| 0x82 | PUSH_CODE_SEND_CONFIRMED | Delivery ACK from remote; carries ACK hash (4 bytes) + trip time (4 bytes) | +| 0x83 | PUSH_CODE_MSG_WAITING | Offline messages queued | +| 0x85 | PUSH_CODE_LOGIN_SUCCESS | Repeater/room login succeeded | +| 0x86 | PUSH_CODE_LOGIN_FAIL | Repeater/room login failed | +| 0x87 | PUSH_CODE_STATUS_RESPONSE | Repeater status response | +| 0x88 | PUSH_CODE_LOG_RX_DATA | Radio RX data with SNR (int8, units 1/4 dB), RSSI, and raw radio packet | +| 0x89 | PUSH_CODE_TRACE_DATA | Path trace result | +| 0x8A | PUSH_CODE_NEW_ADVERT | New node discovered | +| 0x8B | PUSH_CODE_TELEMETRY_RESPONSE | Sensor telemetry data | +| 0x8C | PUSH_CODE_BINARY_RESPONSE | Binary data response | + +## Data Models + +### Contact +32-byte public key (primary identity), name, type (chat/repeater/room/sensor), flags, path data, GPS coordinates, last-seen timestamp. Parsed from 148-byte firmware frames with this layout: + +``` +[0] = resp_code +[1–32] = public key (32 bytes) +[33] = type (1=chat, 2=repeater, 3=room, 4=sensor) +[34] = flags (bit 0 = favorite) +[35] = path_length +[36–99] = path (64 bytes) +[100–131] = name (32 bytes, null-padded) +[132–135] = timestamp (uint32 LE) +[136–139] = latitude (int32 LE, × 1e-6 degrees) +[140–143] = longitude (int32 LE, × 1e-6 degrees) +[144–147] = last_modified (uint32 LE) +``` + +### Message (Direct) +Sender key, text, timestamp, outgoing flag, status (pending/sent/delivered/failed), message ID (UUID), retry count, ACK hash, trip time, path data, reactions. + +### Channel Message +Sender name, text, timestamp, status (pending/sent/failed), repeater hops, path variants, channel index, reactions, reply threading fields. + +### Channel +Index (0–7), name, 16-byte PSK, unread count. PSK derivation methods for hashtag (SHA-256) and community (HMAC-SHA256) channels. + +### Community +UUID, name, 32-byte secret, hashtag channel list. Shared via QR code. + +## Persistence + +All data is stored via `SharedPreferences` (JSON-serialized). No SQLite or other database. + +| Data | Storage Key Pattern | Scope | +|---|---|---| +| Contacts | `contacts` | Per device identity | +| Messages | `messages_` | Per device + contact | +| Channel Messages | `channel_messages_` | Per device + channel | +| Channels | `channels` | Per device identity | +| Channel Order | `channel_order_` | Per device identity | +| Contact Groups | `contact_groups` | Per device identity | +| Communities | `communities_v1` | Per device identity | +| Unread Counts | `contact_unread_count` | Per device identity | +| Discovered Contacts | `discovered_contacts` | Global | +| App Settings | `app_settings` | Global | +| Path History | `path_history_` | Per contact | + +## Auto-Add Configuration Bitmask + +Used by `CMD_SET_AUTO_ADD_CONFIG` (58) and `RESP_CODE_AUTO_ADD_CONFIG` (25): + +| Bit | Flag | Description | +|-----|------|-------------| +| 0 | 0x01 | Overwrite oldest contact when list is full | +| 1 | 0x02 | Auto-add chat users | +| 2 | 0x04 | Auto-add repeaters | +| 3 | 0x08 | Auto-add room servers | +| 4 | 0x10 | Auto-add sensors | + +## Radio Packet Payload Types + +Seen inside `PUSH_CODE_LOG_RX_DATA` raw packets: + +| Code | Type | +|------|------| +| 0x00 | REQ (request) | +| 0x01 | RESPONSE | +| 0x02 | TXTMSG (text message) | +| 0x03 | ACK | +| 0x04 | ADVERT | +| 0x05 | GRPTXT (group/channel text) | +| 0x06 | GRPDATA (group data) | +| 0x07 | ANONREQ (anonymous request) | +| 0x08 | PATH | +| 0x09 | TRACE | +| 0x0A | MULTIPART | +| 0x0B | CONTROL | +| 0x0F | RAW_CUSTOM | + +## State Management + +Uses Flutter `Provider` with `ChangeNotifier`. The central state holder is `MeshCoreConnector`, which owns all in-memory collections and fires debounced (50ms) `notifyListeners()` to update the UI. In-memory conversations are windowed to 200 messages per contact; older messages remain on disk and are loaded on demand. + +### Data Flow + +1. Raw frames arrive over BLE/USB/TCP +2. First byte is parsed as response/push code +3. Appropriate model factory (`fromFrame()`) parses the data +4. In-memory collections are updated +5. Storage stores are persisted (async) +6. `notifyListeners()` triggers UI rebuilds +7. Screens read current state via getters diff --git a/documentation/channels.md b/documentation/channels.md new file mode 100644 index 0000000..21fb52e --- /dev/null +++ b/documentation/channels.md @@ -0,0 +1,164 @@ +# Channels + +## Overview + +Channels are broadcast group-chat spaces secured by a 16-byte pre-shared key (PSK). Any device with the same channel index and PSK will receive and decrypt channel messages. Unlike direct messages, channel messages are broadcast to the entire mesh. + +Up to 8 channels (indices 0–7) can be active simultaneously on one device. + +## How to Access + +QuickSwitchBar tab 1 (middle) from any main screen. + +## Channel Types + +| Type | Icon | Color | Description | +|---|---|---|---| +| Public | Globe | Green | Fixed well-known PSK; any device can join | +| Hashtag | Hash tag | Blue | PSK derived from the hashtag name via SHA-256; discoverable by convention | +| Private | Lock | Blue | Random PSK; requires out-of-band sharing of the 32-hex key | +| Community | Groups/Tag | Purple | PSK derived via HMAC-SHA256 from a community's shared secret | + +## Channels List Screen + +### What the User Sees + +- **Search bar** with live text filtering (300ms debounce) +- **Sort/filter button** +- **Scrollable list of channel cards**, each showing: + - Type icon with color coding (purple badge overlay for community channels) + - Channel name (or "Channel N" if unnamed) + - Subtitle: "Public channel", "Hashtag channel", "Private channel", or "Community channel - {name}" + - Unread badge (if messages are unread) + - Drag handle (when manual sort is active) +- **"+" FAB** to add a new channel +- **Overflow menu**: Disconnect, Manage Communities (only shown when at least one community exists), Settings + +If no channels exist, an empty state with an "Add Public Channel" shortcut is shown. If a search produces no results, a separate "no results" empty state with a search-off icon is shown. + +Pull-to-refresh (swipe down) forces a re-fetch of channels from the device firmware. + +### Sorting Options + +- **Manual** (default): Drag-and-drop reordering, persisted (drag handles are hidden when a search query is active) +- **A–Z**: Alphabetical +- **Latest messages**: Most recent first +- **Unread**: Most unread first + +## Adding a Channel + +Tap the "+" FAB to open a dialog with six options: + +1. **Create Private Channel** — Enter a name (max 31 characters); a random PSK is generated +2. **Join Private Channel** — Enter a name and a 32-hex PSK (non-hex characters like spaces and dashes are silently stripped, so pasted keys with formatting are accepted) +3. **Join Public Channel** — One tap; uses the well-known public PSK (only shown if no public channel exists) +4. **Join Hashtag Channel** — Enter a hashtag name; PSK is derived from the name. If communities exist, choose between regular hashtag (SHA-256) or community hashtag (HMAC) +5. **Scan Community QR** — Opens QR scanner to join a community +6. **Create Community** — Enter a name; generates a random 32-byte secret; optionally adds a community public channel; shows QR code for sharing + +## Channel Actions (Long-Press / Right-Click) + +| Action | Description | +|---|---| +| Edit | Change name, PSK (with a dice icon to generate a random PSK), or SMAZ compression toggle (compresses outgoing messages to allow longer text within the byte limit) | +| Mute / Unmute | Toggle push notification suppression for this channel | +| Delete | Remove the channel from the device (confirmation required) | + +## Channel Chat + +Tap a channel card to open the channel chat screen. + +### App Bar + +- Type icon (public/private/hashtag) +- Channel name +- Subtitle: "{type} - {N} unread" + +### Message Display + +- Reverse-scrolling list (newest at bottom) +- **Incoming messages**: Colored avatar with sender's initial (or first emoji if name starts with one; color is deterministic from sender name hash), sender name in primary color, message bubble +- **Outgoing messages**: Primary container color bubble with a small status icon: pending (clock), sent (checkmark), or failed (red error circle) +- Automatic older-message loading on scroll-to-top +- Jump-to-bottom button when scrolled up +- **Pinch-to-zoom**: Two-finger zoom (0.8x–1.8x) and double-tap to reset text size +- **Message tracing mode** (when enabled in App Settings): Each bubble additionally shows path prefix bytes (`via XX,YY,...`), a timestamp, and a repeat count icon + +### Message Types in Chat + +- **Plain text** with linkified URLs +- **GIFs** (`g:{gifId}`) rendered inline via Giphy CDN +- **Location pins** (`m:{lat},{lon}|{label}|`) shown as tappable location cards +- **Reactions** displayed as emoji pills below target messages + +### Replies (Channel Chat Only) + +- **Mobile**: Swipe an **incoming** message left to trigger reply (with haptic feedback). You cannot swipe your own outgoing messages. Swipe reply is not available on desktop. +- **All platforms**: Long-press → "Reply" +- Reply banner appears above the input bar with the quoted message (tap X to cancel) +- Sent replies are prefixed `@[{senderName}] {text}` +- Received replies show a bordered quote block inside the bubble; tapping scrolls to the original. Reply previews render GIF thumbnails and location pin icons, not just text. + +### Message Path Viewing + +- **Mobile**: Tap a message bubble to view its routing path +- **Desktop**: Long-press/right-click → "Path" (tapping the bubble does nothing on desktop) +- Opens the Channel Message Path Screen (see [Additional Features](additional-features.md)) + +### Context Actions (Long-Press / Right-Click) + +| Action | Availability | Description | +|---|---|---| +| Reply | All messages | Triggers reply mode | +| Path | Desktop only | Opens message path view | +| Add Reaction | Incoming messages only | Opens emoji picker (cannot react to your own messages) | +| Copy | All messages | Copies text to clipboard | +| Delete | All messages | Removes locally (not from mesh) | + +### Message Path Viewing + +Tap a message bubble to open the Channel Message Path Screen, which shows: +- Each hop in the path as a visual chain +- Known contacts identified by name at each hop +- Observed vs. declared hop counts +- Alternative path variants (if received via multiple paths) +- Map view buttons for geographic path visualization + +## Communities + +Communities are a layer above channels that provide a private namespace. + +### What is a Community? + +A community has a name and a 32-byte random secret. Channel PSKs are derived from this secret: +- **Public channel**: `HMAC-SHA256(secret, "channel:v1:__public__")[:16]` +- **Hashtag channel**: `HMAC-SHA256(secret, "channel:v1:{hashtag}")[:16]` + +Outsiders who don't know the secret cannot discover or join community channels. + +### Sharing a Community + +Communities are shared via QR codes containing a JSON payload: +```json +{"v": 1, "type": "meshcore_community", "name": "...", "k": ""} +``` + +### Managing Communities + +From the channels screen overflow menu → "Manage Communities". Opens a draggable scrollable sheet (resizable 30–90% of screen height): + +- Each community shows its name and a short community ID (first 8 hex characters) +- **Tap a community** to directly show its QR code for sharing +- **Popup menu** per community: + - **Show QR** — displays the QR code for sharing with new members + - **Delete** — removes the community locally and deletes all associated device channels (confirmation dialog warns how many channels will be removed) + +## How Channels Differ from Direct Messages + +| Aspect | Channels | Direct Messages | +|---|---|---| +| Addressing | Broadcast to all nodes with matching PSK | Point-to-point to a specific contact | +| Encryption | Shared PSK (symmetric) | Contact's public key (asymmetric) | +| Sender identity | Plain text prefix in payload | Verified via public key | +| Replies | Supported (swipe or long-press) | Not supported | +| Retry mechanism | No automatic retry | Exponential backoff with path rotation | diff --git a/documentation/chat-and-messaging.md b/documentation/chat-and-messaging.md new file mode 100644 index 0000000..22030d5 --- /dev/null +++ b/documentation/chat-and-messaging.md @@ -0,0 +1,120 @@ +# Chat & Messaging + +## Overview + +The app supports two chat modes: +- **Direct messages**: Encrypted point-to-point messages to individual contacts +- **Channel messages**: Broadcast messages to shared channels (see [Channels](channels.md)) + +This page covers direct messaging. For channel chat, see the Channels documentation. + +## How to Access + +From the Contacts screen, tap any Chat-type contact to open the ChatScreen. + +## Chat Screen Layout + +### App Bar + +- **Title**: Contact name +- **Subtitle**: Current routing path label (e.g., "2 hops", "flood (auto)", "direct (forced)") and unread count. Tapping the subtitle shows the full path details. +- **Action buttons**: + - **Routing mode** (waves icon): Switch between Auto, Direct, and Flood routing + - **Path management** (timeline icon): View recent paths with hop count, round-trip time, age, and success count. Paths are color-coded by direct repeater (green/yellow/red/blue for ranked repeaters, grey for unknown). Tap a path to activate it (the device verifies and confirms via snackbar), long-press to view full path details, set custom paths, or force flood mode. A warning banner appears when history reaches 100 entries. + - **Info** (info icon): Contact info dialog showing type, path, GPS coordinates, public key, and SMAZ compression toggle + +### Message List + +- Scrollable list with newest messages at the bottom +- **Outgoing messages**: Right-aligned, primary color background. **Failed messages** change to a red-toned error container background +- **Incoming messages**: Left-aligned, grey background with a colored avatar (initial letter or first emoji of sender name; color is deterministic from a hash of the sender name) +- Bubble width capped at 65% of screen width +- Hyperlinks rendered as tappable green underlined text +- **Pinch-to-zoom**: Two-finger zoom (0.8x–1.8x) and double-tap to reset +- **Jump to bottom**: Floating button appears when scrolled away from the bottom +- **Lazy loading**: Scrolling to top loads older messages from storage + +### Input Bar + +- **GIF button** (left): Opens GIF picker bottom sheet +- **Text field** (center): Auto-capitalization, enforces UTF-8 byte limit in real-time +- **Send button** (right): Submits the message +- On desktop: Enter/Numpad Enter also submits +- When a GIF is selected, the text field shows an inline GIF preview with a dismiss button + +## Message Types + +| Type | Wire Format | Display | +|---|---|---| +| Plain text | Raw UTF-8 string | Inline text with link detection | +| GIF | `g:` | Inline GIF image from Giphy CDN | +| Location pin | `m:,\|