Swap to Last Book Working

This commit is contained in:
Irene Ying 2026-01-19 17:55:39 -08:00
parent 21277e03eb
commit 5c84667c24
12 changed files with 102 additions and 14 deletions

View File

@ -53,7 +53,7 @@ class CrossPointSettings {
enum REFRESH_FREQUENCY { REFRESH_1 = 0, REFRESH_5 = 1, REFRESH_10 = 2, REFRESH_15 = 3, REFRESH_30 = 4 }; enum REFRESH_FREQUENCY { REFRESH_1 = 0, REFRESH_5 = 1, REFRESH_10 = 2, REFRESH_15 = 3, REFRESH_30 = 4 };
// Short power button press actions // Short power button press actions
enum SHORT_PWRBTN { IGNORE = 0, SLEEP = 1, PAGE_TURN = 2 }; enum SHORT_PWRBTN { IGNORE = 0, SLEEP = 1, PAGE_TURN = 2, LAST_BOOK = 3 };
// Hide battery percentage // Hide battery percentage
enum HIDE_BATTERY_PERCENTAGE { HIDE_NEVER = 0, HIDE_READER = 1, HIDE_ALWAYS = 2 }; enum HIDE_BATTERY_PERCENTAGE { HIDE_NEVER = 0, HIDE_READER = 1, HIDE_ALWAYS = 2 };

View File

@ -19,6 +19,7 @@ bool CrossPointState::saveToFile() const {
serialization::writePod(outputFile, STATE_FILE_VERSION); serialization::writePod(outputFile, STATE_FILE_VERSION);
serialization::writeString(outputFile, openEpubPath); serialization::writeString(outputFile, openEpubPath);
serialization::writeString(outputFile, lastOpenBookPath);
serialization::writePod(outputFile, lastSleepImage); serialization::writePod(outputFile, lastSleepImage);
outputFile.close(); outputFile.close();
return true; return true;
@ -39,6 +40,7 @@ bool CrossPointState::loadFromFile() {
} }
serialization::readString(inputFile, openEpubPath); serialization::readString(inputFile, openEpubPath);
serialization::readString(inputFile, lastOpenBookPath);
if (version >= 2) { if (version >= 2) {
serialization::readPod(inputFile, lastSleepImage); serialization::readPod(inputFile, lastSleepImage);
} else { } else {

View File

@ -8,6 +8,7 @@ class CrossPointState {
public: public:
std::string openEpubPath; std::string openEpubPath;
std::string lastOpenBookPath;
uint8_t lastSleepImage; uint8_t lastSleepImage;
~CrossPointState() = default; ~CrossPointState() = default;

View File

@ -74,7 +74,10 @@ void EpubReaderActivity::onEnter() {
} }
} }
// Save current epub as last opened epub // Save last opened epub before setting current opened epub
if (APP_STATE.openEpubPath != epub->getPath()) {
APP_STATE.lastOpenBookPath = APP_STATE.openEpubPath;
}
APP_STATE.openEpubPath = epub->getPath(); APP_STATE.openEpubPath = epub->getPath();
APP_STATE.saveToFile(); APP_STATE.saveToFile();
@ -149,6 +152,25 @@ void EpubReaderActivity::loop() {
return; return;
} }
if (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::LAST_BOOK &&
mappedInput.wasReleased(MappedInputManager::Button::Power)) {
if (APP_STATE.lastOpenBookPath.empty()) {
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, "No last book found.");
constexpr int margin = 20;
const int x = (renderer.getScreenWidth() - textWidth - margin * 2) / 2;
constexpr int y = 117;
const int w = textWidth + margin * 2;
const int h = renderer.getLineHeight(UI_12_FONT_ID) + margin * 2;
renderer.fillRect(x - 5, y - 5, w + 10, h + 10, true);
renderer.fillRect(x + 5, y + 5, w - 10, h - 10, false);
renderer.drawText(UI_12_FONT_ID, x + margin, y + margin, "No last book found.");
renderer.displayBuffer();
} else {
onSwapBooks();
}
return;
}
const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::PageBack) || const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::PageBack) ||
mappedInput.wasReleased(MappedInputManager::Button::Left); mappedInput.wasReleased(MappedInputManager::Button::Left);
const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) || const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) ||

View File

