diff --git a/src/activities/ActivityResult.h b/src/activities/ActivityResult.h index 5c72cbef..150453b0 100644 --- a/src/activities/ActivityResult.h +++ b/src/activities/ActivityResult.h @@ -26,6 +26,7 @@ struct MenuResult { struct ChapterResult { int spineIndex = 0; + int tocIndex = -1; }; struct PercentResult { diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 4df4fc08..8bae555f 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -326,13 +326,38 @@ void EpubReaderActivity::loop() { if (skipChapter) { lastPageTurnTime = millis(); - // We don't want to delete the section mid-render, so grab the semaphore - { + + int currentTocIdx = section ? section->getTocIndexForPage(section->currentPage) + : epub->getTocIndexForSpineIndex(currentSpineIndex); + const int nextTocIdx = nextTriggered ? currentTocIdx + 1 : currentTocIdx - 1; + + if (nextTocIdx >= 0 && nextTocIdx < epub->getTocItemsCount()) { + const int targetSpine = epub->getSpineIndexForTocIndex(nextTocIdx); + if (targetSpine >= 0) { + RenderLock lock(*this); + if (targetSpine == currentSpineIndex && section) { + if (auto page = section->getPageForTocIndex(nextTocIdx)) { + section->currentPage = *page; + } + } else { + currentSpineIndex = targetSpine; + pendingTocIndex = nextTocIdx; + nextPageNumber = 0; + section.reset(); + } + } + } else if (nextTocIdx < 0) { RenderLock lock(*this); + currentSpineIndex = 0; + nextPageNumber = 0; + section.reset(); + } else { + RenderLock lock(*this); + currentSpineIndex = epub->getSpineItemsCount(); nextPageNumber = 0; - currentSpineIndex = nextTriggered ? currentSpineIndex + 1 : currentSpineIndex - 1; section.reset(); } + requestUpdate(); return; } @@ -418,15 +443,24 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction case EpubReaderMenuActivity::MenuAction::TABLE_OF_CONTENTS: case EpubReaderMenuActivity::MenuAction::SELECT_CHAPTER: { const int spineIdx = currentSpineIndex; + const int tocIdx = section ? section->getTocIndexForPage(section->currentPage) + : epub->getTocIndexForSpineIndex(currentSpineIndex); const std::string path = epub->getPath(); const bool consumeRelease = ignoreNextConfirmRelease; startActivityForResult( - std::make_unique(renderer, mappedInput, epub, path, spineIdx, + std::make_unique(renderer, mappedInput, epub, path, spineIdx, tocIdx, consumeRelease), [this](const ActivityResult& result) { - if (!result.isCancelled && currentSpineIndex != std::get(result.data).spineIndex) { - RenderLock lock(*this); - currentSpineIndex = std::get(result.data).spineIndex; + if (result.isCancelled) return; + const auto& ch = std::get(result.data); + RenderLock lock(*this); + if (ch.spineIndex == currentSpineIndex && section && ch.tocIndex >= 0) { + if (auto page = section->getPageForTocIndex(ch.tocIndex)) { + section->currentPage = *page; + } + } else if (ch.spineIndex != currentSpineIndex) { + currentSpineIndex = ch.spineIndex; + pendingTocIndex = ch.tocIndex; nextPageNumber = 0; section.reset(); } @@ -939,6 +973,14 @@ void EpubReaderActivity::render(RenderLock&& lock) { section->currentPage = nextPageNumber; } + if (pendingTocIndex >= 0) { + if (auto page = section->getPageForTocIndex(pendingTocIndex)) { + section->currentPage = *page; + LOG_DBG("ERS", "Resolved TOC index %d to page %d", pendingTocIndex, *page); + } + pendingTocIndex = -1; + } + if (!pendingAnchor.empty()) { if (const auto page = section->getPageForAnchor(pendingAnchor)) { section->currentPage = *page; @@ -1142,7 +1184,8 @@ void EpubReaderActivity::renderStatusBar() const { } else if (SETTINGS.statusBarTitle == CrossPointSettings::STATUS_BAR_TITLE::CHAPTER_TITLE) { title = tr(STR_UNNAMED); - const int tocIndex = epub->getTocIndexForSpineIndex(currentSpineIndex); + const int tocIndex = section ? section->getTocIndexForPage(section->currentPage) + : epub->getTocIndexForSpineIndex(currentSpineIndex); if (tocIndex != -1) { const auto tocItem = epub->getTocItem(tocIndex); title = tocItem.title; diff --git a/src/activities/reader/EpubReaderActivity.h b/src/activities/reader/EpubReaderActivity.h index 9327a495..7a4a8db5 100644 --- a/src/activities/reader/EpubReaderActivity.h +++ b/src/activities/reader/EpubReaderActivity.h @@ -14,6 +14,9 @@ class EpubReaderActivity final : public Activity { // Set when navigating to a footnote href with a fragment (e.g. #note1). // Cleared on the next render after the new section loads and resolves it to a page. std::string pendingAnchor; + // Set when navigating to a specific TOC entry (e.g. from chapter selection or chapter skip). + // Resolved to a page number after the target section loads. + int pendingTocIndex = -1; int pagesUntilFullRefresh = 0; int cachedSpineIndex = 0; int cachedChapterTotalPageCount = 0; diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp index 99fc50dc..9185923f 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp @@ -32,8 +32,8 @@ void EpubReaderChapterSelectionActivity::onEnter() { return; } - selectorIndex = epub->getTocIndexForSpineIndex(currentSpineIndex); - if (selectorIndex == -1) { + selectorIndex = (currentTocIndex >= 0) ? currentTocIndex : epub->getTocIndexForSpineIndex(currentSpineIndex); + if (selectorIndex < 0) { selectorIndex = 0; } @@ -59,7 +59,7 @@ void EpubReaderChapterSelectionActivity::loop() { setResult(std::move(result)); finish(); } else { - setResult(ChapterResult{newSpineIndex}); + setResult(ChapterResult{newSpineIndex, selectorIndex}); finish(); } } else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.h b/src/activities/reader/EpubReaderChapterSelectionActivity.h index 8620359b..07f39a4a 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.h +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.h @@ -11,6 +11,7 @@ class EpubReaderChapterSelectionActivity final : public Activity { std::string epubPath; ButtonNavigator buttonNavigator; int currentSpineIndex = 0; + int currentTocIndex = -1; int selectorIndex = 0; bool ignoreNextConfirmRelease = false; @@ -24,11 +25,13 @@ class EpubReaderChapterSelectionActivity final : public Activity { public: explicit EpubReaderChapterSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, const std::shared_ptr& epub, const std::string& epubPath, - const int currentSpineIndex, bool consumeFirstRelease = false) + const int currentSpineIndex, const int currentTocIndex = -1, + bool consumeFirstRelease = false) : Activity("EpubReaderChapterSelection", renderer, mappedInput), epub(epub), epubPath(epubPath), currentSpineIndex(currentSpineIndex), + currentTocIndex(currentTocIndex), ignoreNextConfirmRelease(consumeFirstRelease) {} void onEnter() override; void onExit() override;