Skip to content

App navigation

The app follows this general flow:

Launch → Scanner Screen → [Connect via BLE/USB/TCP] → Contacts Screen

After connecting, the three main screens (Contacts, Channels, Map) are accessible via a persistent bottom navigation bar called the QuickSwitchBar.

The QuickSwitchBar is a Material 3 NavigationBar with a frosted-glass visual treatment (blur backdrop, transparent theme, rounded corners). It appears at the bottom of all three main screens.

IndexIconLabelScreen
0PeopleContactsContactsScreen
1TagChannelsChannelsScreen
2MapMapMapScreen

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.

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.

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
  • The disconnect button 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 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
  • On web, if a non-Chromium browser is detected, the app shows a ChromeRequiredScreen instead of the Scanner (Web Bluetooth requires Chromium)
ScannerScreen (root, always on stack)
├─ [BLE connect] → push → ContactsScreen
├─ [TCP FAB] → push → TcpScreen
│ └─ [TCP connected] → pushReplacement → ContactsScreen
└─ [USB FAB] → push → UsbScreen
└─ [USB connected] → pushReplacement → ContactsScreen
ContactsScreen (selected=0)
├─ [quick-switch 1] → pushReplacement → ChannelsScreen
├─ [quick-switch 2] → pushReplacement → MapScreen
├─ [tap contact] → push → ChatScreen
├─ [overflow > Settings] → push → SettingsScreen
└─ [overflow > Discovered] → push → DiscoveryScreen
ChannelsScreen (selected=1)
├─ [quick-switch 0] → pushReplacement → ContactsScreen
├─ [quick-switch 2] → pushReplacement → MapScreen
├─ [tap channel] → push → ChannelChatScreen
└─ [overflow > Settings] → push → SettingsScreen
MapScreen (selected=2)
├─ [quick-switch 0] → pushReplacement → ContactsScreen
├─ [quick-switch 1] → pushReplacement → ChannelsScreen
├─ [radar button] → push → PathTraceMapScreen
├─ [terrain button] → push → LineOfSightMapScreen
└─ [long-press] → share marker / set location
Settings (push from any main screen)
└─ [App Settings] → push → AppSettingsScreen
└─ [Offline Map Cache] → push → MapCacheScreen

Any disconnection from any screen triggers popUntil(route.isFirst), returning to the Scanner.