diff --git a/CLAUDE.md b/CLAUDE.md index 55af890e..d3b0cad0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,6 @@ # MeshCore Open - Flutter Client -Open-source Flutter client for MeshCore LoRa mesh networking devices. +Open-source Flutter client for MeshCore LoRa mesh networking devices. Connects to MeshCore-compatible radios over **BLE, TCP, or USB serial** and provides direct/channel chat, contact and channel management, on-map node tracking, repeater administration, and on-device message translation. ## Build Commands @@ -17,6 +17,9 @@ Open-source Flutter client for MeshCore LoRa mesh networking devices. # Build iOS ~/flutter/bin/flutter build ios +# Build versioned web release (uses build_pipe) +~/flutter/bin/dart run build_pipe + # Run static analysis ~/flutter/bin/flutter analyze @@ -28,43 +31,132 @@ Open-source Flutter client for MeshCore LoRa mesh networking devices. ``` lib/ -├── main.dart # App entry point, MaterialApp setup with Provider -├── connector/ -│ └── meshcore_connector.dart # BLE communication layer (MeshCoreConnector) -├── screens/ -│ ├── scanner_screen.dart # BLE device scanning (home screen) -│ ├── device_screen.dart # Connected device hub with navigation -│ ├── chat_screen.dart # Chat interface (placeholder) -│ ├── contacts_screen.dart # Contacts list (placeholder) -│ └── settings_screen.dart # Device info and app settings -└── widgets/ - └── device_tile.dart # Device list item with signal strength +├── main.dart # Entry point: MultiProvider wiring, locale + theme, initial route +├── connector/ # Unified BLE/TCP/USB transport layer +│ ├── meshcore_connector.dart # Central state holder + ChangeNotifier (all transports) +│ ├── meshcore_connector_tcp.dart # TCP transport helper +│ ├── meshcore_connector_usb.dart # USB serial transport helper +│ ├── meshcore_protocol.dart # Frame size + version constants +│ └── meshcore_uuids.dart # Nordic UART UUIDs + scan name prefixes +├── models/ # Plain data classes (Contact, Channel, Message, Community, …) +├── services/ # ChangeNotifier services + IO services (retry, translation, ML, …) +├── storage/ # SharedPreferences-backed stores, scoped per device key +├── helpers/ # Pure utilities (Smaz compression, GIF parsing, scroll helpers) +├── utils/ # Platform / IO / UX utilities (logger, GPX export, dialogs) +├── theme/ # MeshPalette (defined, not yet wired in main.dart) +├── l10n/ # ARB localization for 18 locales +├── icons/ # Custom icon widgets +├── widgets/ # Reusable widgets (AppBar, BatteryUi, QR, jump-to-bottom, …) +└── screens/ # ~26 screens — see Screens section below ``` +## Screens + +All screens are fully implemented (no remaining placeholders). + +### Connection / Scanning +| Screen | Purpose | +|---|---| +| `scanner_screen.dart` | BLE device scan and connect — main entry point | +| `tcp_screen.dart` | Connect to a MeshCore device over TCP/IP | +| `usb_screen.dart` | Connect to a MeshCore device over USB serial | +| `discovery_screen.dart` | Browse all discovered (non-contact) mesh nodes | +| `chrome_required_screen.dart` | Web gate for non-Chrome browsers (BLE unavailable) | + +### Chat / Messaging +| Screen | Purpose | +|---|---| +| `chat_screen.dart` | Direct (private) messaging with a contact | +| `channel_chat_screen.dart` | Group messaging inside a named channel | +| `channels_screen.dart` | List and manage channels (add/edit/delete) | +| `channel_message_path_screen.dart` | Hop-by-hop route a channel message took, with map overlay | + +### Contacts / Neighbors +| Screen | Purpose | +|---|---| +| `contacts_screen.dart` | Full contacts list with previews and management | +| `neighbors_screen.dart` | Nodes directly heard by the connected radio (one-hop) | + +### Repeater Management +| Screen | Purpose | +|---|---| +| `repeater_hub_screen.dart` | Top-level repeater hub; navigates to sub-screens | +| `repeater_status_screen.dart` | Live status of a managed repeater node | +| `repeater_cli_screen.dart` | Raw command-line interface to a repeater | +| `repeater_settings_screen.dart` | Full radio/node settings editor for a repeater | + +### Map / Location +| Screen | Purpose | +|---|---| +| `map_screen.dart` | Main map view of contacts/nodes with live GPS positions | +| `line_of_sight_map_screen.dart` | Terrain LOS analysis between configurable endpoints | +| `path_trace_map.dart` | Animates the hop path a direct message traveled | +| `map_cache_screen.dart` | Download/clear offline map tile cache | +| `community_qr_scanner_screen.dart` | Scan QR to join a mesh community/channel | + +### Settings / Debug / Diagnostics +| Screen | Purpose | +|---|---| +| `settings_screen.dart` | Connected device settings: radio params, identity, GPS | +| `app_settings_screen.dart` | App preferences: theme, units, map source, notifications | +| `app_debug_log_screen.dart` | In-app log viewer (app-layer messages) | +| `ble_debug_log_screen.dart` | In-app log viewer (raw BLE frame traffic) | +| `companion_radio_stats_screen.dart` | RF stats (RSSI, SNR, packet counts) for paired radio | +| `telemetry_screen.dart` | Battery / sensor / environmental telemetry for a contact | + ## Architecture ### State Management -- **Provider** with `ChangeNotifier` pattern -- `MeshCoreConnector` is the central state holder for BLE connection -- Screens use `Consumer` for reactive UI updates + +`Provider` with `ChangeNotifier`. `main.dart` wires a `MultiProvider` with the following: + +| Provider | Role | +|---|---| +| `MeshCoreConnector` | Active transport (BLE/TCP/USB), connection state, frame I/O | +| `MessageRetryService` | ACK tracking and retry scheduling with backoff | +| `PathHistoryService` | Per-contact routing history (LRU cache, 50 contacts) | +| `AppSettingsService` | App preferences (theme, units, locale, notifications) | +| `BleDebugLogService` | Raw BLE frame log buffer | +| `AppDebugLogService` | Structured app log buffer | +| `ChatTextScaleService` | Pinch-to-zoom text scale for chat screens | +| `TranslationService` | On-device LLM translation (llamadart) | +| `UiViewStateService` | Contacts/channels sort/filter/search state | +| `TimeoutPredictionService` | ML linear regression for ACK timeout prediction | +| `StorageService` | Path history + delivery observation persistence | +| `MapTileCacheService` | OSM tile pre-cache | + +Screens consume these via `Consumer` (or `context.watch()` / `context.read()`) for reactive UI. + +### Storage / Persistence + +All stores in `lib/storage/` use `PrefsManager` (a `SharedPreferences` singleton initialized in `main()`). Most stores **scope keys by the first 10 hex chars of the connected device's public key**, so per-radio data is isolated. + +| Store | Persists | +|---|---| +| `message_store`, `channel_message_store` | Direct + channel messages | +| `contact_store`, `contact_discovery_store` | Known + discovered contacts | +| `channel_store`, `channel_order_store`, `channel_settings_store` | Channels, display order, per-channel Smaz toggle | +| `community_store` | Communities (32-byte shared secrets) | +| `contact_group_store`, `contact_settings_store` | Groups, per-contact Smaz toggle | +| `unread_store` | Per-contact unread counts (debounced writes) | + +GGUF translation models are stored as files (not SharedPreferences) via `translation_file_store`. ### Theming - Material 3 design (`useMaterial3: true`) - System-based dark/light mode (`ThemeMode.system`) - Blue color scheme seed +- `lib/theme/mesh_theme.dart` defines a warm-dark `MeshPalette` (phosphor-green accents) but is **not currently wired** in `main.dart` — available for a future redesign -## BLE Protocol +### Localization -### Nordic UART Service (NUS) -- **Service UUID**: `6e400001-b5a3-f393-e0a9-e50e24dcca9e` -- **RX Characteristic**: `6e400002-b5a3-f393-e0a9-e50e24dcca9e` (Write to device) -- **TX Characteristic**: `6e400003-b5a3-f393-e0a9-e50e24dcca9e` (Notify from device) +18 locales supported via Flutter's standard ARB pipeline (`lib/l10n/`): en, de, es, fr, it, pt, ru, uk, bg, hu, ja, ko, nl, pl, sk, sl, sv, zh. Language override comes from `AppSettingsService.settings.languageOverride`. Use the `context.l10n` extension (`lib/l10n/l10n.dart`) for translated strings; contact-type names live in `contact_localization.dart`. -### Device Discovery -- Scans for devices with known name prefixes -- Filters by `platformName` or `advertisementData.advName` +## Transports -### Connection States +`MeshCoreConnector` unifies all three transports under one `ChangeNotifier`. There is **no shared base class** — selection is via the `MeshCoreTransportType { bluetooth, usb, tcp }` enum, and BLE/TCP/USB share the same connection-state enum, send/receive API, and frame protocol. + +### Connection State ```dart enum MeshCoreConnectionState { disconnected, @@ -75,28 +167,136 @@ enum MeshCoreConnectionState { } ``` -### Frame I/O -- **Send**: `MeshCoreConnector.sendFrame(Uint8List data)` -- **Receive**: `MeshCoreConnector.receivedFrames` stream of `Uint8List` +### Frame I/O (all transports) +- **Send**: `MeshCoreConnector.sendFrame(Uint8List data, {String? channelSendQueueId, bool expectsGenericAck})` +- **Receive**: `Stream get receivedFrames` +- **Protocol constants** (`meshcore_protocol.dart`): `maxFrameSize = 172`, `maxTextPayloadBytes = 160`, `appProtocolVersion = 4` + +### BLE — Nordic UART Service (NUS) +- **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` +- **Discovery**: scans for devices whose name starts with `MeshCore-`, `Whisper-`, `WisCore-`, `Seeed`, `Lilygo`, `HT-`, or `LowMesh_MC_` (filters on both `platformName` and `advertisementData.advName`) +- **Linux**: `linux_ble_pairing_service.dart` falls back to `bluetoothctl` when BlueZ agent prompts fail + +### TCP +- Manual host/port entry, persisted via `AppSettingsService` (`tcpServerAddress`, `tcpServerPort`) +- UI hint: `192.168.40.10` / port `5000` +- Disabled on web (`PlatformInfo.isWeb`) +- API: `MeshCoreConnector.connectTcp(host: ..., port: ...)` + +### USB Serial (flserial) +- Default baud rate: `115200` +- Port enumeration: `MeshCoreConnector.listUsbPorts()` +- COBS-framed packets via `usb_serial_frame_codec.dart` +- macOS device-name resolution via `ioreg` (`utils/macos_usb_device_names.dart`) +- API: `MeshCoreConnector.connectUsb(portName: ..., baudRate: 115200)` ## Dependencies +App version: `8.0.0+11` — Dart SDK constraint: `^3.9.2` + +**Connectivity** + | Package | Version | Purpose | |---------|---------|---------| -| flutter_blue_plus | ^2.1.0 | BLE communication | -| provider | ^6.1.5+1 | State management | -| cupertino_icons | ^1.0.8 | iOS-style icons | +| flutter_blue_plus | ^2.1.0 | BLE scanning, connecting, and UART data transfer | +| flutter_blue_plus_platform_interface | ^8.2.1 | Platform-interface layer required by flutter_blue_plus | +| flserial | git (MeshEnvy fork) | USB serial transport for wired device connections (TODO: upstream pending) | + +**State / Storage** + +| Package | Version | Purpose | +|---------|---------|---------| +| provider | ^6.1.5+1 | ChangeNotifier-based state management across screens | +| shared_preferences | ^2.2.2 | Persistent key-value storage for user settings | +| path_provider | ^2.1.5 | Locates platform-appropriate directories for file I/O | + +**Crypto** + +| Package | Version | Purpose | +|---------|---------|---------| +| crypto | ^3.0.3 | SHA/HMAC hashing used in message authentication | +| pointycastle | ^4.0.0 | AES encryption/decryption for channel and direct messages | +| uuid | ^4.3.3 | Generates UUIDs for message and contact identity | + +**Maps & Location** + +| Package | Version | Purpose | +|---------|---------|---------| +| flutter_map | ^8.2.2 | Interactive tile map for node positions and path traces | +| latlong2 | ^0.9.1 | LatLng coordinate type used throughout map and GPS code | +| gpx | ^2.3.0 | Export node paths as GPX track files | + +**UI** + +| Package | Version | Purpose | +|---------|---------|---------| +| material_symbols_icons | ^4.2906.0 | Extended Material Symbols icon set (line-of-sight, etc.) | +| flutter_svg | ^2.0.10+1 | Renders SVG assets (custom icons such as LoS indicator) | +| cached_network_image | ^3.4.1 | Caches map tile images downloaded over the network | +| flutter_cache_manager | ^3.4.1 | Underlying cache manager used by cached_network_image | +| flutter_linkify | ^6.0.0 | Auto-detects and makes URLs tappable in chat messages | +| mobile_scanner | ^7.1.4 | QR/barcode scanning for contact and channel import | +| qr_flutter | ^4.1.0 | Generates QR codes for sharing contacts and channels | +| cupertino_icons | ^1.0.8 | iOS-style icon font (bundled for completeness) | +| characters | ^1.4.0 | Unicode-aware string operations for message text handling | + +**Notifications / Background** + +| Package | Version | Purpose | +|---------|---------|---------| +| flutter_local_notifications | ^20.1.0 | Shows local push notifications for incoming messages | +| flutter_foreground_task | ^9.2.0 | Keeps the app alive in background to maintain BLE/USB connection | + +**ML / AI** + +| Package | Version | Purpose | +|---------|---------|---------| +| ml_algo | ^16.0.0 | OLS regression used in `timeout_prediction_service.dart` to predict message ACK timeouts | +| ml_dataframe | ^1.0.0 | DataFrame input format required by ml_algo | +| llamadart | >=0.6.8 <0.7.0 | On-device LLM inference used in `translation_service.dart` for message translation | + +**Misc** + +| Package | Version | Purpose | +|---------|---------|---------| +| http | ^1.2.0 | Fetches tile URLs and any remote API calls | +| url_launcher | ^6.3.0 | Opens URLs in the system browser from linkified chat text | +| share_plus | ^12.0.1 | Shares files (e.g. exported GPX tracks) via the system share sheet | +| package_info_plus | ^9.0.0 | Reads app version/build number displayed in settings | +| web | ^1.1.1 | Web-platform APIs for USB serial and browser detection on Flutter Web | +| intl | any | Internationalization and locale formatting (required by flutter_localizations) | +| build_pipe | ^0.3.1 | CI/CD build pipeline configuration (web release builds with versioned assets) | ## Platform Configuration ### Android (`android/app/src/main/AndroidManifest.xml`) -- `BLUETOOTH`, `BLUETOOTH_ADMIN` (API 30 and below) -- `BLUETOOTH_SCAN`, `BLUETOOTH_CONNECT`, `BLUETOOTH_ADVERTISE` (API 31+) -- `ACCESS_FINE_LOCATION`, `ACCESS_COARSE_LOCATION` (for BLE scanning) +- `INTERNET` (map tiles, translation model downloads) +- `BLUETOOTH`, `BLUETOOTH_ADMIN` (API ≤ 30) +- `BLUETOOTH_SCAN` (with `neverForLocation`), `BLUETOOTH_CONNECT`, `BLUETOOTH_ADVERTISE` (API 31+) +- `ACCESS_FINE_LOCATION`, `ACCESS_COARSE_LOCATION` (BLE scanning on API ≤ 30) +- `POST_NOTIFICATIONS` (API 33+) +- `FOREGROUND_SERVICE`, `FOREGROUND_SERVICE_CONNECTED_DEVICE` (background BLE/USB connection) +- `WAKE_LOCK` +- `CAMERA` (QR scanning, declared as optional feature) +- USB host hardware feature (optional) + +`flutter_foreground_task` registers a `ForegroundService` with `foregroundServiceType="connectedDevice"` and `stopWithTask="false"`. + +**Build config (`android/app/build.gradle.kts`)**: `applicationId = com.meshcore.meshcore_open`, NDK `29.0.14206865`, Java 8 core-library desugaring (`desugar_jdk_libs:2.1.4`), release signing via `key.properties` (debug fallback). ### iOS (`ios/Runner/Info.plist`) -- `NSBluetoothAlwaysUsageDescription` -- `NSBluetoothPeripheralUsageDescription` +- `NSBluetoothAlwaysUsageDescription`, `NSBluetoothPeripheralUsageDescription` +- `NSCameraUsageDescription` (QR scanning to join communities) +- Background modes: `bluetooth-central` +- `LSApplicationQueriesSchemes`: `http`, `https` + +### Web (`web/`) +PWA scaffold present but boilerplate (`manifest.json` and `index.html` are unmodified Flutter defaults). BLE is unsupported in browsers; TCP and Web Serial USB may work in Chrome only. `ChromeRequiredScreen` gates non-Chrome web users. Versioned releases are produced via `build_pipe` (`?v=` cache busting, no service worker). + +### Desktop +`linux/`, `windows/`, and `macos/` directories are present as Flutter scaffolds. No app-specific native config has been added; BLE on desktop has not been validated. ## Coding Conventions @@ -123,14 +323,14 @@ enum MeshCoreConnectionState { | File | Purpose | |------|---------| -| `lib/connector/meshcore_connector.dart` | All BLE logic - scanning, connecting, data transfer | -| `lib/screens/scanner_screen.dart` | Entry point UI, device list | -| `lib/main.dart` | App configuration, theme, Provider setup | -| `pubspec.yaml` | Dependencies and project metadata | - -## Placeholder Screens - -The following screens are implemented as placeholders and need full implementation: -- `chat_screen.dart` - Mesh chat functionality -- `contacts_screen.dart` - Contact management -- `settings_screen.dart` - Radio settings, node identity, location (partially implemented) +| `lib/main.dart` | App configuration, MultiProvider setup, theme, locale, initial route | +| `lib/connector/meshcore_connector.dart` | Unified BLE/TCP/USB transport state holder | +| `lib/connector/meshcore_protocol.dart` | Frame size limits and protocol version | +| `lib/connector/meshcore_uuids.dart` | NUS UUIDs and BLE scan name prefixes | +| `lib/services/app_settings_service.dart` | App-wide settings (`AppSettings` JSON in SharedPreferences) | +| `lib/services/storage_service.dart` | Path history + delivery observation persistence | +| `lib/services/message_retry_service.dart` | ACK tracking + retry scheduling | +| `lib/services/translation_service.dart` | On-device LLM translation (llamadart) | +| `lib/storage/prefs_manager.dart` | SharedPreferences singleton initialized in `main()` | +| `lib/screens/scanner_screen.dart` | Home screen — BLE scan and connect | +| `pubspec.yaml` | Dependencies and project metadata (current version `8.0.0+11`) | diff --git a/documentation/additional-features.md b/documentation/additional-features.md index f7b83192..5dfd2686 100644 --- a/documentation/additional-features.md +++ b/documentation/additional-features.md @@ -25,8 +25,8 @@ A bottom sheet with a search field and a grid of GIF thumbnails. ### 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 +### Supported Languages (18) +English, French, Spanish, German, Polish, Slovenian, Portuguese, Italian, Chinese, Swedish, Dutch, Slovak, Bulgarian, Russian, Ukrainian, Hungarian, Japanese, Korean ### How It Works - All UI strings go through Flutter's ARB localization system @@ -185,3 +185,77 @@ An ML-based service that predicts expected delivery timeouts: - 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) + +--- + +## On-Device Message Translation + +### What It Is +An optional on-device translation service powered by an embedded LLM (llamadart, running GGUF models). Translation runs entirely on-device — no data leaves the app. + +### How to Access +Tap the translate button on any received message. On first use, the GGUF model file is downloaded and cached locally. + +### How It Works +- Model files are managed by `TranslationFileStore`; download progress is shown in-place +- Translation runs via `TranslationService` using the llamadart CPU backend (arm64 and x64 on Android) +- Translated text is shown in `TranslatedMessageContent` as an inline overlay on the original message bubble +- Each translation is cached; re-tapping shows the cached result without re-running inference + +--- + +## Emoji Reactions + +### How to Access +Long-press a message bubble in any direct or channel chat, then select a reaction emoji. + +### What the User Sees +An emoji picker inline with common reactions. Selected reactions appear below the message bubble with a count. + +### How It Works +- Implemented via `emoji_picker.dart` and `reaction_helper.dart` +- Reactions are transmitted as a special message type visible to all participants with MeshCore Open + +--- + +## Linkification + +### What It Does +URLs and `meshcore://` URIs in received messages are automatically detected and rendered as tappable links. + +### How It Works +- Powered by the `flutter_linkify` package via `link_handler.dart` +- Tapping a URL opens the system browser; tapping a `meshcore://` URI imports the contact + +--- + +## GPX Export + +### How to Access +Settings → Export section (three options: Export Repeaters, Export Contacts, Export All). + +### What It Does +Exports contacts with GPS coordinates to a `.gpx` file via the OS share sheet. Not available on web. + +--- + +## Pinch-to-Zoom Chat Text + +### What It Does +Users can pinch to scale all chat text up or down within a session. + +### How It Works +- Implemented via `ChatTextScaleService` and `ChatZoomWrapper` +- Scale range: 0.8× to 1.8× +- The chosen scale persists across the session via the service + +--- + +## Background Service (Android) + +### What It Does +On Android, a foreground service (`background_service.dart`) keeps the BLE connection and message handling alive when the app is in the background. On other platforms this is a no-op. + +### User Impact +- A persistent notification appears while the service is running +- Messages are received and retry logic continues even when the app is not in the foreground diff --git a/documentation/ble-protocol.md b/documentation/ble-protocol.md index ec240948..f9d2acb3 100644 --- a/documentation/ble-protocol.md +++ b/documentation/ble-protocol.md @@ -33,7 +33,6 @@ RX (device → host): [0x3E][len_lo][len_hi][payload...] - 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 @@ -53,9 +52,11 @@ enum MeshCoreConnectionState { - `MeshCore-` - `Whisper-` - `WisCore-` + - `Seeed` + - `Lilygo` - `HT-` - `LowMesh_MC_` -2. **Connect** with 15-second timeout +2. **Connect** with 15-second timeout (6 seconds on Linux) 3. **Request MTU** 185 bytes (non-web only) 4. **Discover services** and locate NUS 5. **Enable TX notifications** (up to 3 attempts on native) @@ -79,7 +80,7 @@ On unexpected disconnection, auto-reconnect with exponential backoff: | 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 | +| App protocol version | 4 | Sent in device query | | Contact frame size | 148 bytes | Fixed-size contact record | ## Command Codes (App → Device) diff --git a/documentation/channels.md b/documentation/channels.md index 21fb52e8..49db176a 100644 --- a/documentation/channels.md +++ b/documentation/channels.md @@ -28,7 +28,6 @@ QuickSwitchBar tab 1 (middle) from any main screen. - **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 @@ -70,9 +69,9 @@ Tap a channel card to open the channel chat screen. ### App Bar -- Type icon (public/private/hashtag) +- Type icon: globe for public channels, tag (#) for all other channel types - Channel name -- Subtitle: "{type} - {N} unread" +- Subtitle: "{Public|Private} • {N} unread" (e.g., "Public • 3 unread") ### Message Display @@ -113,17 +112,9 @@ Tap a channel card to open the channel chat screen. | 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 | +| Mark as Unread | Incoming messages only | Marks this message and all subsequent incoming messages as unread | | 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. diff --git a/documentation/chat-and-messaging.md b/documentation/chat-and-messaging.md index 22030d52..baf2ab8d 100644 --- a/documentation/chat-and-messaging.md +++ b/documentation/chat-and-messaging.md @@ -37,6 +37,7 @@ From the Contacts screen, tap any Chat-type contact to open the ChatScreen. ### Input Bar - **GIF button** (left): Opens GIF picker bottom sheet +- **Translation button** (optional, between GIF and text field): Shown only when translation is enabled in App Settings. Tap to configure outgoing-message translation language and on/off toggle. - **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 @@ -66,8 +67,8 @@ Outgoing messages display a status indicator: When enabled in App Settings, additional metadata appears inside each bubble: - Timestamp (HH:MM) -- Retry count (e.g., "Retry 2 of 4") -- Status icon +- Retry count (e.g., "Retry 2 of 4") — only shown for outgoing messages where at least one retry has occurred +- Status icon (outgoing only) - Round-trip time in seconds (if delivered) ## Message Length Limits @@ -86,7 +87,7 @@ When a direct message is sent: 1. The app computes an expected ACK hash: `SHA256([timestamp][attempt][text][selfPubKey])[0:4]` — matching the firmware's hash calculation. If SMAZ compression is enabled, the compressed text (not the original) is hashed 2. On device acknowledgment (`RESP_CODE_SENT`), the message transitions to "sent" and a timeout timer starts -3. **Timeout duration**: Preferably from the ML timeout prediction service; otherwise `3000 + 3000 × path_length` milliseconds (15000ms for flood) +3. **Timeout duration**: Preferably from the ML timeout prediction service; otherwise calculated from LoRa airtime physics: `500 + (airtime × 6 + 250) × (pathLength + 1)` ms for direct paths, `500 + 16 × airtime` ms for flood (airtime is estimated from the radio's current spreading factor, bandwidth, and coding rate) 4. On timeout, the message is retried with **exponential backoff**: `1000 × 2^retryCount` ms (1s, 2s, 4s, 8s, 16s...) 5. **Max retries**: Configurable (default 5, range 2–10) 6. After max retries, the message is marked "failed" — but a **30-second grace window** remains during which a late ACK can still resolve the message to "delivered" @@ -115,6 +116,7 @@ Add emoji reactions to incoming messages (not your own): | Add reaction | Incoming messages only | Opens emoji picker | | View path | Mobile: tap bubble directly; Desktop: long-press/right-click menu | Shows message routing path | | Copy | All messages | Copies text to clipboard | +| Mark as Unread | Incoming messages only | Marks this message and all subsequent incoming messages as unread | | Delete | All messages | Removes locally (not from mesh) | | Retry | Failed outgoing messages | Re-sends the message | | Open chat with sender | Room server chats | Opens 1:1 chat with the message sender | diff --git a/documentation/contacts.md b/documentation/contacts.md index 1a94ba27..7ff5ad79 100644 --- a/documentation/contacts.md +++ b/documentation/contacts.md @@ -73,7 +73,8 @@ Groups are stored per radio identity (scoped by public key). | Action | Availability | Description | |---|---|---| -| Path Trace / Ping | Repeaters, Rooms (always); Chat if `pathLength > 0` | Opens PathTraceMapScreen. Label shows "Ping" when no path bytes are known, "Path Trace" otherwise | +| Ping | Repeaters (always) | Opens PathTraceMapScreen targeting the repeater | +| Path Trace | Rooms (always); Chat/Sensor if `pathLength > 0` | Opens PathTraceMapScreen. For rooms, label shows "Ping" when no path bytes are known, "Path Trace" when path bytes are available | | Manage Repeater | Repeaters only | Login dialog → RepeaterHubScreen | | Room Login | Rooms only | Login dialog → ChatScreen | | Room Management | Rooms only | Login dialog → RepeaterHubScreen (management mode) | diff --git a/documentation/map-and-location.md b/documentation/map-and-location.md index f293abe3..93ba6345 100644 --- a/documentation/map-and-location.md +++ b/documentation/map-and-location.md @@ -25,7 +25,7 @@ All contacts with known GPS coordinates are plotted: | Room | Purple | Meeting room | | Sensor | Orange | Sensors | -Node name labels appear automatically at zoom level 12 and above. +Node name labels appear automatically at zoom level 14 and above. ### Shared Map Pins (Flag Icons) Location pins shared in chat messages are displayed as flags: @@ -88,10 +88,10 @@ Shows a bottom sheet with: - **Set as my location**: Updates your device's advertised location ### Filter Dialog (FAB) -Toggle visibility of: chat nodes, repeaters, other nodes, guessed locations, discovery contacts. +Toggle visibility of: chat nodes, repeaters, other nodes, guessed locations, discovery contacts, overlapping markers (stacked markers at similar coordinates), and shared map pins (flag markers). Additional filters: - **Key prefix filter**: Show only contacts whose public key starts with a given prefix -- **Last-seen time slider**: From 1 hour to "all time" +- **Last-seen time slider**: Exponential scale from near-zero to 6 months, with "all time" at the top end ### Legend Card (Top-Right) Shows node count and pin count. Tappable to expand a legend of all marker types. diff --git a/documentation/navigation.md b/documentation/navigation.md index 90031222..b0994fd4 100644 --- a/documentation/navigation.md +++ b/documentation/navigation.md @@ -22,31 +22,16 @@ The QuickSwitchBar is a Material 3 `NavigationBar` with a frosted-glass visual t Tapping a tab replaces the current screen with a subtle fade + slight horizontal nudge transition (220ms forward, 200ms reverse). The back button is suppressed on all three main screens — navigation between them is flat, not stacked. All icons use outline variants (`people_outline`, `tag`, `map_outlined`) following Material 3 conventions. -## Device Screen +## Disconnection -The Device Screen is a transitional hub that shows after connection. In practice, the app navigates directly to Contacts after connecting, but the Device Screen is reachable via the QuickSwitchBar. - -### What the User Sees - -**App Bar**: -- Left: Battery indicator chip (tappable — toggles between percentage and voltage display). Icon changes based on level: `battery_unknown` when data unavailable, `battery_alert` (orange) at 15% or below, `battery_full` otherwise -- Left-aligned title (`centerTitle: false`): Two-line layout — small grey "MeshCore" label above the device name in bold -- Right: Disconnect button (`bluetooth_disabled` crossed-out icon) and Settings button (tune icon) - -**Body**: -- **Connection Card**: Device avatar, device name, device ID, "Connected" chip, and battery chip -- **Quick Switch** section: The QuickSwitchBar widget for navigating to Contacts/Channels/Map - -### Disconnection - -- The disconnect button shows a confirmation dialog before disconnecting +- The disconnect button (available in the Settings screen and other main screens) shows a confirmation dialog before disconnecting - If the device disconnects unexpectedly, the app automatically navigates back to the Scanner screen (fires after the current frame completes via a post-frame callback) - This auto-navigation behavior (`DisconnectNavigationMixin`) is shared across all main screens ## Theme and Locale - **Theme mode** is user-configurable in App Settings (System / Light / Dark) — not locked to system -- **Language** can be overridden to one of 15 supported languages, or follow the system locale +- **Language** can be overridden to one of 18 supported languages, or follow the system locale - On web, if a non-Chromium browser is detected, the app shows a `ChromeRequiredScreen` instead of the Scanner (Web Bluetooth requires Chromium) ## Full Navigation Graph diff --git a/documentation/notifications.md b/documentation/notifications.md index 0eb25742..7db9f0fa 100644 --- a/documentation/notifications.md +++ b/documentation/notifications.md @@ -73,7 +73,7 @@ There is no per-contact muting. The notification system prevents notification storms: - **Minimum interval**: 3 seconds between individual notifications -- **Batch window**: If multiple notifications arrive within 5 seconds, they are combined into a single summary notification on a fourth Android channel (`batch_summary`): "MeshCore Activity — 2 messages, 1 channel message, 3 new nodes". Note: batch summaries are Android-only; on Apple platforms individual notifications are shown +- **Batch window**: If multiple notifications arrive within 5 seconds, they are combined into a single summary notification on a fourth Android channel (`batch_summary`). The title is "MeshCore Activity" and the body lists the grouped counts (e.g., "2 messages, 1 channel message, 3 new nodes"). Batch summaries are Android-only; queued notifications that overflow the batch window are silently dropped on other platforms ## Notification Clearing diff --git a/documentation/repeater-management.md b/documentation/repeater-management.md index be5015fa..754d4e28 100644 --- a/documentation/repeater-management.md +++ b/documentation/repeater-management.md @@ -17,8 +17,8 @@ From the Contacts screen: - Password field with show/hide toggle - "Save password" checkbox (persists for future logins). If a saved password exists, it is pre-filled and the checkbox is pre-checked, making login one-tap - Routing mode selector and "Manage Paths" link are available directly in the dialog (configure routing before login) -- Auto-retries up to 5 times on timeout, showing progress ("Attempt 2 of 5"). A wrong password stops immediately after the first attempt — only timeouts trigger retries -- After 5 failed attempts, further login attempts are blocked +- Auto-retries up to 5 times on timeout, showing progress ("Attempt 2 of 5"). A wrong password (explicit failure response) stops immediately — only timeouts trigger retries +- If auto-clock-sync is enabled for this repeater (configured in Repeater Settings), a `clock sync` command is sent automatically on successful login --- @@ -28,15 +28,17 @@ The central management screen showing: - **Header card**: Repeater name, short public key, path label, GPS coordinates (if known) - **Battery chemistry selector**: NMC / LiFePO4 / LiPo (saved per repeater) -- **Management tool cards** (full-width cards with chevron arrows, not a grid). Title dynamically shows "Repeater Management" or "Room Management" based on contact type: +- **Management tool cards** (full-width cards with chevron arrows, not a grid). Title dynamically shows "Repeater Management" or "Room Management" (admin) or "Repeater Guest" / "Room Guest" (guest) based on contact type and login result: -| Card | Destination | -|---|---| -| Status | Repeater Status Screen | -| Telemetry | Telemetry Screen | -| CLI | Repeater CLI Screen | -| Neighbors | Neighbors Screen | -| Settings | Repeater Settings Screen | +| Card | Destination | Visibility | +|---|---|---| +| Status | Repeater Status Screen | All users | +| Telemetry | Telemetry Screen | All users | +| CLI | Repeater CLI Screen | Admin only | +| Neighbors | Neighbors Screen | All users | +| Settings | Repeater Settings Screen | Admin only | + +The battery chemistry selector and CLI/Settings cards are hidden from guest users. --- @@ -47,26 +49,28 @@ The central management screen showing: Three information cards: **System Information**: -- Battery percentage -- Uptime -- Queue length -- Error flags +- Battery percentage and voltage (e.g. "85% / 3.95V"), using the battery chemistry set in the hub screen - Clock at login time +- Uptime (days/hours/minutes/seconds) +- Queue length +- Debug flags (error event count) **Radio Statistics**: - Last RSSI and SNR - Noise floor -- TX and RX airtime +- TX airtime and RX airtime **Packet Statistics**: -- Packets sent, received, and duplicates -- Broken down by flood vs. direct +- Packets sent and received, each broken down by flood vs. direct +- Duplicates, broken down by flood vs. direct +- Channel utilization (% of uptime used by TX + RX) ### Key Interactions - Auto-queries the repeater on open; shows a loading spinner until data arrives -- On timeout: red snackbar error. On success: data appears with a green snackbar confirmation -- Pull-to-refresh or refresh button to re-query +- On timeout: red snackbar error. On success: data appears in-place (no extra snackbar) +- Pull-to-refresh or refresh button in the app bar to re-query - Routing mode popup and path management dialog in app bar (these controls appear on **all** management sub-screens, not just Status) +- Accepts both binary `RESP_CODE_STATUS_RESPONSE` frames and legacy JSON text responses --- @@ -76,7 +80,7 @@ A terminal-style interface for sending commands directly to the repeater. ### What the User Sees -- **Quick-command bar** (horizontal scroll): Shortcut buttons for common commands (get name, get radio, get tx, neighbors, ver, advert, clock) +- **Quick-command bar** (horizontal scroll): Shortcut buttons for 9 common commands (advert, get name, get radio, get tx, discover.neighbors, neighbors, ver, clock, clock sync) - **Command history list**: Sent commands in primary color, responses in secondary color - **Input bar**: Up/down history arrows, monospace text field with `> ` prefix, send button @@ -92,9 +96,13 @@ A terminal-style interface for sending commands directly to the repeater. ### Available CLI Commands -**General**: `advert`, `reboot`, `clock`, `password`, `ver`, `clear stats` +The in-app help reference (help icon) documents all known commands. Categories: -**Settings**: `set name`, `set af`, `set tx`, `set repeat`, `set allow.read.only`, `set flood.max`, `set int.thresh`, `set agc.reset.interval`, `set multi.acks`, `set advert.interval`, `set flood.advert.interval`, `set guest.password`, `set lat`, `set lon`, `set radio`, `set rxdelay`, `set txdelay`, `set direct.txdelay`, `set bridge.*`, `set adc.multiplier`, `tempradio`, `setperm` +**General**: `advert`, `advert.zerohop`, `reboot`, `clock`, `clock sync`, `password`, `ver`, `clear stats`, `erase`, `poweroff`, `shutdown`, `clkreboot`, `start ota`, `time`, `board`, `discover.neighbors`, `powersaving`, `stats-packets`, `stats-radio`, `stats-core` + +**Get**: `get name`, `get role`, `get public.key`, `get prv.key`, `get repeat`, `get tx`, `get freq`, `get radio`, `get radio.rxgain`, `get af`, `get dutycycle`, `get int.thresh`, `get agc.reset.interval`, `get multi.acks`, `get allow.read.only`, `get advert.interval`, `get flood.advert.interval`, `get guest.password`, `get lat`, `get lon`, `get rxdelay`, `get txdelay`, `get direct.txdelay`, `get flood.max`, `get owner.info`, `get path.hash.mode`, `get loop.detect`, `get acl`, `get bridge.*`, `get adc.multiplier`, `get bootloader.ver` + +**Set**: `set name`, `set af`, `set tx`, `set repeat`, `set allow.read.only`, `set flood.max`, `set int.thresh`, `set agc.reset.interval`, `set multi.acks`, `set advert.interval`, `set flood.advert.interval`, `set guest.password`, `set lat`, `set lon`, `set freq`, `set radio`, `set rxdelay`, `set txdelay`, `set direct.txdelay`, `set radio.rxgain`, `set dutycycle`, `set loop.detect`, `set path.hash.mode`, `set owner.info`, `set prv.key`, `set bridge.*`, `set adc.multiplier`, `tempradio`, `setperm` **Bridge**: `get bridge.type` @@ -102,9 +110,11 @@ A terminal-style interface for sending commands directly to the repeater. **Neighbors**: `neighbors`, `neighbor.remove` -**Region Management**: `region`, `region load/get/put/remove/allowf/denyf/home/save` +**Power Management**: `get pwrmgt.support`, `get pwrmgt.source`, `get pwrmgt.bootreason`, `get pwrmgt.bootmv` -**GPS**: `gps`, `gps on/off/sync/setloc/advert` +**Sensors**: `sensor get {key}` + +**Region Management**: `region`, `region load`, `region get`, `region put`, `region remove`, `region allowf`, `region denyf`, `region home`, `region save`, `region default`, `region list allowed`, `region list denied` --- @@ -147,40 +157,63 @@ A card titled "Repeater's Neighbors - N" listing each neighbor as: ### What the User Sees -Five configuration cards: +Nine configuration cards, each with its own per-field refresh button(s): **1. Basic Settings** - Name field -- Admin password field -- Guest password field +- Admin password field (write-only; always sent when non-empty) +- Guest password field (write-only; always sent when non-empty) **2. Radio Settings** - Frequency (MHz) -- TX Power (dBm) +- TX Power (dBm) — has its own independent refresh button - Bandwidth dropdown (kHz) - Spreading Factor (SF5–SF12) - Coding Rate (4/5–4/8) +- RX Gain boost toggle **3. Location Settings** -- Latitude and longitude fields +- Latitude and longitude fields, each with an independent refresh button **4. Features** -- Packet forwarding toggle -- Guest access toggle +- Packet forwarding toggle (`set repeat`) +- Guest access toggle (`set allow.read.only`) +- Multi-ACKs toggle (`set multi.acks`) +- Auto clock sync after login toggle (local app setting only, not sent to repeater) -**5. Advertisement Settings** +**5. Network Health** +- Loop detection dropdown (off / minimal / moderate / strict; `set loop.detect`) +- Duty cycle slider (1–100%; `set dutycycle`) + +**6. Advertisement Settings** - Local advert interval slider (60–240 minutes) with enable/disable toggle - Flood advert interval slider (3–168 hours) with enable/disable toggle +- Flood max hops slider (0–64; `set flood.max`) -**6. Danger Zone** (red-styled card) -- Reboot repeater -- Erase filesystem (serial-only warning) +**7. Owner Info** +- Multi-line text field for operator contact info (`set owner.info`); newlines sent as `|` + +**8. Actions** (one-tap, no save needed) +- Send Advertisement (`advert`) +- Send Zero-Hop Advertisement (`advert.zerohop`) +- Clock Sync (`clock sync`) + +**9. Advanced** (collapsed by default) +- Path hash mode dropdown (0–2; `set path.hash.mode`) +- TX delay field (`set txdelay`) +- Direct TX delay field (`set direct.txdelay`) +- Interference threshold field (`set int.thresh`) +- AGC reset interval slider (0–240s in multiples of 4; `set agc.reset.interval`) + +**Danger Zone** (red-styled card) +- Reboot repeater (sends `reboot` with confirmation dialog) +- Erase filesystem (serial-only; shows informational snackbar only — no command is sent over the air) ### Key Interactions -- **Settings are NOT auto-fetched on open**. Only name and location are pre-filled from locally cached contact data. You must tap each section's refresh button to fetch live values from the repeater -- TX Power has its own separate refresh button, independent from the main Radio Settings refresh -- Save button appears when changes are detected -- Settings are sent sequentially with 200ms delays between commands (fire-and-forget, no per-command acknowledgment wait) -- Validation prevents invalid values (e.g., frequency range, LoRa parameter compatibility) +- **Settings are NOT auto-fetched on open**. Name is pre-filled from cached contact data. Each section has its own refresh button to fetch live values from the repeater +- TX Power, RX Gain, latitude, longitude, and advanced fields each have independent inline refresh buttons +- Save button in app bar appears when any change is detected; failed commands keep those fields dirty for retry +- Settings are sent sequentially with 200ms delays between commands; firmware responses are checked and partial failures are reported in a snackbar +- Some changes (e.g. radio frequency) require a reboot; the firmware response triggers an orange "reboot needed" snackbar - Advertisement interval sliders reset to defaults when re-enabled (local: 60 min, flood: 3 hours) -- **Erase Filesystem** does NOT send any command over the air — tapping it only shows a snackbar explaining the operation requires physical serial access. It is effectively non-functional when connected wirelessly +- **Erase Filesystem** does NOT send any command over the air — tapping it only shows a snackbar explaining the operation requires physical serial access diff --git a/documentation/scanner-and-connection.md b/documentation/scanner-and-connection.md index 2c5dbae8..080e4483 100644 --- a/documentation/scanner-and-connection.md +++ b/documentation/scanner-and-connection.md @@ -51,7 +51,7 @@ Note: The weak (-80 to -90 dBm) and poor (< -90 dBm) tiers share the same icon s ### How Scanning Works -- Filters for devices with names starting with `MeshCore-` or `Whisper-` +- Filters for devices with names starting with one of the known prefixes: `MeshCore-`, `Whisper-`, `WisCore-`, `Seeed`, `Lilygo`, `HT-`, `LowMesh_MC_` - Uses low-latency scan mode on Android - Scans for 10 seconds then auto-stops - On iOS/macOS, waits for BLE adapter initialization before starting @@ -61,7 +61,7 @@ Note: The weak (-80 to -90 dBm) and poor (< -90 dBm) tiers share the same icon s Tap a device tile or its Connect button: 1. The connector stops scanning and transitions to "connecting" -2. Connects to the device with a 15-second timeout +2. Connects to the device with a 15-second timeout (6 seconds on Linux) 3. Requests MTU 185 bytes for optimal throughput 4. Discovers BLE services and locates the Nordic UART Service 5. Subscribes to TX notifications for receiving data diff --git a/documentation/settings.md b/documentation/settings.md index 70e39e2f..74e8c933 100644 --- a/documentation/settings.md +++ b/documentation/settings.md @@ -46,7 +46,7 @@ A dedicated sub-screen for app-level preferences (nothing here is sent to the de ### Appearance - **Theme**: System / Light / Dark -- **Language**: System default or one of 15 languages (English, French, Spanish, German, Polish, Slovenian, Portuguese, Italian, Chinese, Swedish, Dutch, Slovak, Bulgarian, Russian, Ukrainian) +- **Language**: System default or one of 18 languages (English, French, Spanish, German, Polish, Slovenian, Portuguese, Italian, Chinese, Swedish, Dutch, Slovak, Bulgarian, Russian, Ukrainian, Hungarian, Japanese, Korean) - **Enable Message Tracing**: Shows path trace overlays and extra metadata on messages ### Notifications @@ -57,6 +57,7 @@ A dedicated sub-screen for app-level preferences (nothing here is sent to the de ### Messaging - **Clear Path on Max Retry**: Erases the stored routing path after all retries fail +- **Jump to Oldest Unread**: When opening a chat, scrolls to the oldest unread message instead of the newest - **Auto Route Rotation**: Enables weighted routing algorithm. When enabled, expands to show five slider sub-settings (hidden when off): - Max Route Weight (1–10, default 5, integer steps) - Initial Route Weight (0.5–5.0, default 3.0) @@ -67,6 +68,15 @@ A dedicated sub-screen for app-level preferences (nothing here is sent to the de ### Battery - **Battery Chemistry**: NMC / LiFePO4 / LiPo (per device, used to calibrate percentage from voltage) +### Translation +Not shown on web. Controls on-device message translation powered by a locally-downloaded ML model: +- **Enable Translation**: Translates incoming messages into the selected target language +- **Translate Composer**: Translates outgoing messages from the target language back before sending +- **Target Language**: Language to translate into (searchable list; defaults to the app language) +- **Downloaded Model**: Dropdown to select among already-downloaded translation models +- **Preset Model**: Download a curated preset model with one tap +- **Custom Model URL**: Enter a URL to download a custom GGUF-format model; shows download progress and a cancel button + ### Map Display - **Show Repeaters**: Toggle repeater markers on map - **Show Chat Nodes**: Toggle chat node markers @@ -91,7 +101,7 @@ These settings are sent directly to the connected device firmware. ### Radio Settings Opens a dialog pre-populated with the device's current radio settings. Contains: -- **Preset dropdown**: 19 regional presets — selecting a preset immediately fills all fields below. Full list: Australia, Australia (Narrow), Australia SA/WA/QLD, Czech Republic, EU 433MHz, EU/UK (Long Range), EU/UK (Medium Range), EU/UK (Narrow), New Zealand, New Zealand (Narrow), Portugal 433, Portugal 869, Switzerland, USA Arizona, USA/Canada, Vietnam, Off-Grid 433, Off-Grid 869, Off-Grid 918 +- **Preset dropdown**: 19 regional presets — selecting a preset immediately fills all fields below. Full list: Australia, Australia (Narrow), Australia SA, WA, QLD, Czech Republic, EU 433MHz, EU/UK (Long Range), EU/UK (Medium Range), EU/UK (Narrow), New Zealand, New Zealand (Narrow), Portugal 433, Portugal 869, Switzerland, USA Arizona, USA/Canada, Vietnam, Off-Grid 433, Off-Grid 869, Off-Grid 918 - **Frequency** (MHz): Free text, validated 300–2500 MHz - **Bandwidth**: Dropdown (7.8 / 10.4 / 15.6 / 20.8 / 31.25 / 41.7 / 62.5 / 125 / 250 / 500 kHz) - **Spreading Factor**: SF5–SF12 diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 93e46829..379e36fa 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -8,7 +8,6 @@ list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST flserial - jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 533a1712..f02857f4 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -11,7 +11,6 @@ list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST flserial flutter_local_notifications_windows - jni ) set(PLUGIN_BUNDLED_LIBRARIES)