@ -18,6 +18,7 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
bool updateRequired = false; bool updateRequired = false;
const std::function<void()> onGoBack; const std::function<void()> onGoBack;
const std::function<void()> onGoHome; const std::function<void()> onGoHome;
const std::function<void()> onSwapBooks;
static void taskTrampoline(void* param); static void taskTrampoline(void* param);
[[noreturn]] void displayTaskLoop(); [[noreturn]] void displayTaskLoop();
@ -28,11 +29,13 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
public: public:
explicit EpubReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr<Epub> epub, explicit EpubReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr<Epub> epub,
const std::function<void()>& onGoBack, const std::function<void()>& onGoHome) const std::function<void()>& onGoBack, const std::function<void()>& onGoHome,
const std::function<void()>& onSwapBooks)
: ActivityWithSubactivity("EpubReader", renderer, mappedInput), : ActivityWithSubactivity("EpubReader", renderer, mappedInput),
epub(std::move(epub)), epub(std::move(epub)),
onGoBack(onGoBack), onGoBack(onGoBack),
onGoHome(onGoHome) {} onGoHome(onGoHome),
onSwapBooks(onSwapBooks) {}
void onEnter() override; void onEnter() override;
void onExit() override; void onExit() override;
void loop() override; void loop() override;

View File

@ -1,5 +1,6 @@
#include "ReaderActivity.h" #include "ReaderActivity.h"
#include "CrossPointState.h"
#include "Epub.h" #include "Epub.h"
#include "EpubReaderActivity.h" #include "EpubReaderActivity.h"
#include "FileSelectionActivity.h" #include "FileSelectionActivity.h"
@ -74,7 +75,12 @@ std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) {
} }
void ReaderActivity::onSelectBookFile(const std::string& path) { void ReaderActivity::onSelectBookFile(const std::string& path) {
if (path.empty()) {
return;
}
currentBookPath = path; // Track current book path currentBookPath = path; // Track current book path
exitActivity(); exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Loading...")); enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Loading..."));
@ -131,7 +137,7 @@ void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
exitActivity(); exitActivity();
enterNewActivity(new EpubReaderActivity( enterNewActivity(new EpubReaderActivity(
renderer, mappedInput, std::move(epub), [this, epubPath] { onGoToFileSelection(epubPath); }, renderer, mappedInput, std::move(epub), [this, epubPath] { onGoToFileSelection(epubPath); },
[this] { onGoBack(); })); [this] { onGoBack(); }, [this] { onSelectBookFile(APP_STATE.lastOpenBookPath); }));
} }
void ReaderActivity::onGoToXtcReader(std::unique_ptr<Xtc> xtc) { void ReaderActivity::onGoToXtcReader(std::unique_ptr<Xtc> xtc) {
@ -139,8 +145,8 @@ void ReaderActivity::onGoToXtcReader(std::unique_ptr<Xtc> xtc) {
currentBookPath = xtcPath; currentBookPath = xtcPath;
exitActivity(); exitActivity();
enterNewActivity(new XtcReaderActivity( enterNewActivity(new XtcReaderActivity(
renderer, mappedInput, std::move(xtc), [this, xtcPath] { onGoToFileSelection(xtcPath); }, renderer, mappedInput, std::move(xtc), [this, xtcPath] { onGoToFileSelection(xtcPath); }, [this] { onGoBack(); },
[this] { onGoBack(); })); [this] { onSelectBookFile(APP_STATE.lastOpenBookPath); }));
} }
void ReaderActivity::onGoToTxtReader(std::unique_ptr<Txt> txt) { void ReaderActivity::onGoToTxtReader(std::unique_ptr<Txt> txt) {
@ -148,8 +154,8 @@ void ReaderActivity::onGoToTxtReader(std::unique_ptr<Txt> txt) {
currentBookPath = txtPath; currentBookPath = txtPath;
exitActivity(); exitActivity();
enterNewActivity(new TxtReaderActivity( enterNewActivity(new TxtReaderActivity(
renderer, mappedInput, std::move(txt), [this, txtPath] { onGoToFileSelection(txtPath); }, renderer, mappedInput, std::move(txt), [this, txtPath] { onGoToFileSelection(txtPath); }, [this] { onGoBack(); },
[this] { onGoBack(); })); [this] { onSelectBookFile(APP_STATE.lastOpenBookPath); }));
} }
void ReaderActivity::onEnter() { void ReaderActivity::onEnter() {

View File

@ -56,6 +56,9 @@ void TxtReaderActivity::onEnter() {
txt->setupCacheDir(); txt->setupCacheDir();
// Save current txt as last opened file // Save current txt as last opened file
if (APP_STATE.openEpubPath != txt->getPath()) {
APP_STATE.lastOpenBookPath = APP_STATE.openEpubPath;
}
APP_STATE.openEpubPath = txt->getPath(); APP_STATE.openEpubPath = txt->getPath();
APP_STATE.saveToFile(); APP_STATE.saveToFile();
@ -107,6 +110,25 @@ void TxtReaderActivity::loop() {
return; return;
} }
if (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::LAST_BOOK &&
mappedInput.wasReleased(MappedInputManager::Button::Power)) {
if (APP_STATE.lastOpenBookPath.empty()) {
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, "No last book found.");
constexpr int margin = 20;
const int x = (renderer.getScreenWidth() - textWidth - margin * 2) / 2;
constexpr int y = 117;
const int w = textWidth + margin * 2;
const int h = renderer.getLineHeight(UI_12_FONT_ID) + margin * 2;
renderer.fillRect(x - 5, y - 5, w + 10, h + 10, true);
renderer.fillRect(x + 5, y + 5, w - 10, h - 10, false);
renderer.drawText(UI_12_FONT_ID, x + margin, y + margin, "No last book found.");
renderer.displayBuffer();
} else {
onSwapBooks();
}
return;
}
const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::PageBack) || const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::PageBack) ||
mappedInput.wasReleased(MappedInputManager::Button::Left); mappedInput.wasReleased(MappedInputManager::Button::Left);
const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) || const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) ||

