mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 14:47:37 +03:00
316 lines
10 KiB
C++
316 lines
10 KiB
C++
#include "CrossPointSettings.h"
|
|
|
|
#include <HardwareSerial.h>
|
|
#include <SDCardManager.h>
|
|
#include <Serialization.h>
|
|
|
|
#include <cstring>
|
|
|
|
#include "fontIds.h"
|
|
|
|
// Initialize the static instance
|
|
CrossPointSettings CrossPointSettings::instance;
|
|
|
|
void readAndValidate(FsFile& file, uint8_t& member, const uint8_t maxValue) {
|
|
uint8_t tempValue;
|
|
serialization::readPod(file, tempValue);
|
|
if (tempValue < maxValue) {
|
|
member = tempValue;
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
|
|
// Increment this when adding new persisted settings fields
|
|
constexpr uint8_t SETTINGS_COUNT = 24;
|
|
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
|
|
} // namespace
|
|
|
|
bool CrossPointSettings::saveToFile() const {
|
|
// Make sure the directory exists
|
|
SdMan.mkdir("/.crosspoint");
|
|
|
|
FsFile outputFile;
|
|
if (!SdMan.openFileForWrite("CPS", SETTINGS_FILE, outputFile)) {
|
|
return false;
|
|
}
|
|
|
|
serialization::writePod(outputFile, SETTINGS_FILE_VERSION);
|
|
serialization::writePod(outputFile, SETTINGS_COUNT);
|
|
serialization::writePod(outputFile, sleepScreen);
|
|
serialization::writePod(outputFile, extraParagraphSpacing);
|
|
serialization::writePod(outputFile, shortPwrBtn);
|
|
serialization::writePod(outputFile, statusBar);
|
|
serialization::writePod(outputFile, orientation);
|
|
serialization::writePod(outputFile, frontButtonLayout);
|
|
serialization::writePod(outputFile, sideButtonLayout);
|
|
serialization::writePod(outputFile, fontFamily);
|
|
serialization::writePod(outputFile, fontSize);
|
|
serialization::writePod(outputFile, lineSpacing);
|
|
serialization::writePod(outputFile, paragraphAlignment);
|
|
serialization::writePod(outputFile, sleepTimeout);
|
|
serialization::writePod(outputFile, refreshFrequency);
|
|
serialization::writePod(outputFile, screenMargin);
|
|
serialization::writePod(outputFile, sleepScreenCoverMode);
|
|
serialization::writeString(outputFile, std::string(opdsServerUrl));
|
|
serialization::writePod(outputFile, textAntiAliasing);
|
|
serialization::writePod(outputFile, hideBatteryPercentage);
|
|
serialization::writePod(outputFile, longPressChapterSkip);
|
|
serialization::writePod(outputFile, hyphenationEnabled);
|
|
serialization::writeString(outputFile, std::string(selectedSleepBmp));
|
|
serialization::writeString(outputFile, std::string(opdsUsername));
|
|
serialization::writeString(outputFile, std::string(opdsPassword));
|
|
serialization::writePod(outputFile, sleepScreenCoverFilter);
|
|
outputFile.close();
|
|
|
|
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
|
|
return true;
|
|
}
|
|
|
|
bool CrossPointSettings::loadFromFile() {
|
|
FsFile inputFile;
|
|
if (!SdMan.openFileForRead("CPS", SETTINGS_FILE, inputFile)) {
|
|
return false;
|
|
}
|
|
|
|
uint8_t version;
|
|
serialization::readPod(inputFile, version);
|
|
if (version != SETTINGS_FILE_VERSION) {
|
|
Serial.printf("[%lu] [CPS] Deserialization failed: Unknown version %u\n", millis(), version);
|
|
inputFile.close();
|
|
return false;
|
|
}
|
|
|
|
uint8_t fileSettingsCount = 0;
|
|
serialization::readPod(inputFile, fileSettingsCount);
|
|
|
|
// load settings that exist (support older files with fewer fields)
|
|
uint8_t settingsRead = 0;
|
|
do {
|
|
readAndValidate(inputFile, sleepScreen, SLEEP_SCREEN_MODE_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
serialization::readPod(inputFile, extraParagraphSpacing);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, shortPwrBtn, SHORT_PWRBTN_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, statusBar, STATUS_BAR_MODE_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, orientation, ORIENTATION_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, frontButtonLayout, FRONT_BUTTON_LAYOUT_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, sideButtonLayout, SIDE_BUTTON_LAYOUT_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, fontFamily, FONT_FAMILY_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, fontSize, FONT_SIZE_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, lineSpacing, LINE_COMPRESSION_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, paragraphAlignment, PARAGRAPH_ALIGNMENT_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, sleepTimeout, SLEEP_TIMEOUT_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, refreshFrequency, REFRESH_FREQUENCY_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
serialization::readPod(inputFile, screenMargin);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, sleepScreenCoverMode, SLEEP_SCREEN_COVER_MODE_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
{
|
|
std::string urlStr;
|
|
serialization::readString(inputFile, urlStr);
|
|
strncpy(opdsServerUrl, urlStr.c_str(), sizeof(opdsServerUrl) - 1);
|
|
opdsServerUrl[sizeof(opdsServerUrl) - 1] = '\0';
|
|
}
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
serialization::readPod(inputFile, textAntiAliasing);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, hideBatteryPercentage, HIDE_BATTERY_PERCENTAGE_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
serialization::readPod(inputFile, longPressChapterSkip);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
serialization::readPod(inputFile, hyphenationEnabled);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
{
|
|
std::string bmpStr;
|
|
serialization::readString(inputFile, bmpStr);
|
|
strncpy(selectedSleepBmp, bmpStr.c_str(), sizeof(selectedSleepBmp) - 1);
|
|
selectedSleepBmp[sizeof(selectedSleepBmp) - 1] = '\0';
|
|
}
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
{
|
|
std::string usernameStr;
|
|
serialization::readString(inputFile, usernameStr);
|
|
strncpy(opdsUsername, usernameStr.c_str(), sizeof(opdsUsername) - 1);
|
|
opdsUsername[sizeof(opdsUsername) - 1] = '\0';
|
|
}
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
{
|
|
std::string passwordStr;
|
|
serialization::readString(inputFile, passwordStr);
|
|
strncpy(opdsPassword, passwordStr.c_str(), sizeof(opdsPassword) - 1);
|
|
opdsPassword[sizeof(opdsPassword) - 1] = '\0';
|
|
}
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
readAndValidate(inputFile, sleepScreenCoverFilter, SLEEP_SCREEN_COVER_FILTER_COUNT);
|
|
if (++settingsRead >= fileSettingsCount) break;
|
|
} while (false);
|
|
|
|
inputFile.close();
|
|
Serial.printf("[%lu] [CPS] Settings loaded from file\n", millis());
|
|
return true;
|
|
}
|
|
|
|
float CrossPointSettings::getReaderLineCompression() const {
|
|
switch (fontFamily) {
|
|
case BOOKERLY:
|
|
default:
|
|
switch (lineSpacing) {
|
|
case TIGHT:
|
|
return 0.95f;
|
|
case NORMAL:
|
|
default:
|
|
return 1.0f;
|
|
case WIDE:
|
|
return 1.1f;
|
|
}
|
|
case NOTOSANS:
|
|
switch (lineSpacing) {
|
|
case TIGHT:
|
|
return 0.90f;
|
|
case NORMAL:
|
|
default:
|
|
return 0.95f;
|
|
case WIDE:
|
|
return 1.0f;
|
|
}
|
|
case OPENDYSLEXIC:
|
|
switch (lineSpacing) {
|
|
case TIGHT:
|
|
return 0.90f;
|
|
case NORMAL:
|
|
default:
|
|
return 0.95f;
|
|
case WIDE:
|
|
return 1.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned long CrossPointSettings::getSleepTimeoutMs() const {
|
|
switch (sleepTimeout) {
|
|
case SLEEP_1_MIN:
|
|
return 1UL * 60 * 1000;
|
|
case SLEEP_5_MIN:
|
|
return 5UL * 60 * 1000;
|
|
case SLEEP_10_MIN:
|
|
default:
|
|
return 10UL * 60 * 1000;
|
|
case SLEEP_15_MIN:
|
|
return 15UL * 60 * 1000;
|
|
case SLEEP_30_MIN:
|
|
return 30UL * 60 * 1000;
|
|
}
|
|
}
|
|
|
|
int CrossPointSettings::getRefreshFrequency() const {
|
|
switch (refreshFrequency) {
|
|
case REFRESH_1:
|
|
return 1;
|
|
case REFRESH_5:
|
|
return 5;
|
|
case REFRESH_10:
|
|
return 10;
|
|
case REFRESH_15:
|
|
default:
|
|
return 15;
|
|
case REFRESH_30:
|
|
return 30;
|
|
}
|
|
}
|
|
|
|
int CrossPointSettings::getReaderFontId() const {
|
|
switch (fontFamily) {
|
|
case BOOKERLY:
|
|
default:
|
|
switch (fontSize) {
|
|
case SMALL:
|
|
return BOOKERLY_12_FONT_ID;
|
|
case MEDIUM:
|
|
default:
|
|
return BOOKERLY_14_FONT_ID;
|
|
case LARGE:
|
|
return BOOKERLY_16_FONT_ID;
|
|
case EXTRA_LARGE:
|
|
return BOOKERLY_18_FONT_ID;
|
|
}
|
|
case NOTOSANS:
|
|
switch (fontSize) {
|
|
case SMALL:
|
|
return NOTOSANS_12_FONT_ID;
|
|
case MEDIUM:
|
|
default:
|
|
return NOTOSANS_14_FONT_ID;
|
|
case LARGE:
|
|
return NOTOSANS_16_FONT_ID;
|
|
case EXTRA_LARGE:
|
|
return NOTOSANS_18_FONT_ID;
|
|
}
|
|
case OPENDYSLEXIC:
|
|
switch (fontSize) {
|
|
case SMALL:
|
|
return OPENDYSLEXIC_8_FONT_ID;
|
|
case MEDIUM:
|
|
default:
|
|
return OPENDYSLEXIC_10_FONT_ID;
|
|
case LARGE:
|
|
return OPENDYSLEXIC_12_FONT_ID;
|
|
case EXTRA_LARGE:
|
|
return OPENDYSLEXIC_14_FONT_ID;
|
|
}
|
|
}
|
|
}
|
|
|
|
const char* CrossPointSettings::getRefreshFrequencyString(uint8_t value) {
|
|
static const char* options[] = {"1 page", "5 pages", "10 pages", "15 pages", "30 pages"};
|
|
static constexpr size_t count = sizeof(options) / sizeof(options[0]);
|
|
if (value < count) {
|
|
return options[value];
|
|
}
|
|
return options[REFRESH_15]; // Default
|
|
}
|
|
|
|
size_t CrossPointSettings::getRefreshFrequencyCount() {
|
|
static const char* options[] = {"1 page", "5 pages", "10 pages", "15 pages", "30 pages"};
|
|
return sizeof(options) / sizeof(options[0]);
|
|
}
|
|
|
|
const char* CrossPointSettings::getSleepScreenString(uint8_t value) {
|
|
static const char* options[] = {"Dark", "Light", "Custom", "Cover", "None"};
|
|
static constexpr size_t count = sizeof(options) / sizeof(options[0]);
|
|
if (value < count) {
|
|
return options[value];
|
|
}
|
|
return options[DARK]; // Default
|
|
}
|
|
|
|
size_t CrossPointSettings::getSleepScreenCount() {
|
|
static const char* options[] = {"Dark", "Light", "Custom", "Cover", "None"};
|
|
return sizeof(options) / sizeof(options[0]);
|
|
}
|
|
|
|
const char* CrossPointSettings::getSleepTimeoutString(uint8_t value) {
|
|
static const char* options[] = {"1 min", "5 min", "10 min", "15 min", "30 min"};
|
|
static constexpr size_t count = sizeof(options) / sizeof(options[0]);
|
|
if (value < count) {
|
|
return options[value];
|
|
}
|
|
return options[SLEEP_10_MIN]; // Default
|
|
}
|
|
|
|
size_t CrossPointSettings::getSleepTimeoutCount() {
|
|
static const char* options[] = {"1 min", "5 min", "10 min", "15 min", "30 min"};
|
|
return sizeof(options) / sizeof(options[0]);
|
|
}
|