From e10bf85fc332e5c2f3735c1bd0bf63c3fb9500fb Mon Sep 17 00:00:00 2001 From: dj2ls Date: Mon, 8 Jun 2026 10:20:58 +0200 Subject: [PATCH] implement a battery bar --- src/config/UserConfig.cpp | 7 ++++ src/config/UserConfig.h | 3 ++ src/main.cpp | 6 ++++ src/ui/LvStatusBar.cpp | 53 +++++++++++++++++++++++------ src/ui/LvStatusBar.h | 4 +++ src/ui/screens/LvSettingsScreen.cpp | 13 +++++++ 6 files changed, 75 insertions(+), 11 deletions(-) diff --git a/src/config/UserConfig.cpp b/src/config/UserConfig.cpp index 9ac3aac..0724dbf 100644 --- a/src/config/UserConfig.cpp +++ b/src/config/UserConfig.cpp @@ -85,6 +85,9 @@ bool UserConfig::parseJson(const String& json) { _settings.touchSensitivity = doc["touch_sens"] | 3; _settings.bleEnabled = false; + // battery settings + _settings.batteryDisplay = doc["batt_display"] | 0; + _settings.gpsTimeEnabled = doc["gps_time"] | true; _settings.gpsLocationEnabled = doc["gps_location"] | false; _settings.timezoneIdx = doc["tz_idx"] | 6; @@ -157,6 +160,10 @@ String UserConfig::serializeToJson() const { doc["touch_sens"] = _settings.touchSensitivity; doc["ble_enabled"] = false; + // battery settings + doc["batt_display"] = _settings.batteryDisplay; + + doc["gps_time"] = _settings.gpsTimeEnabled; doc["gps_location"] = _settings.gpsLocationEnabled; doc["tz_idx"] = _settings.timezoneIdx; diff --git a/src/config/UserConfig.h b/src/config/UserConfig.h index 00ad06e..7436627 100644 --- a/src/config/UserConfig.h +++ b/src/config/UserConfig.h @@ -57,6 +57,9 @@ struct UserSettings { uint8_t brightness = 100; // Percentage 1-100 bool denseFontMode = false; // T-Deck Plus: adaptive font toggle + // Battery + uint8_t batteryDisplay = 0; // 0 = percent, 1 = bar + // Keyboard uint8_t keyboardBrightness = 100; // Percentage 0-100 (0 = off) bool keyboardAutoOn = false; // Backlight ON when switching to ACTIVE power state diff --git a/src/main.cpp b/src/main.cpp index d1c80f2..97735ca 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1244,6 +1244,11 @@ void setup() { audio.setVolume(userConfig.settings().audioVolume); audio.begin(); + + // Step 26: Battery init + ui.lvStatusBar().setBatteryDisplay(userConfig.settings().batteryDisplay); + + // Boot complete — transition to Home screen // Yield to LVGL instead of blocking delay lvBootScreen.setProgress(0.98f, "Ready"); @@ -1907,6 +1912,7 @@ void loop() { lastStatusUpdate = millis(); if (powerMgr.isScreenOn()) { ui.lvStatusBar().setBatteryPercent(powerMgr.batteryPercent()); + ui.lvStatusBar().setBatteryDisplay(userConfig.settings().batteryDisplay); // Switch between bar and percent // Update TCP connection indicator bool anyTcpUp = false; for (auto* tcp : tcpClients) { diff --git a/src/ui/LvStatusBar.cpp b/src/ui/LvStatusBar.cpp index efa1ab4..bd3b368 100644 --- a/src/ui/LvStatusBar.cpp +++ b/src/ui/LvStatusBar.cpp @@ -54,6 +54,17 @@ void LvStatusBar::create(lv_obj_t* parent) { lv_label_set_long_mode(_lblBatt, LV_LABEL_LONG_CLIP); lv_obj_align(_lblBatt, LV_ALIGN_RIGHT_MID, -4, 0); + // Right: battery bar + _barBatt = lv_bar_create(_bar); + lv_obj_set_size(_barBatt, 20, 8); + lv_bar_set_range(_barBatt, 0, 100); + lv_bar_set_value(_barBatt, 0, LV_ANIM_OFF); + lv_obj_align(_barBatt, LV_ALIGN_RIGHT_MID, -4, 0); + lv_obj_set_style_bg_color(_barBatt, lv_color_hex(0x444444), LV_PART_MAIN); + lv_obj_set_style_bg_opa(_barBatt, LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_bg_color(_barBatt, lv_color_hex(0xFFFFFF), LV_PART_INDICATOR); + lv_obj_set_style_bg_opa(_barBatt, LV_OPA_COVER, LV_PART_INDICATOR); + // Toast overlay (hidden by default). It is a child of the bar so boot mode // and other shell visibility changes affect it with the status bar. _toast = lv_obj_create(_bar); @@ -185,6 +196,12 @@ void LvStatusBar::setBatteryPercent(int pct) { refreshBattery(); } +void LvStatusBar::setBatteryDisplay(uint8_t mode) { + if (_battDisplay == mode) return; + _battDisplay = mode; + refreshBattery(); +} + void LvStatusBar::flashAnnounce() { _announceFlashEnd = millis() + 1000; refreshIndicators(); @@ -224,21 +241,35 @@ void LvStatusBar::refreshIndicators() { } void LvStatusBar::refreshBattery() { - if (!_lblBatt) return; + if (!_lblBatt || !_barBatt) return; + + if(_battDisplay == 1){ + // Bar mode + lv_obj_clear_flag(_barBatt, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(_lblBatt, LV_OBJ_FLAG_HIDDEN); + + lv_bar_set_value(_barBatt, _battPct < 0 ? 0 : _battPct, LV_ANIM_OFF); - char buf[8]; - uint32_t col = Theme::TEXT_MUTED; - if (_battPct < 0) { - snprintf(buf, sizeof(buf), "--%%"); } else { - snprintf(buf, sizeof(buf), "%d%%", _battPct); - col = Theme::TEXT_PRIMARY; - if (_battPct <= 15) col = Theme::ERROR_CLR; - else if (_battPct <= 30) col = Theme::WARNING_CLR; + // Percent mode + lv_obj_clear_flag(_lblBatt, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(_barBatt, LV_OBJ_FLAG_HIDDEN); + + char buf[8]; + uint32_t col = Theme::TEXT_MUTED; + if (_battPct < 0) { + snprintf(buf, sizeof(buf), "--%%"); + } else { + snprintf(buf, sizeof(buf), "%d%%", _battPct); + col = Theme::TEXT_PRIMARY; + if (_battPct <= 15) col = Theme::ERROR_CLR; + else if (_battPct <= 30) col = Theme::WARNING_CLR; + } + lv_label_set_text(_lblBatt, buf); + lv_obj_set_style_text_color(_lblBatt, lv_color_hex(col), 0); } - lv_label_set_text(_lblBatt, buf); - lv_obj_set_style_text_color(_lblBatt, lv_color_hex(col), 0); + } void LvStatusBar::refreshTimeColor() { diff --git a/src/ui/LvStatusBar.h b/src/ui/LvStatusBar.h index 91cd6d7..ce820d2 100644 --- a/src/ui/LvStatusBar.h +++ b/src/ui/LvStatusBar.h @@ -19,6 +19,7 @@ public: void setAutoIfacePeers(int n); void setGPSFix(bool hasFix); void setBatteryPercent(int pct); + void setBatteryDisplay(uint8_t mode); // 0 = percent, 1 = bar void flashAnnounce(); void showToast(const char* msg, uint32_t durationMs = 1500); @@ -37,6 +38,7 @@ private: lv_obj_t* _lblTime = nullptr; // Left: current time lv_obj_t* _lblLinks = nullptr; // Center: brand/status text lv_obj_t* _lblBatt = nullptr; // Right: battery % + lv_obj_t* _barBatt = nullptr; // Right: Battery bar lv_obj_t* _toast = nullptr; lv_obj_t* _lblToast = nullptr; @@ -51,6 +53,8 @@ private: bool _gpsFix = false; bool _use24h = false; int _battPct = -1; + uint8_t _battDisplay = 0; + int _lastHour = -1; int _lastMinute = -1; unsigned long _announceFlashEnd = 0; diff --git a/src/ui/screens/LvSettingsScreen.cpp b/src/ui/screens/LvSettingsScreen.cpp index 0bb2672..bde49bd 100644 --- a/src/ui/screens/LvSettingsScreen.cpp +++ b/src/ui/screens/LvSettingsScreen.cpp @@ -514,6 +514,19 @@ void LvSettingsScreen::buildItems() { return summary; }}); + // Battery + int battStart = idx; + _items.push_back({"Battery Display", SettingType::ENUM_CHOICE, + [&s]() { return (int)s.batteryDisplay; }, + [&s](int v) { s.batteryDisplay = (uint8_t)v; }, + nullptr, 0, 1, 1, {"Percent", "Bar"}}); + idx++; + _categories.push_back({"Battery", battStart, idx - battStart, + [&s]() -> String { + return s.batteryDisplay == 0 ? String("Percent") : String("Bar"); + }}); + + // LoRa link int radioStart = idx; _items.push_back({"LoRa Radio", SettingType::TOGGLE,