diff --git a/docs/development/l2-roadmap.md b/docs/development/l2-roadmap.md index 1cb4840e..b688e52b 100644 --- a/docs/development/l2-roadmap.md +++ b/docs/development/l2-roadmap.md @@ -257,5 +257,6 @@ User list, second batch (2026-09-26): default; off: only the top button wakes it). - [x] Favourites as their own screen in the menu rather than a tile: a Home card left of the main page (six slots, unread badges). -- [ ] WiFi indicator icon in the status bar. +- [x] WiFi indicator icon in the status bar: while WiFi is switched on, + bright when connected, dim otherwise. diff --git a/examples/companion_radio/ui-lvgl/LvglPort.h b/examples/companion_radio/ui-lvgl/LvglPort.h index 45991762..90660d4c 100644 --- a/examples/companion_radio/ui-lvgl/LvglPort.h +++ b/examples/companion_radio/ui-lvgl/LvglPort.h @@ -140,14 +140,18 @@ static void saveWifi(const char* ssid, const char* pass) { } // Settings > WiFi's switch: off keeps the radio off for everything (scan, map // download). Kept with the credentials. +static int8_t s_wifi_allowed = -1; // read once (the status bar asks every second) static bool wifiAllowed() { - Preferences p; - if (!p.begin("mc_wifi", true)) return true; - bool on = p.getBool("on", true); - p.end(); - return on; + if (s_wifi_allowed < 0) { + Preferences p; + bool on = true; + if (p.begin("mc_wifi", true)) { on = p.getBool("on", true); p.end(); } + s_wifi_allowed = on; + } + return s_wifi_allowed; } static void setWifiAllowed(bool on) { + s_wifi_allowed = on; Preferences p; if (!p.begin("mc_wifi", false)) return; p.putBool("on", on); @@ -316,8 +320,9 @@ static void netEnd() { WiFi.disconnect(true); WiFi.mode(WIFI_OFF); } -// One line for the download popup: link details and the internal heap (TLS, -// WiFi and BLE all compete for it). +// For the status bar: NET_UP once connected, else NET_OFF (radio off, a scan, +// still connecting). +static int netRadio() { return WiFi.getMode() != WIFI_OFF && WiFi.status() == WL_CONNECTED ? NET_UP : NET_OFF; } // Async scan: scanStart(), then scanResults() returns -1 while running, else // the count, filling `names` (strongest first, as the driver reports them). static void scanStart() { @@ -545,9 +550,11 @@ static void setWifiAllowed(bool on) { s_wifi_on = on; } static bool s_live_tiles = true; static bool liveTiles() { return s_live_tiles; } static void setLiveTiles(bool on) { s_live_tiles = on; } -static void netBegin(const char*, const char*) {} +static bool s_net_on = false; +static void netBegin(const char*, const char*) { s_net_on = true; } static int netState() { return NET_UP; } -static void netEnd() {} +static void netEnd() { s_net_on = false; } +static int netRadio() { return s_net_on ? NET_UP : NET_OFF; } static uint32_t s_scan_at = 0; static void scanStart() { s_scan_at = millis(); } static int scanResults(char names[][33], int max) { // a pretend scan, for the UI diff --git a/examples/companion_radio/ui-lvgl/UITask.cpp b/examples/companion_radio/ui-lvgl/UITask.cpp index a6c86655..59e2f04f 100644 --- a/examples/companion_radio/ui-lvgl/UITask.cpp +++ b/examples/companion_radio/ui-lvgl/UITask.cpp @@ -624,14 +624,16 @@ void UITask::refreshStatusBar() { lv_label_set_text_fmt(_status_batt, "%s%s%s", _board->isExternalPowered() ? LV_SYMBOL_CHARGE : "", batt, level); // Status icons, as the original's status bar (ui-new): Bluetooth (bright - // when the app is connected), GPS (green with a fix), the alarm, mute, then + // when the app is connected), WiFi (when switched on), GPS (green with a fix), the alarm, mute, then // the modes that keep running in the background -- auto-advert, trail, live // share, repeater, arrival alert -- in the accent colour. Right to left in // that order, next to the battery. struct Icon { const char* sym; uint32_t col; }; - Icon icons[10]; + Icon icons[11]; int n = 0; if (isSerialEnabled()) icons[n++] = { LV_SYMBOL_BLUETOOTH, hasConnection() ? theme::TEXT : theme::TEXT_MUTED }; + if (lvport::wifiAllowed()) // WiFi switched on: bright while connected (map tiles, update) + icons[n++] = { LV_SYMBOL_WIFI, lvport::netRadio() == lvport::NET_UP ? theme::TEXT : theme::TEXT_MUTED }; int32_t lat, lon; bool fix = _core->course.currentLocation(lat, lon); if (_core->gpsEnabled() || fix) icons[n++] = { LV_SYMBOL_GPS, fix ? theme::OK : theme::TEXT_MUTED }; @@ -644,7 +646,7 @@ void UITask::refreshStatusBar() { if (_prefs && _prefs->loc_share_enabled) icons[n++] = { UI_SYMBOL_PIN, theme::ACCENT }; if (_prefs && _prefs->client_repeat) icons[n++] = { LV_SYMBOL_LOOP, theme::ACCENT }; if (_prefs && _prefs->locator_enabled && _prefs->locator_has_target) icons[n++] = { UI_SYMBOL_FLAG, theme::ACCENT }; - char sig[48]; + char sig[sizeof(_status_sig)]; int o = 0; for (int i = 0; i < n && o < (int)sizeof(sig) - 12; i++) o += snprintf(sig + o, sizeof(sig) - o, "%s%lx", icons[i].sym, (unsigned long)icons[i].col); sig[o] = '\0'; diff --git a/examples/companion_radio/ui-lvgl/UITask.h b/examples/companion_radio/ui-lvgl/UITask.h index f6f64f3b..3b3b4744 100644 --- a/examples/companion_radio/ui-lvgl/UITask.h +++ b/examples/companion_radio/ui-lvgl/UITask.h @@ -427,7 +427,7 @@ private: lv_obj_t* _status_time = nullptr; lv_obj_t* _status_icons = nullptr; // a row of icon labels, rebuilt with the state lv_obj_t* _status_batt = nullptr; - char _status_sig[48] = ""; // what the icon row shows, to skip unchanged rebuilds + char _status_sig[128] = ""; // what the icon row shows, to skip unchanged rebuilds lv_obj_t* _toast = nullptr; lv_timer_t* _toast_timer = nullptr; lv_obj_t* _home_clock = nullptr;