Simplify
This commit is contained in:
@@ -51,22 +51,37 @@ void logReaderMemSnapshot(const char* stage) {
|
|||||||
inline void logReaderMemSnapshot(const char*) {}
|
inline void logReaderMemSnapshot(const char*) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Computes the [0..100] EPUB progress percent. Returns 0 when pageCount is unknown (sync/bookmark
|
||||||
|
// pre-render writes), in which case the next saveProgress() will overwrite progress.bin with the
|
||||||
|
// real value before the user can leave the reader.
|
||||||
|
uint8_t epubProgressPercentByte(const Epub& epub, const int spineIndex, const int currentPage, const int pageCount) {
|
||||||
|
if (pageCount <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const float chapterProgress = static_cast<float>(currentPage) / static_cast<float>(pageCount);
|
||||||
|
return ReaderUtils::fractionProgressPercentByte(epub.calculateProgress(spineIndex, chapterProgress));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes the canonical EPUB progress.bin layout: spine(2) + page(2) + pageCount(2) + percent(1).
|
||||||
|
// Used by the per-page saveProgress() and by transient writers (sync restore, bookmark jump) so
|
||||||
|
// the on-disk format stays consistent regardless of caller.
|
||||||
bool writeReaderProgressCache(const std::string& cachePath, const int spineIndex, const int currentPage,
|
bool writeReaderProgressCache(const std::string& cachePath, const int spineIndex, const int currentPage,
|
||||||
const int pageCount) {
|
const int pageCount, const uint8_t percent) {
|
||||||
FsFile f;
|
FsFile f;
|
||||||
if (!Storage.openFileForWrite("ERS", cachePath + "/progress.bin", f)) {
|
if (!Storage.openFileForWrite("ERS", cachePath + "/progress.bin", f)) {
|
||||||
LOG_ERR("ERS", "Failed to open progress cache for sync restore: %s", cachePath.c_str());
|
LOG_ERR("ERS", "Failed to open progress cache: %s", cachePath.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[6];
|
uint8_t data[7];
|
||||||
data[0] = spineIndex & 0xFF;
|
data[0] = spineIndex & 0xFF;
|
||||||
data[1] = (spineIndex >> 8) & 0xFF;
|
data[1] = (spineIndex >> 8) & 0xFF;
|
||||||
data[2] = currentPage & 0xFF;
|
data[2] = currentPage & 0xFF;
|
||||||
data[3] = (currentPage >> 8) & 0xFF;
|
data[3] = (currentPage >> 8) & 0xFF;
|
||||||
data[4] = pageCount & 0xFF;
|
data[4] = pageCount & 0xFF;
|
||||||
data[5] = (pageCount >> 8) & 0xFF;
|
data[5] = (pageCount >> 8) & 0xFF;
|
||||||
f.write(data, 6);
|
data[6] = percent;
|
||||||
|
f.write(data, 7);
|
||||||
f.close();
|
f.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -900,7 +915,9 @@ void EpubReaderActivity::applyPendingSyncSession() {
|
|||||||
// Store 0 to disable rescaling; the paragraph lookup handles precise positioning.
|
// Store 0 to disable rescaling; the paragraph lookup handles precise positioning.
|
||||||
const int restorePageCount = (restoreSpineIndex == sync.spineIndex) ? sync.totalPagesInSpine : 0;
|
const int restorePageCount = (restoreSpineIndex == sync.spineIndex) ? sync.totalPagesInSpine : 0;
|
||||||
|
|
||||||
if (writeReaderProgressCache(epub->getCachePath(), restoreSpineIndex, restorePage, restorePageCount)) {
|
// Transient write — the next render's saveProgress() supplies the real percent before the user
|
||||||
|
// can return to the home screen, so a placeholder 0 here is harmless.
|
||||||
|
if (writeReaderProgressCache(epub->getCachePath(), restoreSpineIndex, restorePage, restorePageCount, 0)) {
|
||||||
cachedSpineIndex = restoreSpineIndex;
|
cachedSpineIndex = restoreSpineIndex;
|
||||||
cachedChapterTotalPageCount = restorePageCount;
|
cachedChapterTotalPageCount = restorePageCount;
|
||||||
LOG_DBG("ERS", "Prepared progress.bin for sync restore: spine=%d page=%d/%d", restoreSpineIndex, restorePage,
|
LOG_DBG("ERS", "Prepared progress.bin for sync restore: spine=%d page=%d/%d", restoreSpineIndex, restorePage,
|
||||||
@@ -924,7 +941,8 @@ void EpubReaderActivity::applyPendingBookmarkJump() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOG_DBG("ERS", "Applying pending bookmark jump: spine=%u page=%u", jump.spineIndex, jump.pageNumber);
|
LOG_DBG("ERS", "Applying pending bookmark jump: spine=%u page=%u", jump.spineIndex, jump.pageNumber);
|
||||||
if (writeReaderProgressCache(epub->getCachePath(), jump.spineIndex, jump.pageNumber, 0)) {
|
// Transient write before initializeReader; saveProgress() overwrites with the real percent.
|
||||||
|
if (writeReaderProgressCache(epub->getCachePath(), jump.spineIndex, jump.pageNumber, 0, 0)) {
|
||||||
cachedSpineIndex = jump.spineIndex;
|
cachedSpineIndex = jump.spineIndex;
|
||||||
cachedChapterTotalPageCount = 0;
|
cachedChapterTotalPageCount = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -1383,28 +1401,12 @@ void EpubReaderActivity::silentIndexNextChapterIfNeeded(const uint16_t viewportW
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EpubReaderActivity::saveProgress(int spineIndex, int currentPage, int pageCount) {
|
void EpubReaderActivity::saveProgress(int spineIndex, int currentPage, int pageCount) {
|
||||||
FsFile f;
|
const uint8_t percent = epubProgressPercentByte(*epub, spineIndex, currentPage, pageCount);
|
||||||
if (Storage.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) {
|
if (!writeReaderProgressCache(epub->getCachePath(), spineIndex, currentPage, pageCount, percent)) {
|
||||||
uint8_t overallPercent = 0;
|
|
||||||
if (epub->getBookSize() > 0 && pageCount > 0) {
|
|
||||||
const float chapterProgress = static_cast<float>(currentPage) / static_cast<float>(pageCount);
|
|
||||||
overallPercent = static_cast<uint8_t>(
|
|
||||||
clampPercent(static_cast<int>(epub->calculateProgress(spineIndex, chapterProgress) * 100.0f + 0.5f)));
|
|
||||||
}
|
|
||||||
uint8_t data[7];
|
|
||||||
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;
|
|
||||||
data[6] = overallPercent;
|
|
||||||
f.write(data, 7);
|
|
||||||
f.close();
|
|
||||||
LOG_DBG("ERS", "Progress saved: Chapter %d, Page %d (%d%%)", spineIndex, currentPage, overallPercent);
|
|
||||||
} else {
|
|
||||||
LOG_ERR("ERS", "Could not save progress!");
|
LOG_ERR("ERS", "Could not save progress!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
LOG_DBG("ERS", "Progress saved: Chapter %d, Page %d (%d%%)", spineIndex, currentPage, percent);
|
||||||
}
|
}
|
||||||
void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int orientedMarginTop,
|
void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int orientedMarginTop,
|
||||||
const int orientedMarginRight, const int orientedMarginBottom,
|
const int orientedMarginRight, const int orientedMarginBottom,
|
||||||
|
|||||||
@@ -750,7 +750,6 @@ void MdReaderActivity::saveProgress() const {
|
|||||||
// 7-byte format matching TxtReaderActivity: page(2 bytes LE) + file offset(4 bytes LE) + overallPercent(1 byte)
|
// 7-byte format matching TxtReaderActivity: page(2 bytes LE) + file offset(4 bytes LE) + overallPercent(1 byte)
|
||||||
const size_t offset =
|
const size_t offset =
|
||||||
(currentPage >= 0 && currentPage < static_cast<int>(pageOffsets.size())) ? pageOffsets[currentPage] : 0;
|
(currentPage >= 0 && currentPage < static_cast<int>(pageOffsets.size())) ? pageOffsets[currentPage] : 0;
|
||||||
const uint8_t overallPercent = (totalPages > 0) ? static_cast<uint8_t>((currentPage + 1) * 100 / totalPages) : 0;
|
|
||||||
uint8_t data[7];
|
uint8_t data[7];
|
||||||
data[0] = currentPage & 0xFF;
|
data[0] = currentPage & 0xFF;
|
||||||
data[1] = (currentPage >> 8) & 0xFF;
|
data[1] = (currentPage >> 8) & 0xFF;
|
||||||
@@ -758,7 +757,7 @@ void MdReaderActivity::saveProgress() const {
|
|||||||
data[3] = (offset >> 8) & 0xFF;
|
data[3] = (offset >> 8) & 0xFF;
|
||||||
data[4] = (offset >> 16) & 0xFF;
|
data[4] = (offset >> 16) & 0xFF;
|
||||||
data[5] = (offset >> 24) & 0xFF;
|
data[5] = (offset >> 24) & 0xFF;
|
||||||
data[6] = overallPercent;
|
data[6] = ReaderUtils::pageProgressPercentByte(currentPage, totalPages);
|
||||||
f.write(data, 7);
|
f.write(data, 7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -770,10 +769,8 @@ void MdReaderActivity::loadProgress() {
|
|||||||
const int dataSize = f.read(data, 7);
|
const int dataSize = f.read(data, 7);
|
||||||
f.close();
|
f.close();
|
||||||
if (dataSize >= 4) {
|
if (dataSize >= 4) {
|
||||||
// Old 4-byte format: uint32 page — detect by checking if bytes 2-3 are non-zero
|
// Page sits in bytes 0-1 in both the old 4-byte uint32 format and the new 7-byte format
|
||||||
// (new format stores page in bytes 0-1 only, bytes 2-3 are offset low bytes).
|
// (page counts stay well under 65536, so the upper bytes were always zero).
|
||||||
// Since page counts are small (< 65536), bytes 2-3 of the old uint32 page are always 0.
|
|
||||||
// We can safely read bytes 0-1 as the page number in both formats.
|
|
||||||
int loadedPage = data[0] + (data[1] << 8);
|
int loadedPage = data[0] + (data[1] << 8);
|
||||||
if (totalPages == 0) {
|
if (totalPages == 0) {
|
||||||
currentPage = 0;
|
currentPage = 0;
|
||||||
|
|||||||
@@ -4,12 +4,37 @@
|
|||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <Logging.h>
|
#include <Logging.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include "MappedInputManager.h"
|
#include "MappedInputManager.h"
|
||||||
|
|
||||||
namespace ReaderUtils {
|
namespace ReaderUtils {
|
||||||
|
|
||||||
constexpr unsigned long GO_HOME_MS = 1000;
|
constexpr unsigned long GO_HOME_MS = 1000;
|
||||||
|
|
||||||
|
// Round-half-up integer division clamped to [0, 100], used as the percent byte appended to
|
||||||
|
// progress.bin so the home screen can render a per-book badge without re-loading the document.
|
||||||
|
// All reader types must funnel through this so the displayed value matches across formats.
|
||||||
|
inline uint8_t pageProgressPercentByte(int currentPage, int totalPages) {
|
||||||
|
if (totalPages <= 0 || currentPage < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const long numerator = static_cast<long>(currentPage + 1) * 200L + totalPages;
|
||||||
|
const long percent = numerator / (2L * totalPages);
|
||||||
|
if (percent < 0) return 0;
|
||||||
|
if (percent > 100) return 100;
|
||||||
|
return static_cast<uint8_t>(percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round-half-up clamp for a pre-computed [0,1] progress fraction (used by EPUB, where progress
|
||||||
|
// is byte-weighted across spine items rather than a simple page ratio).
|
||||||
|
inline uint8_t fractionProgressPercentByte(float fraction) {
|
||||||
|
const int percent = static_cast<int>(fraction * 100.0f + 0.5f);
|
||||||
|
if (percent < 0) return 0;
|
||||||
|
if (percent > 100) return 100;
|
||||||
|
return static_cast<uint8_t>(percent);
|
||||||
|
}
|
||||||
|
|
||||||
inline void applyOrientation(GfxRenderer& renderer, const uint8_t orientation) {
|
inline void applyOrientation(GfxRenderer& renderer, const uint8_t orientation) {
|
||||||
switch (orientation) {
|
switch (orientation) {
|
||||||
case CrossPointSettings::ORIENTATION::PORTRAIT:
|
case CrossPointSettings::ORIENTATION::PORTRAIT:
|
||||||
|
|||||||
@@ -411,7 +411,6 @@ void TxtReaderActivity::saveProgress() const {
|
|||||||
// 7-byte format: page(2 bytes LE) + file offset(4 bytes LE) + overallPercent(1 byte)
|
// 7-byte format: page(2 bytes LE) + file offset(4 bytes LE) + overallPercent(1 byte)
|
||||||
// The offset lets drawCurrentPageToBuffer render without requiring index.bin.
|
// The offset lets drawCurrentPageToBuffer render without requiring index.bin.
|
||||||
const size_t offset = (currentPage < static_cast<int>(pageOffsets.size())) ? pageOffsets[currentPage] : 0;
|
const size_t offset = (currentPage < static_cast<int>(pageOffsets.size())) ? pageOffsets[currentPage] : 0;
|
||||||
const uint8_t overallPercent = (totalPages > 0) ? static_cast<uint8_t>((currentPage + 1) * 100 / totalPages) : 0;
|
|
||||||
uint8_t data[7];
|
uint8_t data[7];
|
||||||
data[0] = currentPage & 0xFF;
|
data[0] = currentPage & 0xFF;
|
||||||
data[1] = (currentPage >> 8) & 0xFF;
|
data[1] = (currentPage >> 8) & 0xFF;
|
||||||
@@ -419,7 +418,7 @@ void TxtReaderActivity::saveProgress() const {
|
|||||||
data[3] = (offset >> 8) & 0xFF;
|
data[3] = (offset >> 8) & 0xFF;
|
||||||
data[4] = (offset >> 16) & 0xFF;
|
data[4] = (offset >> 16) & 0xFF;
|
||||||
data[5] = (offset >> 24) & 0xFF;
|
data[5] = (offset >> 24) & 0xFF;
|
||||||
data[6] = overallPercent;
|
data[6] = ReaderUtils::pageProgressPercentByte(currentPage, totalPages);
|
||||||
f.write(data, 7);
|
f.write(data, 7);
|
||||||
f.close();
|
f.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,14 +334,13 @@ void XtcReaderActivity::renderPage() {
|
|||||||
void XtcReaderActivity::saveProgress() const {
|
void XtcReaderActivity::saveProgress() const {
|
||||||
FsFile f;
|
FsFile f;
|
||||||
if (Storage.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) {
|
if (Storage.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) {
|
||||||
const uint32_t pageCount = xtc->getPageCount();
|
|
||||||
const uint8_t overallPercent = (pageCount > 0) ? static_cast<uint8_t>((currentPage + 1) * 100 / pageCount) : 0;
|
|
||||||
uint8_t data[5];
|
uint8_t data[5];
|
||||||
data[0] = currentPage & 0xFF;
|
data[0] = currentPage & 0xFF;
|
||||||
data[1] = (currentPage >> 8) & 0xFF;
|
data[1] = (currentPage >> 8) & 0xFF;
|
||||||
data[2] = (currentPage >> 16) & 0xFF;
|
data[2] = (currentPage >> 16) & 0xFF;
|
||||||
data[3] = (currentPage >> 24) & 0xFF;
|
data[3] = (currentPage >> 24) & 0xFF;
|
||||||
data[4] = overallPercent;
|
data[4] =
|
||||||
|
ReaderUtils::pageProgressPercentByte(static_cast<int>(currentPage), static_cast<int>(xtc->getPageCount()));
|
||||||
f.write(data, 5);
|
f.write(data, 5);
|
||||||
f.close();
|
f.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ int LyraTheme::getRecentBookProgressPercent(const RecentBook& book) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string cachePath;
|
std::string cachePath;
|
||||||
int percentByteOffset; // byte index of the percent field in progress.bin
|
int percentByteOffset = 0; // byte index of the percent field in progress.bin
|
||||||
|
|
||||||
if (FsHelpers::hasEpubExtension(book.path)) {
|
if (FsHelpers::hasEpubExtension(book.path)) {
|
||||||
cachePath = Epub(book.path, "/.crosspoint").getCachePath();
|
cachePath = Epub(book.path, "/.crosspoint").getCachePath();
|
||||||
@@ -160,8 +160,8 @@ int LyraTheme::getRecentBookProgressPercent(const RecentBook& book) {
|
|||||||
const int dataSize = progressFile.read(data, 7);
|
const int dataSize = progressFile.read(data, 7);
|
||||||
progressFile.close();
|
progressFile.close();
|
||||||
|
|
||||||
if (dataSize <= percentByteOffset) {
|
if (dataSize < percentByteOffset + 1) {
|
||||||
return -1; // old format without percent byte — not yet read by new firmware
|
return -1; // old format (or pre-render placeholder) without the percent byte
|
||||||
}
|
}
|
||||||
|
|
||||||
return clampProgressPercent(static_cast<int>(data[percentByteOffset]));
|
return clampProgressPercent(static_cast<int>(data[percentByteOffset]));
|
||||||
|
|||||||
Reference in New Issue
Block a user