mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 06:37:38 +03:00
Merge 201d7f9a85 into d403044f76
This commit is contained in:
commit
232e58f453
@ -22,7 +22,7 @@ void readAndValidate(FsFile& file, uint8_t& member, const uint8_t maxValue) {
|
||||
namespace {
|
||||
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
|
||||
// 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";
|
||||
} // namespace
|
||||
|
||||
@ -60,6 +60,7 @@ bool CrossPointSettings::saveToFile() const {
|
||||
serialization::writeString(outputFile, std::string(opdsUsername));
|
||||
serialization::writeString(outputFile, std::string(opdsPassword));
|
||||
serialization::writePod(outputFile, sleepScreenCoverFilter);
|
||||
serialization::writeString(outputFile, std::string(lastConnectedSSID));
|
||||
// New fields added at end for backward compatibility
|
||||
outputFile.close();
|
||||
|
||||
|
||||
@ -137,6 +137,7 @@ class CrossPointSettings {
|
||||
uint8_t hideBatteryPercentage = HIDE_NEVER;
|
||||
// Long-press chapter skip on side buttons
|
||||
uint8_t longPressChapterSkip = 1;
|
||||
char lastConnectedSSID[33] = "";
|
||||
|
||||
~CrossPointSettings() = default;
|
||||
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
#include <SDCardManager.h>
|
||||
#include <Serialization.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// Initialize the static instance
|
||||
WifiCredentialStore WifiCredentialStore::instance;
|
||||
|
||||
@ -102,8 +104,8 @@ bool WifiCredentialStore::loadFromFile() {
|
||||
|
||||
bool WifiCredentialStore::addCredential(const std::string& ssid, const std::string& password) {
|
||||
// Check if this SSID already exists and update it
|
||||
const auto cred = find_if(credentials.begin(), credentials.end(),
|
||||
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
|
||||
auto cred = std::find_if(credentials.begin(), credentials.end(),
|
||||
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
|
||||
if (cred != credentials.end()) {
|
||||
cred->password = password;
|
||||
Serial.printf("[%lu] [WCS] Updated credentials for: %s\n", millis(), ssid.c_str());
|
||||
@ -123,8 +125,8 @@ bool WifiCredentialStore::addCredential(const std::string& ssid, const std::stri
|
||||
}
|
||||
|
||||
bool WifiCredentialStore::removeCredential(const std::string& ssid) {
|
||||
const auto cred = find_if(credentials.begin(), credentials.end(),
|
||||
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
|
||||
auto cred = std::find_if(credentials.begin(), credentials.end(),
|
||||
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
|
||||
if (cred != credentials.end()) {
|
||||
credentials.erase(cred);
|
||||
Serial.printf("[%lu] [WCS] Removed credentials for: %s\n", millis(), ssid.c_str());
|
||||
@ -134,8 +136,8 @@ bool WifiCredentialStore::removeCredential(const std::string& ssid) {
|
||||
}
|
||||
|
||||
const WifiCredential* WifiCredentialStore::findCredential(const std::string& ssid) const {
|
||||
const auto cred = find_if(credentials.begin(), credentials.end(),
|
||||
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
|
||||
auto cred = std::find_if(credentials.begin(), credentials.end(),
|
||||
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
|
||||
|
||||
if (cred != credentials.end()) {
|
||||
return &*cred;
|
||||
|
||||
75
src/activities/network/AutoConnectingActivity.cpp
Normal file
75
src/activities/network/AutoConnectingActivity.cpp
Normal 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();
|
||||
}
|
||||
26
src/activities/network/AutoConnectingActivity.h
Normal file
26
src/activities/network/AutoConnectingActivity.h
Normal 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;
|
||||
};
|
||||
@ -3,8 +3,10 @@
|
||||
#include <GfxRenderer.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
#include "MappedInputManager.h"
|
||||
#include "WifiCredentialStore.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]);
|
||||
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
|
||||
// Otherwise, immediately complete so parent can start web server
|
||||
if (!usedSavedPassword && !enteredPassword.empty()) {
|
||||
@ -311,14 +318,12 @@ void WifiSelectionActivity::loop() {
|
||||
|
||||
// Handle save prompt state
|
||||
if (state == WifiSelectionState::SAVE_PROMPT) {
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Up) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Left)) {
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Left)) {
|
||||
if (savePromptSelection > 0) {
|
||||
savePromptSelection--;
|
||||
updateRequired = true;
|
||||
}
|
||||
} else if (mappedInput.wasPressed(MappedInputManager::Button::Down) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Right)) {
|
||||
} else if (mappedInput.wasPressed(MappedInputManager::Button::Right)) {
|
||||
if (savePromptSelection < 1) {
|
||||
savePromptSelection++;
|
||||
updateRequired = true;
|
||||
@ -341,14 +346,12 @@ void WifiSelectionActivity::loop() {
|
||||
|
||||
// Handle forget prompt state (connection failed with saved credentials)
|
||||
if (state == WifiSelectionState::FORGET_PROMPT) {
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Up) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Left)) {
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Left)) {
|
||||
if (forgetPromptSelection > 0) {
|
||||
forgetPromptSelection--;
|
||||
updateRequired = true;
|
||||
}
|
||||
} else if (mappedInput.wasPressed(MappedInputManager::Button::Down) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Right)) {
|
||||
} else if (mappedInput.wasPressed(MappedInputManager::Button::Right)) {
|
||||
if (forgetPromptSelection < 1) {
|
||||
forgetPromptSelection++;
|
||||
updateRequired = true;
|
||||
@ -360,8 +363,8 @@ void WifiSelectionActivity::loop() {
|
||||
WIFI_STORE.removeCredential(selectedSSID);
|
||||
xSemaphoreGive(renderingMutex);
|
||||
// Update the network list to reflect the change
|
||||
const auto network = find_if(networks.begin(), networks.end(),
|
||||
[this](const WifiNetworkInfo& net) { return net.ssid == selectedSSID; });
|
||||
const auto network = std::find_if(networks.begin(), networks.end(),
|
||||
[this](const WifiNetworkInfo& net) { return net.ssid == selectedSSID; });
|
||||
if (network != networks.end()) {
|
||||
network->hasSavedPassword = false;
|
||||
}
|
||||
@ -420,18 +423,23 @@ void WifiSelectionActivity::loop() {
|
||||
}
|
||||
|
||||
// Handle UP/DOWN navigation
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Up) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Left)) {
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Up)) {
|
||||
if (selectedNetworkIndex > 0) {
|
||||
selectedNetworkIndex--;
|
||||
updateRequired = true;
|
||||
}
|
||||
} else if (mappedInput.wasPressed(MappedInputManager::Button::Down) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Right)) {
|
||||
} else if (mappedInput.wasPressed(MappedInputManager::Button::Down)) {
|
||||
if (!networks.empty() && selectedNetworkIndex < static_cast<int>(networks.size()) - 1) {
|
||||
selectedNetworkIndex++;
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
@ -689,7 +697,7 @@ void WifiSelectionActivity::renderForgetPrompt() const {
|
||||
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
||||
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;
|
||||
if (ssidInfo.length() > 28) {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "KOReaderSettingsActivity.h"
|
||||
#include "MappedInputManager.h"
|
||||
#include "OtaUpdateActivity.h"
|
||||
#include "activities/network/WifiSelectionActivity.h"
|
||||
#include "fontIds.h"
|
||||
|
||||
void CategorySettingsActivity::taskTrampoline(void* param) {
|
||||
@ -95,7 +96,15 @@ void CategorySettingsActivity::toggleCurrentSetting() {
|
||||
SETTINGS.*(setting.valuePtr) = currentValue + setting.valueRange.step;
|
||||
}
|
||||
} 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);
|
||||
exitActivity();
|
||||
enterNewActivity(new KOReaderSettingsActivity(renderer, mappedInput, [this] {
|
||||
|
||||
@ -48,11 +48,14 @@ const SettingInfo controlsSettings[controlsSettingsCount] = {
|
||||
SettingInfo::Toggle("Long-press Chapter Skip", &CrossPointSettings::longPressChapterSkip),
|
||||
SettingInfo::Enum("Short Power Button Click", &CrossPointSettings::shortPwrBtn, {"Ignore", "Sleep", "Page Turn"})};
|
||||
|
||||
constexpr int systemSettingsCount = 5;
|
||||
constexpr int systemSettingsCount = 6;
|
||||
const SettingInfo systemSettings[systemSettingsCount] = {
|
||||
SettingInfo::Enum("Time to Sleep", &CrossPointSettings::sleepTimeout,
|
||||
{"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")};
|
||||
} // namespace
|
||||
|
||||
|
||||
42
src/main.cpp
42
src/main.cpp
@ -5,6 +5,7 @@
|
||||
#include <HalGPIO.h>
|
||||
#include <SDCardManager.h>
|
||||
#include <SPI.h>
|
||||
#include <WiFi.h>
|
||||
#include <builtinFonts/all.h>
|
||||
|
||||
#include <cstring>
|
||||
@ -20,7 +21,9 @@
|
||||
#include "activities/browser/OpdsBookBrowserActivity.h"
|
||||
#include "activities/home/HomeActivity.h"
|
||||
#include "activities/home/MyLibraryActivity.h"
|
||||
#include "activities/network/AutoConnectingActivity.h"
|
||||
#include "activities/network/CrossPointWebServerActivity.h"
|
||||
#include "activities/network/WifiSelectionActivity.h"
|
||||
#include "activities/reader/ReaderActivity.h"
|
||||
#include "activities/settings/SettingsActivity.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 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() {
|
||||
exitActivity();
|
||||
enterNewActivity(new CrossPointWebServerActivity(renderer, mappedInputManager, onGoHome));
|
||||
withWifi([]() {
|
||||
exitActivity();
|
||||
enterNewActivity(new CrossPointWebServerActivity(renderer, mappedInputManager, onGoHome));
|
||||
});
|
||||
}
|
||||
|
||||
void onGoToSettings() {
|
||||
@ -232,8 +264,10 @@ void onGoToMyLibraryWithTab(const std::string& path, MyLibraryActivity::Tab tab)
|
||||
}
|
||||
|
||||
void onGoToBrowser() {
|
||||
exitActivity();
|
||||
enterNewActivity(new OpdsBookBrowserActivity(renderer, mappedInputManager, onGoHome));
|
||||
withWifi([]() {
|
||||
exitActivity();
|
||||
enterNewActivity(new OpdsBookBrowserActivity(renderer, mappedInputManager, onGoHome));
|
||||
});
|
||||
}
|
||||
|
||||
void onGoHome() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user