feat(nav): improve back button navigation with long press support

EPUB Reader:
- Short press BACK: go to file browser at the book's folder
- Long press BACK (1s+): go directly to home menu

File Browser:
- Short press BACK: go up one directory (or home if at root)
- Long press BACK (1s+): go directly to root folder
This commit is contained in:
Eunchurn Park 2025-12-26 02:15:16 +09:00
parent 1047802896
commit 6d041c9a18
No known key found for this signature in database
GPG Key ID: 29D94D9C697E3F92
5 changed files with 59 additions and 24 deletions

View File

@ -109,13 +109,15 @@ void EpubReaderActivity::loop() {
xSemaphoreGive(renderingMutex); xSemaphoreGive(renderingMutex);
} }
// Long press (1s+) goes to home, short press goes to file selection // Long press BACK (1s+) goes directly to home
if (inputManager.wasReleased(InputManager::BTN_BACK)) { if (inputManager.isPressed(InputManager::BTN_BACK) && inputManager.getHeldTime() >= goHomeMs) {
if (inputManager.getHeldTime() >= goHomeMs) { onGoHome();
onGoHome(); return;
} else { }
onGoBack();
} // Short press BACK goes to file selection
if (inputManager.wasReleased(InputManager::BTN_BACK) && inputManager.getHeldTime() < goHomeMs) {
onGoBack();
return; return;
} }

View File

@ -9,6 +9,7 @@
namespace { namespace {
constexpr int PAGE_ITEMS = 23; constexpr int PAGE_ITEMS = 23;
constexpr int SKIP_PAGE_MS = 700; constexpr int SKIP_PAGE_MS = 700;
constexpr unsigned long GO_HOME_MS = 1000;
} // namespace } // namespace
void sortFileList(std::vector<std::string>& strs) { void sortFileList(std::vector<std::string>& strs) {
@ -53,7 +54,7 @@ void FileSelectionActivity::onEnter() {
renderingMutex = xSemaphoreCreateMutex(); renderingMutex = xSemaphoreCreateMutex();
basepath = "/"; // basepath is set via constructor parameter (defaults to "/" if not specified)
loadFiles(); loadFiles();
selectorIndex = 0; selectorIndex = 0;
@ -83,6 +84,16 @@ void FileSelectionActivity::onExit() {
} }
void FileSelectionActivity::loop() { void FileSelectionActivity::loop() {
// Long press BACK (1s+) goes to root folder
if (inputManager.isPressed(InputManager::BTN_BACK) && inputManager.getHeldTime() >= GO_HOME_MS) {
if (basepath != "/") {
basepath = "/";
loadFiles();
updateRequired = true;
}
return;
}
const bool prevReleased = const bool prevReleased =
inputManager.wasReleased(InputManager::BTN_UP) || inputManager.wasReleased(InputManager::BTN_LEFT); inputManager.wasReleased(InputManager::BTN_UP) || inputManager.wasReleased(InputManager::BTN_LEFT);
const bool nextReleased = const bool nextReleased =
@ -103,15 +114,17 @@ void FileSelectionActivity::loop() {
} else { } else {
onSelect(basepath + files[selectorIndex]); onSelect(basepath + files[selectorIndex]);
} }
} else if (inputManager.wasPressed(InputManager::BTN_BACK)) { } else if (inputManager.wasReleased(InputManager::BTN_BACK)) {
if (basepath != "/") { // Short press: go up one directory, or go home if at root
basepath.replace(basepath.find_last_of('/'), std::string::npos, ""); if (inputManager.getHeldTime() < GO_HOME_MS) {
if (basepath.empty()) basepath = "/"; if (basepath != "/") {
loadFiles(); basepath.replace(basepath.find_last_of('/'), std::string::npos, "");
updateRequired = true; if (basepath.empty()) basepath = "/";
} else { loadFiles();
// At root level, go back home updateRequired = true;
onGoHome(); } else {
onGoHome();
}
} }
} else if (prevReleased) { } else if (prevReleased) {
if (skipPage) { if (skipPage) {

View File

@ -27,8 +27,11 @@ class FileSelectionActivity final : public Activity {
public: public:
explicit FileSelectionActivity(GfxRenderer& renderer, InputManager& inputManager, explicit FileSelectionActivity(GfxRenderer& renderer, InputManager& inputManager,
const std::function<void(const std::string&)>& onSelect, const std::function<void(const std::string&)>& onSelect,
const std::function<void()>& onGoHome) const std::function<void()>& onGoHome, std::string initialPath = "/")
: Activity("FileSelection", renderer, inputManager), onSelect(onSelect), onGoHome(onGoHome) {} : Activity("FileSelection", renderer, inputManager),
basepath(initialPath.empty() ? "/" : std::move(initialPath)),
onSelect(onSelect),
onGoHome(onGoHome) {}
void onEnter() override; void onEnter() override;
void onExit() override; void onExit() override;
void loop() override; void loop() override;

View File

@ -7,6 +7,14 @@
#include "FileSelectionActivity.h" #include "FileSelectionActivity.h"
#include "activities/util/FullScreenMessageActivity.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) { std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
if (!SD.exists(path.c_str())) { if (!SD.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), 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) { void ReaderActivity::onSelectEpubFile(const std::string& path) {
currentEpubPath = path; // Track current book path
exitActivity(); exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Loading...")); enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Loading..."));
@ -38,26 +47,32 @@ void ReaderActivity::onSelectEpubFile(const std::string& path) {
} }
} }
void ReaderActivity::onGoToFileSelection() { void ReaderActivity::onGoToFileSelection(const std::string& fromEpubPath) {
exitActivity(); 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( 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) { void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
const auto epubPath = epub->getPath();
currentEpubPath = epubPath;
exitActivity(); exitActivity();
enterNewActivity(new EpubReaderActivity( enterNewActivity(new EpubReaderActivity(
renderer, inputManager, std::move(epub), [this] { onGoToFileSelection(); }, [this] { onGoBack(); })); renderer, inputManager, std::move(epub), [this, epubPath] { onGoToFileSelection(epubPath); },
[this] { onGoBack(); }));
} }
void ReaderActivity::onEnter() { void ReaderActivity::onEnter() {
ActivityWithSubactivity::onEnter(); ActivityWithSubactivity::onEnter();
if (initialEpubPath.empty()) { if (initialEpubPath.empty()) {
onGoToFileSelection(); onGoToFileSelection(); // Start from root when entering via Browse
return; return;
} }
currentEpubPath = initialEpubPath;
auto epub = loadEpub(initialEpubPath); auto epub = loadEpub(initialEpubPath);
if (!epub) { if (!epub) {
onGoBack(); onGoBack();

View File

@ -7,11 +7,13 @@ class Epub;
class ReaderActivity final : public ActivityWithSubactivity { class ReaderActivity final : public ActivityWithSubactivity {
std::string initialEpubPath; std::string initialEpubPath;
std::string currentEpubPath; // Track current book path for navigation
const std::function<void()> onGoBack; const std::function<void()> onGoBack;
static std::unique_ptr<Epub> loadEpub(const std::string& path); static std::unique_ptr<Epub> loadEpub(const std::string& path);
static std::string extractFolderPath(const std::string& filePath);
void onSelectEpubFile(const std::string& path); void onSelectEpubFile(const std::string& path);
void onGoToFileSelection(); void onGoToFileSelection(const std::string& fromEpubPath = "");
void onGoToEpubReader(std::unique_ptr<Epub> epub); void onGoToEpubReader(std::unique_ptr<Epub> epub);
public: public: