diff --git a/src/CrossPointSettings.h b/src/CrossPointSettings.h index a5641aad..20b287e4 100644 --- a/src/CrossPointSettings.h +++ b/src/CrossPointSettings.h @@ -53,7 +53,7 @@ class CrossPointSettings { enum REFRESH_FREQUENCY { REFRESH_1 = 0, REFRESH_5 = 1, REFRESH_10 = 2, REFRESH_15 = 3, REFRESH_30 = 4 }; // 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 enum HIDE_BATTERY_PERCENTAGE { HIDE_NEVER = 0, HIDE_READER = 1, HIDE_ALWAYS = 2 }; diff --git a/src/CrossPointState.cpp b/src/CrossPointState.cpp index 91aa2536..2c5c4abb 100644 --- a/src/CrossPointState.cpp +++ b/src/CrossPointState.cpp @@ -19,6 +19,7 @@ bool CrossPointState::saveToFile() const { serialization::writePod(outputFile, STATE_FILE_VERSION); serialization::writeString(outputFile, openEpubPath); + serialization::writeString(outputFile, lastOpenBookPath); serialization::writePod(outputFile, lastSleepImage); outputFile.close(); return true; @@ -39,6 +40,7 @@ bool CrossPointState::loadFromFile() { } serialization::readString(inputFile, openEpubPath); + serialization::readString(inputFile, lastOpenBookPath); if (version >= 2) { serialization::readPod(inputFile, lastSleepImage); } else { diff --git a/src/CrossPointState.h b/src/CrossPointState.h index 87ce4e96..c37c7b35 100644 --- a/src/CrossPointState.h +++ b/src/CrossPointState.h @@ -8,6 +8,7 @@ class CrossPointState { public: std::string openEpubPath; + std::string lastOpenBookPath; uint8_t lastSleepImage; ~CrossPointState() = default; diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 2eeba80f..7447815c 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -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.saveToFile(); @@ -149,6 +152,25 @@ void EpubReaderActivity::loop() { 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) || mappedInput.wasReleased(MappedInputManager::Button::Left); const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) || diff --git a/src/activities/reader/EpubReaderActivity.h b/src/activities/reader/EpubReaderActivity.h index 63d48872..c1badf5c 100644 --- a/src/activities/reader/EpubReaderActivity.h +++ b/src/activities/reader/EpubReaderActivity.h @@ -18,6 +18,7 @@ class EpubReaderActivity final : public ActivityWithSubactivity { bool updateRequired = false; const std::function onGoBack; const std::function onGoHome; + const std::function onSwapBooks; static void taskTrampoline(void* param); [[noreturn]] void displayTaskLoop(); @@ -28,11 +29,13 @@ class EpubReaderActivity final : public ActivityWithSubactivity { public: explicit EpubReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr epub, - const std::function& onGoBack, const std::function& onGoHome) + const std::function& onGoBack, const std::function& onGoHome, + const std::function& onSwapBooks) : ActivityWithSubactivity("EpubReader", renderer, mappedInput), epub(std::move(epub)), onGoBack(onGoBack), - onGoHome(onGoHome) {} + onGoHome(onGoHome), + onSwapBooks(onSwapBooks) {} void onEnter() override; void onExit() override; void loop() override; diff --git a/src/activities/reader/ReaderActivity.cpp b/src/activities/reader/ReaderActivity.cpp index c00f6236..6e22e83e 100644 --- a/src/activities/reader/ReaderActivity.cpp +++ b/src/activities/reader/ReaderActivity.cpp @@ -1,5 +1,6 @@ #include "ReaderActivity.h" +#include "CrossPointState.h" #include "Epub.h" #include "EpubReaderActivity.h" #include "FileSelectionActivity.h" @@ -74,7 +75,12 @@ std::unique_ptr ReaderActivity::loadTxt(const std::string& path) { } void ReaderActivity::onSelectBookFile(const std::string& path) { + if (path.empty()) { + return; + } + currentBookPath = path; // Track current book path + exitActivity(); enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Loading...")); @@ -131,7 +137,7 @@ void ReaderActivity::onGoToEpubReader(std::unique_ptr epub) { exitActivity(); enterNewActivity(new EpubReaderActivity( 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) { @@ -139,8 +145,8 @@ void ReaderActivity::onGoToXtcReader(std::unique_ptr xtc) { currentBookPath = xtcPath; exitActivity(); enterNewActivity(new XtcReaderActivity( - renderer, mappedInput, std::move(xtc), [this, xtcPath] { onGoToFileSelection(xtcPath); }, - [this] { onGoBack(); })); + renderer, mappedInput, std::move(xtc), [this, xtcPath] { onGoToFileSelection(xtcPath); }, [this] { onGoBack(); }, + [this] { onSelectBookFile(APP_STATE.lastOpenBookPath); })); } void ReaderActivity::onGoToTxtReader(std::unique_ptr txt) { @@ -148,8 +154,8 @@ void ReaderActivity::onGoToTxtReader(std::unique_ptr txt) { currentBookPath = txtPath; exitActivity(); enterNewActivity(new TxtReaderActivity( - renderer, mappedInput, std::move(txt), [this, txtPath] { onGoToFileSelection(txtPath); }, - [this] { onGoBack(); })); + renderer, mappedInput, std::move(txt), [this, txtPath] { onGoToFileSelection(txtPath); }, [this] { onGoBack(); }, + [this] { onSelectBookFile(APP_STATE.lastOpenBookPath); })); } void ReaderActivity::onEnter() { diff --git a/src/activities/reader/TxtReaderActivity.cpp b/src/activities/reader/TxtReaderActivity.cpp index db725320..ae346bdb 100644 --- a/src/activities/reader/TxtReaderActivity.cpp +++ b/src/activities/reader/TxtReaderActivity.cpp @@ -56,6 +56,9 @@ void TxtReaderActivity::onEnter() { txt->setupCacheDir(); // 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.saveToFile(); @@ -107,6 +110,25 @@ void TxtReaderActivity::loop() { 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) || mappedInput.wasReleased(MappedInputManager::Button::Left); const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) || diff --git a/src/activities/reader/TxtReaderActivity.h b/src/activities/reader/TxtReaderActivity.h index 41ccbfbb..46b4af74 100644 --- a/src/activities/reader/TxtReaderActivity.h +++ b/src/activities/reader/TxtReaderActivity.h @@ -20,6 +20,7 @@ class TxtReaderActivity final : public ActivityWithSubactivity { bool updateRequired = false; const std::function onGoBack; const std::function onGoHome; + const std::function onSwapBooks; // Streaming text reader - stores file offsets for each page std::vector pageOffsets; // File offset for start of each page @@ -49,11 +50,13 @@ class TxtReaderActivity final : public ActivityWithSubactivity { public: explicit TxtReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr txt, - const std::function& onGoBack, const std::function& onGoHome) + const std::function& onGoBack, const std::function& onGoHome, + const std::function& onSwapBooks) : ActivityWithSubactivity("TxtReader", renderer, mappedInput), txt(std::move(txt)), onGoBack(onGoBack), - onGoHome(onGoHome) {} + onGoHome(onGoHome), + onSwapBooks(onSwapBooks) {} void onEnter() override; void onExit() override; void loop() override; diff --git a/src/activities/reader/XtcReaderActivity.cpp b/src/activities/reader/XtcReaderActivity.cpp index a211e61c..25dd3b58 100644 --- a/src/activities/reader/XtcReaderActivity.cpp +++ b/src/activities/reader/XtcReaderActivity.cpp @@ -42,6 +42,9 @@ void XtcReaderActivity::onEnter() { loadProgress(); // 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.saveToFile(); @@ -109,12 +112,33 @@ void XtcReaderActivity::loop() { 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) || mappedInput.wasReleased(MappedInputManager::Button::Left); const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) || (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::PAGE_TURN && mappedInput.wasReleased(MappedInputManager::Button::Power)) || mappedInput.wasReleased(MappedInputManager::Button::Right); + const bool swapBooks = (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::LAST_BOOK && + mappedInput.wasReleased(MappedInputManager::Button::Power)); if (!prevReleased && !nextReleased) { return; diff --git a/src/activities/reader/XtcReaderActivity.h b/src/activities/reader/XtcReaderActivity.h index 579e1777..c96faa79 100644 --- a/src/activities/reader/XtcReaderActivity.h +++ b/src/activities/reader/XtcReaderActivity.h @@ -23,6 +23,7 @@ class XtcReaderActivity final : public ActivityWithSubactivity { bool updateRequired = false; const std::function onGoBack; const std::function onGoHome; + const std::function onSwapBooks; static void taskTrampoline(void* param); [[noreturn]] void displayTaskLoop(); @@ -33,11 +34,13 @@ class XtcReaderActivity final : public ActivityWithSubactivity { public: explicit XtcReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr xtc, - const std::function& onGoBack, const std::function& onGoHome) + const std::function& onGoBack, const std::function& onGoHome, + const std::function& onSwapBooks) : ActivityWithSubactivity("XtcReader", renderer, mappedInput), xtc(std::move(xtc)), onGoBack(onGoBack), - onGoHome(onGoHome) {} + onGoHome(onGoHome), + onSwapBooks(onSwapBooks) {} void onEnter() override; void onExit() override; void loop() override; diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index efa0b9e1..9064c5c3 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -22,7 +22,8 @@ const SettingInfo settingsList[settingsCount] = { SettingInfo::Enum("Hide Battery %", &CrossPointSettings::hideBatteryPercentage, {"Never", "In Reader", "Always"}), SettingInfo::Toggle("Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing), 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, {"Portrait", "Landscape CW", "Inverted", "Landscape CCW"}), SettingInfo::Enum("Front Button Layout", &CrossPointSettings::frontButtonLayout, diff --git a/src/main.cpp b/src/main.cpp index 8a7c3b91..4e339776 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -308,6 +308,7 @@ void setup() { // Clear app state to avoid getting into a boot loop if the epub doesn't load const auto path = APP_STATE.openEpubPath; APP_STATE.openEpubPath = ""; + APP_STATE.lastOpenBookPath = ""; APP_STATE.lastSleepImage = 0; APP_STATE.saveToFile(); onGoToReader(path);