Port three unmerged upstream PRs with adaptations for the fork's callback-based ActivityWithSubactivity architecture: - PR #1185: Cache KOReader document hash using mtime fingerprint + file size validation to avoid repeated MD5 computation on sync. - PR #1217: Proper KOReader XPath synchronisation via new ChapterXPathIndexer (Expat-based on-demand XHTML parsing) with XPath-first mapping and percentage fallback in ProgressMapper. - PR #1090: Push Progress & Sleep menu option with PUSH_ONLY sync mode. Adapted to fork's callback pattern with deferFinish() for thread-safe completion. Modified to sleep silently on any failure (hash, upload, no credentials) rather than returning to reader. Made-with: Cursor
This commit is contained in:
@@ -24,6 +24,8 @@
|
||||
#include "util/BookmarkStore.h"
|
||||
#include "util/Dictionary.h"
|
||||
|
||||
extern void enterDeepSleep();
|
||||
|
||||
namespace {
|
||||
// pagesPerRefresh now comes from SETTINGS.getRefreshFrequency()
|
||||
constexpr unsigned long skipChapterMs = 700;
|
||||
@@ -210,6 +212,18 @@ void EpubReaderActivity::loop() {
|
||||
}
|
||||
return; // Don't access 'this' after callback
|
||||
}
|
||||
if (pendingSleep) {
|
||||
pendingSleep = false;
|
||||
exitActivity();
|
||||
enterDeepSleep();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingSleep) {
|
||||
pendingSleep = false;
|
||||
enterDeepSleep();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -814,6 +828,28 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EpubReaderMenuActivity::MenuAction::PUSH_AND_SLEEP: {
|
||||
if (KOREADER_STORE.hasCredentials()) {
|
||||
const int cp = section ? section->currentPage : 0;
|
||||
const int tp = section ? section->pageCount : 0;
|
||||
exitActivity();
|
||||
enterNewActivity(new KOReaderSyncActivity(
|
||||
renderer, mappedInput, epub, epub->getPath(), currentSpineIndex, cp, tp,
|
||||
[this]() {
|
||||
// Push failed -- sleep anyway (silent failure)
|
||||
pendingSleep = true;
|
||||
},
|
||||
[this](int, int) {
|
||||
// Push succeeded -- sleep
|
||||
pendingSleep = true;
|
||||
},
|
||||
KOReaderSyncActivity::SyncMode::PUSH_ONLY));
|
||||
} else {
|
||||
// No credentials -- just sleep
|
||||
pendingSleep = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Handled locally in the menu activity (cycle on Confirm, never dispatched here)
|
||||
case EpubReaderMenuActivity::MenuAction::ROTATE_SCREEN:
|
||||
case EpubReaderMenuActivity::MenuAction::TOGGLE_FONT_SIZE:
|
||||
|
||||
@@ -22,6 +22,7 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
|
||||
float pendingSpineProgress = 0.0f;
|
||||
bool pendingSubactivityExit = false; // Defer subactivity exit to avoid use-after-free
|
||||
bool pendingGoHome = false; // Defer go home to avoid race condition with display task
|
||||
bool pendingSleep = false; // Defer deep sleep until after push-and-sleep completes
|
||||
bool skipNextButtonCheck = false; // Skip button processing for one frame after subactivity exit
|
||||
bool ignoreNextConfirmRelease = false; // Suppress short-press after long-press Confirm
|
||||
volatile bool loadingSection = false; // True during the entire !section block (read from main loop)
|
||||
|
||||
@@ -27,6 +27,7 @@ class EpubReaderMenuActivity final : public ActivityWithSubactivity {
|
||||
GO_TO_PERCENT,
|
||||
GO_HOME,
|
||||
SYNC,
|
||||
PUSH_AND_SLEEP,
|
||||
DELETE_CACHE,
|
||||
MANAGE_BOOK,
|
||||
ARCHIVE_BOOK,
|
||||
@@ -140,6 +141,7 @@ class EpubReaderMenuActivity final : public ActivityWithSubactivity {
|
||||
items.push_back({MenuAction::GO_TO_PERCENT, StrId::STR_GO_TO_PERCENT});
|
||||
items.push_back({MenuAction::GO_HOME, StrId::STR_CLOSE_BOOK});
|
||||
items.push_back({MenuAction::SYNC, StrId::STR_SYNC_PROGRESS});
|
||||
items.push_back({MenuAction::PUSH_AND_SLEEP, StrId::STR_PUSH_AND_SLEEP});
|
||||
items.push_back({MenuAction::MANAGE_BOOK, StrId::STR_MANAGE_BOOK});
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ void KOReaderSyncActivity::onWifiSelectionComplete(const bool success) {
|
||||
performSync();
|
||||
}
|
||||
|
||||
void KOReaderSyncActivity::deferFinish(bool success) {
|
||||
RenderLock lock(*this);
|
||||
pendingFinishSuccess = success;
|
||||
pendingFinish = true;
|
||||
}
|
||||
|
||||
void KOReaderSyncActivity::performSync() {
|
||||
// Calculate document hash based on user's preferred method
|
||||
if (KOREADER_STORE.getMatchMethod() == DocumentMatchMethod::FILENAME) {
|
||||
@@ -52,6 +58,10 @@ void KOReaderSyncActivity::performSync() {
|
||||
documentHash = KOReaderDocumentId::calculate(epubPath);
|
||||
}
|
||||
if (documentHash.empty()) {
|
||||
if (syncMode == SyncMode::PUSH_ONLY) {
|
||||
deferFinish(false);
|
||||
return;
|
||||
}
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
state = SYNC_FAILED;
|
||||
@@ -63,6 +73,11 @@ void KOReaderSyncActivity::performSync() {
|
||||
|
||||
LOG_DBG("KOSync", "Document hash: %s", documentHash.c_str());
|
||||
|
||||
if (syncMode == SyncMode::PUSH_ONLY) {
|
||||
performUpload();
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
statusMessage = tr(STR_FETCH_PROGRESS);
|
||||
@@ -137,6 +152,10 @@ void KOReaderSyncActivity::performUpload() {
|
||||
const auto result = KOReaderSyncClient::updateProgress(progress);
|
||||
|
||||
if (result != KOReaderSyncClient::OK) {
|
||||
if (syncMode == SyncMode::PUSH_ONLY) {
|
||||
deferFinish(false);
|
||||
return;
|
||||
}
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
state = SYNC_FAILED;
|
||||
@@ -146,6 +165,11 @@ void KOReaderSyncActivity::performUpload() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (syncMode == SyncMode::PUSH_ONLY) {
|
||||
deferFinish(true);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
state = UPLOAD_COMPLETE;
|
||||
@@ -334,6 +358,27 @@ void KOReaderSyncActivity::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (syncMode == SyncMode::PUSH_ONLY) {
|
||||
bool ready = false;
|
||||
bool success = false;
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
if (pendingFinish) {
|
||||
pendingFinish = false;
|
||||
ready = true;
|
||||
success = pendingFinishSuccess;
|
||||
}
|
||||
}
|
||||
if (ready) {
|
||||
if (success) {
|
||||
onSyncComplete(currentSpineIndex, currentPage);
|
||||
} else {
|
||||
onCancel();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == NO_CREDENTIALS || state == SYNC_FAILED || state == UPLOAD_COMPLETE) {
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
|
||||
onCancel();
|
||||
|
||||
@@ -15,18 +15,21 @@
|
||||
* 1. Connect to WiFi (if not connected)
|
||||
* 2. Calculate document hash
|
||||
* 3. Fetch remote progress
|
||||
* 4. Show comparison and options (Apply/Upload)
|
||||
* 4. Show comparison and options (Apply/Upload) or skip when SyncMode::PUSH_ONLY
|
||||
* 5. Apply or upload progress
|
||||
*/
|
||||
class KOReaderSyncActivity final : public ActivityWithSubactivity {
|
||||
public:
|
||||
enum class SyncMode { INTERACTIVE, PUSH_ONLY };
|
||||
|
||||
using OnCancelCallback = std::function<void()>;
|
||||
using OnSyncCompleteCallback = std::function<void(int newSpineIndex, int newPageNumber)>;
|
||||
|
||||
explicit KOReaderSyncActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||
const std::shared_ptr<Epub>& epub, const std::string& epubPath, int currentSpineIndex,
|
||||
int currentPage, int totalPagesInSpine, OnCancelCallback onCancel,
|
||||
OnSyncCompleteCallback onSyncComplete)
|
||||
OnSyncCompleteCallback onSyncComplete,
|
||||
SyncMode syncMode = SyncMode::INTERACTIVE)
|
||||
: ActivityWithSubactivity("KOReaderSync", renderer, mappedInput),
|
||||
epub(epub),
|
||||
epubPath(epubPath),
|
||||
@@ -37,7 +40,8 @@ class KOReaderSyncActivity final : public ActivityWithSubactivity {
|
||||
remotePosition{},
|
||||
localProgress{},
|
||||
onCancel(std::move(onCancel)),
|
||||
onSyncComplete(std::move(onSyncComplete)) {}
|
||||
onSyncComplete(std::move(onSyncComplete)),
|
||||
syncMode(syncMode) {}
|
||||
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
@@ -82,6 +86,11 @@ class KOReaderSyncActivity final : public ActivityWithSubactivity {
|
||||
OnCancelCallback onCancel;
|
||||
OnSyncCompleteCallback onSyncComplete;
|
||||
|
||||
SyncMode syncMode;
|
||||
bool pendingFinish = false;
|
||||
bool pendingFinishSuccess = false;
|
||||
|
||||
void deferFinish(bool success);
|
||||
void onWifiSelectionComplete(bool success);
|
||||
void performSync();
|
||||
void performUpload();
|
||||
|
||||
Reference in New Issue
Block a user