Add Continue Reading menu and remember last book folder (#129)

## Summary

* **What is the goal of this PR?**

Add a "Continue Reading" feature to improve user experience when
returning to a previously opened book.

* **What changes are included?**

- Add dynamic "Continue: <book name>" menu item in Home screen when a
book was previously opened

- File browser now starts from the folder of the last opened book
instead of always starting from root directory
- Menu dynamically shows 3 or 4 items based on reading history:
  - Without history: `Browse`, `File transfer`, `Settings`
- With history: `Continue: <book>`, `Browse`, `File transfer`,
`Settings`

## Additional Context

* This feature leverages the existing `APP_STATE.openEpubPath` which
already persists the last opened book path
* The Continue Reading menu only appears if the book file still exists
on the SD card
* Book name in the menu is truncated to 25 characters with "..." suffix
if too long
* If the last book's folder was deleted, the file browser gracefully
falls back to root directory
* No new dependencies or significant memory overhead - reuses existing
state management
This commit is contained in:
Eunchurn Park
2025-12-26 09:55:23 +09:00
committed by GitHub
parent e3c1e28b8f
commit b77af16caa
9 changed files with 140 additions and 37 deletions

View File

@@ -7,6 +7,14 @@
#include "FileSelectionActivity.h"
#include "activities/util/FullScreenMessageActivity.h"
std::string ReaderActivity::extractFolderPath(const std::string& filePath) {
const auto lastSlash = filePath.find_last_of('/');
if (lastSlash == std::string::npos || lastSlash == 0) {
return "/";
}
return filePath.substr(0, lastSlash);
}
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
if (!SD.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
@@ -23,6 +31,7 @@ std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
}
void ReaderActivity::onSelectEpubFile(const std::string& path) {
currentEpubPath = path; // Track current book path
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Loading..."));
@@ -38,25 +47,32 @@ void ReaderActivity::onSelectEpubFile(const std::string& path) {
}
}
void ReaderActivity::onGoToFileSelection() {
void ReaderActivity::onGoToFileSelection(const std::string& fromEpubPath) {
exitActivity();
// If coming from a book, start in that book's folder; otherwise start from root
const auto initialPath = fromEpubPath.empty() ? "/" : extractFolderPath(fromEpubPath);
enterNewActivity(new FileSelectionActivity(
renderer, inputManager, [this](const std::string& path) { onSelectEpubFile(path); }, onGoBack));
renderer, inputManager, [this](const std::string& path) { onSelectEpubFile(path); }, onGoBack, initialPath));
}
void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
const auto epubPath = epub->getPath();
currentEpubPath = epubPath;
exitActivity();
enterNewActivity(new EpubReaderActivity(renderer, inputManager, std::move(epub), [this] { onGoToFileSelection(); }));
enterNewActivity(new EpubReaderActivity(
renderer, inputManager, std::move(epub), [this, epubPath] { onGoToFileSelection(epubPath); },
[this] { onGoBack(); }));
}
void ReaderActivity::onEnter() {
ActivityWithSubactivity::onEnter();
if (initialEpubPath.empty()) {
onGoToFileSelection();
onGoToFileSelection(); // Start from root when entering via Browse
return;
}
currentEpubPath = initialEpubPath;
auto epub = loadEpub(initialEpubPath);
if (!epub) {
onGoBack();