View File

@ -20,6 +20,7 @@ class TxtReaderActivity final : public ActivityWithSubactivity {
bool updateRequired = false; bool updateRequired = false;
const std::function<void()> onGoBack; const std::function<void()> onGoBack;
const std::function<void()> onGoHome; const std::function<void()> onGoHome;
const std::function<void()> onSwapBooks;
// Streaming text reader - stores file offsets for each page // Streaming text reader - stores file offsets for each page
std::vector<size_t> pageOffsets; // File offset for start of each page std::vector<size_t> pageOffsets; // File offset for start of each page
@ -49,11 +50,13 @@ class TxtReaderActivity final : public ActivityWithSubactivity {
public: public:
explicit TxtReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr<Txt> txt, explicit TxtReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr<Txt> txt,
const std::function<void()>& onGoBack, const std::function<void()>& onGoHome) const std::function<void()>& onGoBack, const std::function<void()>& onGoHome,
const std::function<void()>& onSwapBooks)
: ActivityWithSubactivity("TxtReader", renderer, mappedInput), : ActivityWithSubactivity("TxtReader", renderer, mappedInput),
txt(std::move(txt)), txt(std::move(txt)),
onGoBack(onGoBack), onGoBack(onGoBack),
onGoHome(onGoHome) {} onGoHome(onGoHome),
onSwapBooks(onSwapBooks) {}
void onEnter() override; void onEnter() override;
void onExit() override; void onExit() override;
void loop() override; void loop() override;

View File

