diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 9f67bc50..041135d2 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -32,6 +32,7 @@ namespace { // pagesPerRefresh now comes from SETTINGS.getRefreshFrequency() constexpr unsigned long skipChapterMs = 700; constexpr unsigned long goHomeMs = 1000; +constexpr unsigned long longPressConfirmMs = 700; constexpr int statusBarMargin = 19; constexpr int progressBarMarginTop = 1; @@ -230,12 +231,27 @@ void EpubReaderActivity::loop() { !mappedInput.wasReleased(MappedInputManager::Button::Back); if (confirmCleared && backCleared) { skipNextButtonCheck = false; + ignoreNextConfirmRelease = false; } return; } - // Enter reader menu activity. + // Long press CONFIRM opens Table of Contents directly (skip menu) + if (mappedInput.isPressed(MappedInputManager::Button::Confirm) && + mappedInput.getHeldTime() >= longPressConfirmMs) { + ignoreNextConfirmRelease = true; + if (epub && epub->getTocItemsCount() > 0) { + openChapterSelection(true); // skip the stale release from this long-press + } + return; + } + + // Short press CONFIRM opens reader menu if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { + if (ignoreNextConfirmRelease) { + ignoreNextConfirmRelease = false; + return; + } const int currentPage = section ? section->currentPage + 1 : 0; const int totalPages = section ? section->pageCount : 0; float bookProgress = 0.0f; @@ -417,6 +433,39 @@ void EpubReaderActivity::jumpToPercent(int percent) { } } +void EpubReaderActivity::openChapterSelection(bool initialSkipRelease) { + const int currentP = section ? section->currentPage : 0; + const int totalP = section ? section->pageCount : 0; + const int spineIdx = currentSpineIndex; + const std::string path = epub->getPath(); + + enterNewActivity(new EpubReaderChapterSelectionActivity( + this->renderer, this->mappedInput, epub, path, spineIdx, currentP, totalP, + [this] { + exitActivity(); + requestUpdate(); + }, + [this](const int newSpineIndex) { + if (currentSpineIndex != newSpineIndex) { + currentSpineIndex = newSpineIndex; + nextPageNumber = 0; + section.reset(); + } + exitActivity(); + requestUpdate(); + }, + [this](const int newSpineIndex, const int newPage) { + if (currentSpineIndex != newSpineIndex || (section && section->currentPage != newPage)) { + currentSpineIndex = newSpineIndex; + nextPageNumber = newPage; + section.reset(); + } + exitActivity(); + requestUpdate(); + }, + initialSkipRelease)); +} + void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction action) { switch (action) { case EpubReaderMenuActivity::MenuAction::ADD_BOOKMARK: { @@ -512,36 +561,8 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction if (bookmarks.empty()) { // No bookmarks: fall back to Table of Contents if available, otherwise go back if (epub->getTocItemsCount() > 0) { - const int currentP = section ? section->currentPage : 0; - const int totalP = section ? section->pageCount : 0; - const int spineIdx = currentSpineIndex; - const std::string path = epub->getPath(); - exitActivity(); - enterNewActivity(new EpubReaderChapterSelectionActivity( - this->renderer, this->mappedInput, epub, path, spineIdx, currentP, totalP, - [this] { - exitActivity(); - requestUpdate(); - }, - [this](const int newSpineIndex) { - if (currentSpineIndex != newSpineIndex) { - currentSpineIndex = newSpineIndex; - nextPageNumber = 0; - section.reset(); - } - exitActivity(); - requestUpdate(); - }, - [this](const int newSpineIndex, const int newPage) { - if (currentSpineIndex != newSpineIndex || (section && section->currentPage != newPage)) { - currentSpineIndex = newSpineIndex; - nextPageNumber = newPage; - section.reset(); - } - exitActivity(); - requestUpdate(); - })); + openChapterSelection(); } // If no TOC either, just return to reader (menu already closed by callback) break; @@ -566,41 +587,8 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction break; } case EpubReaderMenuActivity::MenuAction::SELECT_CHAPTER: { - // Calculate values BEFORE we start destroying things - const int currentP = section ? section->currentPage : 0; - const int totalP = section ? section->pageCount : 0; - const int spineIdx = currentSpineIndex; - const std::string path = epub->getPath(); - - // 1. Close the menu exitActivity(); - - // 2. Open the Chapter Selector - enterNewActivity(new EpubReaderChapterSelectionActivity( - this->renderer, this->mappedInput, epub, path, spineIdx, currentP, totalP, - [this] { - exitActivity(); - requestUpdate(); - }, - [this](const int newSpineIndex) { - if (currentSpineIndex != newSpineIndex) { - currentSpineIndex = newSpineIndex; - nextPageNumber = 0; - section.reset(); - } - exitActivity(); - requestUpdate(); - }, - [this](const int newSpineIndex, const int newPage) { - if (currentSpineIndex != newSpineIndex || (section && section->currentPage != newPage)) { - currentSpineIndex = newSpineIndex; - nextPageNumber = newPage; - section.reset(); - } - exitActivity(); - requestUpdate(); - })); - + openChapterSelection(); break; } case EpubReaderMenuActivity::MenuAction::GO_TO_PERCENT: { diff --git a/src/activities/reader/EpubReaderActivity.h b/src/activities/reader/EpubReaderActivity.h index 94ce2573..754f3756 100644 --- a/src/activities/reader/EpubReaderActivity.h +++ b/src/activities/reader/EpubReaderActivity.h @@ -22,8 +22,9 @@ class EpubReaderActivity final : public ActivityWithSubactivity { float pendingSpineProgress = 0.0f; bool pendingSubactivityExit = false; // Defer subactivity exit to avoid use-after-free bool pendingGoHome = false; // Defer go home to avoid race condition with display task - bool skipNextButtonCheck = false; // Skip button processing for one frame after subactivity exit - volatile bool loadingSection = false; // True during the entire !section block (read from main loop) + bool skipNextButtonCheck = false; // Skip button processing for one frame after subactivity exit + bool ignoreNextConfirmRelease = false; // Suppress short-press after long-press Confirm + volatile bool loadingSection = false; // True during the entire !section block (read from main loop) const std::function onGoBack; const std::function onGoHome; @@ -33,6 +34,9 @@ class EpubReaderActivity final : public ActivityWithSubactivity { void saveProgress(int spineIndex, int currentPage, int pageCount); // Jump to a percentage of the book (0-100), mapping it to spine and page. void jumpToPercent(int percent); + // Open the Table of Contents (chapter selection) as a subactivity. + // Pass initialSkipRelease=true when triggered by long-press to consume the stale release. + void openChapterSelection(bool initialSkipRelease = false); void onReaderMenuBack(uint8_t orientation, uint8_t fontSize); void onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction action); void applyOrientation(uint8_t orientation); diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp index 6089a7d2..dd1a320a 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp @@ -53,11 +53,15 @@ void EpubReaderChapterSelectionActivity::loop() { const int totalItems = getTotalItems(); if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - const auto newSpineIndex = epub->getSpineIndexForTocIndex(selectorIndex); - if (newSpineIndex == -1) { - onGoBack(); + if (ignoreNextConfirmRelease) { + ignoreNextConfirmRelease = false; } else { - onSelectSpineIndex(newSpineIndex); + const auto newSpineIndex = epub->getSpineIndexForTocIndex(selectorIndex); + if (newSpineIndex == -1) { + onGoBack(); + } else { + onSelectSpineIndex(newSpineIndex); + } } } else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { onGoBack(); diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.h b/src/activities/reader/EpubReaderChapterSelectionActivity.h index 28a6f165..2eb8c61c 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.h +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.h @@ -14,6 +14,7 @@ class EpubReaderChapterSelectionActivity final : public ActivityWithSubactivity int currentPage = 0; int totalPagesInSpine = 0; int selectorIndex = 0; + bool ignoreNextConfirmRelease = false; const std::function onGoBack; const std::function onSelectSpineIndex; @@ -32,13 +33,15 @@ class EpubReaderChapterSelectionActivity final : public ActivityWithSubactivity const int currentSpineIndex, const int currentPage, const int totalPagesInSpine, const std::function& onGoBack, const std::function& onSelectSpineIndex, - const std::function& onSyncPosition) + const std::function& onSyncPosition, + bool initialSkipRelease = false) : ActivityWithSubactivity("EpubReaderChapterSelection", renderer, mappedInput), epub(epub), epubPath(epubPath), currentSpineIndex(currentSpineIndex), currentPage(currentPage), totalPagesInSpine(totalPagesInSpine), + ignoreNextConfirmRelease(initialSkipRelease), onGoBack(onGoBack), onSelectSpineIndex(onSelectSpineIndex), onSyncPosition(onSyncPosition) {}