Compare commits

...

13 Commits

Author SHA1 Message Date
Arthur Tazhitdinov
447b948442
Merge 6873404f50 into 3ce11f14ce 2026-01-26 15:39:13 +05:00
Arthur Tazhitdinov
6873404f50 refactor: restore wording 2026-01-26 15:39:07 +05:00
Arthur Tazhitdinov
adda1954b9 refactor: simplify popup logic in renderScreen function 2026-01-26 15:12:21 +05:00
Arthur Tazhitdinov
192acba809 refactor: add popup callback to section file creation for indexing feedback 2026-01-26 15:09:35 +05:00
Arthur Tazhitdinov
d9006b2991 refactor: remove progress callback and related logic from section file creation and indexing 2026-01-26 15:01:09 +05:00
Arthur Tazhitdinov
11366862cb refactor: remove unnecessary blank line in platformio.ini 2026-01-26 14:29:17 +05:00
Arthur Tazhitdinov
c78a0db558 refactor: revert build flags changes 2026-01-26 14:28:53 +05:00
Arthur Tazhitdinov
43cd44c061 refactor: Remove MIN_SIZE_FOR_PROGRESS constant from ChapterHtmlSlimParser 2026-01-26 14:27:12 +05:00
Arthur Tazhitdinov
aa2e6ad0b3 refactor: Move MIN_SIZE_FOR_PROGRESS constant to the correct location and remove unused include 2026-01-26 14:26:38 +05:00
Arthur Tazhitdinov
f4625b56e1 refactor: Add grayscale revert function and remove unused variable in renderScreen 2026-01-26 14:23:55 +05:00
Arthur Tazhitdinov
492e79f9c0 rectangular frame for popups 2026-01-26 14:18:12 +05:00
Arthur Tazhitdinov
1facf55fbd refactor: Update popup dimensions and styles; add rounded rectangle drawing functions 2026-01-23 08:23:19 +05:00
Arthur Tazhitdinov
d418948a76 refactor: Update popup dimensions and styles; add sleep entry message 2026-01-22 18:35:28 +05:00
11 changed files with 42 additions and 70 deletions

View File

@ -123,7 +123,7 @@ bool Section::clearCache() const {
bool Section::createSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
const uint16_t viewportHeight, const bool hyphenationEnabled,
const std::function<void(int)>& progressFn) {
const std::function<void()>& popupFn) {
const auto localPath = epub->getSpineItem(spineIndex).href;
const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html";
@ -179,8 +179,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
ChapterHtmlSlimParser visitor(
tmpHtmlPath, renderer, fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth,
viewportHeight, hyphenationEnabled,
[this, &lut](std::unique_ptr<Page> page) { lut.emplace_back(this->onPageComplete(std::move(page))); },
progressFn);
[this, &lut](std::unique_ptr<Page> page) { lut.emplace_back(this->onPageComplete(std::move(page))); }, popupFn);
Hyphenator::setPreferredLanguage(epub->getLanguage());
success = visitor.parseAndBuildPages();

View File

@ -33,6 +33,6 @@ class Section {
bool clearCache() const;
bool createSectionFile(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled,
const std::function<void(int)>& progressFn = nullptr);
const std::function<void()>& popupFn = nullptr);
std::unique_ptr<Page> loadPageFromSectionFile();
};

View File