@ -42,6 +42,9 @@ void XtcReaderActivity::onEnter() {
loadProgress(); loadProgress();
// Save current XTC as last opened book // Save current XTC as last opened book
if (APP_STATE.openEpubPath != xtc->getPath()) {
APP_STATE.lastOpenBookPath = APP_STATE.openEpubPath;
}
APP_STATE.openEpubPath = xtc->getPath(); APP_STATE.openEpubPath = xtc->getPath();
APP_STATE.saveToFile(); APP_STATE.saveToFile();
@ -109,12 +112,33 @@ void XtcReaderActivity::loop() {
return; return;
} }
if (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::LAST_BOOK &&
mappedInput.wasReleased(MappedInputManager::Button::Power)) {
if (APP_STATE.lastOpenBookPath.empty()) {
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, "No last book found.");
constexpr int margin = 20;
const int x = (renderer.getScreenWidth() - textWidth - margin * 2) / 2;
constexpr int y = 117;
const int w = textWidth + margin * 2;
const int h = renderer.getLineHeight(UI_12_FONT_ID) + margin * 2;
renderer.fillRect(x - 5, y - 5, w + 10, h + 10, true);
renderer.fillRect(x + 5, y + 5, w - 10, h - 10, false);
renderer.drawText(UI_12_FONT_ID, x + margin, y + margin, "No last book found.");
renderer.displayBuffer();
} else {
onSwapBooks();
}
return;
}
const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::PageBack) || const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::PageBack) ||
mappedInput.wasReleased(MappedInputManager::Button::Left); mappedInput.wasReleased(MappedInputManager::Button::Left);
const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) || const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) ||
(SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::PAGE_TURN && (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::PAGE_TURN &&
mappedInput.wasReleased(MappedInputManager::Button::Power)) || mappedInput.wasReleased(MappedInputManager::Button::Power)) ||
mappedInput.wasReleased(MappedInputManager::Button::Right); mappedInput.wasReleased(MappedInputManager::Button::Right);
const bool swapBooks = (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::LAST_BOOK &&
mappedInput.wasReleased(MappedInputManager::Button::Power));
if (!prevReleased && !nextReleased) { if (!prevReleased && !nextReleased) {
return; return;

View File

@ -23,6 +23,7 @@ class XtcReaderActivity final : public ActivityWithSubactivity {
bool updateRequired = false; bool updateRequired = false;
const std::function<void()> onGoBack; const std::function<void()> onGoBack;
const std::function<void()> onGoHome; const std::function<void()> onGoHome;
const std::function<void()> onSwapBooks;
static void taskTrampoline(void* param); static void taskTrampoline(void* param);
[[noreturn]] void displayTaskLoop(); [[noreturn]] void displayTaskLoop();
@ -33,11 +34,13 @@ class XtcReaderActivity final : public ActivityWithSubactivity {
public: public:
explicit XtcReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr<Xtc> xtc, explicit XtcReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr<Xtc> xtc,
const std::function<void()>& onGoBack, const std::function<void()>& onGoHome) const std::function<void()>& onGoBack, const std::function<void()>& onGoHome,
const std::function<void()>& onSwapBooks)
: ActivityWithSubactivity("XtcReader", renderer, mappedInput), : ActivityWithSubactivity("XtcReader", renderer, mappedInput),
xtc(std::move(xtc)), xtc(std::move(xtc)),
onGoBack(onGoBack), onGoBack(onGoBack),
onGoHome(onGoHome) {} onGoHome(onGoHome),
onSwapBooks(onSwapBooks) {}
void onEnter() override; void onEnter() override;
void onExit() override; void onExit() override;
void loop() override; void loop() override;

View File

@ -22,7 +22,8 @@ const SettingInfo settingsList[settingsCount] = {
SettingInfo::Enum("Hide Battery %", &CrossPointSettings::hideBatteryPercentage, {"Never", "In Reader", "Always"}), SettingInfo::Enum("Hide Battery %", &CrossPointSettings::hideBatteryPercentage, {"Never", "In Reader", "Always"}),
SettingInfo::Toggle("Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing), SettingInfo::Toggle("Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing),
SettingInfo::Toggle("Text Anti-Aliasing", &CrossPointSettings::textAntiAliasing), SettingInfo::Toggle("Text Anti-Aliasing", &CrossPointSettings::textAntiAliasing),
SettingInfo::Enum("Short Power Button Click", &CrossPointSettings::shortPwrBtn, {"Ignore", "Sleep", "Page Turn"}), SettingInfo::Enum("Short Power Button Click", &CrossPointSettings::shortPwrBtn,
{"Ignore", "Sleep", "Page Turn", "Last Book"}),
SettingInfo::Enum("Reading Orientation", &CrossPointSettings::orientation, SettingInfo::Enum("Reading Orientation", &CrossPointSettings::orientation,
{"Portrait", "Landscape CW", "Inverted", "Landscape CCW"}), {"Portrait", "Landscape CW", "Inverted", "Landscape CCW"}),
SettingInfo::Enum("Front Button Layout", &CrossPointSettings::frontButtonLayout, SettingInfo::Enum("Front Button Layout", &CrossPointSettings::frontButtonLayout,

View File

@ -308,6 +308,7 @@ void setup() {
// Clear app state to avoid getting into a boot loop if the epub doesn't load // Clear app state to avoid getting into a boot loop if the epub doesn't load
const auto path = APP_STATE.openEpubPath; const auto path = APP_STATE.openEpubPath;
APP_STATE.openEpubPath = ""; APP_STATE.openEpubPath = "";
APP_STATE.lastOpenBookPath = "";
APP_STATE.lastSleepImage = 0; APP_STATE.lastSleepImage = 0;
APP_STATE.saveToFile(); APP_STATE.saveToFile();
onGoToReader(path); onGoToReader(path);