mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-06 23:57:39 +03:00
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:
parent
1047802896
commit
6d041c9a18
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user