From 6dc719ca69fd759a4c541896a3686f9589aa3ae5 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Tue, 17 Mar 2026 21:05:46 +0100 Subject: [PATCH] Add Info Activitiy --- lib/I18n/translations/english.yaml | 1 + src/SystemStatus.h | 43 ++++++++++++ src/activities/settings/SettingsActivity.cpp | 5 ++ src/activities/settings/SettingsActivity.h | 1 + .../settings/SystemInformationActivity.cpp | 70 +++++++++++++++++++ .../settings/SystemInformationActivity.h | 14 ++++ src/network/CrossPointWebServer.cpp | 16 ++--- 7 files changed, 142 insertions(+), 8 deletions(-) create mode 100644 src/SystemStatus.h create mode 100644 src/activities/settings/SystemInformationActivity.cpp create mode 100644 src/activities/settings/SystemInformationActivity.h diff --git a/lib/I18n/translations/english.yaml b/lib/I18n/translations/english.yaml index 38192cc9..7f44a93c 100644 --- a/lib/I18n/translations/english.yaml +++ b/lib/I18n/translations/english.yaml @@ -341,3 +341,4 @@ STR_LINK: "[link]" STR_SCREENSHOT_BUTTON: "Take screenshot" STR_AUTO_TURN_ENABLED: "Auto Turn Enabled: " STR_AUTO_TURN_PAGES_PER_MIN: "Auto Turn (Pages Per Minute)" +STR_SYSTEM_INFO: "System Information" diff --git a/src/SystemStatus.h b/src/SystemStatus.h new file mode 100644 index 00000000..38b39f46 --- /dev/null +++ b/src/SystemStatus.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +// Snapshot of device system status, shared between the web server and the +// System Information activity so both surfaces show consistent data. +struct SystemStatus { + const char* version; + std::string ip; + std::string wifiMode; // "STA", "AP", or "Off" + int rssi; // dBm; 0 when not in STA mode + std::string macAddress; + uint32_t freeHeapBytes; + uint32_t uptimeSeconds; + + static SystemStatus collect() { + SystemStatus s; + s.version = CROSSPOINT_VERSION; + s.freeHeapBytes = ESP.getFreeHeap(); + s.uptimeSeconds = millis() / 1000; + s.macAddress = WiFi.macAddress().c_str(); + + const wifi_mode_t mode = WiFi.getMode(); + const bool isAP = (mode == WIFI_MODE_AP) || (mode == WIFI_MODE_APSTA); + + if (isAP) { + s.wifiMode = "AP"; + s.ip = WiFi.softAPIP().toString().c_str(); + s.rssi = 0; + } else if (WiFi.status() == WL_CONNECTED) { + s.wifiMode = "STA"; + s.ip = WiFi.localIP().toString().c_str(); + s.rssi = WiFi.RSSI(); + } else { + s.wifiMode = "Off"; + s.ip = "-"; + s.rssi = 0; + } + + return s; + } +}; diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index e5824a89..f981f444 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -6,6 +6,7 @@ #include "ButtonRemapActivity.h" #include "CalibreSettingsActivity.h" #include "ClearCacheActivity.h" +#include "SystemInformationActivity.h" #include "CrossPointSettings.h" #include "KOReaderSettingsActivity.h" #include "LanguageSelectActivity.h" @@ -52,6 +53,7 @@ void SettingsActivity::onEnter() { systemSettings.push_back(SettingInfo::Action(StrId::STR_CLEAR_READING_CACHE, SettingAction::ClearCache)); systemSettings.push_back(SettingInfo::Action(StrId::STR_CHECK_UPDATES, SettingAction::CheckForUpdates)); systemSettings.push_back(SettingInfo::Action(StrId::STR_LANGUAGE, SettingAction::Language)); + systemSettings.push_back(SettingInfo::Action(StrId::STR_SYSTEM_INFO, SettingAction::SystemInfo)); readerSettings.push_back(SettingInfo::Action(StrId::STR_CUSTOMISE_STATUS_BAR, SettingAction::CustomiseStatusBar)); // Reset selection to first category @@ -192,6 +194,9 @@ void SettingsActivity::toggleCurrentSetting() { case SettingAction::Language: startActivityForResult(std::make_unique(renderer, mappedInput), resultHandler); break; + case SettingAction::SystemInfo: + startActivityForResult(std::make_unique(renderer, mappedInput), resultHandler); + break; case SettingAction::None: // Do nothing break; diff --git a/src/activities/settings/SettingsActivity.h b/src/activities/settings/SettingsActivity.h index 9d5778a9..e09c571a 100644 --- a/src/activities/settings/SettingsActivity.h +++ b/src/activities/settings/SettingsActivity.h @@ -21,6 +21,7 @@ enum class SettingAction { ClearCache, CheckForUpdates, Language, + SystemInfo, }; struct SettingInfo { diff --git a/src/activities/settings/SystemInformationActivity.cpp b/src/activities/settings/SystemInformationActivity.cpp new file mode 100644 index 00000000..d0bd2fd7 --- /dev/null +++ b/src/activities/settings/SystemInformationActivity.cpp @@ -0,0 +1,70 @@ +#include "SystemInformationActivity.h" + +#include +#include + +#include "MappedInputManager.h" +#include "SystemStatus.h" +#include "components/UITheme.h" +#include "fontIds.h" + +void SystemInformationActivity::onEnter() { + Activity::onEnter(); + requestUpdate(); +} + +void SystemInformationActivity::onExit() { Activity::onExit(); } + +void SystemInformationActivity::loop() { + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + finish(); + } +} + +void SystemInformationActivity::render(RenderLock&&) { + const auto& metrics = UITheme::getInstance().getMetrics(); + const auto pageWidth = renderer.getScreenWidth(); + const auto pageHeight = renderer.getScreenHeight(); + + renderer.clearScreen(); + + GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, + tr(STR_SYSTEM_INFO), CROSSPOINT_VERSION); + + const auto status = SystemStatus::collect(); + + // Layout: label on the left, value on the right of the midpoint + const int leftX = metrics.verticalSpacing * 3; + const int valueX = pageWidth / 2; + const int lineH = renderer.getLineHeight(UI_10_FONT_ID); + const int startY = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing * 3; + + auto drawRow = [&](int row, const char* label, const std::string& value) { + const int y = startY + row * (lineH + metrics.verticalSpacing); + renderer.drawText(UI_10_FONT_ID, leftX, y, label, true, EpdFontFamily::BOLD); + renderer.drawText(UI_10_FONT_ID, valueX, y, value.c_str()); + }; + + drawRow(0, "Version", status.version); + drawRow(1, "Free heap", std::to_string(status.freeHeapBytes / 1024) + " KB"); + + const uint32_t h = status.uptimeSeconds / 3600; + const uint32_t m = (status.uptimeSeconds % 3600) / 60; + const uint32_t s = status.uptimeSeconds % 60; + char uptimeBuf[16]; + snprintf(uptimeBuf, sizeof(uptimeBuf), "%uh %02um %02us", h, m, s); + drawRow(2, "Uptime", uptimeBuf); + + std::string wifiLabel = status.wifiMode; + if (status.rssi != 0) { + wifiLabel += " (" + std::to_string(status.rssi) + " dBm)"; + } + drawRow(3, "WiFi", wifiLabel); + drawRow(4, "IP address", status.ip); + drawRow(5, "MAC address", status.macAddress); + + const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); + GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + + renderer.displayBuffer(); +} diff --git a/src/activities/settings/SystemInformationActivity.h b/src/activities/settings/SystemInformationActivity.h new file mode 100644 index 00000000..4beab5af --- /dev/null +++ b/src/activities/settings/SystemInformationActivity.h @@ -0,0 +1,14 @@ +#pragma once + +#include "activities/Activity.h" + +class SystemInformationActivity final : public Activity { + public: + explicit SystemInformationActivity(GfxRenderer& renderer, MappedInputManager& mappedInput) + : Activity("SystemInformation", renderer, mappedInput) {} + + void onEnter() override; + void onExit() override; + void loop() override; + void render(RenderLock&&) override; +}; diff --git a/src/network/CrossPointWebServer.cpp b/src/network/CrossPointWebServer.cpp index ede4aa39..320aaada 100644 --- a/src/network/CrossPointWebServer.cpp +++ b/src/network/CrossPointWebServer.cpp @@ -12,6 +12,7 @@ #include "CrossPointSettings.h" #include "SettingsList.h" +#include "SystemStatus.h" #include "WebDAVHandler.h" #include "html/FilesPageHtml.generated.h" #include "html/HomePageHtml.generated.h" @@ -316,16 +317,15 @@ void CrossPointWebServer::handleNotFound() const { } void CrossPointWebServer::handleStatus() const { - // Get correct IP based on AP vs STA mode - const String ipAddr = apMode ? WiFi.softAPIP().toString() : WiFi.localIP().toString(); + const auto status = SystemStatus::collect(); JsonDocument doc; - doc["version"] = CROSSPOINT_VERSION; - doc["ip"] = ipAddr; - doc["mode"] = apMode ? "AP" : "STA"; - doc["rssi"] = apMode ? 0 : WiFi.RSSI(); - doc["freeHeap"] = ESP.getFreeHeap(); - doc["uptime"] = millis() / 1000; + doc["version"] = status.version; + doc["ip"] = status.ip; + doc["mode"] = status.wifiMode; + doc["rssi"] = status.rssi; + doc["freeHeap"] = status.freeHeapBytes; + doc["uptime"] = status.uptimeSeconds; String json; serializeJson(doc, json);