feat: Add per-book letterbox fill override
Introduce BookSettings utility for per-book settings stored in the book's cache directory (book_settings.bin). Add "Letterbox Fill" option to the EPUB reader menu that cycles Default/Dithered/Solid/None. At sleep time, the per-book override is loaded and takes precedence over the global setting for all book types (EPUB, XTC, TXT). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
60
src/util/BookSettings.cpp
Normal file
60
src/util/BookSettings.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "BookSettings.h"
|
||||
|
||||
#include <HalStorage.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Serialization.h>
|
||||
|
||||
namespace {
|
||||
constexpr uint8_t BOOK_SETTINGS_VERSION = 1;
|
||||
constexpr uint8_t BOOK_SETTINGS_COUNT = 1; // Number of persisted fields
|
||||
} // namespace
|
||||
|
||||
std::string BookSettings::filePath(const std::string& cachePath) { return cachePath + "/book_settings.bin"; }
|
||||
|
||||
BookSettings BookSettings::load(const std::string& cachePath) {
|
||||
BookSettings settings;
|
||||
FsFile f;
|
||||
if (!Storage.openFileForRead("BST", filePath(cachePath), f)) {
|
||||
return settings;
|
||||
}
|
||||
|
||||
uint8_t version;
|
||||
serialization::readPod(f, version);
|
||||
if (version != BOOK_SETTINGS_VERSION) {
|
||||
f.close();
|
||||
return settings;
|
||||
}
|
||||
|
||||
uint8_t fieldCount;
|
||||
serialization::readPod(f, fieldCount);
|
||||
|
||||
// Read fields that exist (supports older files with fewer fields)
|
||||
uint8_t fieldsRead = 0;
|
||||
do {
|
||||
serialization::readPod(f, settings.letterboxFillOverride);
|
||||
if (++fieldsRead >= fieldCount) break;
|
||||
// New fields added here for forward compatibility
|
||||
} while (false);
|
||||
|
||||
f.close();
|
||||
Serial.printf("[%lu] [BST] Loaded book settings from %s (letterboxFill=%d)\n", millis(), filePath(cachePath).c_str(),
|
||||
settings.letterboxFillOverride);
|
||||
return settings;
|
||||
}
|
||||
|
||||
bool BookSettings::save(const std::string& cachePath, const BookSettings& settings) {
|
||||
FsFile f;
|
||||
if (!Storage.openFileForWrite("BST", filePath(cachePath), f)) {
|
||||
Serial.printf("[%lu] [BST] Could not save book settings!\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
serialization::writePod(f, BOOK_SETTINGS_VERSION);
|
||||
serialization::writePod(f, BOOK_SETTINGS_COUNT);
|
||||
serialization::writePod(f, settings.letterboxFillOverride);
|
||||
// New fields added here
|
||||
f.close();
|
||||
|
||||
Serial.printf("[%lu] [BST] Saved book settings to %s\n", millis(), filePath(cachePath).c_str());
|
||||
return true;
|
||||
}
|
||||
31
src/util/BookSettings.h
Normal file
31
src/util/BookSettings.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
|
||||
// Per-book settings stored in the book's cache directory.
|
||||
// Fields default to sentinel values (0xFF) meaning "use global setting".
|
||||
class BookSettings {
|
||||
public:
|
||||
// 0xFF = use global default; otherwise one of SLEEP_SCREEN_LETTERBOX_FILL values (0-2).
|
||||
uint8_t letterboxFillOverride = USE_GLOBAL;
|
||||
|
||||
static constexpr uint8_t USE_GLOBAL = 0xFF;
|
||||
|
||||
// Returns the effective letterbox fill mode: the per-book override if set,
|
||||
// otherwise the global setting from CrossPointSettings.
|
||||
uint8_t getEffectiveLetterboxFill() const {
|
||||
if (letterboxFillOverride != USE_GLOBAL &&
|
||||
letterboxFillOverride < CrossPointSettings::SLEEP_SCREEN_LETTERBOX_FILL_COUNT) {
|
||||
return letterboxFillOverride;
|
||||
}
|
||||
return SETTINGS.sleepScreenLetterboxFill;
|
||||
}
|
||||
|
||||
static BookSettings load(const std::string& cachePath);
|
||||
static bool save(const std::string& cachePath, const BookSettings& settings);
|
||||
|
||||
private:
|
||||
static std::string filePath(const std::string& cachePath);
|
||||
};
|
||||
Reference in New Issue
Block a user