mod: restore missing mod features from resync audit

Re-add KOReaderSyncActivity PUSH_ONLY mode (PR #1090):
- SyncMode enum with INTERACTIVE/PUSH_ONLY, deferFinish pattern
- Push & Sleep menu action in EpubReaderMenuActivity
- ActivityManager::requestSleep() for activity-initiated sleep
- main.cpp checks isSleepRequested() each loop iteration

Wire EndOfBookMenuActivity into EpubReaderActivity:
- pendingEndOfBookMenu deferred flag avoids render-lock deadlock
- Handles all 6 actions: ARCHIVE, DELETE, TABLE_OF_CONTENTS,
  BACK_TO_BEGINNING, CLOSE_BOOK, CLOSE_MENU

Add book management to reader menu:
- ARCHIVE_BOOK, DELETE_BOOK, REINDEX_BOOK actions with handlers

Port silent next-chapter pre-indexing:
- silentIndexNextChapterIfNeeded() proactively indexes next chapter
  when user is near end of current one, eliminating load screens

Add per-book letterbox fill toggle in reader menu:
- LETTERBOX_FILL cycles Default/Dithered/Solid/None
- Loads/saves per-book override via BookSettings
- bookCachePath constructor param added to EpubReaderMenuActivity

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-07 16:53:17 -05:00
parent 60a3e21c0e
commit 9464df1727
12 changed files with 422 additions and 11 deletions

View File

@@ -10,7 +10,9 @@
#include "CrossPointSettings.h"
#include "CrossPointState.h"
#include "activities/ActivityManager.h"
#include "DictionaryWordSelectActivity.h"
#include "EndOfBookMenuActivity.h"
#include "EpubReaderBookmarkSelectionActivity.h"
#include "EpubReaderChapterSelectionActivity.h"
#include "EpubReaderFootnotesActivity.h"
@@ -23,6 +25,7 @@
#include "RecentBooksStore.h"
#include "components/UITheme.h"
#include "fontIds.h"
#include "util/BookManager.h"
#include "util/BookmarkStore.h"
#include "util/Dictionary.h"
#include "util/ScreenshotUtil.h"
@@ -133,6 +136,53 @@ void EpubReaderActivity::loop() {
return;
}
if (pendingEndOfBookMenu) {
pendingEndOfBookMenu = false;
endOfBookMenuOpened = true;
startActivityForResult(
std::make_unique<EndOfBookMenuActivity>(renderer, mappedInput, epub->getPath()),
[this](const ActivityResult& result) {
if (result.isCancelled) {
return;
}
const auto action = static_cast<EndOfBookMenuActivity::Action>(std::get<MenuResult>(result.data).action);
switch (action) {
case EndOfBookMenuActivity::Action::ARCHIVE:
BookManager::archiveBook(epub->getPath());
activityManager.goHome();
return;
case EndOfBookMenuActivity::Action::DELETE:
BookManager::deleteBook(epub->getPath());
activityManager.goHome();
return;
case EndOfBookMenuActivity::Action::TABLE_OF_CONTENTS: {
endOfBookMenuOpened = false;
RenderLock lock(*this);
currentSpineIndex = epub->getSpineItemsCount() - 1;
nextPageNumber = UINT16_MAX;
section.reset();
break;
}
case EndOfBookMenuActivity::Action::BACK_TO_BEGINNING: {
endOfBookMenuOpened = false;
RenderLock lock(*this);
currentSpineIndex = 0;
nextPageNumber = 0;
section.reset();
break;
}
case EndOfBookMenuActivity::Action::CLOSE_BOOK:
activityManager.goHome();
return;
case EndOfBookMenuActivity::Action::CLOSE_MENU:
endOfBookMenuOpened = false;
break;
}
requestUpdate();
});
return;
}
if (automaticPageTurnActive) {
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm) ||
mappedInput.wasReleased(MappedInputManager::Button::Back)) {
@@ -173,7 +223,8 @@ void EpubReaderActivity::loop() {
section ? BookmarkStore::hasBookmark(epub->getCachePath(), currentSpineIndex, section->currentPage) : false;
startActivityForResult(std::make_unique<EpubReaderMenuActivity>(
renderer, mappedInput, epub->getTitle(), currentPage, totalPages, bookProgressPercent,
SETTINGS.orientation, !currentPageFootnotes.empty(), isBookmarked, SETTINGS.fontSize),
SETTINGS.orientation, !currentPageFootnotes.empty(), isBookmarked, SETTINGS.fontSize,
epub->getCachePath()),
[this](const ActivityResult& result) {
// Always apply orientation and font size even if the menu was cancelled
const auto& menu = std::get<MenuResult>(result.data);
@@ -254,6 +305,8 @@ void EpubReaderActivity::loop() {
} else {
pageTurn(true);
}
silentIndexNextChapterIfNeeded();
}
// Translate an absolute percent into a spine index plus a normalized position
@@ -441,6 +494,19 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
}
break;
}
case EpubReaderMenuActivity::MenuAction::PUSH_AND_SLEEP: {
const int cp = section ? section->currentPage : 0;
const int tp = section ? section->pageCount : 0;
if (KOREADER_STORE.hasCredentials()) {
startActivityForResult(
std::make_unique<KOReaderSyncActivity>(renderer, mappedInput, epub, epub->getPath(), currentSpineIndex, cp,
tp, KOReaderSyncActivity::SyncMode::PUSH_ONLY),
[](const ActivityResult&) { activityManager.requestSleep(); });
} else {
activityManager.requestSleep();
}
break;
}
case EpubReaderMenuActivity::MenuAction::CLOSE_BOOK:
onGoHome();
return;
@@ -514,6 +580,23 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
requestUpdate();
break;
}
case EpubReaderMenuActivity::MenuAction::ARCHIVE_BOOK: {
if (epub) BookManager::archiveBook(epub->getPath());
activityManager.goHome();
return;
}
case EpubReaderMenuActivity::MenuAction::DELETE_BOOK: {
if (epub) BookManager::deleteBook(epub->getPath());
activityManager.goHome();
return;
}
case EpubReaderMenuActivity::MenuAction::REINDEX_BOOK: {
if (epub) BookManager::reindexBook(epub->getPath(), false);
activityManager.goHome();
return;
}
case EpubReaderMenuActivity::MenuAction::LETTERBOX_FILL:
break;
}
}
@@ -618,6 +701,45 @@ void EpubReaderActivity::pageTurn(bool isForwardTurn) {
requestUpdate();
}
bool EpubReaderActivity::silentIndexNextChapterIfNeeded() {
if (!epub || !section) return false;
if (preIndexedNextSpine == currentSpineIndex + 1) return false;
const bool nearEnd = (section->pageCount == 1 && section->currentPage == 0) ||
(section->pageCount >= 2 && section->currentPage == section->pageCount - 2);
if (!nearEnd) return false;
const int nextSpine = currentSpineIndex + 1;
if (nextSpine >= epub->getSpineItemsCount()) return false;
int marginTop, marginRight, marginBottom, marginLeft;
renderer.getOrientedViewableTRBL(&marginTop, &marginRight, &marginBottom, &marginLeft);
marginTop += SETTINGS.screenMargin;
marginLeft += SETTINGS.screenMargin;
marginRight += SETTINGS.screenMargin;
marginBottom += std::max(SETTINGS.screenMargin, UITheme::getInstance().getStatusBarHeight());
const uint16_t vpWidth = renderer.getScreenWidth() - marginLeft - marginRight;
const uint16_t vpHeight = renderer.getScreenHeight() - marginTop - marginBottom;
Section nextSection(epub, nextSpine, renderer);
if (nextSection.loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, vpWidth, vpHeight,
SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, SETTINGS.imageRendering)) {
preIndexedNextSpine = nextSpine;
return false;
}
LOG_DBG("ERS", "Silently indexing next chapter: %d", nextSpine);
if (!nextSection.createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, vpWidth, vpHeight,
SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, SETTINGS.imageRendering)) {
LOG_ERR("ERS", "Failed silent indexing for chapter: %d", nextSpine);
return false;
}
preIndexedNextSpine = nextSpine;
return true;
}
// TODO: Failure handling
void EpubReaderActivity::render(RenderLock&& lock) {
if (!epub) {
@@ -633,12 +755,15 @@ void EpubReaderActivity::render(RenderLock&& lock) {
currentSpineIndex = epub->getSpineItemsCount();
}
// Show end of book screen
// Show end of book screen (defer menu launch to loop() to avoid deadlock)
if (currentSpineIndex == epub->getSpineItemsCount()) {
renderer.clearScreen();
renderer.drawCenteredText(UI_12_FONT_ID, 300, tr(STR_END_OF_BOOK), true, EpdFontFamily::BOLD);
renderer.displayBuffer();
automaticPageTurnActive = false;
if (!endOfBookMenuOpened) {
pendingEndOfBookMenu = true;
}
return;
}