feat(ui): add progress bar for chapter indexing
- Add progressFn callback to ChapterHtmlSlimParser for file-based progress - Update progress every 10% to avoid excessive e-ink refreshes - Display 200px progress bar below "Indexing..." text - Use FAST_REFRESH for responsive progress updates
This commit is contained in:
parent
8c726549bf
commit
f11d70279e
@ -115,7 +115,7 @@ bool Section::clearCache() const {
|
||||
|
||||
bool Section::persistPageDataToSD(const int fontId, const float lineCompression, const int marginTop,
|
||||
const int marginRight, const int marginBottom, const int marginLeft,
|
||||
const bool extraParagraphSpacing) {
|
||||
const bool extraParagraphSpacing, const std::function<void(int)>& progressFn) {
|
||||
const auto localPath = epub->getSpineItem(spineIndex).href;
|
||||
const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html";
|
||||
|
||||
@ -144,7 +144,8 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
|
||||
|
||||
ChapterHtmlSlimParser visitor(tmpHtmlPath, renderer, fontId, lineCompression, marginTop, marginRight, marginBottom,
|
||||
marginLeft, extraParagraphSpacing,
|
||||
[this](std::unique_ptr<Page> page) { this->onPageComplete(std::move(page)); });
|
||||
[this](std::unique_ptr<Page> page) { this->onPageComplete(std::move(page)); },
|
||||
progressFn);
|
||||
success = visitor.parseAndBuildPages();
|
||||
|
||||
SD.remove(tmpHtmlPath.c_str());
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "Epub.h"
|
||||
@ -31,6 +32,7 @@ class Section {
|
||||
void setupCacheDir() const;
|
||||
bool clearCache() const;
|
||||
bool persistPageDataToSD(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom,
|
||||
int marginLeft, bool extraParagraphSpacing);
|
||||
int marginLeft, bool extraParagraphSpacing,
|
||||
const std::function<void(int)>& progressFn = nullptr);
|
||||
std::unique_ptr<Page> loadPageFromSD() const;
|
||||
};
|
||||
|
||||
@ -221,6 +221,11 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get file size for progress calculation
|
||||
const size_t totalSize = file.size();
|
||||
size_t bytesRead = 0;
|
||||
int lastProgress = -1;
|
||||
|
||||
XML_SetUserData(parser, this);
|
||||
XML_SetElementHandler(parser, startElement, endElement);
|
||||
XML_SetCharacterDataHandler(parser, characterData);
|
||||
@ -249,6 +254,16 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update progress (call every 10% change to avoid too frequent updates)
|
||||
bytesRead += len;
|
||||
if (progressFn && totalSize > 0) {
|
||||
const int progress = static_cast<int>((bytesRead * 100) / totalSize);
|
||||
if (progress != lastProgress && progress % 10 == 0) {
|
||||
lastProgress = progress;
|
||||
progressFn(progress);
|
||||
}
|
||||
}
|
||||
|
||||
done = file.available() == 0;
|
||||
|
||||
if (XML_ParseBuffer(parser, static_cast<int>(len), done) == XML_STATUS_ERROR) {
|
||||
|
||||
@ -18,6 +18,7 @@ class ChapterHtmlSlimParser {
|
||||
const std::string& filepath;
|
||||
GfxRenderer& renderer;
|
||||
std::function<void(std::unique_ptr<Page>)> completePageFn;
|
||||
std::function<void(int)> progressFn; // Progress callback (0-100)
|
||||
int depth = 0;
|
||||
int skipUntilDepth = INT_MAX;
|
||||
int boldUntilDepth = INT_MAX;
|
||||
@ -48,7 +49,8 @@ class ChapterHtmlSlimParser {
|
||||
explicit ChapterHtmlSlimParser(const std::string& filepath, GfxRenderer& renderer, const int fontId,
|
||||
const float lineCompression, const int marginTop, const int marginRight,
|
||||
const int marginBottom, const int marginLeft, const bool extraParagraphSpacing,
|
||||
const std::function<void(std::unique_ptr<Page>)>& completePageFn)
|
||||
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
|
||||
const std::function<void(int)>& progressFn = nullptr)
|
||||
: filepath(filepath),
|
||||
renderer(renderer),
|
||||
fontId(fontId),
|
||||
@ -58,7 +60,8 @@ class ChapterHtmlSlimParser {
|
||||
marginBottom(marginBottom),
|
||||
marginLeft(marginLeft),
|
||||
extraParagraphSpacing(extraParagraphSpacing),
|
||||
completePageFn(completePageFn) {}
|
||||
completePageFn(completePageFn),
|
||||
progressFn(progressFn) {}
|
||||
~ChapterHtmlSlimParser() = default;
|
||||
bool parseAndBuildPages();
|
||||
void addLineToPage(std::shared_ptr<TextBlock> line);
|
||||
|
||||
@ -219,23 +219,40 @@ void EpubReaderActivity::renderScreen() {
|
||||
SETTINGS.extraParagraphSpacing)) {
|
||||
Serial.printf("[%lu] [ERS] Cache not found, building...\n", millis());
|
||||
|
||||
// Progress bar dimensions
|
||||
constexpr int barWidth = 200;
|
||||
constexpr int barHeight = 10;
|
||||
constexpr int boxMargin = 20;
|
||||
const int textWidth = renderer.getTextWidth(READER_FONT_ID, "Indexing...");
|
||||
const int boxWidth = (barWidth > textWidth ? barWidth : textWidth) + boxMargin * 2;
|
||||
const int boxHeight = renderer.getLineHeight(READER_FONT_ID) + barHeight + boxMargin * 3;
|
||||
const int boxX = (GfxRenderer::getScreenWidth() - boxWidth) / 2;
|
||||
constexpr int boxY = 50;
|
||||
const int barX = boxX + (boxWidth - barWidth) / 2;
|
||||
const int barY = boxY + renderer.getLineHeight(READER_FONT_ID) + boxMargin * 2;
|
||||
|
||||
// Draw initial indexing box with 0% progress
|
||||
{
|
||||
const int textWidth = renderer.getTextWidth(READER_FONT_ID, "Indexing...");
|
||||
constexpr int margin = 20;
|
||||
const int x = (GfxRenderer::getScreenWidth() - textWidth - margin * 2) / 2;
|
||||
constexpr int y = 50;
|
||||
const int w = textWidth + margin * 2;
|
||||
const int h = renderer.getLineHeight(READER_FONT_ID) + margin * 2;
|
||||
renderer.fillRect(x, y, w, h, false);
|
||||
renderer.drawText(READER_FONT_ID, x + margin, y + margin, "Indexing...");
|
||||
renderer.drawRect(x + 5, y + 5, w - 10, h - 10);
|
||||
renderer.fillRect(boxX, boxY, boxWidth, boxHeight, false);
|
||||
renderer.drawText(READER_FONT_ID, boxX + boxMargin, boxY + boxMargin, "Indexing...");
|
||||
renderer.drawRect(boxX + 5, boxY + 5, boxWidth - 10, boxHeight - 10);
|
||||
// Draw empty progress bar outline
|
||||
renderer.drawRect(barX, barY, barWidth, barHeight);
|
||||
renderer.displayBuffer();
|
||||
pagesUntilFullRefresh = 0;
|
||||
}
|
||||
|
||||
section->setupCacheDir();
|
||||
|
||||
// Progress callback to update progress bar
|
||||
auto progressCallback = [this, barX, barY, barWidth, barHeight](int progress) {
|
||||
const int fillWidth = (barWidth - 2) * progress / 100;
|
||||
renderer.fillRect(barX + 1, barY + 1, fillWidth, barHeight - 2, true);
|
||||
renderer.displayBuffer(EInkDisplay::FAST_REFRESH);
|
||||
};
|
||||
|
||||
if (!section->persistPageDataToSD(READER_FONT_ID, lineCompression, marginTop, marginRight, marginBottom,
|
||||
marginLeft, SETTINGS.extraParagraphSpacing)) {
|
||||
marginLeft, SETTINGS.extraParagraphSpacing, progressCallback)) {
|
||||
Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis());
|
||||
section.reset();
|
||||
return;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user