diff --git a/src/CrossPointState.h b/src/CrossPointState.h index ee38d5eb..d7d58c1d 100644 --- a/src/CrossPointState.h +++ b/src/CrossPointState.h @@ -56,9 +56,8 @@ struct KOReaderSyncSessionState { // completion. Without this, AUTO_PUSH would bounce back into the reader the user just left. bool exitToHomeAfterSync = false; // Set by RecentBooks / FileBrowser long-press to ask the reader to perform an AUTO_PULL - // before rendering its first page. Consumed once on reader entry. Stored separately from - // `intent` because the long-press path bypasses `launchKOReaderSync`'s reader-state capture. - bool autoPullOnOpen = false; + // before rendering its first page. Stored by EPUB path so the flag cannot leak across books. + std::string autoPullEpubPath; void clear() { active = false; @@ -76,7 +75,7 @@ struct KOReaderSyncSessionState { resultParagraphIndex = 0; resultHasParagraphIndex = false; exitToHomeAfterSync = false; - autoPullOnOpen = false; + autoPullEpubPath.clear(); } }; diff --git a/src/JsonSettingsIO.cpp b/src/JsonSettingsIO.cpp index 28989d66..d079e189 100644 --- a/src/JsonSettingsIO.cpp +++ b/src/JsonSettingsIO.cpp @@ -91,7 +91,7 @@ bool JsonSettingsIO::saveState(const CrossPointState& s, const char* path) { sync["resultParagraphIndex"] = s.koReaderSyncSession.resultParagraphIndex; sync["resultHasParagraphIndex"] = s.koReaderSyncSession.resultHasParagraphIndex; sync["exitToHomeAfterSync"] = s.koReaderSyncSession.exitToHomeAfterSync; - sync["autoPullOnOpen"] = s.koReaderSyncSession.autoPullOnOpen; + sync["autoPullEpubPath"] = s.koReaderSyncSession.autoPullEpubPath; // Information about a pending bookmark jump JsonObject jump = doc["pendingBookmarkJump"].to(); jump["active"] = s.pendingBookmarkJump.active; @@ -148,7 +148,10 @@ bool JsonSettingsIO::loadState(CrossPointState& s, const char* json) { s.koReaderSyncSession.resultParagraphIndex = sync["resultParagraphIndex"] | (uint16_t)0; s.koReaderSyncSession.resultHasParagraphIndex = sync["resultHasParagraphIndex"] | false; s.koReaderSyncSession.exitToHomeAfterSync = sync["exitToHomeAfterSync"] | false; - s.koReaderSyncSession.autoPullOnOpen = sync["autoPullOnOpen"] | false; + s.koReaderSyncSession.autoPullEpubPath = sync["autoPullEpubPath"] | std::string(""); + if (s.koReaderSyncSession.autoPullEpubPath.empty() && (sync["autoPullOnOpen"] | false)) { + LOG_DBG("CPS", "Legacy autoPullOnOpen state found without epubPath - ignoring"); + } JsonObject jump = doc["pendingBookmarkJump"].as(); s.pendingBookmarkJump.active = jump["active"] | false; diff --git a/src/activities/home/FileBrowserActivity.cpp b/src/activities/home/FileBrowserActivity.cpp index ba495a74..0e537524 100644 --- a/src/activities/home/FileBrowserActivity.cpp +++ b/src/activities/home/FileBrowserActivity.cpp @@ -187,9 +187,9 @@ void FileBrowserActivity::loop() { std::string fullPath = basepath; if (fullPath.back() != '/') fullPath += "/"; fullPath += entry; - if (longPress && KOREADER_STORE.hasCredentials()) { + if (longPress && KOREADER_STORE.hasCredentials() && FsHelpers::hasEpubExtension(fullPath)) { auto& sync = APP_STATE.koReaderSyncSession; - sync.autoPullOnOpen = true; + sync.autoPullEpubPath = fullPath; sync.exitToHomeAfterSync = false; APP_STATE.saveToFile(); } diff --git a/src/activities/home/RecentBooksActivity.cpp b/src/activities/home/RecentBooksActivity.cpp index 827b7117..b2125f67 100644 --- a/src/activities/home/RecentBooksActivity.cpp +++ b/src/activities/home/RecentBooksActivity.cpp @@ -56,13 +56,16 @@ void RecentBooksActivity::loop() { if (mappedInput.wasReleased(MappedInputManager::Button::Confirm) && !recentBooks.empty() && selectorIndex < static_cast(recentBooks.size())) { - // Long-press Confirm signals "open with KOReader sync": the reader will perform an - // AUTO_PULL before rendering its first page. Short-press is the unchanged direct open. + // Long-press Confirm signals "open with KOReader sync" only for EPUBs. + // Short-press is unchanged direct open. const bool longPress = mappedInput.getHeldTime() >= ReaderUtils::GO_HOME_MS && KOREADER_STORE.hasCredentials(); - LOG_DBG("RBA", "Selected recent book: %s (sync=%d)", recentBooks[selectorIndex].path.c_str(), longPress ? 1 : 0); - if (longPress) { + const std::string& selectedPath = recentBooks[selectorIndex].path; + const bool isEpubBook = FsHelpers::hasEpubExtension(selectedPath); + LOG_DBG("RBA", "Selected recent book: %s (sync=%d epub=%d)", selectedPath.c_str(), longPress ? 1 : 0, + isEpubBook ? 1 : 0); + if (longPress && isEpubBook) { auto& sync = APP_STATE.koReaderSyncSession; - sync.autoPullOnOpen = true; + sync.autoPullEpubPath = selectedPath; sync.exitToHomeAfterSync = false; APP_STATE.saveToFile(); } diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 2eaa2ec7..5f70f5bf 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -898,6 +898,14 @@ bool EpubReaderActivity::tryAutoPushOnClose() { if (!epub) { return false; } + + const int spineCount = epub->getSpineItemsCount(); + if (spineCount == 0 || currentSpineIndex >= spineCount || !section) { + LOG_DBG("ERS", "Skipping AUTO_PUSH on end-of-book sentinel: spine=%d section=%s", currentSpineIndex, + section ? "present" : "null"); + return false; + } + // exitToHomeAfterSync flag is set inside launchKOReaderSync for AUTO_PUSH mode. launchKOReaderSync(SyncLaunchMode::AUTO_PUSH); return true; diff --git a/src/activities/reader/ReaderActivity.cpp b/src/activities/reader/ReaderActivity.cpp index 889246ed..0a7a045e 100644 --- a/src/activities/reader/ReaderActivity.cpp +++ b/src/activities/reader/ReaderActivity.cpp @@ -112,14 +112,14 @@ void ReaderActivity::onGoToEpubReader(std::unique_ptr epub) { const auto epubPath = epub->getPath(); currentBookPath = epubPath; - // Long-press Confirm on RecentBooks/FileBrowser sets autoPullOnOpen so the user can ask - // for KOReader sync at open time. Route into the sync activity instead of creating the + // Long-press Confirm on RecentBooks/FileBrowser sets autoPullEpubPath so the user can + // ask for KOReader sync at open time. Route into the sync activity instead of creating the // reader; sync's resumeReader() will create the reader once the remote position is applied. // Pull-only mode does not need accurate local reader state, so we hand off zeros for spine/page. auto& sync = APP_STATE.koReaderSyncSession; - if (sync.autoPullOnOpen && KOREADER_STORE.hasCredentials()) { + if (!sync.autoPullEpubPath.empty() && sync.autoPullEpubPath == epubPath && KOREADER_STORE.hasCredentials()) { LOG_DBG("READER", "AUTO_PULL on open: %s", epubPath.c_str()); - sync.autoPullOnOpen = false; // consume the flag + sync.autoPullEpubPath.clear(); // consume the flag sync.active = true; sync.epubPath = epubPath; sync.spineIndex = 0;