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:
Eunchurn Park 2025-12-25 19:53:46 +09:00
parent 8c726549bf
commit f11d70279e
No known key found for this signature in database
GPG Key ID: 29D94D9C697E3F92
5 changed files with 53 additions and 15 deletions

View File

@ -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());

View File

@ -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;
};

View File

@ -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) {

View File

@ -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);

View File

@ -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;