This commit is contained in:
Eliz 2026-02-03 18:32:56 +03:00 committed by GitHub
commit 232e58f453
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 189 additions and 30 deletions

View File

@ -22,7 +22,7 @@ void readAndValidate(FsFile& file, uint8_t& member, const uint8_t maxValue) {
namespace { namespace {
constexpr uint8_t SETTINGS_FILE_VERSION = 1; constexpr uint8_t SETTINGS_FILE_VERSION = 1;
// Increment this when adding new persisted settings fields // Increment this when adding new persisted settings fields
constexpr uint8_t SETTINGS_COUNT = 23; constexpr uint8_t SETTINGS_COUNT = 24;
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin"; constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
} // namespace } // namespace
@ -60,6 +60,7 @@ bool CrossPointSettings::saveToFile() const {
serialization::writeString(outputFile, std::string(opdsUsername)); serialization::writeString(outputFile, std::string(opdsUsername));
serialization::writeString(outputFile, std::string(opdsPassword)); serialization::writeString(outputFile, std::string(opdsPassword));
serialization::writePod(outputFile, sleepScreenCoverFilter); serialization::writePod(outputFile, sleepScreenCoverFilter);
serialization::writeString(outputFile, std::string(lastConnectedSSID));
// New fields added at end for backward compatibility // New fields added at end for backward compatibility
outputFile.close(); outputFile.close();

View File

@ -137,6 +137,7 @@ class CrossPointSettings {
uint8_t hideBatteryPercentage = HIDE_NEVER; uint8_t hideBatteryPercentage = HIDE_NEVER;
// Long-press chapter skip on side buttons // Long-press chapter skip on side buttons
uint8_t longPressChapterSkip = 1; uint8_t longPressChapterSkip = 1;
char lastConnectedSSID[33] = "";
~CrossPointSettings() = default; ~CrossPointSettings() = default;

View File

@ -4,6 +4,8 @@
#include <SDCardManager.h> #include <SDCardManager.h>
#include <Serialization.h> #include <Serialization.h>
#include <algorithm>
// Initialize the static instance // Initialize the static instance
WifiCredentialStore WifiCredentialStore::instance; WifiCredentialStore WifiCredentialStore::instance;
@ -102,7 +104,7 @@ bool WifiCredentialStore::loadFromFile() {
bool WifiCredentialStore::addCredential(const std::string& ssid, const std::string& password) { bool WifiCredentialStore::addCredential(const std::string& ssid, const std::string& password) {
// Check if this SSID already exists and update it // Check if this SSID already exists and update it
const auto cred = find_if(credentials.begin(), credentials.end(), auto cred = std::find_if(credentials.begin(), credentials.end(),
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; }); [&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
if (cred != credentials.end()) { if (cred != credentials.end()) {
cred->password = password; cred->password = password;
@ -123,7 +125,7 @@ bool WifiCredentialStore::addCredential(const std::string& ssid, const std::stri
} }
bool WifiCredentialStore::removeCredential(const std::string& ssid) { bool WifiCredentialStore::removeCredential(const std::string& ssid) {
const auto cred = find_if(credentials.begin(), credentials.end(), auto cred = std::find_if(credentials.begin(), credentials.end(),
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; }); [&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
if (cred != credentials.end()) { if (cred != credentials.end()) {
credentials.erase(cred); credentials.erase(cred);
@ -134,7 +136,7 @@ bool WifiCredentialStore::removeCredential(const std::string& ssid) {
} }
const WifiCredential* WifiCredentialStore::findCredential(const std::string& ssid) const { const WifiCredential* WifiCredentialStore::findCredential(const std::string& ssid) const {
const auto cred = find_if(credentials.begin(), credentials.end(), auto cred = std::find_if(credentials.begin(), credentials.end(),
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; }); [&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
if (cred != credentials.end()) { if (cred != credentials.end()) {

View File

@ -0,0 +1,75 @@
#include "AutoConnectingActivity.h"
#include <GfxRenderer.h>
#include <WiFi.h>
#include <string>
#include "CrossPointSettings.h"
#include "MappedInputManager.h"
#include "WifiCredentialStore.h"
#include "fontIds.h"
AutoConnectingActivity::AutoConnectingActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
const std::function<void()>& on_success,
const std::function<void()>& on_failure)
: Activity("AutoConnecting", renderer, mappedInput), on_success(on_success), on_failure(on_failure) {}
void AutoConnectingActivity::onEnter() {
Activity::onEnter();
render();
attemptConnection();
}
void AutoConnectingActivity::onExit() { Activity::onExit(); }
void AutoConnectingActivity::loop() { checkConnectionStatus(); }
void AutoConnectingActivity::attemptConnection() {
connectionStartTime = millis();
std::string ssid = SETTINGS.lastConnectedSSID;
const auto* cred = WIFI_STORE.findCredential(ssid);
if (!cred) {
on_failure();
return;
}
WiFi.mode(WIFI_STA);
WiFi.begin(ssid.c_str(), cred->password.c_str());
}
void AutoConnectingActivity::checkConnectionStatus() {
const wl_status_t status = WiFi.status();
if (status == WL_CONNECTED) {
on_success();
return;
}
if (status == WL_CONNECT_FAILED || status == WL_NO_SSID_AVAIL) {
on_failure();
return;
}
if (millis() - connectionStartTime > CONNECTION_TIMEOUT_MS) {
WiFi.disconnect();
on_failure();
return;
}
}
void AutoConnectingActivity::render() const {
renderer.clearScreen();
const auto pageHeight = renderer.getScreenHeight();
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height) / 2;
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Connecting...", true, EpdFontFamily::BOLD);
std::string ssidInfo = "to " + std::string(SETTINGS.lastConnectedSSID);
if (ssidInfo.length() > 25) {
ssidInfo.replace(22, ssidInfo.length() - 22, "...");
}
renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str());
renderer.displayBuffer();
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <functional>
#include "activities/Activity.h"
class AutoConnectingActivity final : public Activity {
public:
AutoConnectingActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
const std::function<void()>& on_success, const std::function<void()>& on_failure);
void onEnter() override;
void onExit() override;
void loop() override;
private:
void render() const;
void attemptConnection();
void checkConnectionStatus();
const std::function<void()> on_success;
const std::function<void()> on_failure;
unsigned long connectionStartTime = 0;
static constexpr unsigned long CONNECTION_TIMEOUT_MS = 15000;
};

View File

@ -3,8 +3,10 @@
#include <GfxRenderer.h> #include <GfxRenderer.h>
#include <WiFi.h> #include <WiFi.h>
#include <algorithm>
#include <map> #include <map>
#include "CrossPointSettings.h"
#include "MappedInputManager.h" #include "MappedInputManager.h"
#include "WifiCredentialStore.h" #include "WifiCredentialStore.h"
#include "activities/util/KeyboardEntryActivity.h" #include "activities/util/KeyboardEntryActivity.h"
@ -251,6 +253,11 @@ void WifiSelectionActivity::checkConnectionStatus() {
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;
// Save the last connected SSID
strncpy(SETTINGS.lastConnectedSSID, selectedSSID.c_str(), sizeof(SETTINGS.lastConnectedSSID) - 1);
SETTINGS.lastConnectedSSID[sizeof(SETTINGS.lastConnectedSSID) - 1] = '\0';
SETTINGS.saveToFile();
// 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
if (!usedSavedPassword && !enteredPassword.empty()) { if (!usedSavedPassword && !enteredPassword.empty()) {
@ -311,14 +318,12 @@ void WifiSelectionActivity::loop() {
// Handle save prompt state // Handle save prompt state
if (state == WifiSelectionState::SAVE_PROMPT) { if (state == WifiSelectionState::SAVE_PROMPT) {
if (mappedInput.wasPressed(MappedInputManager::Button::Up) || if (mappedInput.wasPressed(MappedInputManager::Button::Left)) {
mappedInput.wasPressed(MappedInputManager::Button::Left)) {
if (savePromptSelection > 0) { if (savePromptSelection > 0) {
savePromptSelection--; savePromptSelection--;
updateRequired = true; updateRequired = true;
} }
} else if (mappedInput.wasPressed(MappedInputManager::Button::Down) || } else if (mappedInput.wasPressed(MappedInputManager::Button::Right)) {
mappedInput.wasPressed(MappedInputManager::Button::Right)) {
if (savePromptSelection < 1) { if (savePromptSelection < 1) {
savePromptSelection++; savePromptSelection++;
updateRequired = true; updateRequired = true;
@ -341,14 +346,12 @@ void WifiSelectionActivity::loop() {
// Handle forget prompt state (connection failed with saved credentials) // Handle forget prompt state (connection failed with saved credentials)
if (state == WifiSelectionState::FORGET_PROMPT) { if (state == WifiSelectionState::FORGET_PROMPT) {
if (mappedInput.wasPressed(MappedInputManager::Button::Up) || if (mappedInput.wasPressed(MappedInputManager::Button::Left)) {
mappedInput.wasPressed(MappedInputManager::Button::Left)) {
if (forgetPromptSelection > 0) { if (forgetPromptSelection > 0) {
forgetPromptSelection--; forgetPromptSelection--;
updateRequired = true; updateRequired = true;
} }
} else if (mappedInput.wasPressed(MappedInputManager::Button::Down) || } else if (mappedInput.wasPressed(MappedInputManager::Button::Right)) {
mappedInput.wasPressed(MappedInputManager::Button::Right)) {
if (forgetPromptSelection < 1) { if (forgetPromptSelection < 1) {
forgetPromptSelection++; forgetPromptSelection++;
updateRequired = true; updateRequired = true;
@ -360,7 +363,7 @@ void WifiSelectionActivity::loop() {
WIFI_STORE.removeCredential(selectedSSID); WIFI_STORE.removeCredential(selectedSSID);
xSemaphoreGive(renderingMutex); xSemaphoreGive(renderingMutex);
// Update the network list to reflect the change // Update the network list to reflect the change
const auto network = find_if(networks.begin(), networks.end(), const auto network = std::find_if(networks.begin(), networks.end(),
[this](const WifiNetworkInfo& net) { return net.ssid == selectedSSID; }); [this](const WifiNetworkInfo& net) { return net.ssid == selectedSSID; });
if (network != networks.end()) { if (network != networks.end()) {
network->hasSavedPassword = false; network->hasSavedPassword = false;
@ -420,18 +423,23 @@ void WifiSelectionActivity::loop() {
} }
// Handle UP/DOWN navigation // Handle UP/DOWN navigation
if (mappedInput.wasPressed(MappedInputManager::Button::Up) || if (mappedInput.wasPressed(MappedInputManager::Button::Up)) {
mappedInput.wasPressed(MappedInputManager::Button::Left)) {
if (selectedNetworkIndex > 0) { if (selectedNetworkIndex > 0) {
selectedNetworkIndex--; selectedNetworkIndex--;
updateRequired = true; updateRequired = true;
} }
} else if (mappedInput.wasPressed(MappedInputManager::Button::Down) || } else if (mappedInput.wasPressed(MappedInputManager::Button::Down)) {
mappedInput.wasPressed(MappedInputManager::Button::Right)) {
if (!networks.empty() && selectedNetworkIndex < static_cast<int>(networks.size()) - 1) { if (!networks.empty() && selectedNetworkIndex < static_cast<int>(networks.size()) - 1) {
selectedNetworkIndex++; selectedNetworkIndex++;
updateRequired = true; updateRequired = true;
} }
} else if (mappedInput.wasPressed(MappedInputManager::Button::Left)) {
if (!networks.empty() && networks[selectedNetworkIndex].hasSavedPassword) {
selectedSSID = networks[selectedNetworkIndex].ssid;
state = WifiSelectionState::FORGET_PROMPT;
forgetPromptSelection = 0; // Default to "Cancel"
updateRequired = true;
}
} }
} }
} }
@ -585,7 +593,7 @@ 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 auto labels = mappedInput.mapLabels("« Back", "Connect", "Forget", "");
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
} }
@ -689,7 +697,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) {

View File

@ -11,6 +11,7 @@
#include "KOReaderSettingsActivity.h" #include "KOReaderSettingsActivity.h"
#include "MappedInputManager.h" #include "MappedInputManager.h"
#include "OtaUpdateActivity.h" #include "OtaUpdateActivity.h"
#include "activities/network/WifiSelectionActivity.h"
#include "fontIds.h" #include "fontIds.h"
void CategorySettingsActivity::taskTrampoline(void* param) { void CategorySettingsActivity::taskTrampoline(void* param) {
@ -95,7 +96,15 @@ void CategorySettingsActivity::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, "KOReader Sync") == 0) { if (strcmp(setting.name, "Network") == 0) {
xSemaphoreTake(renderingMutex, portMAX_DELAY);
exitActivity();
enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, [this](bool) {
exitActivity();
updateRequired = true;
}));
xSemaphoreGive(renderingMutex);
} else if (strcmp(setting.name, "KOReader Sync") == 0) {
xSemaphoreTake(renderingMutex, portMAX_DELAY); xSemaphoreTake(renderingMutex, portMAX_DELAY);
exitActivity(); exitActivity();
enterNewActivity(new KOReaderSettingsActivity(renderer, mappedInput, [this] { enterNewActivity(new KOReaderSettingsActivity(renderer, mappedInput, [this] {

View File

@ -48,11 +48,14 @@ const SettingInfo controlsSettings[controlsSettingsCount] = {
SettingInfo::Toggle("Long-press Chapter Skip", &CrossPointSettings::longPressChapterSkip), SettingInfo::Toggle("Long-press Chapter Skip", &CrossPointSettings::longPressChapterSkip),
SettingInfo::Enum("Short Power Button Click", &CrossPointSettings::shortPwrBtn, {"Ignore", "Sleep", "Page Turn"})}; SettingInfo::Enum("Short Power Button Click", &CrossPointSettings::shortPwrBtn, {"Ignore", "Sleep", "Page Turn"})};
constexpr int systemSettingsCount = 5; constexpr int systemSettingsCount = 6;
const SettingInfo systemSettings[systemSettingsCount] = { const SettingInfo systemSettings[systemSettingsCount] = {
SettingInfo::Enum("Time to Sleep", &CrossPointSettings::sleepTimeout, SettingInfo::Enum("Time to Sleep", &CrossPointSettings::sleepTimeout,
{"1 min", "5 min", "10 min", "15 min", "30 min"}), {"1 min", "5 min", "10 min", "15 min", "30 min"}),
SettingInfo::Action("KOReader Sync"), SettingInfo::Action("OPDS Browser"), SettingInfo::Action("Clear Cache"), SettingInfo::Action("Network"),
SettingInfo::Action("KOReader Sync"),
SettingInfo::Action("OPDS Browser"),
SettingInfo::Action("Clear Cache"),
SettingInfo::Action("Check for updates")}; SettingInfo::Action("Check for updates")};
} // namespace } // namespace

View File

@ -5,6 +5,7 @@
#include <HalGPIO.h> #include <HalGPIO.h>
#include <SDCardManager.h> #include <SDCardManager.h>
#include <SPI.h> #include <SPI.h>
#include <WiFi.h>
#include <builtinFonts/all.h> #include <builtinFonts/all.h>
#include <cstring> #include <cstring>
@ -20,7 +21,9 @@
#include "activities/browser/OpdsBookBrowserActivity.h" #include "activities/browser/OpdsBookBrowserActivity.h"
#include "activities/home/HomeActivity.h" #include "activities/home/HomeActivity.h"
#include "activities/home/MyLibraryActivity.h" #include "activities/home/MyLibraryActivity.h"
#include "activities/network/AutoConnectingActivity.h"
#include "activities/network/CrossPointWebServerActivity.h" #include "activities/network/CrossPointWebServerActivity.h"
#include "activities/network/WifiSelectionActivity.h"
#include "activities/reader/ReaderActivity.h" #include "activities/reader/ReaderActivity.h"
#include "activities/settings/SettingsActivity.h" #include "activities/settings/SettingsActivity.h"
#include "activities/util/FullScreenMessageActivity.h" #include "activities/util/FullScreenMessageActivity.h"
@ -211,9 +214,38 @@ void onGoToReader(const std::string& initialEpubPath, MyLibraryActivity::Tab fro
} }
void onContinueReading() { onGoToReader(APP_STATE.openEpubPath, MyLibraryActivity::Tab::Recent); } void onContinueReading() { onGoToReader(APP_STATE.openEpubPath, MyLibraryActivity::Tab::Recent); }
void onGoHome(); // forward declaration
void withWifi(std::function<void()> on_success) {
if (WiFi.isConnected()) {
on_success();
return;
}
auto on_failure = [on_success]() {
exitActivity();
enterNewActivity(new WifiSelectionActivity(renderer, mappedInputManager, [on_success](bool connected) {
if (connected) {
on_success();
} else {
onGoHome();
}
}));
};
if (strlen(SETTINGS.lastConnectedSSID) > 0) {
exitActivity();
enterNewActivity(new AutoConnectingActivity(renderer, mappedInputManager, on_success, on_failure));
} else {
on_failure();
}
}
void onGoToFileTransfer() { void onGoToFileTransfer() {
withWifi([]() {
exitActivity(); exitActivity();
enterNewActivity(new CrossPointWebServerActivity(renderer, mappedInputManager, onGoHome)); enterNewActivity(new CrossPointWebServerActivity(renderer, mappedInputManager, onGoHome));
});
} }
void onGoToSettings() { void onGoToSettings() {
@ -232,8 +264,10 @@ void onGoToMyLibraryWithTab(const std::string& path, MyLibraryActivity::Tab tab)
} }
void onGoToBrowser() { void onGoToBrowser() {
withWifi([]() {
exitActivity(); exitActivity();
enterNewActivity(new OpdsBookBrowserActivity(renderer, mappedInputManager, onGoHome)); enterNewActivity(new OpdsBookBrowserActivity(renderer, mappedInputManager, onGoHome));
});
} }
void onGoHome() { void onGoHome() {