Cache reader progress
This commit is contained in:
@@ -51,9 +51,9 @@ class HomeActivity final : public Activity {
|
||||
void dispatchMenuAction(MenuAction action);
|
||||
|
||||
void rebuildMenuEntries();
|
||||
bool storeCoverBuffer(); // Store frame buffer for cover image
|
||||
bool restoreCoverBuffer(); // Restore frame buffer from stored cover
|
||||
void freeCoverBuffer(); // Free the stored cover buffer
|
||||
bool storeCoverBuffer();
|
||||
bool restoreCoverBuffer();
|
||||
void freeCoverBuffer();
|
||||
void loadRecentBooks(int maxBooks);
|
||||
void loadRecentCovers(int coverHeight);
|
||||
|
||||
|
||||
@@ -1385,16 +1385,23 @@ void EpubReaderActivity::silentIndexNextChapterIfNeeded(const uint16_t viewportW
|
||||
void EpubReaderActivity::saveProgress(int spineIndex, int currentPage, int pageCount) {
|
||||
FsFile f;
|
||||
if (Storage.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) {
|
||||
uint8_t data[6];
|
||||
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;
|
||||
f.write(data, 6);
|
||||
data[6] = overallPercent;
|
||||
f.write(data, 7);
|
||||
f.close();
|
||||
LOG_DBG("ERS", "Progress saved: Chapter %d, Page %d", spineIndex, currentPage);
|
||||
LOG_DBG("ERS", "Progress saved: Chapter %d, Page %d (%d%%)", spineIndex, currentPage, overallPercent);
|
||||
} else {
|
||||
LOG_ERR("ERS", "Could not save progress!");
|
||||
}
|
||||
|
||||
@@ -747,29 +747,40 @@ void MdReaderActivity::renderStatusBar() const {
|
||||
void MdReaderActivity::saveProgress() const {
|
||||
FsFile f;
|
||||
if (Storage.openFileForWrite("MDR", txt->getCachePath() + "/progress.bin", f)) {
|
||||
uint32_t page = static_cast<uint32_t>(currentPage < 0 ? 0 : currentPage);
|
||||
uint8_t data[4];
|
||||
data[0] = page & 0xFF;
|
||||
data[1] = (page >> 8) & 0xFF;
|
||||
data[2] = (page >> 16) & 0xFF;
|
||||
data[3] = (page >> 24) & 0xFF;
|
||||
f.write(data, 4);
|
||||
// 7-byte format matching TxtReaderActivity: page(2 bytes LE) + file offset(4 bytes LE) + overallPercent(1 byte)
|
||||
const size_t offset =
|
||||
(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];
|
||||
data[0] = currentPage & 0xFF;
|
||||
data[1] = (currentPage >> 8) & 0xFF;
|
||||
data[2] = offset & 0xFF;
|
||||
data[3] = (offset >> 8) & 0xFF;
|
||||
data[4] = (offset >> 16) & 0xFF;
|
||||
data[5] = (offset >> 24) & 0xFF;
|
||||
data[6] = overallPercent;
|
||||
f.write(data, 7);
|
||||
}
|
||||
}
|
||||
|
||||
void MdReaderActivity::loadProgress() {
|
||||
FsFile f;
|
||||
if (Storage.openFileForRead("MDR", txt->getCachePath() + "/progress.bin", f)) {
|
||||
uint8_t data[4];
|
||||
if (f.read(data, 4) == 4) {
|
||||
uint32_t loadedPage = static_cast<uint32_t>(data[0]) | (static_cast<uint32_t>(data[1]) << 8) |
|
||||
(static_cast<uint32_t>(data[2]) << 16) | (static_cast<uint32_t>(data[3]) << 24);
|
||||
uint8_t data[7];
|
||||
const int dataSize = f.read(data, 7);
|
||||
f.close();
|
||||
if (dataSize >= 4) {
|
||||
// Old 4-byte format: uint32 page — detect by checking if bytes 2-3 are non-zero
|
||||
// (new format stores page in bytes 0-1 only, bytes 2-3 are offset low bytes).
|
||||
// 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);
|
||||
if (totalPages == 0) {
|
||||
currentPage = 0;
|
||||
} else if (loadedPage >= static_cast<uint32_t>(totalPages)) {
|
||||
} else if (loadedPage >= totalPages) {
|
||||
currentPage = totalPages - 1;
|
||||
} else {
|
||||
currentPage = static_cast<int>(loadedPage);
|
||||
currentPage = loadedPage;
|
||||
}
|
||||
LOG_DBG("MDR", "Loaded progress: page %d/%d", currentPage, totalPages);
|
||||
}
|
||||
|
||||
@@ -408,17 +408,19 @@ void TxtReaderActivity::renderStatusBar() const {
|
||||
void TxtReaderActivity::saveProgress() const {
|
||||
FsFile f;
|
||||
if (Storage.openFileForWrite("TRS", txt->getCachePath() + "/progress.bin", f)) {
|
||||
// 6-byte format: page(2 bytes LE) + file offset(4 bytes LE)
|
||||
// 7-byte format: page(2 bytes LE) + file offset(4 bytes LE) + overallPercent(1 byte)
|
||||
// The offset lets drawCurrentPageToBuffer render without requiring index.bin.
|
||||
const size_t offset = (currentPage < static_cast<int>(pageOffsets.size())) ? pageOffsets[currentPage] : 0;
|
||||
uint8_t data[6];
|
||||
const uint8_t overallPercent = (totalPages > 0) ? static_cast<uint8_t>((currentPage + 1) * 100 / totalPages) : 0;
|
||||
uint8_t data[7];
|
||||
data[0] = currentPage & 0xFF;
|
||||
data[1] = (currentPage >> 8) & 0xFF;
|
||||
data[2] = offset & 0xFF;
|
||||
data[3] = (offset >> 8) & 0xFF;
|
||||
data[4] = (offset >> 16) & 0xFF;
|
||||
data[5] = (offset >> 24) & 0xFF;
|
||||
f.write(data, 6);
|
||||
data[6] = overallPercent;
|
||||
f.write(data, 7);
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,12 +334,15 @@ void XtcReaderActivity::renderPage() {
|
||||
void XtcReaderActivity::saveProgress() const {
|
||||
FsFile f;
|
||||
if (Storage.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) {
|
||||
uint8_t data[4];
|
||||
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];
|
||||
data[0] = currentPage & 0xFF;
|
||||
data[1] = (currentPage >> 8) & 0xFF;
|
||||
data[2] = (currentPage >> 16) & 0xFF;
|
||||
data[3] = (currentPage >> 24) & 0xFF;
|
||||
f.write(data, 4);
|
||||
data[4] = overallPercent;
|
||||
f.write(data, 5);
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <HalPowerManager.h>
|
||||
#include <HalStorage.h>
|
||||
#include <I18n.h>
|
||||
#include <Serialization.h>
|
||||
#include <Txt.h>
|
||||
#include <Xtc.h>
|
||||
|
||||
@@ -58,30 +57,6 @@ int clampProgressPercent(const int progressPercent) {
|
||||
return progressPercent;
|
||||
}
|
||||
|
||||
int readTxtTotalPages(const std::string& cachePath) {
|
||||
FsFile indexFile;
|
||||
if (!Storage.openFileForRead("LYR", cachePath + "/index.bin", indexFile)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t magic = 0;
|
||||
uint8_t version = 0;
|
||||
serialization::readPod(indexFile, magic);
|
||||
serialization::readPod(indexFile, version);
|
||||
static constexpr uint32_t INDEX_CACHE_MAGIC = 0x54585449; // "TXTI"
|
||||
static constexpr uint8_t INDEX_CACHE_VERSION = 2;
|
||||
if (magic != INDEX_CACHE_MAGIC || version != INDEX_CACHE_VERSION) {
|
||||
indexFile.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
indexFile.seek(32);
|
||||
uint32_t totalPages = 0;
|
||||
serialization::readPod(indexFile, totalPages);
|
||||
indexFile.close();
|
||||
return static_cast<int>(totalPages);
|
||||
}
|
||||
|
||||
void drawLyraBatteryIcon(const GfxRenderer& renderer, int x, int y, int battWidth, int rectHeight,
|
||||
uint16_t percentage) {
|
||||
BaseTheme::drawBatteryOutline(renderer, x, y, battWidth, rectHeight);
|
||||
@@ -152,92 +127,44 @@ const uint8_t* iconForName(UIIcon icon, int size) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Reads the overall progress percent stored as the last byte of progress.bin.
|
||||
// The cache path is derived from the book path alone (no epub/xtc/txt loading needed).
|
||||
// Returns -1 if the file is absent or the percent byte is not yet written.
|
||||
int LyraTheme::getRecentBookProgressPercent(const RecentBook& book) {
|
||||
if (book.path.empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string cachePath;
|
||||
int percentByteOffset; // byte index of the percent field in progress.bin
|
||||
|
||||
if (FsHelpers::hasEpubExtension(book.path)) {
|
||||
Epub epub(book.path, "/.crosspoint");
|
||||
if (!epub.load(true, true)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
FsFile progressFile;
|
||||
if (!Storage.openFileForRead("LYR", epub.getCachePath() + "/progress.bin", progressFile)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t data[6];
|
||||
const int dataSize = progressFile.read(data, 6);
|
||||
progressFile.close();
|
||||
if (dataSize != 4 && dataSize != 6) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int currentSpineIndex = data[0] + (data[1] << 8);
|
||||
const int currentPage = data[2] + (data[3] << 8);
|
||||
const int pageCount = (dataSize == 6) ? (data[4] + (data[5] << 8)) : 0;
|
||||
if (pageCount <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const float chapterProgress = static_cast<float>(currentPage) / static_cast<float>(pageCount);
|
||||
return clampProgressPercent(
|
||||
static_cast<int>(std::lround(epub.calculateProgress(currentSpineIndex, chapterProgress) * 100.0f)));
|
||||
cachePath = Epub(book.path, "/.crosspoint").getCachePath();
|
||||
percentByteOffset = 6; // epub: [spineIdx(2), page(2), chapterPageCount(2), percent(1)]
|
||||
} else if (FsHelpers::hasXtcExtension(book.path)) {
|
||||
cachePath = Xtc(book.path, "/.crosspoint").getCachePath();
|
||||
percentByteOffset = 4; // xtc: [page(4), percent(1)]
|
||||
} else if (FsHelpers::hasTxtExtension(book.path) || FsHelpers::hasMarkdownExtension(book.path)) {
|
||||
cachePath = Txt(book.path, "/.crosspoint").getCachePath();
|
||||
percentByteOffset = 6; // [page(2), offset(4), percent(1)]
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (FsHelpers::hasXtcExtension(book.path)) {
|
||||
Xtc xtc(book.path, "/.crosspoint");
|
||||
if (!xtc.load()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
FsFile progressFile;
|
||||
if (!Storage.openFileForRead("LYR", xtc.getCachePath() + "/progress.bin", progressFile)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t data[4];
|
||||
if (progressFile.read(data, 4) != 4) {
|
||||
progressFile.close();
|
||||
return -1;
|
||||
}
|
||||
progressFile.close();
|
||||
|
||||
const uint32_t currentPage = static_cast<uint32_t>(data[0]) | (static_cast<uint32_t>(data[1]) << 8) |
|
||||
(static_cast<uint32_t>(data[2]) << 16) | (static_cast<uint32_t>(data[3]) << 24);
|
||||
return clampProgressPercent(static_cast<int>(xtc.calculateProgress(currentPage)));
|
||||
FsFile progressFile;
|
||||
if (!Storage.openFileForRead("LYR", cachePath + "/progress.bin", progressFile)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (FsHelpers::hasTxtExtension(book.path) || FsHelpers::hasMarkdownExtension(book.path)) {
|
||||
Txt txt(book.path, "/.crosspoint");
|
||||
if (!txt.load()) {
|
||||
return -1;
|
||||
}
|
||||
uint8_t data[7];
|
||||
const int dataSize = progressFile.read(data, 7);
|
||||
progressFile.close();
|
||||
|
||||
FsFile progressFile;
|
||||
if (!Storage.openFileForRead("LYR", txt.getCachePath() + "/progress.bin", progressFile)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t data[4];
|
||||
if (progressFile.read(data, 4) != 4) {
|
||||
progressFile.close();
|
||||
return -1;
|
||||
}
|
||||
progressFile.close();
|
||||
|
||||
const int currentPage = data[0] + (data[1] << 8);
|
||||
const int totalPages = readTxtTotalPages(txt.getCachePath());
|
||||
if (totalPages <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return clampProgressPercent(static_cast<int>(std::lround((currentPage + 1) * 100.0f / totalPages)));
|
||||
if (dataSize <= percentByteOffset) {
|
||||
return -1; // old format without percent byte — not yet read by new firmware
|
||||
}
|
||||
|
||||
return -1;
|
||||
return clampProgressPercent(static_cast<int>(data[percentByteOffset]));
|
||||
}
|
||||
|
||||
void LyraTheme::drawProgressBadge(const GfxRenderer& renderer, Rect anchorRect, int progressPercent) {
|
||||
|
||||
Reference in New Issue
Block a user