Integrate PT 1455
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -27,6 +28,7 @@ struct MenuResult {
|
||||
|
||||
struct ChapterResult {
|
||||
int spineIndex = 0;
|
||||
std::optional<int> tocIndex;
|
||||
};
|
||||
|
||||
struct PercentResult {
|
||||
|
||||
@@ -219,14 +219,58 @@ void EpubReaderActivity::loop() {
|
||||
|
||||
const bool skipChapter = SETTINGS.longPressChapterSkip && mappedInput.getHeldTime() > skipChapterMs;
|
||||
|
||||
// Chapter skip navigates by TOC entries, not spine boundaries.
|
||||
// Spine items without their own TOC entry inherit the previous spine's tocIndex
|
||||
// (see BookMetadataCache), so they're treated as continuations of the last chapter.
|
||||
// At the boundaries: skipping forward past the last TOC entry jumps to end-of-book
|
||||
// (clamped in render()); skipping backward before the first TOC entry jumps to the
|
||||
// spine before the current chapter's first spine (clamped to 0 in render()).
|
||||
if (skipChapter) {
|
||||
lastPageTurnTime = millis();
|
||||
// We don't want to delete the section mid-render, so grab the semaphore
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = nextTriggered ? currentSpineIndex + 1 : currentSpineIndex - 1;
|
||||
section.reset();
|
||||
|
||||
if (section && section->pageCount > 0) {
|
||||
const int curTocIndex = section->getTocIndexForPage(section->currentPage);
|
||||
const int nextTocIndex = nextTriggered ? curTocIndex + 1 : curTocIndex - 1;
|
||||
|
||||
if (curTocIndex < 0) {
|
||||
// No TOC entry for this spine, fall back to spine-level skip
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = nextTriggered ? currentSpineIndex + 1 : currentSpineIndex - 1;
|
||||
section.reset();
|
||||
} else if (nextTocIndex >= 0 && nextTocIndex < epub->getTocItemsCount()) {
|
||||
const int newSpineIndex = epub->getSpineIndexForTocIndex(nextTocIndex);
|
||||
|
||||
if (newSpineIndex == currentSpineIndex) {
|
||||
if (const auto resolvedPage = section->getPageForTocIndex(nextTocIndex)) {
|
||||
section->currentPage = *resolvedPage;
|
||||
} else {
|
||||
LOG_DBG("ERS", "No page boundary for TOC %d in spine %d, staying on current page", nextTocIndex,
|
||||
currentSpineIndex);
|
||||
}
|
||||
} else {
|
||||
pendingTocIndex = nextTocIndex;
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = newSpineIndex;
|
||||
section.reset();
|
||||
}
|
||||
} else if (nextTriggered) {
|
||||
// Beyond last TOC entry, go to end of book
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = epub->getSpineItemsCount();
|
||||
section.reset();
|
||||
} else {
|
||||
// Before first TOC entry, skip to spine before the current chapter
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = epub->getTocItem(curTocIndex).spineIndex - 1;
|
||||
section.reset();
|
||||
}
|
||||
} else {
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = nextTriggered ? currentSpineIndex + 1 : currentSpineIndex - 1;
|
||||
section.reset();
|
||||
}
|
||||
}
|
||||
requestUpdate();
|
||||
return;
|
||||
@@ -312,13 +356,23 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
|
||||
switch (action) {
|
||||
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();
|
||||
startActivityForResult(
|
||||
std::make_unique<EpubReaderChapterSelectionActivity>(renderer, mappedInput, epub, path, spineIdx),
|
||||
std::make_unique<EpubReaderChapterSelectionActivity>(renderer, mappedInput, epub, path, spineIdx, tocIdx),
|
||||
[this](const ActivityResult& result) {
|
||||
if (!result.isCancelled && currentSpineIndex != std::get<ChapterResult>(result.data).spineIndex) {
|
||||
RenderLock lock(*this);
|
||||
currentSpineIndex = std::get<ChapterResult>(result.data).spineIndex;
|
||||
if (result.isCancelled) return;
|
||||
RenderLock lock(*this);
|
||||
const auto& chapter = std::get<ChapterResult>(result.data);
|
||||
auto resolvedPage = (chapter.tocIndex && chapter.spineIndex == currentSpineIndex && section)
|
||||
? section->getPageForTocIndex(*chapter.tocIndex)
|
||||
: std::nullopt;
|
||||
if (resolvedPage) {
|
||||
section->currentPage = *resolvedPage;
|
||||
} else {
|
||||
pendingTocIndex = chapter.tocIndex;
|
||||
currentSpineIndex = chapter.spineIndex;
|
||||
nextPageNumber = 0;
|
||||
section.reset();
|
||||
}
|
||||
@@ -613,7 +667,7 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
const uint8_t imageRendering = getEffectiveImageRendering();
|
||||
const auto filepath = epub->getSpineItem(currentSpineIndex).href;
|
||||
LOG_DBG("ERS", "Loading file: %s, index: %d", filepath.c_str(), currentSpineIndex);
|
||||
section = std::unique_ptr<Section>(new Section(epub, currentSpineIndex, renderer));
|
||||
section = std::make_unique<Section>(epub, currentSpineIndex, renderer);
|
||||
|
||||
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||
@@ -646,6 +700,13 @@ void EpubReaderActivity::render(RenderLock&& lock) {
|
||||
section->currentPage = nextPageNumber;
|
||||
}
|
||||
|
||||
if (pendingTocIndex) {
|
||||
if (const auto resolvedPage = section->getPageForTocIndex(*pendingTocIndex)) {
|
||||
section->currentPage = *resolvedPage;
|
||||
}
|
||||
pendingTocIndex.reset();
|
||||
}
|
||||
|
||||
if (!pendingAnchor.empty()) {
|
||||
if (const auto page = section->getPageForAnchor(pendingAnchor)) {
|
||||
section->currentPage = *page;
|
||||
@@ -895,28 +956,25 @@ void EpubReaderActivity::renderStatusBar() const {
|
||||
const float bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg) * 100;
|
||||
|
||||
std::string title;
|
||||
|
||||
int textYOffset = 0;
|
||||
|
||||
if (automaticPageTurnActive) {
|
||||
title = tr(STR_AUTO_TURN_ENABLED) + std::to_string(60 * 1000 / pageTurnDuration);
|
||||
|
||||
// calculates textYOffset when rendering title in status bar
|
||||
const uint8_t statusBarHeight = UITheme::getInstance().getStatusBarHeight();
|
||||
|
||||
// offsets text if no status bar or progress bar only
|
||||
if (statusBarHeight == 0 || statusBarHeight == UITheme::getInstance().getProgressBarHeight()) {
|
||||
textYOffset += UITheme::getInstance().getMetrics().statusBarVerticalMargin;
|
||||
}
|
||||
|
||||
} else if (SETTINGS.statusBarTitle == CrossPointSettings::STATUS_BAR_TITLE::CHAPTER_TITLE) {
|
||||
title = tr(STR_UNNAMED);
|
||||
const int tocIndex = epub->getTocIndexForSpineIndex(currentSpineIndex);
|
||||
if (tocIndex != -1) {
|
||||
const int tocIndex =
|
||||
section ? section->getTocIndexForPage(section->currentPage) : epub->getTocIndexForSpineIndex(currentSpineIndex);
|
||||
if (tocIndex == -1) {
|
||||
title = tr(STR_UNNAMED);
|
||||
} else {
|
||||
const auto tocItem = epub->getTocItem(tocIndex);
|
||||
title = tocItem.title;
|
||||
}
|
||||
|
||||
} else if (SETTINGS.statusBarTitle == CrossPointSettings::STATUS_BAR_TITLE::BOOK_TITLE) {
|
||||
title = epub->getTitle();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <Epub/FootnoteEntry.h>
|
||||
#include <Epub/Section.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "EpubReaderMenuActivity.h"
|
||||
#include "activities/Activity.h"
|
||||
|
||||
@@ -11,6 +13,9 @@ class EpubReaderActivity final : public Activity {
|
||||
std::unique_ptr<Section> section = nullptr;
|
||||
int currentSpineIndex = 0;
|
||||
int nextPageNumber = 0;
|
||||
// Set when navigating to a TOC entry in a different spine (chapter skip or chapter selector).
|
||||
// Cleared on the next render after the new section loads and resolves it to a page.
|
||||
std::optional<int> pendingTocIndex;
|
||||
// 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;
|
||||
|
||||
@@ -25,7 +25,9 @@ void EpubReaderChapterSelectionActivity::onEnter() {
|
||||
return;
|
||||
}
|
||||
|
||||
selectorIndex = epub->getTocIndexForSpineIndex(currentSpineIndex);
|
||||
selectorIndex = (currentTocIndex >= 0 && currentTocIndex < epub->getTocItemsCount())
|
||||
? currentTocIndex
|
||||
: epub->getTocIndexForSpineIndex(currentSpineIndex);
|
||||
if (selectorIndex == -1) {
|
||||
selectorIndex = 0;
|
||||
}
|
||||
@@ -48,7 +50,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)) {
|
||||
|
||||
@@ -11,6 +11,7 @@ class EpubReaderChapterSelectionActivity final : public Activity {
|
||||
std::string epubPath;
|
||||
ButtonNavigator buttonNavigator;
|
||||
int currentSpineIndex = 0;
|
||||
int currentTocIndex = 0;
|
||||
int selectorIndex = 0;
|
||||
|
||||
// Number of items that fit on a page, derived from logical screen height.
|
||||
@@ -23,11 +24,12 @@ class EpubReaderChapterSelectionActivity final : public Activity {
|
||||
public:
|
||||
explicit EpubReaderChapterSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||
const std::shared_ptr<Epub>& epub, const std::string& epubPath,
|
||||
const int currentSpineIndex)
|
||||
const int currentSpineIndex, const int currentTocIndex)
|
||||
: Activity("EpubReaderChapterSelection", renderer, mappedInput),
|
||||
epub(epub),
|
||||
epubPath(epubPath),
|
||||
currentSpineIndex(currentSpineIndex) {}
|
||||
currentSpineIndex(currentSpineIndex),
|
||||
currentTocIndex(currentTocIndex) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void loop() override;
|
||||
|
||||
Reference in New Issue
Block a user