diff --git a/lib/Epub/Epub/Page.cpp b/lib/Epub/Epub/Page.cpp index 781b978b..1d9da65a 100644 --- a/lib/Epub/Epub/Page.cpp +++ b/lib/Epub/Epub/Page.cpp @@ -61,6 +61,49 @@ std::unique_ptr PageImage::deserialize(FsFile& file) { return std::unique_ptr(new PageImage(std::move(ib), xPos, yPos)); } +bool PageImage::isCached() const { return imageBlock->isCached(); } + +void PageImage::renderPlaceholder(GfxRenderer& renderer, const int xOffset, const int yOffset) const { + int x = xPos + xOffset; + int y = yPos + yOffset; + int w = imageBlock->getWidth(); + int h = imageBlock->getHeight(); + renderer.fillRect(x, y, w, h, true); + if (w > 2 && h > 2) { + renderer.fillRect(x + 1, y + 1, w - 2, h - 2, false); + } +} + +void Page::renderTextOnly(GfxRenderer& renderer, const int fontId, const int xOffset, const int yOffset) const { + for (auto& element : elements) { + if (element->getTag() == TAG_PageLine) { + element->render(renderer, fontId, xOffset, yOffset); + } + } +} + +int Page::countUncachedImages() const { + int count = 0; + for (auto& element : elements) { + if (element->getTag() == TAG_PageImage) { + auto* img = static_cast(element.get()); + if (!img->isCached()) { + count++; + } + } + } + return count; +} + +void Page::renderImagePlaceholders(GfxRenderer& renderer, const int xOffset, const int yOffset) const { + for (auto& element : elements) { + if (element->getTag() == TAG_PageImage) { + auto* img = static_cast(element.get()); + img->renderPlaceholder(renderer, xOffset, yOffset); + } + } +} + // --------------------------------------------------------------------------- // PageTableRow // --------------------------------------------------------------------------- diff --git a/lib/Epub/Epub/Page.h b/lib/Epub/Epub/Page.h index 756322a1..0777f178 100644 --- a/lib/Epub/Epub/Page.h +++ b/lib/Epub/Epub/Page.h @@ -80,6 +80,8 @@ class PageImage final : public PageElement { void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override; bool serialize(FsFile& file) override; PageElementTag getTag() const override { return TAG_PageImage; } + bool isCached() const; + void renderPlaceholder(GfxRenderer& renderer, int xOffset, int yOffset) const; static std::unique_ptr deserialize(FsFile& file); // Helper to get image block dimensions (needed for bounding box calculation) @@ -104,4 +106,8 @@ class Page { // Returns true if page has images and fills out the bounding box coordinates. // If no images, returns false. bool getImageBoundingBox(int& outX, int& outY, int& outWidth, int& outHeight) const; + + void renderTextOnly(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) const; + int countUncachedImages() const; + void renderImagePlaceholders(GfxRenderer& renderer, int xOffset, int yOffset) const; }; diff --git a/lib/Epub/Epub/blocks/ImageBlock.cpp b/lib/Epub/Epub/blocks/ImageBlock.cpp index aa42865b..3bacb52a 100644 --- a/lib/Epub/Epub/blocks/ImageBlock.cpp +++ b/lib/Epub/Epub/blocks/ImageBlock.cpp @@ -93,6 +93,11 @@ bool renderFromCache(GfxRenderer& renderer, const std::string& cachePath, int x, } // namespace +bool ImageBlock::isCached() const { + std::string cachePath = getCachePath(imagePath); + return Storage.exists(cachePath.c_str()); +} + void ImageBlock::render(GfxRenderer& renderer, const int x, const int y) { LOG_DBG("IMG", "Rendering image at %d,%d: %s (%dx%d)", x, y, imagePath.c_str(), width, height); diff --git a/lib/Epub/Epub/blocks/ImageBlock.h b/lib/Epub/Epub/blocks/ImageBlock.h index dd37eddf..975c84b6 100644 --- a/lib/Epub/Epub/blocks/ImageBlock.h +++ b/lib/Epub/Epub/blocks/ImageBlock.h @@ -16,6 +16,7 @@ class ImageBlock final : public Block { int16_t getHeight() const { return height; } bool imageExists() const; + bool isCached() const; BlockType getType() override { return IMAGE_BLOCK; } bool isEmpty() override { return false; } diff --git a/lib/hal/HalPowerManager.cpp b/lib/hal/HalPowerManager.cpp index 6cf5a311..0b6040c4 100644 --- a/lib/hal/HalPowerManager.cpp +++ b/lib/hal/HalPowerManager.cpp @@ -78,7 +78,7 @@ void HalPowerManager::startDeepSleep(HalGPIO& gpio) const { esp_deep_sleep_start(); } -int HalPowerManager::getBatteryPercentage() const { +uint16_t HalPowerManager::getBatteryPercentage() const { static const BatteryMonitor battery = BatteryMonitor(BAT_GPIO0); return battery.readPercentage(); } diff --git a/lib/hal/HalPowerManager.h b/lib/hal/HalPowerManager.h index ceff9287..60137bb4 100644 --- a/lib/hal/HalPowerManager.h +++ b/lib/hal/HalPowerManager.h @@ -28,7 +28,7 @@ class HalPowerManager { void startDeepSleep(HalGPIO& gpio) const; // Get battery percentage (range 0-100) - int getBatteryPercentage() const; + uint16_t getBatteryPercentage() const; // RAII lock to prevent low-power mode during critical work (e.g. rendering) class Lock { diff --git a/src/Battery.h b/src/Battery.h deleted file mode 100644 index dcfcbf79..00000000 --- a/src/Battery.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include - -#define BAT_GPIO0 0 // Battery voltage - -static BatteryMonitor battery(BAT_GPIO0); diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index 418015e4..ac731eec 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -13,7 +13,6 @@ #include #include -#include "Battery.h" #include "CrossPointSettings.h" #include "CrossPointState.h" #include "MappedInputManager.h" diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 4ed7a595..08c2f3e0 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -1020,6 +1020,14 @@ void EpubReaderActivity::renderContents(std::unique_ptr page, const int or // Force special handling for pages with images when anti-aliasing is on bool imagePageWithAA = page->hasImages() && SETTINGS.textAntiAliasing; + if (page->countUncachedImages() > 0) { + page->renderTextOnly(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop); + page->renderImagePlaceholders(renderer, orientedMarginLeft, orientedMarginTop); + renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft); + renderer.displayBuffer(); + renderer.clearScreen(); + } + page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop); // Draw bookmark ribbon indicator in top-right corner if current page is bookmarked diff --git a/src/components/themes/BaseTheme.cpp b/src/components/themes/BaseTheme.cpp index 4336a073..0e9b4ad7 100644 --- a/src/components/themes/BaseTheme.cpp +++ b/src/components/themes/BaseTheme.cpp @@ -1,6 +1,7 @@ #include "BaseTheme.h" #include +#include #include #include #include @@ -9,7 +10,6 @@ #include #include -#include "Battery.h" #include "CrossPointSettings.h" #include "I18n.h" #include "RecentBooksStore.h" @@ -49,7 +49,7 @@ void drawBatteryIcon(const GfxRenderer& renderer, int x, int y, int battWidth, i void BaseTheme::drawBatteryLeft(const GfxRenderer& renderer, Rect rect, const bool showPercentage) const { // Left aligned: icon on left, percentage on right (reader mode) - const uint16_t percentage = battery.readPercentage(); + const uint16_t percentage = powerManager.getBatteryPercentage(); const int y = rect.y + 6; if (showPercentage) { @@ -64,7 +64,7 @@ void BaseTheme::drawBatteryLeft(const GfxRenderer& renderer, Rect rect, const bo void BaseTheme::drawBatteryRight(const GfxRenderer& renderer, Rect rect, const bool showPercentage) const { // Right aligned: percentage on left, icon on right (UI headers) // rect.x is already positioned for the icon (drawHeader calculated it) - const uint16_t percentage = battery.readPercentage(); + const uint16_t percentage = powerManager.getBatteryPercentage(); const int y = rect.y + 6; if (showPercentage) { diff --git a/src/components/themes/lyra/LyraTheme.cpp b/src/components/themes/lyra/LyraTheme.cpp index fefb02fa..b5b06e8c 100644 --- a/src/components/themes/lyra/LyraTheme.cpp +++ b/src/components/themes/lyra/LyraTheme.cpp @@ -1,6 +1,7 @@ #include "LyraTheme.h" #include +#include #include #include #include @@ -10,7 +11,6 @@ #include #include -#include "Battery.h" #include "CrossPointSettings.h" #include "RecentBooksStore.h" #include "components/UITheme.h" @@ -88,7 +88,7 @@ const uint8_t* iconForName(UIIcon icon, int size) { void LyraTheme::drawBatteryLeft(const GfxRenderer& renderer, Rect rect, const bool showPercentage) const { // Left aligned: icon on left, percentage on right (reader mode) - const uint16_t percentage = battery.readPercentage(); + const uint16_t percentage = powerManager.getBatteryPercentage(); const int y = rect.y + 6; const int battWidth = LyraMetrics::values.batteryWidth; @@ -125,7 +125,7 @@ void LyraTheme::drawBatteryLeft(const GfxRenderer& renderer, Rect rect, const bo void LyraTheme::drawBatteryRight(const GfxRenderer& renderer, Rect rect, const bool showPercentage) const { // Right aligned: percentage on left, icon on right (UI headers) - const uint16_t percentage = battery.readPercentage(); + const uint16_t percentage = powerManager.getBatteryPercentage(); const int y = rect.y + 6; const int battWidth = LyraMetrics::values.batteryWidth; diff --git a/src/main.cpp b/src/main.cpp index 8f178fdf..9cfa7033 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,7 +15,6 @@ #include #include -#include "Battery.h" #include "CrossPointSettings.h" #include "CrossPointState.h" #include "KOReaderCredentialStore.h" @@ -227,9 +226,9 @@ void onGoHome(); void onGoToMyLibraryWithPath(const std::string& path); void onGoToRecentBooks(); void onGoToReader(const std::string& initialEpubPath) { + const std::string bookPath = initialEpubPath; // Copy before exitActivity() invalidates the reference exitActivity(); - enterNewActivity( - new ReaderActivity(renderer, mappedInputManager, initialEpubPath, onGoHome, onGoToMyLibraryWithPath)); + enterNewActivity(new ReaderActivity(renderer, mappedInputManager, bookPath, onGoHome, onGoToMyLibraryWithPath)); } void onGoToFileTransfer() {