Attempt at closing reader and sync
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <HalStorage.h>
|
||||
#include <I18n.h>
|
||||
#include <Logging.h>
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_system.h>
|
||||
|
||||
#include <memory>
|
||||
@@ -18,7 +19,6 @@
|
||||
#include "EpubReaderFootnotesActivity.h"
|
||||
#include "EpubReaderPercentSelectionActivity.h"
|
||||
#include "KOReaderCredentialStore.h"
|
||||
#include "KOReaderSyncActivity.h"
|
||||
#include "MappedInputManager.h"
|
||||
#include "QrDisplayActivity.h"
|
||||
#include "ReaderUtils.h"
|
||||
@@ -33,6 +33,31 @@ constexpr unsigned long skipChapterMs = 700;
|
||||
// pages per minute, first item is 1 to prevent division by zero if accessed
|
||||
const std::vector<int> PAGE_TURN_LABELS = {1, 1, 3, 6, 12};
|
||||
|
||||
void logReaderMemSnapshot(const char* stage) {
|
||||
const uint32_t freeHeap = esp_get_free_heap_size();
|
||||
const uint32_t contigHeap = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_DEFAULT);
|
||||
LOG_DBG("ERS", "Reader mem[%s]: free=%lu contig=%lu", stage, freeHeap, contigHeap);
|
||||
}
|
||||
|
||||
bool writeReaderProgressCache(const std::string& cachePath, const int spineIndex, const int currentPage, const int pageCount) {
|
||||
FsFile f;
|
||||
if (!Storage.openFileForWrite("ERS", cachePath + "/progress.bin", f)) {
|
||||
LOG_ERR("ERS", "Failed to open progress cache for sync restore: %s", cachePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t data[6];
|
||||
data[0] = spineIndex & 0xFF;
|
||||
data[1] = (spineIndex >> 8) & 0xFF;
|
||||
data[2] = currentPage & 0xFF;
|
||||
data[3] = (currentPage >> 8) & 0xFF;
|
||||
data[4] = pageCount & 0xFF;
|
||||
data[5] = (pageCount >> 8) & 0xFF;
|
||||
f.write(data, 6);
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
int clampPercent(int percent) {
|
||||
if (percent < 0) {
|
||||
return 0;
|
||||
@@ -47,6 +72,7 @@ int clampPercent(int percent) {
|
||||
|
||||
void EpubReaderActivity::onEnter() {
|
||||
Activity::onEnter();
|
||||
logReaderMemSnapshot("onEnter_begin");
|
||||
|
||||
// Drop any input events that arrived from the activity that launched us (e.g. a wake-up power
|
||||
// button hold) before they reach detectPageTurn() — see ReaderUtils::InputDrainGuard.
|
||||
@@ -64,6 +90,7 @@ void EpubReaderActivity::onEnter() {
|
||||
}
|
||||
|
||||
epub->setupCacheDir();
|
||||
applyPendingSyncSession();
|
||||
|
||||
FsFile f;
|
||||
if (Storage.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) {
|
||||
@@ -104,10 +131,12 @@ void EpubReaderActivity::onEnter() {
|
||||
|
||||
// Trigger first update
|
||||
requestUpdate();
|
||||
logReaderMemSnapshot("onEnter_ready");
|
||||
}
|
||||
|
||||
void EpubReaderActivity::onExit() {
|
||||
Activity::onExit();
|
||||
logReaderMemSnapshot("onExit_before_release");
|
||||
|
||||
// Reset orientation back to portrait for the rest of the UI
|
||||
renderer.setOrientation(GfxRenderer::Orientation::Portrait);
|
||||
@@ -116,6 +145,9 @@ void EpubReaderActivity::onExit() {
|
||||
APP_STATE.saveToFile();
|
||||
section.reset();
|
||||
epub.reset();
|
||||
currentPageFootnotes.clear();
|
||||
currentPageFootnotes.shrink_to_fit();
|
||||
logReaderMemSnapshot("onExit_after_release");
|
||||
}
|
||||
|
||||
void EpubReaderActivity::loop() {
|
||||
@@ -498,70 +530,77 @@ void EpubReaderActivity::launchKOReaderSync(const SyncLaunchMode mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string syncEpubPath = epub->getPath();
|
||||
const int currentPage = section ? section->currentPage : 0;
|
||||
const int totalPages = section ? section->pageCount : 0;
|
||||
|
||||
{
|
||||
// Drop large reader state before TLS-heavy sync to improve contiguous heap
|
||||
// and reduce long-run fragmentation across repeated sync attempts.
|
||||
RenderLock lock(*this);
|
||||
nextPageNumber = currentPage;
|
||||
cachedSpineIndex = currentSpineIndex;
|
||||
cachedChapterTotalPageCount = totalPages;
|
||||
section.reset();
|
||||
epub.reset();
|
||||
currentPageFootnotes.clear();
|
||||
currentPageFootnotes.shrink_to_fit();
|
||||
}
|
||||
deferredSyncEpubPath = syncEpubPath;
|
||||
|
||||
renderer.cleanupGrayscaleWithFrameBuffer();
|
||||
if (auto* cacheManager = renderer.getFontCacheManager()) {
|
||||
cacheManager->clearCache();
|
||||
cacheManager->resetStats();
|
||||
}
|
||||
|
||||
LOG_DBG("ERS", "Pre-sync trim: spine=%d page=%d/%d heap=%lu", currentSpineIndex, currentPage, totalPages,
|
||||
static_cast<unsigned long>(esp_get_free_heap_size()));
|
||||
|
||||
// Map reader-level launch mode to activity-level intent once, then pass a
|
||||
// stable intent into KOReaderSyncActivity so it can own the sync state machine.
|
||||
KOReaderSyncActivity::SyncIntent syncIntent = KOReaderSyncActivity::SyncIntent::COMPARE;
|
||||
KOReaderSyncIntentState syncIntent = KOReaderSyncIntentState::COMPARE;
|
||||
if (mode == SyncLaunchMode::PULL_REMOTE) {
|
||||
syncIntent = KOReaderSyncActivity::SyncIntent::PULL_REMOTE;
|
||||
syncIntent = KOReaderSyncIntentState::PULL_REMOTE;
|
||||
} else if (mode == SyncLaunchMode::PUSH_LOCAL) {
|
||||
syncIntent = KOReaderSyncActivity::SyncIntent::PUSH_LOCAL;
|
||||
syncIntent = KOReaderSyncIntentState::PUSH_LOCAL;
|
||||
}
|
||||
|
||||
startActivityForResult(
|
||||
std::make_unique<KOReaderSyncActivity>(renderer, mappedInput, std::shared_ptr<Epub>{}, syncEpubPath,
|
||||
currentSpineIndex, currentPage, totalPages, 0, false, syncIntent),
|
||||
[this](const ActivityResult& result) { handleSyncResult(result); });
|
||||
auto& sync = APP_STATE.koReaderSyncSession;
|
||||
sync.active = true;
|
||||
sync.epubPath = epub->getPath();
|
||||
sync.spineIndex = currentSpineIndex;
|
||||
sync.page = currentPage;
|
||||
sync.totalPagesInSpine = totalPages;
|
||||
sync.paragraphIndex = 0;
|
||||
sync.hasParagraphIndex = false;
|
||||
sync.intent = syncIntent;
|
||||
sync.outcome = KOReaderSyncOutcomeState::PENDING;
|
||||
sync.resultSpineIndex = 0;
|
||||
sync.resultPage = 0;
|
||||
sync.resultParagraphIndex = 0;
|
||||
sync.resultHasParagraphIndex = false;
|
||||
APP_STATE.saveToFile();
|
||||
|
||||
LOG_DBG("ERS", "Standalone sync handoff: spine=%d page=%d/%d", currentSpineIndex, currentPage, totalPages);
|
||||
logReaderMemSnapshot("before_replace_with_sync");
|
||||
activityManager.goToKOReaderSync();
|
||||
}
|
||||
|
||||
void EpubReaderActivity::handleSyncResult(const ActivityResult& result) {
|
||||
if (!epub && !deferredSyncEpubPath.empty()) {
|
||||
epub = std::make_shared<Epub>(deferredSyncEpubPath, "/.crosspoint");
|
||||
if (!epub->load(true, true)) {
|
||||
LOG_ERR("ERS", "Failed to reload EPUB after sync: %s", deferredSyncEpubPath.c_str());
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
epub->setupCacheDir();
|
||||
LOG_DBG("ERS", "Reloaded EPUB after sync: %s", deferredSyncEpubPath.c_str());
|
||||
deferredSyncEpubPath.clear();
|
||||
void EpubReaderActivity::applyPendingSyncSession() {
|
||||
auto& sync = APP_STATE.koReaderSyncSession;
|
||||
if (!sync.active || !epub || sync.epubPath != epub->getPath()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.isCancelled) {
|
||||
const auto& sync = std::get<SyncResult>(result.data);
|
||||
if (currentSpineIndex != sync.spineIndex || (section && section->currentPage != sync.page)) {
|
||||
RenderLock lock(*this);
|
||||
currentSpineIndex = sync.spineIndex;
|
||||
nextPageNumber = sync.page;
|
||||
section.reset();
|
||||
}
|
||||
LOG_DBG("ERS", "Applying pending sync session outcome=%d path=%s", static_cast<int>(sync.outcome), sync.epubPath.c_str());
|
||||
|
||||
int restoreSpineIndex = sync.spineIndex;
|
||||
int restorePage = sync.page;
|
||||
pendingParagraphLookup = sync.hasParagraphIndex;
|
||||
pendingParagraphIndex = sync.paragraphIndex;
|
||||
|
||||
if (sync.outcome == KOReaderSyncOutcomeState::APPLIED_REMOTE) {
|
||||
restoreSpineIndex = sync.resultSpineIndex;
|
||||
restorePage = sync.resultPage;
|
||||
pendingParagraphLookup = sync.resultHasParagraphIndex;
|
||||
pendingParagraphIndex = sync.resultParagraphIndex;
|
||||
LOG_DBG("ERS", "Applied synced remote position: spine=%d page=%d paragraph=%u hasParagraph=%s",
|
||||
restoreSpineIndex, restorePage, pendingParagraphIndex, pendingParagraphLookup ? "yes" : "no");
|
||||
} else {
|
||||
LOG_DBG("ERS", "Restored local pre-sync position: spine=%d page=%d paragraph=%u hasParagraph=%s", restoreSpineIndex,
|
||||
restorePage, pendingParagraphIndex, pendingParagraphLookup ? "yes" : "no");
|
||||
}
|
||||
|
||||
if (writeReaderProgressCache(epub->getCachePath(), restoreSpineIndex, restorePage, sync.totalPagesInSpine)) {
|
||||
cachedSpineIndex = restoreSpineIndex;
|
||||
cachedChapterTotalPageCount = sync.totalPagesInSpine;
|
||||
LOG_DBG("ERS", "Prepared progress.bin for sync restore: spine=%d page=%d/%d", restoreSpineIndex, restorePage,
|
||||
sync.totalPagesInSpine);
|
||||
} else {
|
||||
// Fall back to directly seeding live state if cache write fails.
|
||||
currentSpineIndex = restoreSpineIndex;
|
||||
nextPageNumber = restorePage;
|
||||
cachedSpineIndex = restoreSpineIndex;
|
||||
cachedChapterTotalPageCount = sync.totalPagesInSpine;
|
||||
}
|
||||
|
||||
sync.clear();
|
||||
APP_STATE.saveToFile();
|
||||
logReaderMemSnapshot("after_apply_pending_sync_session");
|
||||
}
|
||||
|
||||
void EpubReaderActivity::applyOrientation(const uint8_t orientation) {
|
||||
@@ -914,8 +953,8 @@ void EpubReaderActivity::saveProgress(int spineIndex, int currentPage, int pageC
|
||||
FsFile f;
|
||||
if (Storage.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) {
|
||||
uint8_t data[6];
|
||||
data[0] = currentSpineIndex & 0xFF;
|
||||
data[1] = (currentSpineIndex >> 8) & 0xFF;
|
||||
data[0] = spineIndex & 0xFF;
|
||||
data[1] = (spineIndex >> 8) & 0xFF;
|
||||
data[2] = currentPage & 0xFF;
|
||||
data[3] = (currentPage >> 8) & 0xFF;
|
||||
data[4] = pageCount & 0xFF;
|
||||
|
||||
Reference in New Issue
Block a user