From 2976113c0a55a7863138d25c2dbb66fd7a0e71be Mon Sep 17 00:00:00 2001 From: Justin Mitchell Date: Sat, 3 Jan 2026 22:42:37 -0500 Subject: [PATCH] Moves Calibre settings into 1 single Calibre setting which will match how the KOReader PR works too --- .../settings/CalibreSettingsActivity.cpp | 188 ++++++++++++++++++ .../settings/CalibreSettingsActivity.h | 36 ++++ src/activities/settings/SettingsActivity.cpp | 62 +----- 3 files changed, 233 insertions(+), 53 deletions(-) create mode 100644 src/activities/settings/CalibreSettingsActivity.cpp create mode 100644 src/activities/settings/CalibreSettingsActivity.h diff --git a/src/activities/settings/CalibreSettingsActivity.cpp b/src/activities/settings/CalibreSettingsActivity.cpp new file mode 100644 index 00000000..e1573173 --- /dev/null +++ b/src/activities/settings/CalibreSettingsActivity.cpp @@ -0,0 +1,188 @@ +#include "CalibreSettingsActivity.h" + +#include +#include + +#include + +#include "CrossPointSettings.h" +#include "MappedInputManager.h" +#include "activities/network/CalibreWirelessActivity.h" +#include "activities/network/WifiSelectionActivity.h" +#include "activities/util/KeyboardEntryActivity.h" +#include "fontIds.h" + +namespace { +constexpr int MENU_ITEMS = 2; +const char* menuNames[MENU_ITEMS] = {"Calibre Web URL", "Connect as Wireless Device"}; +} // namespace + +void CalibreSettingsActivity::taskTrampoline(void* param) { + auto* self = static_cast(param); + self->displayTaskLoop(); +} + +void CalibreSettingsActivity::onEnter() { + ActivityWithSubactivity::onEnter(); + + renderingMutex = xSemaphoreCreateMutex(); + selectedIndex = 0; + updateRequired = true; + + xTaskCreate(&CalibreSettingsActivity::taskTrampoline, "CalibreSettingsTask", + 4096, // Stack size + this, // Parameters + 1, // Priority + &displayTaskHandle // Task handle + ); +} + +void CalibreSettingsActivity::onExit() { + ActivityWithSubactivity::onExit(); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + if (displayTaskHandle) { + vTaskDelete(displayTaskHandle); + displayTaskHandle = nullptr; + } + vSemaphoreDelete(renderingMutex); + renderingMutex = nullptr; +} + +void CalibreSettingsActivity::loop() { + if (subActivity) { + subActivity->loop(); + return; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + onBack(); + return; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + handleSelection(); + return; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Up) || + mappedInput.wasPressed(MappedInputManager::Button::Left)) { + selectedIndex = (selectedIndex + MENU_ITEMS - 1) % MENU_ITEMS; + updateRequired = true; + } else if (mappedInput.wasPressed(MappedInputManager::Button::Down) || + mappedInput.wasPressed(MappedInputManager::Button::Right)) { + selectedIndex = (selectedIndex + 1) % MENU_ITEMS; + updateRequired = true; + } +} + +void CalibreSettingsActivity::handleSelection() { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + + if (selectedIndex == 0) { + // Calibre Web URL + exitActivity(); + enterNewActivity(new KeyboardEntryActivity( + renderer, mappedInput, "Calibre Web URL", SETTINGS.opdsServerUrl, 10, + 127, // maxLength + false, // not password + [this](const std::string& url) { + strncpy(SETTINGS.opdsServerUrl, url.c_str(), sizeof(SETTINGS.opdsServerUrl) - 1); + SETTINGS.opdsServerUrl[sizeof(SETTINGS.opdsServerUrl) - 1] = '\0'; + SETTINGS.saveToFile(); + exitActivity(); + updateRequired = true; + }, + [this]() { + exitActivity(); + updateRequired = true; + })); + } else if (selectedIndex == 1) { + // Wireless Device - toggle and launch activity if enabling + const bool wasEnabled = SETTINGS.calibreWirelessEnabled; + SETTINGS.calibreWirelessEnabled = !wasEnabled; + SETTINGS.saveToFile(); + + if (!wasEnabled) { + // Just enabled - launch the wireless activity + exitActivity(); + if (WiFi.status() != WL_CONNECTED) { + enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, [this](bool connected) { + exitActivity(); + if (connected) { + enterNewActivity(new CalibreWirelessActivity(renderer, mappedInput, [this] { + exitActivity(); + updateRequired = true; + })); + } else { + // WiFi connection failed/cancelled, turn off the setting + SETTINGS.calibreWirelessEnabled = 0; + SETTINGS.saveToFile(); + updateRequired = true; + } + })); + } else { + enterNewActivity(new CalibreWirelessActivity(renderer, mappedInput, [this] { + exitActivity(); + updateRequired = true; + })); + } + } else { + // Just disabled - just update the display + updateRequired = true; + } + } + + xSemaphoreGive(renderingMutex); +} + +void CalibreSettingsActivity::displayTaskLoop() { + while (true) { + if (updateRequired && !subActivity) { + updateRequired = false; + xSemaphoreTake(renderingMutex, portMAX_DELAY); + render(); + xSemaphoreGive(renderingMutex); + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} + +void CalibreSettingsActivity::render() { + renderer.clearScreen(); + + const auto pageWidth = renderer.getScreenWidth(); + + // Draw header + renderer.drawCenteredText(UI_12_FONT_ID, 15, "Calibre", true, EpdFontFamily::BOLD); + + // Draw selection highlight + renderer.fillRect(0, 60 + selectedIndex * 30 - 2, pageWidth - 1, 30); + + // Draw menu items + for (int i = 0; i < MENU_ITEMS; i++) { + const int settingY = 60 + i * 30; + const bool isSelected = (i == selectedIndex); + + renderer.drawText(UI_10_FONT_ID, 20, settingY, menuNames[i], !isSelected); + + // Draw status + const char* status = ""; + if (i == 0) { + // Calibre Web URL + status = (strlen(SETTINGS.opdsServerUrl) > 0) ? "[Set]" : "[Not Set]"; + } else if (i == 1) { + // Wireless Device + status = SETTINGS.calibreWirelessEnabled ? "ON" : "OFF"; + } + + const auto width = renderer.getTextWidth(UI_10_FONT_ID, status); + renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, status, !isSelected); + } + + // Draw button hints + const auto labels = mappedInput.mapLabels("« Back", "Select", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + + renderer.displayBuffer(); +} diff --git a/src/activities/settings/CalibreSettingsActivity.h b/src/activities/settings/CalibreSettingsActivity.h new file mode 100644 index 00000000..77b9218c --- /dev/null +++ b/src/activities/settings/CalibreSettingsActivity.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include + +#include + +#include "activities/ActivityWithSubactivity.h" + +/** + * Submenu for Calibre settings. + * Shows Calibre Web URL and Calibre Wireless Device options. + */ +class CalibreSettingsActivity final : public ActivityWithSubactivity { + public: + explicit CalibreSettingsActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, + const std::function& onBack) + : ActivityWithSubactivity("CalibreSettings", renderer, mappedInput), onBack(onBack) {} + + void onEnter() override; + void onExit() override; + void loop() override; + + private: + TaskHandle_t displayTaskHandle = nullptr; + SemaphoreHandle_t renderingMutex = nullptr; + bool updateRequired = false; + + int selectedIndex = 0; + const std::function onBack; + + static void taskTrampoline(void* param); + [[noreturn]] void displayTaskLoop(); + void render(); + void handleSelection(); +}; diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 91eeaf70..bfaa61c0 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -1,21 +1,18 @@ #include "SettingsActivity.h" #include -#include #include +#include "CalibreSettingsActivity.h" #include "CrossPointSettings.h" #include "MappedInputManager.h" #include "OtaUpdateActivity.h" -#include "activities/network/CalibreWirelessActivity.h" -#include "activities/network/WifiSelectionActivity.h" -#include "activities/util/KeyboardEntryActivity.h" #include "fontIds.h" // Define the static settings list namespace { -constexpr int settingsCount = 15; +constexpr int settingsCount = 14; const SettingInfo settingsList[settingsCount] = { // Should match with SLEEP_SCREEN_MODE {"Sleep Screen", SettingType::ENUM, &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover"}}, @@ -45,8 +42,7 @@ const SettingInfo settingsList[settingsCount] = { &CrossPointSettings::paragraphAlignment, {"Justify", "Left", "Center", "Right"}}, {"Reader Side Margin", SettingType::ENUM, &CrossPointSettings::sideMargin, {"None", "Small", "Medium", "Large"}}, - {"Calibre Web URL", SettingType::ACTION, nullptr, {}}, - {"Calibre Wireless Device", SettingType::TOGGLE, &CrossPointSettings::calibreWirelessEnabled, {}}, + {"Calibre Settings", SettingType::ACTION, nullptr, {}}, {"Check for updates", SettingType::ACTION, nullptr, {}}, }; } // namespace @@ -135,59 +131,19 @@ void SettingsActivity::toggleCurrentSetting() { // Toggle the boolean value using the member pointer const bool currentValue = SETTINGS.*(setting.valuePtr); SETTINGS.*(setting.valuePtr) = !currentValue; - - // Special handling for Calibre Wireless Device - launch activity when toggled ON - if (std::string(setting.name) == "Calibre Wireless Device" && !currentValue) { - SETTINGS.saveToFile(); - xSemaphoreTake(renderingMutex, portMAX_DELAY); - exitActivity(); - // Check WiFi connectivity first - if (WiFi.status() != WL_CONNECTED) { - enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, [this](bool connected) { - exitActivity(); - if (connected) { - enterNewActivity(new CalibreWirelessActivity(renderer, mappedInput, [this] { - exitActivity(); - updateRequired = true; - })); - } else { - // WiFi connection failed/cancelled, turn off the setting - SETTINGS.calibreWirelessEnabled = 0; - SETTINGS.saveToFile(); - updateRequired = true; - } - })); - } else { - enterNewActivity(new CalibreWirelessActivity(renderer, mappedInput, [this] { - exitActivity(); - updateRequired = true; - })); - } - xSemaphoreGive(renderingMutex); - return; // Don't save again at the end - } } else if (setting.type == SettingType::ENUM && setting.valuePtr != nullptr) { const uint8_t currentValue = SETTINGS.*(setting.valuePtr); SETTINGS.*(setting.valuePtr) = (currentValue + 1) % static_cast(setting.enumValues.size()); } else if (setting.type == SettingType::ACTION) { - if (std::string(setting.name) == "Calibre Web URL") { + if (strcmp(setting.name, "Calibre Settings") == 0) { xSemaphoreTake(renderingMutex, portMAX_DELAY); exitActivity(); - enterNewActivity(new KeyboardEntryActivity( - renderer, mappedInput, "Calibre Web URL", SETTINGS.opdsServerUrl, 10, 127, false, - [this](const std::string& url) { - strncpy(SETTINGS.opdsServerUrl, url.c_str(), sizeof(SETTINGS.opdsServerUrl) - 1); - SETTINGS.opdsServerUrl[sizeof(SETTINGS.opdsServerUrl) - 1] = '\0'; - SETTINGS.saveToFile(); - exitActivity(); - updateRequired = true; - }, - [this] { - exitActivity(); - updateRequired = true; - })); + enterNewActivity(new CalibreSettingsActivity(renderer, mappedInput, [this] { + exitActivity(); + updateRequired = true; + })); xSemaphoreGive(renderingMutex); - } else if (std::string(setting.name) == "Check for updates") { + } else if (strcmp(setting.name, "Check for updates") == 0) { xSemaphoreTake(renderingMutex, portMAX_DELAY); exitActivity(); enterNewActivity(new OtaUpdateActivity(renderer, mappedInput, [this] {