diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h
index 1802ac76..9eacfb19 100644
--- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h
+++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h
@@ -84,6 +84,14 @@ class ChapterHtmlSlimParser {
int xpathBodyDepth = -1; // depth of the
element (-1 = not yet seen)
std::vector paragraphIndexPerPage; // index at each page completion
+ // Paragraph index tracking for XPath-to-page lookup table.
+ // Counts
sibling indices (1-based, matching XPath convention) during page building.
+ // Stored per page in the section cache so that XPath p[N] can be resolved to a page
+ // without reparsing, and current page can generate an XPath without reparsing.
+ uint16_t xpathParagraphIndex = 0; // current
sibling index (1-based)
+ int xpathBodyDepth = -1; // depth of the
element (-1 = not yet seen)
+ std::vector paragraphIndexPerPage; // index at each page completion
+
// Footnote link tracking
bool insideFootnoteLink = false;
int footnoteLinkDepth = -1;
diff --git a/lib/hal/HalStorage.cpp b/lib/hal/HalStorage.cpp
index 82b6e03c..9a6d1c9e 100644
--- a/lib/hal/HalStorage.cpp
+++ b/lib/hal/HalStorage.cpp
@@ -176,5 +176,8 @@ HalFile HalFile::openNextFile() {
assert(impl != nullptr);
return HalFile(std::make_unique(impl->file.openNextFile()));
}
+bool HalFile::getModifyDateTime(uint16_t* pdate, uint16_t* ptime) {
+ HAL_FILE_WRAPPED_CALL(getModifyDateTime, pdate, ptime);
+}
bool HalFile::isOpen() const { return impl != nullptr && impl->file.isOpen(); } // already thread-safe, no need to wrap
HalFile::operator bool() const { return isOpen(); }
diff --git a/lib/hal/HalStorage.h b/lib/hal/HalStorage.h
index d9bee706..79b92178 100644
--- a/lib/hal/HalStorage.h
+++ b/lib/hal/HalStorage.h
@@ -95,6 +95,7 @@ class HalFile : public Print {
void rewindDirectory();
bool close();
HalFile openNextFile();
+ bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime);
bool isOpen() const;
operator bool() const;
};
diff --git a/src/activities/reader/KOReaderSyncActivity.cpp b/src/activities/reader/KOReaderSyncActivity.cpp
index 74192b2a..ae9aa525 100644
--- a/src/activities/reader/KOReaderSyncActivity.cpp
+++ b/src/activities/reader/KOReaderSyncActivity.cpp
@@ -201,6 +201,7 @@ void KOReaderSyncActivity::performUpload() {
{
RenderLock lock(*this);
state = UPLOAD_COMPLETE;
+ uploadCompleteTime = millis();
}
requestUpdate(true);
}
@@ -351,6 +352,13 @@ void KOReaderSyncActivity::render(RenderLock&&) {
void KOReaderSyncActivity::loop() {
if (state == NO_CREDENTIALS || state == SYNC_FAILED || state == UPLOAD_COMPLETE) {
+ if (state == UPLOAD_COMPLETE && millis() - uploadCompleteTime >= 3000) {
+ ActivityResult result;
+ result.isCancelled = true;
+ setResult(std::move(result));
+ finish();
+ return;
+ }
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
ActivityResult result;
result.isCancelled = true;
diff --git a/src/activities/reader/KOReaderSyncActivity.h b/src/activities/reader/KOReaderSyncActivity.h
index 1cdd8477..d0276444 100644
--- a/src/activities/reader/KOReaderSyncActivity.h
+++ b/src/activities/reader/KOReaderSyncActivity.h
@@ -78,6 +78,9 @@ class KOReaderSyncActivity final : public Activity {
// Selection in result screen (0=Apply, 1=Upload)
int selectedOption = 0;
+ // Timestamp when UPLOAD_COMPLETE state was entered (for auto-close)
+ unsigned long uploadCompleteTime = 0;
+
void onWifiSelectionComplete(bool success);
void performSync();
void performUpload();