feat: Connect to last wifi by default (#752)

## Summary

* **What is the goal of this PR?** 

Use last connected network as default

* **What changes are included?**

- Refactor how an action type of Settings are handled
- Add a new System Settings option → Network
- Add the ability to forget a network in the Network Selection Screen
- Add the ability to Refresh network list
- Save the last connected network SSID
- Use the last connection whenever network is needed (OPDS, Koreader
sync, update etc)

## Additional Context

* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks,
  specific areas to focus on).


![IMG_6504](https://github.com/user-attachments/assets/e48fb013-b5c3-45c0-b284-e183e6fd5a68)

![IMG_6503](https://github.com/user-attachments/assets/78c4b6b6-4e7b-4656-b356-19d65ff6aa12)




https://github.com/user-attachments/assets/95bf34a8-44ce-4279-8cd8-f78524ce745b





---

### AI Usage

Did you use AI tools to help write this code? _** PARTIALLY: I wrote
most of it but I also used Gemini as assist.

---------

Co-authored-by: Eliz Kilic <elizk@google.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Eliz
2026-02-10 09:41:44 +00:00
committed by GitHub
parent b5d28a3a9c
commit 98e6789626
6 changed files with 183 additions and 70 deletions

View File

@@ -9,7 +9,7 @@ WifiCredentialStore WifiCredentialStore::instance;
namespace { namespace {
// File format version // File format version
constexpr uint8_t WIFI_FILE_VERSION = 1; constexpr uint8_t WIFI_FILE_VERSION = 2; // Increased version
// WiFi credentials file path // WiFi credentials file path
constexpr char WIFI_FILE[] = "/.crosspoint/wifi.bin"; constexpr char WIFI_FILE[] = "/.crosspoint/wifi.bin";
@@ -38,6 +38,7 @@ bool WifiCredentialStore::saveToFile() const {
// Write header // Write header
serialization::writePod(file, WIFI_FILE_VERSION); serialization::writePod(file, WIFI_FILE_VERSION);
serialization::writeString(file, lastConnectedSsid); // Save last connected SSID
serialization::writePod(file, static_cast<uint8_t>(credentials.size())); serialization::writePod(file, static_cast<uint8_t>(credentials.size()));
// Write each credential // Write each credential
@@ -67,12 +68,18 @@ bool WifiCredentialStore::loadFromFile() {
// Read and verify version // Read and verify version
uint8_t version; uint8_t version;
serialization::readPod(file, version); serialization::readPod(file, version);
if (version != WIFI_FILE_VERSION) { if (version > WIFI_FILE_VERSION) {
Serial.printf("[%lu] [WCS] Unknown file version: %u\n", millis(), version); Serial.printf("[%lu] [WCS] Unknown file version: %u\n", millis(), version);
file.close(); file.close();
return false; return false;
} }
if (version >= 2) {
serialization::readString(file, lastConnectedSsid);
} else {
lastConnectedSsid.clear();
}
// Read credential count // Read credential count
uint8_t count; uint8_t count;
serialization::readPod(file, count); serialization::readPod(file, count);
@@ -128,6 +135,9 @@ bool WifiCredentialStore::removeCredential(const std::string& ssid) {
if (cred != credentials.end()) { if (cred != credentials.end()) {
credentials.erase(cred); credentials.erase(cred);
Serial.printf("[%lu] [WCS] Removed credentials for: %s\n", millis(), ssid.c_str()); Serial.printf("[%lu] [WCS] Removed credentials for: %s\n", millis(), ssid.c_str());
if (ssid == lastConnectedSsid) {
clearLastConnectedSsid();
}
return saveToFile(); return saveToFile();
} }
return false; // Not found return false; // Not found
@@ -146,8 +156,25 @@ const WifiCredential* WifiCredentialStore::findCredential(const std::string& ssi
bool WifiCredentialStore::hasSavedCredential(const std::string& ssid) const { return findCredential(ssid) != nullptr; } bool WifiCredentialStore::hasSavedCredential(const std::string& ssid) const { return findCredential(ssid) != nullptr; }
void WifiCredentialStore::setLastConnectedSsid(const std::string& ssid) {
if (lastConnectedSsid != ssid) {
lastConnectedSsid = ssid;
saveToFile();
}
}
const std::string& WifiCredentialStore::getLastConnectedSsid() const { return lastConnectedSsid; }
void WifiCredentialStore::clearLastConnectedSsid() {
if (!lastConnectedSsid.empty()) {
lastConnectedSsid.clear();
saveToFile();
}
}
void WifiCredentialStore::clearAll() { void WifiCredentialStore::clearAll() {
credentials.clear(); credentials.clear();
lastConnectedSsid.clear();
saveToFile(); saveToFile();
Serial.printf("[%lu] [WCS] Cleared all WiFi credentials\n", millis()); Serial.printf("[%lu] [WCS] Cleared all WiFi credentials\n", millis());
} }

View File

@@ -16,6 +16,7 @@ class WifiCredentialStore {
private: private:
static WifiCredentialStore instance; static WifiCredentialStore instance;
std::vector<WifiCredential> credentials; std::vector<WifiCredential> credentials;
std::string lastConnectedSsid;
static constexpr size_t MAX_NETWORKS = 8; static constexpr size_t MAX_NETWORKS = 8;
@@ -48,6 +49,11 @@ class WifiCredentialStore {
// Check if a network is saved // Check if a network is saved
bool hasSavedCredential(const std::string& ssid) const; bool hasSavedCredential(const std::string& ssid) const;
// Last connected network
void setLastConnectedSsid(const std::string& ssid);
const std::string& getLastConnectedSsid() const;
void clearLastConnectedSsid();
// Clear all credentials // Clear all credentials
void clearAll(); void clearAll();
}; };

View File

@@ -21,7 +21,8 @@ void WifiSelectionActivity::onEnter() {
renderingMutex = xSemaphoreCreateMutex(); renderingMutex = xSemaphoreCreateMutex();
// Load saved WiFi credentials - SD card operations need lock as we use SPI for both // Load saved WiFi credentials - SD card operations need lock as we use SPI
// for both
xSemaphoreTake(renderingMutex, portMAX_DELAY); xSemaphoreTake(renderingMutex, portMAX_DELAY);
WIFI_STORE.loadFromFile(); WIFI_STORE.loadFromFile();
xSemaphoreGive(renderingMutex); xSemaphoreGive(renderingMutex);
@@ -37,6 +38,7 @@ void WifiSelectionActivity::onEnter() {
usedSavedPassword = false; usedSavedPassword = false;
savePromptSelection = 0; savePromptSelection = 0;
forgetPromptSelection = 0; forgetPromptSelection = 0;
autoConnecting = false;
// Cache MAC address for display // Cache MAC address for display
uint8_t mac[6]; uint8_t mac[6];
@@ -46,9 +48,7 @@ void WifiSelectionActivity::onEnter() {
mac[5]); mac[5]);
cachedMacAddress = std::string(macStr); cachedMacAddress = std::string(macStr);
// Trigger first update to show scanning message // Task creation
updateRequired = true;
xTaskCreate(&WifiSelectionActivity::taskTrampoline, "WifiSelectionTask", xTaskCreate(&WifiSelectionActivity::taskTrampoline, "WifiSelectionTask",
4096, // Stack size (larger for WiFi operations) 4096, // Stack size (larger for WiFi operations)
this, // Parameters this, // Parameters
@@ -56,7 +56,26 @@ void WifiSelectionActivity::onEnter() {
&displayTaskHandle // Task handle &displayTaskHandle // Task handle
); );
// Start WiFi scan // Attempt to auto-connect to the last network
if (allowAutoConnect) {
const std::string lastSsid = WIFI_STORE.getLastConnectedSsid();
if (!lastSsid.empty()) {
const auto* cred = WIFI_STORE.findCredential(lastSsid);
if (cred) {
Serial.printf("[%lu] [WIFI] Attempting to auto-connect to %s\n", millis(), lastSsid.c_str());
selectedSSID = cred->ssid;
enteredPassword = cred->password;
selectedRequiresPassword = !cred->password.empty();
usedSavedPassword = true;
autoConnecting = true;
attemptConnection();
updateRequired = true;
return;
}
}
}
// Fallback to scanning
startWifiScan(); startWifiScan();
} }
@@ -70,15 +89,17 @@ void WifiSelectionActivity::onExit() {
WiFi.scanDelete(); WiFi.scanDelete();
Serial.printf("[%lu] [WIFI] [MEM] Free heap after scanDelete: %d bytes\n", millis(), ESP.getFreeHeap()); Serial.printf("[%lu] [WIFI] [MEM] Free heap after scanDelete: %d bytes\n", millis(), ESP.getFreeHeap());
// Note: We do NOT disconnect WiFi here - the parent activity (CrossPointWebServerActivity) // Note: We do NOT disconnect WiFi here - the parent activity
// manages WiFi connection state. We just clean up the scan and task. // (CrossPointWebServerActivity) manages WiFi connection state. We just clean
// up the scan and task.
// Acquire mutex before deleting task to ensure task isn't using it // Acquire mutex before deleting task to ensure task isn't using it
// This prevents hangs/crashes if the task holds the mutex when deleted // This prevents hangs/crashes if the task holds the mutex when deleted
Serial.printf("[%lu] [WIFI] Acquiring rendering mutex before task deletion...\n", millis()); Serial.printf("[%lu] [WIFI] Acquiring rendering mutex before task deletion...\n", millis());
xSemaphoreTake(renderingMutex, portMAX_DELAY); xSemaphoreTake(renderingMutex, portMAX_DELAY);
// Delete the display task (we now hold the mutex, so task is blocked if it needs it) // Delete the display task (we now hold the mutex, so task is blocked if it
// needs it)
Serial.printf("[%lu] [WIFI] Deleting display task...\n", millis()); Serial.printf("[%lu] [WIFI] Deleting display task...\n", millis());
if (displayTaskHandle) { if (displayTaskHandle) {
vTaskDelete(displayTaskHandle); vTaskDelete(displayTaskHandle);
@@ -96,6 +117,7 @@ void WifiSelectionActivity::onExit() {
} }
void WifiSelectionActivity::startWifiScan() { void WifiSelectionActivity::startWifiScan() {
autoConnecting = false;
state = WifiSelectionState::SCANNING; state = WifiSelectionState::SCANNING;
networks.clear(); networks.clear();
updateRequired = true; updateRequired = true;
@@ -181,6 +203,7 @@ void WifiSelectionActivity::selectNetwork(const int index) {
selectedRequiresPassword = network.isEncrypted; selectedRequiresPassword = network.isEncrypted;
usedSavedPassword = false; usedSavedPassword = false;
enteredPassword.clear(); enteredPassword.clear();
autoConnecting = false;
// Check if we have saved credentials for this network // Check if we have saved credentials for this network
const auto* savedCred = WIFI_STORE.findCredential(selectedSSID); const auto* savedCred = WIFI_STORE.findCredential(selectedSSID);
@@ -223,7 +246,7 @@ void WifiSelectionActivity::selectNetwork(const int index) {
} }
void WifiSelectionActivity::attemptConnection() { void WifiSelectionActivity::attemptConnection() {
state = WifiSelectionState::CONNECTING; state = autoConnecting ? WifiSelectionState::AUTO_CONNECTING : WifiSelectionState::CONNECTING;
connectionStartTime = millis(); connectionStartTime = millis();
connectedIP.clear(); connectedIP.clear();
connectionError.clear(); connectionError.clear();
@@ -239,7 +262,7 @@ void WifiSelectionActivity::attemptConnection() {
} }
void WifiSelectionActivity::checkConnectionStatus() { void WifiSelectionActivity::checkConnectionStatus() {
if (state != WifiSelectionState::CONNECTING) { if (state != WifiSelectionState::CONNECTING && state != WifiSelectionState::AUTO_CONNECTING) {
return; return;
} }
@@ -251,6 +274,13 @@ void WifiSelectionActivity::checkConnectionStatus() {
char ipStr[16]; char ipStr[16];
snprintf(ipStr, sizeof(ipStr), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); snprintf(ipStr, sizeof(ipStr), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
connectedIP = ipStr; connectedIP = ipStr;
autoConnecting = false;
// Save this as the last connected network - SD card operations need lock as
// we use SPI for both
xSemaphoreTake(renderingMutex, portMAX_DELAY);
WIFI_STORE.setLastConnectedSsid(selectedSSID);
xSemaphoreGive(renderingMutex);
// If we entered a new password, ask if user wants to save it // If we entered a new password, ask if user wants to save it
// Otherwise, immediately complete so parent can start web server // Otherwise, immediately complete so parent can start web server
@@ -260,7 +290,10 @@ void WifiSelectionActivity::checkConnectionStatus() {
updateRequired = true; updateRequired = true;
} else { } else {
// Using saved password or open network - complete immediately // Using saved password or open network - complete immediately
Serial.printf("[%lu] [WIFI] Connected with saved/open credentials, completing immediately\n", millis()); Serial.printf(
"[%lu] [WIFI] Connected with saved/open credentials, "
"completing immediately\n",
millis());
onComplete(true); onComplete(true);
} }
return; return;
@@ -299,7 +332,7 @@ void WifiSelectionActivity::loop() {
} }
// Check connection progress // Check connection progress
if (state == WifiSelectionState::CONNECTING) { if (state == WifiSelectionState::CONNECTING || state == WifiSelectionState::AUTO_CONNECTING) {
checkConnectionStatus(); checkConnectionStatus();
return; return;
} }
@@ -368,17 +401,16 @@ void WifiSelectionActivity::loop() {
} }
} }
// Go back to network list (whether Cancel or Forget network was selected) // Go back to network list (whether Cancel or Forget network was selected)
state = WifiSelectionState::NETWORK_LIST; startWifiScan();
updateRequired = true;
} else if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { } else if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
// Skip forgetting, go back to network list // Skip forgetting, go back to network list
state = WifiSelectionState::NETWORK_LIST; startWifiScan();
updateRequired = true;
} }
return; return;
} }
// Handle connected state (should not normally be reached - connection completes immediately) // Handle connected state (should not normally be reached - connection
// completes immediately)
if (state == WifiSelectionState::CONNECTED) { if (state == WifiSelectionState::CONNECTED) {
// Safety fallback - immediately complete // Safety fallback - immediately complete
onComplete(true); onComplete(true);
@@ -389,12 +421,14 @@ void WifiSelectionActivity::loop() {
if (state == WifiSelectionState::CONNECTION_FAILED) { if (state == WifiSelectionState::CONNECTION_FAILED) {
if (mappedInput.wasPressed(MappedInputManager::Button::Back) || if (mappedInput.wasPressed(MappedInputManager::Button::Back) ||
mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
// If we used saved credentials, offer to forget the network // If we were auto-connecting or using a saved credential, offer to forget
if (usedSavedPassword) { // the network
if (autoConnecting || usedSavedPassword) {
autoConnecting = false;
state = WifiSelectionState::FORGET_PROMPT; state = WifiSelectionState::FORGET_PROMPT;
forgetPromptSelection = 0; // Default to "Cancel" forgetPromptSelection = 0; // Default to "Cancel"
} else { } else {
// Go back to network list on failure // Go back to network list on failure for non-saved credentials
state = WifiSelectionState::NETWORK_LIST; state = WifiSelectionState::NETWORK_LIST;
} }
updateRequired = true; updateRequired = true;
@@ -420,6 +454,23 @@ void WifiSelectionActivity::loop() {
return; return;
} }
if (mappedInput.wasPressed(MappedInputManager::Button::Right)) {
startWifiScan();
return;
}
const bool leftPressed = mappedInput.wasPressed(MappedInputManager::Button::Left);
if (leftPressed) {
const bool hasSavedPassword = !networks.empty() && networks[selectedNetworkIndex].hasSavedPassword;
if (hasSavedPassword) {
selectedSSID = networks[selectedNetworkIndex].ssid;
state = WifiSelectionState::FORGET_PROMPT;
forgetPromptSelection = 0; // Default to "Cancel"
updateRequired = true;
return;
}
}
// Handle navigation // Handle navigation
buttonNavigator.onNext([this] { buttonNavigator.onNext([this] {
selectedNetworkIndex = ButtonNavigator::nextIndex(selectedNetworkIndex, networks.size()); selectedNetworkIndex = ButtonNavigator::nextIndex(selectedNetworkIndex, networks.size());
@@ -479,6 +530,9 @@ void WifiSelectionActivity::render() const {
renderer.clearScreen(); renderer.clearScreen();
switch (state) { switch (state) {
case WifiSelectionState::AUTO_CONNECTING:
renderConnecting();
break;
case WifiSelectionState::SCANNING: case WifiSelectionState::SCANNING:
renderConnecting(); // Reuse connecting screen with different message renderConnecting(); // Reuse connecting screen with different message
break; break;
@@ -582,7 +636,11 @@ void WifiSelectionActivity::renderNetworkList() const {
// Draw help text // Draw help text
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 75, "* = Encrypted | + = Saved"); renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 75, "* = Encrypted | + = Saved");
const auto labels = mappedInput.mapLabels("« Back", "Connect", "", "");
const bool hasSavedPassword = !networks.empty() && networks[selectedNetworkIndex].hasSavedPassword;
const char* forgetLabel = hasSavedPassword ? "Forget" : "";
const auto labels = mappedInput.mapLabels("« Back", "Connect", forgetLabel, "Refresh");
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
} }
@@ -686,8 +744,7 @@ void WifiSelectionActivity::renderForgetPrompt() const {
const auto height = renderer.getLineHeight(UI_10_FONT_ID); const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height * 3) / 2; const auto top = (pageHeight - height * 3) / 2;
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Connection Failed", true, EpdFontFamily::BOLD); renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Forget Network", true, EpdFontFamily::BOLD);
std::string ssidInfo = "Network: " + selectedSSID; std::string ssidInfo = "Network: " + selectedSSID;
if (ssidInfo.length() > 28) { if (ssidInfo.length() > 28) {
ssidInfo.replace(25, ssidInfo.length() - 25, "..."); ssidInfo.replace(25, ssidInfo.length() - 25, "...");

View File

@@ -22,6 +22,7 @@ struct WifiNetworkInfo {
// WiFi selection states // WiFi selection states
enum class WifiSelectionState { enum class WifiSelectionState {
AUTO_CONNECTING, // Trying to connect to the last known network
SCANNING, // Scanning for networks SCANNING, // Scanning for networks
NETWORK_LIST, // Displaying available networks NETWORK_LIST, // Displaying available networks
PASSWORD_ENTRY, // Entering password for selected network PASSWORD_ENTRY, // Entering password for selected network
@@ -70,6 +71,12 @@ class WifiSelectionActivity final : public ActivityWithSubactivity {
// Whether network was connected using a saved password (skip save prompt) // Whether network was connected using a saved password (skip save prompt)
bool usedSavedPassword = false; bool usedSavedPassword = false;
// Whether to attempt auto-connect on entry
const bool allowAutoConnect;
// Whether we are attempting to auto-connect
bool autoConnecting = false;
// Save/forget prompt selection (0 = Yes, 1 = No) // Save/forget prompt selection (0 = Yes, 1 = No)
int savePromptSelection = 0; int savePromptSelection = 0;
int forgetPromptSelection = 0; int forgetPromptSelection = 0;
@@ -98,8 +105,10 @@ class WifiSelectionActivity final : public ActivityWithSubactivity {
public: public:
explicit WifiSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, explicit WifiSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
const std::function<void(bool connected)>& onComplete) const std::function<void(bool connected)>& onComplete, bool autoConnect = true)
: ActivityWithSubactivity("WifiSelection", renderer, mappedInput), onComplete(onComplete) {} : ActivityWithSubactivity("WifiSelection", renderer, mappedInput),
onComplete(onComplete),
allowAutoConnect(autoConnect) {}
void onEnter() override; void onEnter() override;
void onExit() override; void onExit() override;
void loop() override; void loop() override;

View File

@@ -11,6 +11,7 @@
#include "MappedInputManager.h" #include "MappedInputManager.h"
#include "OtaUpdateActivity.h" #include "OtaUpdateActivity.h"
#include "SettingsList.h" #include "SettingsList.h"
#include "activities/network/WifiSelectionActivity.h"
#include "components/UITheme.h" #include "components/UITheme.h"
#include "fontIds.h" #include "fontIds.h"
@@ -46,11 +47,13 @@ void SettingsActivity::onEnter() {
} }
// Append device-only ACTION items // Append device-only ACTION items
controlsSettings.insert(controlsSettings.begin(), SettingInfo::Action("Remap Front Buttons")); controlsSettings.insert(controlsSettings.begin(),
systemSettings.push_back(SettingInfo::Action("KOReader Sync")); SettingInfo::Action("Remap Front Buttons", SettingAction::RemapFrontButtons));
systemSettings.push_back(SettingInfo::Action("OPDS Browser")); systemSettings.push_back(SettingInfo::Action("Network", SettingAction::Network));
systemSettings.push_back(SettingInfo::Action("Clear Cache")); systemSettings.push_back(SettingInfo::Action("KOReader Sync", SettingAction::KOReaderSync));
systemSettings.push_back(SettingInfo::Action("Check for updates")); systemSettings.push_back(SettingInfo::Action("OPDS Browser", SettingAction::OPDSBrowser));
systemSettings.push_back(SettingInfo::Action("Clear Cache", SettingAction::ClearCache));
systemSettings.push_back(SettingInfo::Action("Check for updates", SettingAction::CheckForUpdates));
// Reset selection to first category // Reset selection to first category
selectedCategoryIndex = 0; selectedCategoryIndex = 0;
@@ -178,46 +181,45 @@ void SettingsActivity::toggleCurrentSetting() {
SETTINGS.*(setting.valuePtr) = currentValue + setting.valueRange.step; SETTINGS.*(setting.valuePtr) = currentValue + setting.valueRange.step;
} }
} else if (setting.type == SettingType::ACTION) { } else if (setting.type == SettingType::ACTION) {
if (strcmp(setting.name, "Remap Front Buttons") == 0) { auto enterSubActivity = [this](Activity* activity) {
xSemaphoreTake(renderingMutex, portMAX_DELAY); xSemaphoreTake(renderingMutex, portMAX_DELAY);
exitActivity(); exitActivity();
enterNewActivity(new ButtonRemapActivity(renderer, mappedInput, [this] { enterNewActivity(activity);
xSemaphoreGive(renderingMutex);
};
auto onComplete = [this] {
exitActivity(); exitActivity();
updateRequired = true; updateRequired = true;
})); };
xSemaphoreGive(renderingMutex);
} else if (strcmp(setting.name, "KOReader Sync") == 0) { auto onCompleteBool = [this](bool) {
xSemaphoreTake(renderingMutex, portMAX_DELAY);
exitActivity();
enterNewActivity(new KOReaderSettingsActivity(renderer, mappedInput, [this] {
exitActivity(); exitActivity();
updateRequired = true; updateRequired = true;
})); };
xSemaphoreGive(renderingMutex);
} else if (strcmp(setting.name, "OPDS Browser") == 0) { switch (setting.action) {
xSemaphoreTake(renderingMutex, portMAX_DELAY); case SettingAction::RemapFrontButtons:
exitActivity(); enterSubActivity(new ButtonRemapActivity(renderer, mappedInput, onComplete));
enterNewActivity(new CalibreSettingsActivity(renderer, mappedInput, [this] { break;
exitActivity(); case SettingAction::KOReaderSync:
updateRequired = true; enterSubActivity(new KOReaderSettingsActivity(renderer, mappedInput, onComplete));
})); break;
xSemaphoreGive(renderingMutex); case SettingAction::OPDSBrowser:
} else if (strcmp(setting.name, "Clear Cache") == 0) { enterSubActivity(new CalibreSettingsActivity(renderer, mappedInput, onComplete));
xSemaphoreTake(renderingMutex, portMAX_DELAY); break;
exitActivity(); case SettingAction::Network:
enterNewActivity(new ClearCacheActivity(renderer, mappedInput, [this] { enterSubActivity(new WifiSelectionActivity(renderer, mappedInput, onCompleteBool, false));
exitActivity(); break;
updateRequired = true; case SettingAction::ClearCache:
})); enterSubActivity(new ClearCacheActivity(renderer, mappedInput, onComplete));
xSemaphoreGive(renderingMutex); break;
} else if (strcmp(setting.name, "Check for updates") == 0) { case SettingAction::CheckForUpdates:
xSemaphoreTake(renderingMutex, portMAX_DELAY); enterSubActivity(new OtaUpdateActivity(renderer, mappedInput, onComplete));
exitActivity(); break;
enterNewActivity(new OtaUpdateActivity(renderer, mappedInput, [this] { case SettingAction::None:
exitActivity(); // Do nothing
updateRequired = true; break;
}));
xSemaphoreGive(renderingMutex);
} }
} else { } else {
return; return;

View File

@@ -14,11 +14,22 @@ class CrossPointSettings;
enum class SettingType { TOGGLE, ENUM, ACTION, VALUE, STRING }; enum class SettingType { TOGGLE, ENUM, ACTION, VALUE, STRING };
enum class SettingAction {
None,
RemapFrontButtons,
KOReaderSync,
OPDSBrowser,
Network,
ClearCache,
CheckForUpdates,
};
struct SettingInfo { struct SettingInfo {
const char* name; const char* name;
SettingType type; SettingType type;
uint8_t CrossPointSettings::* valuePtr = nullptr; uint8_t CrossPointSettings::* valuePtr = nullptr;
std::vector<std::string> enumValues; std::vector<std::string> enumValues;
SettingAction action = SettingAction::None;
struct ValueRange { struct ValueRange {
uint8_t min; uint8_t min;
@@ -63,10 +74,11 @@ struct SettingInfo {
return s; return s;
} }
static SettingInfo Action(const char* name) { static SettingInfo Action(const char* name, SettingAction action) {
SettingInfo s; SettingInfo s;
s.name = name; s.name = name;
s.type = SettingType::ACTION; s.type = SettingType::ACTION;
s.action = action;
return s; return s;
} }