From 42ca85d560f877a6cfd040c7f9d11b90bd4ed961 Mon Sep 17 00:00:00 2001 From: cottongin Date: Mon, 9 Mar 2026 02:22:51 -0400 Subject: [PATCH] feat: show loading popup in BookInfo when parsing unopened book MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When BookInfo is opened for a book with no existing cache, epub.load(true, true) triggers a 1-2s full parse. Show a "Loading..." popup with progress bar so the device doesn't appear frozen. Popup only appears on the fallback path — cached books load silently. Same pattern for XTC books. Made-with: Cursor --- chat-summaries/2026-03-09_03-15-summary.md | 23 +++++++++ src/activities/home/BookInfoActivity.cpp | 55 +++++++++++++++------- 2 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 chat-summaries/2026-03-09_03-15-summary.md diff --git a/chat-summaries/2026-03-09_03-15-summary.md b/chat-summaries/2026-03-09_03-15-summary.md new file mode 100644 index 00000000..d064a393 --- /dev/null +++ b/chat-summaries/2026-03-09_03-15-summary.md @@ -0,0 +1,23 @@ +# BookInfo Loading Popup for Unopened Books + +**Date**: 2026-03-09 +**Task**: Show a progress popup when BookInfo needs to parse an unopened book + +## Changes Made + +### BookInfoActivity.cpp + +Added a "Loading..." progress popup with progress bar to `onEnter()` when the book cache doesn't exist and a full parse is required: + +- **EPUB branch**: `epub.load(false, true)` is tried first (fast, cache-only). If it fails, `GUI.drawPopup(tr(STR_LOADING))` is shown at 10%, `epub.load(true, true)` runs (slow full parse), progress updates to 50%, thumbnail generation runs, then progress hits 100%. +- **XTC branch**: Checks `Storage.exists(xtc.getCachePath())` before `xtc.load()`. If cache directory is missing, shows the same popup pattern around load + thumbnail generation. +- For books with existing cache, no popup is shown — the fast path completes silently. + +## Build Result + +Build succeeded — 0 errors, 0 linter warnings. RAM: 30.3%, Flash: 95.7%. + +## Follow-up + +- Test on device: open BookInfo for a book that has never been opened, verify popup appears +- Verify no popup appears for books that have been previously opened/cached diff --git a/src/activities/home/BookInfoActivity.cpp b/src/activities/home/BookInfoActivity.cpp index 8b710ed3..410e49f7 100644 --- a/src/activities/home/BookInfoActivity.cpp +++ b/src/activities/home/BookInfoActivity.cpp @@ -63,32 +63,48 @@ void BookInfoActivity::onEnter() { if (FsHelpers::hasEpubExtension(fileName)) { Epub epub(filePath, "/.crosspoint"); - if (!epub.load(false, true)) { + bool needsBuild = !epub.load(false, true); + Rect popupRect{}; + if (needsBuild) { + popupRect = GUI.drawPopup(renderer, tr(STR_LOADING)); + GUI.fillPopupProgress(renderer, popupRect, 10); epub.load(true, true); + GUI.fillPopupProgress(renderer, popupRect, 50); } - { - title = epub.getTitle(); - author = epub.getAuthor(); - series = epub.getSeries(); - seriesIndex = epub.getSeriesIndex(); - description = normalizeWhitespace(epub.getDescription()); - language = epub.getLanguage(); - const int coverH = renderer.getScreenHeight() * 2 / 5; - if (epub.generateThumbBmp(coverH)) { - coverBmpPath = epub.getThumbBmpPath(coverH); - } else { - const int thumbW = static_cast(coverH * 0.6); - const std::string placeholderPath = epub.getCachePath() + "/placeholder_" + std::to_string(coverH) + ".bmp"; - if (PlaceholderCoverGenerator::generate(placeholderPath, title.empty() ? fileName : title, author, thumbW, - coverH)) { - coverBmpPath = placeholderPath; - } + title = epub.getTitle(); + author = epub.getAuthor(); + series = epub.getSeries(); + seriesIndex = epub.getSeriesIndex(); + description = normalizeWhitespace(epub.getDescription()); + language = epub.getLanguage(); + + const int coverH = renderer.getScreenHeight() * 2 / 5; + if (epub.generateThumbBmp(coverH)) { + coverBmpPath = epub.getThumbBmpPath(coverH); + } else { + const int thumbW = static_cast(coverH * 0.6); + const std::string placeholderPath = epub.getCachePath() + "/placeholder_" + std::to_string(coverH) + ".bmp"; + if (PlaceholderCoverGenerator::generate(placeholderPath, title.empty() ? fileName : title, author, thumbW, + coverH)) { + coverBmpPath = placeholderPath; } } + if (needsBuild) { + GUI.fillPopupProgress(renderer, popupRect, 100); + } } else if (FsHelpers::hasXtcExtension(fileName)) { Xtc xtc(filePath, "/.crosspoint"); + bool needsBuild = !Storage.exists(xtc.getCachePath().c_str()); + Rect popupRect{}; + if (needsBuild) { + popupRect = GUI.drawPopup(renderer, tr(STR_LOADING)); + GUI.fillPopupProgress(renderer, popupRect, 10); + } if (xtc.load()) { + if (needsBuild) { + GUI.fillPopupProgress(renderer, popupRect, 50); + } title = xtc.getTitle(); author = xtc.getAuthor(); @@ -104,6 +120,9 @@ void BookInfoActivity::onEnter() { } } } + if (needsBuild) { + GUI.fillPopupProgress(renderer, popupRect, 100); + } } if (title.empty()) {