@ -10,8 +10,8 @@
const char* HEADER_TAGS[] = {"h1", "h2", "h3", "h4", "h5", "h6"};
constexpr int NUM_HEADER_TAGS = sizeof(HEADER_TAGS) / sizeof(HEADER_TAGS[0]);
// Minimum file size (in bytes) to show progress bar - smaller chapters don't benefit from it
constexpr size_t MIN_SIZE_FOR_PROGRESS = 50 * 1024; // 50KB
// Minimum file size (in bytes) to show indexing popup - smaller chapters don't benefit from it
constexpr size_t MIN_SIZE_FOR_POPUP = 50 * 1024; // 50KB
const char* BLOCK_TAGS[] = {"p", "li", "div", "br", "blockquote"};
constexpr int NUM_BLOCK_TAGS = sizeof(BLOCK_TAGS) / sizeof(BLOCK_TAGS[0]);
@ -269,10 +269,10 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
return false;
}
// Get file size for progress calculation
const size_t totalSize = file.size();
size_t bytesRead = 0;
int lastProgress = -1;
// Get file size to decide whether to show indexing popup.
if (popupFn && file.size() >= MIN_SIZE_FOR_POPUP) {
popupFn();
}
XML_SetUserData(parser, this);
XML_SetElementHandler(parser, startElement, endElement);
@ -302,17 +302,6 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
return false;
}
// Update progress (call every 10% change to avoid too frequent updates)
// Only show progress for larger chapters where rendering overhead is worth it
bytesRead += len;
if (progressFn && totalSize >= MIN_SIZE_FOR_PROGRESS) {
const int progress = static_cast<int>((bytesRead * 100) / totalSize);
if (lastProgress / 10 != progress / 10) {
lastProgress = progress;
progressFn(progress);
}
}
done = file.available() == 0;
if (XML_ParseBuffer(parser, static_cast<int>(len), done) == XML_STATUS_ERROR) {

View File

@ -18,7 +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)
std::function<void()> popupFn; // Popup callback
int depth = 0;
int skipUntilDepth = INT_MAX;
int boldUntilDepth = INT_MAX;
@ -51,7 +51,7 @@ class ChapterHtmlSlimParser {
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
const uint16_t viewportHeight, const bool hyphenationEnabled,
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
const std::function<void(int)>& progressFn = nullptr)
const std::function<void()>& popupFn = nullptr)
: filepath(filepath),
renderer(renderer),
fontId(fontId),
@ -62,7 +62,7 @@ class ChapterHtmlSlimParser {
viewportHeight(viewportHeight),
hyphenationEnabled(hyphenationEnabled),
completePageFn(completePageFn),
progressFn(progressFn) {}
popupFn(popupFn) {}
~ChapterHtmlSlimParser() = default;
bool parseAndBuildPages();
void addLineToPage(std::shared_ptr<TextBlock> line);

View File

@ -55,6 +55,8 @@ class GfxRenderer {
int getScreenWidth() const;
int getScreenHeight() const;
void displayBuffer(EInkDisplay::RefreshMode refreshMode = EInkDisplay::FAST_REFRESH) const;
// EXPERIMENTAL: Windowed update - display only a rectangular region -- not implemented
// void displayWindow(int x, int y, int width, int height) const;
void invertScreen() const;
void clearScreen(uint8_t color = 0xFF) const;

View File

@ -42,40 +42,35 @@ void ScreenComponents::drawBattery(const GfxRenderer& renderer, const int left,
renderer.fillRect(x + 2, y + 2, filledWidth, batteryHeight - 4);
}
ScreenComponents::PopupLayout ScreenComponents::drawPopup(const GfxRenderer& renderer, const char* message, const int y,
const int minWidth, const int minHeight) {
ScreenComponents::PopupLayout ScreenComponents::drawPopup(const GfxRenderer& renderer, const char* message) {
constexpr int margin = 15;
constexpr int y = 60;
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, message, EpdFontFamily::BOLD);
constexpr int margin = 16;
const int contentWidth = textWidth > minWidth ? textWidth : minWidth;
const int x = (renderer.getScreenWidth() - contentWidth - margin * 2) / 2;
const int w = contentWidth + margin * 2;
const int contentHeight = renderer.getLineHeight(UI_12_FONT_ID) + margin * 2;
const int h = contentHeight >= minHeight ? contentHeight : minHeight;
renderer.fillRect(x - 2, y - 2, w + 4, h + 4, true);
renderer.fillRect(x + 2, y + 2, w - 4, h - 4, false);
const int textHeight = renderer.getLineHeight(UI_12_FONT_ID);
const int w = textWidth + margin * 2;
const int h = textHeight + margin * 2;
const int x = (renderer.getScreenWidth() - w) / 2;
const int textX = x + margin + (contentWidth - textWidth) / 2;
renderer.drawText(UI_12_FONT_ID, textX, y + margin, message, true, EpdFontFamily::BOLD);
renderer.fillRect(x - 2, y - 2, w + 4, h + 4, true); // frame thickness 2
renderer.fillRect(x, y, w, h, false);
const int textX = x + (w - textWidth) / 2;
const int textY = y + margin - 2;
renderer.drawText(UI_12_FONT_ID, textX, textY, message, true, EpdFontFamily::BOLD);
renderer.displayBuffer();
return {x, y, w, h};
}
void ScreenComponents::fillPopupProgress(const GfxRenderer& renderer, const PopupLayout& layout, const int progress) {
const int barWidth = POPUP_DEFAULT_MIN_WIDTH;
const int barHeight = POPUP_DEFAULT_BAR_HEIGHT;
constexpr int barHeight = 4;
const int barWidth = layout.width - 30; // twice the margin in drawPopup to match text width
const int barX = layout.x + (layout.width - barWidth) / 2;
const int barY = layout.y + layout.height - 16; // 16 pixels above bottom of popup
const int barY = layout.y + layout.height - 10;
int fillWidth = barWidth * progress / 100;
if (fillWidth < 0) {
fillWidth = 0;
} else if (fillWidth > barWidth) {
fillWidth = barWidth;
}
if (fillWidth > 2) {
renderer.fillRect(barX + 1, barY + 1, fillWidth - 2, barHeight - 2, true);
}
renderer.fillRect(barX, barY, fillWidth, barHeight, true);
renderer.displayBuffer(EInkDisplay::FAST_REFRESH);
}

View File

@ -13,10 +13,6 @@ struct TabInfo {
class ScreenComponents {
public:
static constexpr int POPUP_DEFAULT_MIN_HEIGHT = 72;
static constexpr int POPUP_DEFAULT_BAR_HEIGHT = 6;
static constexpr int POPUP_DEFAULT_MIN_WIDTH = 200;
struct PopupLayout {
int x;
int y;
@ -26,8 +22,7 @@ class ScreenComponents {
static void drawBattery(const GfxRenderer& renderer, int left, int top, bool showPercentage = true);
static PopupLayout drawPopup(const GfxRenderer& renderer, const char* message, int y = 117,
int minWidth = POPUP_DEFAULT_MIN_WIDTH, int minHeight = POPUP_DEFAULT_MIN_HEIGHT);
static PopupLayout drawPopup(const GfxRenderer& renderer, const char* message);
static void fillPopupProgress(const GfxRenderer& renderer, const PopupLayout& layout, int progress);

View File

@ -8,6 +8,7 @@
#include "CrossPointSettings.h"
#include "CrossPointState.h"
#include "ScreenComponents.h"
#include "fontIds.h"
#include "images/CrossLarge.h"
#include "util/StringUtils.h"
@ -15,6 +16,8 @@
void SleepActivity::onEnter() {
Activity::onEnter();
ScreenComponents::drawPopup(renderer, "Entering Sleep...");
if (SETTINGS.sleepScreen == CrossPointSettings::SLEEP_SCREEN_MODE::BLANK) {
return renderBlankSleepScreen();
}

View File

@ -285,15 +285,11 @@ void EpubReaderActivity::renderScreen() {
viewportHeight, SETTINGS.hyphenationEnabled)) {
Serial.printf("[%lu] [ERS] Cache not found, building...\n", millis());
pagesUntilFullRefresh = 0;
const auto popupLayout = ScreenComponents::drawPopup(renderer, "Indexing...");
const auto progressCallback = [this, popupLayout](int progress) {
ScreenComponents::fillPopupProgress(renderer, popupLayout, progress);
};
const auto popupFn = [this]() { ScreenComponents::drawPopup(renderer, "Indexing..."); };
if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
viewportHeight, SETTINGS.hyphenationEnabled, progressCallback)) {
viewportHeight, SETTINGS.hyphenationEnabled, popupFn)) {
Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis());
section.reset();
return;

View File

@ -188,11 +188,10 @@ void TxtReaderActivity::buildPageIndex() {
size_t offset = 0;
const size_t fileSize = txt->getFileSize();
int lastProgressPercent = -1;
Serial.printf("[%lu] [TRS] Building page index for %zu bytes...\n", millis(), fileSize);
const auto popupLayout = ScreenComponents::drawPopup(renderer, "Indexing...");
ScreenComponents::drawPopup(renderer, "Indexing...");
while (offset < fileSize) {
std::vector<std::string> tempLines;
@ -212,15 +211,6 @@ void TxtReaderActivity::buildPageIndex() {
pageOffsets.push_back(offset);
}
// Update progress bar every 10% (matching EpubReaderActivity logic)
int progressPercent = (offset * 100) / fileSize;
if (lastProgressPercent / 10 != progressPercent / 10) {
lastProgressPercent = progressPercent;
// Fill progress bar
ScreenComponents::fillPopupProgress(renderer, popupLayout, progressPercent);
}
// Yield to other tasks periodically
if (pageOffsets.size() % 20 == 0) {
vTaskDelay(1);

View File

@ -332,6 +332,9 @@ void setup() {
setupDisplayAndFonts();
exitActivity();
enterNewActivity(new BootActivity(renderer, mappedInputManager));
APP_STATE.loadFromFile();
RECENT_BOOKS.loadFromFile();