Releases: marcoand75/cpr-vcodex-steroids
Release list
1.3.0.35-dev4-cpr-vcodex-steroids
This release delivers a full graphic restyle of the UI, a large set of new
vector icons, reader-menu icons, plus several bug fixes — most importantly a
PNG-decoding fix that prevented folder-selector image previews from rendering.
Highlights
- 🎨 Complete UI graphic restyle with a new "cyberpunk" panel style (Marcoand75 theme)
- 🖼️ 19 new SVG icons generated into 38 C++ header files (32 px + 24 px variants)
- 📖 Reader menu now shows per-item icons
- 🐛 PNG image previews in the screensaver / sleep folder selectors no longer fail
with "Invalid image file" - 🔧 Various stability and UI fixes
🎨 UI / Graphic Restyle
- New angular "cyberpunk" panel style (chamfered borders, corner brackets, scanline
separators) for the Marcoand75 theme, applied across homepage stats, icon bar,
carousel and popup overlays. - Centralized panel drawing into a shared
PanelDrawHelperhelper
(drawCyberpunkPanel,drawBackground,drawAngularPanel,drawRowIcon, …)
used by popups, context menus and overlays. - Restyle of homepage panels and the book-context popup with the cyberpunk style.
- All Lyra / Marcoand75 theme panels reworked for consistent layout and metrics.
- Settings screens restored/refreshed as part of the restyle.
🖼️ Icons
- Added 19 new custom SVG icons, each emitted as both 32 px and 24 px C++ headers
(38 newcomponents/icons/*.hfiles): SearchPlus, SearchMinus, TimeFast,
SortAsc, SortDesc, LibraryNew, GpsFound, MedalAlt, Dictionary2, AppsHub,
CalendarTime, LibraryBook, DeleteFile, CacheCleaner, FinishFlag,
NotificationUnread, FileTransfer, Calibre, plus Bookmark/Search/Rotation/Pageview. - New icon-generation tooling:
scripts/generate_cpr_icons.py— converts SVGs into the C++ header format.scripts/fetch_koreader_icons.py— fetches upstream KOReader icon sources.
- Reader menu (
EpubReaderMenuActivity) now renders an icon per menu item
(Settings, Chapter, Bookmarks, Dictionary, Rotate, Auto-turn, Screenshot, QR,
Mark finished, Sync, Delete cache, …).
🐛 Bug Fixes
- PNG folder-selector previews (
ScreenSaverPreviewActivity): PNG decoding
failed with "Invalid image file" while BMP previews kept working. Root cause:
PNGdec keeps its entire ~58 KB working set (32 KB zlib window + inflate state +
row/palette/file buffers) inline in thePNGobject, sonew PNG()needed one
large contiguous heap block that is frequently unavailable on the ESP32-C3 due
to heap fragmentation. The decoder now uses a single static instance living in
.bss, so decoding no longer depends on contiguous heap. Font caches are also
cleared right before each decode (mirroringSleepActivity). BMP path unaffected. - Long refresh after exiting the Library fixed.
- Mark as Unread now correctly resets the book "completed" status
(ReadingStatsStore::beginSession).
🔧 Improvements
- Homepage panel label changed from "Tempo" to "ETA" (estimated time to finish),
already present in IT/EN translations. - Minor
GfxRendereradditions to support the new panel drawing.
🌐 Translations
- English and Italian string tables updated for the new labels/icons.
🛠️ Internal / Developer
src/components/PanelDrawHelper.hadded as the shared panel-drawing utility.src/util/PngSleepRenderer.cppreworked to reuse a staticPNGdecoder instance
(safe:PNG::open()re-initializes the struct on every call, and decoding is
always synchronous from a single activity).README.mdupdated with the full feature list.ShortcutRegistry.hextended with the new shortcut icons.
Affected areas (by file count)
| Area | Files |
|---|---|
| Icons | 82 |
| Other | 23 |
| Activities | 7 |
| Themes | 5 |
| Core / PNG | 4 |
| Scripts | 3 |
| Translations | 2 |
Build note: the static PNG decoder working set raises static RAM usage
(~31% → ~49% of DRAM); this is intentional to guarantee PNG decoding without
relying on fragmented heap.
1.3.0.35-dev3-cpr-vcodex-steroids
Reading statistics no longer inflated by screensaver time
When the "Replace sleep with screensaver" option is active and the reader launches the screensaver via a long press on the power button, the time spent looking at the screensaver is no longer counted toward the reading stats for the current book.
Previously, the screensaver was placed directly on top of the reader's activity without a proper result callback that would reset the reading timer. This caused the entire screensaver duration — potentially several minutes or hours — to be recorded as reading time when the user returned to the book. Now the reading session timer is correctly reset every time the screensaver is dismissed, so the statistics reflect only the time actually spent reading.
1.3.0.35-dev2-cpr-vcodex-steroids
Screensaver & Sleep Enhancements
Overview
This release adds separate image directories and ordering for the reader screensaver, the ability to replace the power-button long-press with a screensaver while reading, and a major rework of transparent PNG compositing for both the screensaver and the sleep screen.
New Features
Separate screensaver directories
- General screensaver folder and sequential/shuffle order (settings → Screensaver).
- Reader screensaver folder and sequential/shuffle order (settings → Screensaver (reading)), used only when the screensaver is triggered from inside a book.
- Dedicated settings UI for both directories with live preview and mode selection.
Replace sleep with screensaver (reading only)
- When enabled (
screenSaverReplaceSleep), a long press on the power button while reading a book launches the screensaver instead of going to deep sleep. - The underlying reader activity is kept on the stack; pressing a wake button returns to the book immediately.
- Battery-minimum checks are respected: if the battery is below the configured threshold, normal deep sleep is used even when the replacement is enabled.
- Outside reading activities the power button behaves as before (normal sleep).
Per-image-ordering per mode
- Each screensaver mode (general / reader) has its own shuffle/sequential setting, so the user can have, for example, sequential images in the general screensaver but shuffled images while reading.
Removal of screensaver from the reader context menu
- The “Launch screensaver” menu item has been removed from the reader's overflow menu. The screensaver from the reader is now only accessible via the long-press power button (when the replacement option is active).
Transparent PNG Background Handling
Unified snapshot approach (both sleep and screensaver)
- Before any sleep screen or screensaver is drawn, the current frame buffer is saved to a file on the SD card (
/.crosspoint/screensaver-caller.tmpfor the screensaver,/.crosspoint/last_reader_page.binfor the sleep cycle). - On every image change (screensaver slideshow or sleep cycle), this snapshot is restored to the frame buffer before the new transparent PNG is drawn. This guarantees that transparent areas always show the original caller content (reader page, home, library, settings, …) instead of accumulating residues from previous images.
In-line with the proven sleep-cycle pattern
- The cache saving and restoring logic has been unified between the screensaver activity and the sleep cycle. Both now follow the same pattern that the existing cycle-screensaver-on-tap feature already used successfully.
Memory Optimisations
Heap-friendly PNG decoder allocation
- SD card font caches are explicitly cleared before PNG decoding during sleep entry, maximising contiguous free space for the ~44 KB decoder.
- The
MemoryBudgetcheck indrawTransparentPnghas been relaxed: instead of immediately returningfalsewhen the heuristic suggests low memory, the decoder attempts allocation anyway (which may still succeed inside the available headroom).
File-based frame buffer cache
- Replaced the in-memory
std::vector<uint8_t>snapshot (48 KB) with a file on the SD card. This removes persistent heap pressure during the entire screensaver session and leaves more space for the PNG decoder.
Exit & Transition Improvements
No forced full refresh on screensaver exit
- Exiting the screensaver (both from the app and from reading) no longer forces a
FULL_REFRESH. The underlying activity re-renders with its natural refresh mode, making the transition as fast as a normal screen change.
Immediate underlying activity render
- On screensaver exit, an immediate render notification is sent so the home page or reader appears without a visible blank gap.
1.3.0.35-dev1-cpr-vcodex-steroids
sync Steroids baseline to upstream CPR-vCodex 1.3.0.35
1.3.0.34-dev2-cpr-vcodex-steroids
Library grid browsing improvements
Pages that are already indexed now become interactive instantly, instead of waiting for a redundant per-tile readiness pass.
Tile selection within a page now uses a lighter incremental redraw (only the previously and currently selected tiles plus the title line are updated) instead of repainting the entire grid, making navigation feel smoother.
Cover generation, indexing, and library refresh logic are unchanged.
1.3.0.34-dev1-cpr-vcodex-steroids
Upstream sync to CPR-vCodex 1.3.0.34: EPUB Go to % now serializes metadata access with rendering and hides local paths from broken-image labels; File Transfer frees caches before startup and stays resilient when WebSocket/WebDAV allocations fail; long flashcards support side-rocker paging with cached wrapped lines; build system gains warm-build support and incremental compile isolation.
perf(epub): fix cover generation stalls and optimize JPEG decode speed
Root cause: the previous MCU-row buffer subsampling (gridWidth) was
fundamentally broken — it reduced ctx.srcWidth while JPEGDEC still
delivered callback blocks at the original decodedSrcWidth, causing
out-of-bounds memcpy into mcuBuf, ctx.error=true, and a permanent
sentinel that blocked future retries.
Replace manual gridWidth subsampling with native JPEGDEC scaling
(JPEG_SCALE_HALF / QUARTER / EIGHTH). JPEGDEC adjusts callback
coordinates automatically, the MCU buffer stays coherent, and no
memory corruption occurs.
1.3.0.32-dev5-cpr-vcodex-steroids
Library indexing overhaul — safer, faster, and more reliable on low-memory ESP32
Been working on the library indexing code (the part that scans your SD card, reads EPUB/XTC/TXT metadata, and keeps the library cache in sync). A few things were bugging me — crashes on large libraries, slow parsing, and a couple of bugs that only showed up with custom library root folders. Here's what changed:
Bug fix: Custom library root was ignored on filter change When you switched between "All books", "Favourites", or "Latest read", the device would re-scan the SD card using the default root (/) instead of your configured library folder. So if your books lived in /books/, switching filters could make them disappear. Fixed — it now respects your library root setting everywhere.
Safer EPUB parsing — no more crashes on big libraries The old code would happily try to open and parse every EPUB it found, even when the device was running low on memory. On the ESP32-C3 with ~380 KB of usable RAM, that's a recipe for crashes. Now each book gets a memory check before parsing starts:
EPUB files need at least 40 KB free + 30 KB contiguous block
XTC files need 20 KB free
TXT/Markdown files need 16 KB free
If there's not enough room, the book is skipped with a log message and indexing continues. Much better than a hard crash.
File validation before parsing Added a sanity check before opening any book: the path must be valid, the file must exist, and it must have content (size > 0). Corrupt files or stale cache entries pointing to deleted books are now rejected early, before they can cause trouble deep inside the parser.
Depth limit on directory scanning The directory walker used to recurse indefinitely. A malformed SD card with deeply nested folders could push thousands of paths into memory and crash the device. Now there's a sensible depth limit (8 levels) — more than enough for any realistic library layout like genre/author/series/book.epub.
Incremental sync improvements The sync path (which checks for new/deleted books without a full rescan) got the same depth limit and better error handling. If a newly discovered book fails to parse, it's skipped instead of breaking the whole sync.
Safer library deletion The removeBook() function (used when you delete a book from the library cache) now checks that there's enough free memory before attempting the operation. Loading and saving the entire cache can temporarily double its memory footprint, which was risky on large libraries.
1.3.0.32-dev4-cpr-vcodex-steroids
Release Notes
Core Refactor: List-Activity Helpers & Book-Store Deduplication
All list-based screens (settings menus, app selectors, network mode, etc.) now share three composable helpers — ListInputMapper, ListLayout, and ListRenderHelper. This eliminates ~1,350 lines of duplicated boilerplate across 15 activities (TimeZone, Language, Font, KOReader, Status Bar, Shortcuts, OPDS, Favorites, Flashcards, Sleep, ScreenSaver, ScreenClean, Network, Reading Stats Import) while fixing several navigation bugs:
- Double-advance on quick taps — replaced
setNavAll(which registered press + release + continuous simultaneously) with the correct mode-specific calls. - Inverted delta mapping —
onNextRelease/onPreviousReleasenow properly aligned with positive/negative scroll deltas. - Restored missing continuous navigation — Network mode selector now scrolls continuously as originally intended.
- Binary size reduced by ~4.5 KB despite adding three new shared headers.
Book-Store Deduplication: FavoritesStore and RecentBooksStore now delegate shared algorithms (fallback titles, book indexing, normalization, dedup + metadata merge) to a single BookStoreUtils.h template header, cutting ~162 lines and eliminating duplicated private helpers.
E-Ink Refresh Tuning
- Library exit now uses half-refresh (avoiding unnecessary full flashes).
- ScreenSaver slideshow image transitions use half-refresh for smoother browsing.
- Library entry still uses a clean full refresh once after the shelf is ready.
EPUB Cover / Thumbnail Generation Overhaul
A series of fixes addressing EPUB cover generation failures on the ESP32-C3 (~380 KB RAM, fragmented heap):
- Relaxed heap guard: cover generation now requires only 32 KB contiguous (down from 48-95 KB), matching the actual peak allocation requirement.
- Empty cover detection: 0-byte JPEGs extracted from broken EPUBs no longer cause infinite retry loops.
- Adaptive JPEG subsampling: when the MCU row buffer exceeds available contiguous heap, the decoder automatically halves the sampling grid width until it fits — no quality penalty for thumbnails.
- Metadata pre-extraction:
extractBookMetadatanow builds theBookMetadataCacheduring the library scan pass, so subsequent cover generation reuses the cache and skips the expensive full-ZIP parse (~1-2 seconds saved per book).
XTC Cover / Thumbnail Performance Fix
XTC (plain-text book) thumbnails went from ~30 seconds to under 1 second:
- Streaming row-buffered downscaling: replaced ~165,000 individual SD card seek+read operations per thumbnail with ~1,080 batched row reads — a 150× reduction in I/O operations.
- Library heap guard lowered from 95 KB to 8 KB: after the streaming rewrite, the peak contiguous allocation is ~300 bytes, not 48-96 KB. The old guard was incorrectly blocking all XTC cover generation on fragmented heaps.
Library Cover Indexing Speed-Up
Cover generation in the Library view is significantly faster and visually cleaner:
- Batch e-ink rendering (tunable via
kCoverRenderBatchEvery): multiple covers can be drawn before a single display refresh, reducing render cycles on a 4×4 grid from ~17 to as few as 5. - Compact header counter replaces the full-screen blocking "INDEXING" popup — shows
covers N/Min the top-left corner with no flicker. - Intra-page navigation fix: Left/Right moves within the same grid page no longer falsely restart cover generation (uninitialized
lastPage_guard fixed). - First frame now paints placeholders instantly: icons appear immediately on library entry, with covers filling in progressively.
Book Context Menu — Visual Consistency
- Popup style unified with the Library sort/filter overlay: white background, bold title + separator, inline layout.
- Icons switched from 24px mappings to native 32×32 bitmaps (same as library popups).
- Scroll indicator triangles added when the item list exceeds visible rows.
Other Fixes
- Lexend font made optional:
-DOMIT_LEXENDbuild flag excludes the Lexend font from compilation, reducing firmware size. - Full refresh on Library exit restored: prevents e-ink ghosting from the dense grayscale cover grid after exiting the Library.
- Book time-left failover: when pace data (pages-per-minute) is unavailable but at least 10 minutes of reading time is recorded, a linear time-vs-progress estimate is used instead of showing nothing.
1.3.0.32-dev3-cpr-vcodex-steroids
Replaced the previous CrossPoint boot/sleep logo with the new "Steroids" logo.
Converted src/images/Logo-steroids.png (later regenerated at higher resolution from src/images/vcodex steroids.png) into src/images/Logo.h, the bitmap header consumed by GfxRenderer::drawIcon() on the boot and sleep screens.
The bitmap is 1bpp, MSB-first, row-major, and stored rotated 90° CCW so it displays upright; the on-screen height is kept as a multiple of 8 (required by EInkDisplay::drawImageTransparent, which strides rows with integer w/8).
Final logo size is on-screen 350×96 (stored bitmap 96×350, 4200 bytes), generated at full resolution from the source PNG for crisp output (an earlier 2× software-upscale attempt was reverted because of poor quality).
Updated BootActivity.cpp and SleepActivity.cpp to draw the new logo at 350×96 (constants BOOT_LOGO_WIDTH/HEIGHT and logoWidth/logoHeight), removing the temporary upscale helper.
Added scripts/convert_logo.py, a reusable PNG/SVG → C bitmap converter that handles source rotation, transparency flattening, the mandatory 90° CCW display transform, automatic multiple-of-8 height rounding, and an ASCII on-screen preview.
Screensaver changes summary
Screensaver folder picker: Replaced the manual Screensaver Directory text field with the same folder selector used by the Sleep app. You can now pick a photo folder (and set shuffle/sequential order) from a list with image preview, instead of typing the path by hand. The Sleep app and its settings are unchanged.
1.3.0.32-dev2-cpr-vcodex-steroids
Library & Homepage Carousel Improvements & updated to mainstream 1.3.0.32
Library sort/filter popups
Restyled the library Sort and Filter popups to match the homepage carousel book popup (BookContextMenuActivity): an 80%-wide white rounded panel with a bold header, a separator, an inverted (filled-black) highlight for the focused row, row icons, and scroll indicators.
Added per-row icons (e.g. text, heart, recent, reading-stats, bookshelf, transfer) drawn at their native bitmap size so they render correctly instead of appearing corrupted.
The popup now overlays the library screen (books stay visible behind the panel) rather than covering it with a blank white screen.
Long-press Up opens Sort and long-press Down opens Filter. Fixed a bug where releasing the button that opened the popup also shifted the selection by one; the opening button press is now consumed.
While a popup is open, the button hints show Back=Close, Select=Choose, Up/Down=navigate, and closing the popup immediately repaints the library.
Cover thumbnails are generated one at a time during page indexing to respect the device's limited RAM/CPU.
Homepage carousel cache (Lyra / Lyra‑Marcoand75)
Added carousel frame-cache pruning: out-of-date cached frames (e.g. with old reading statistics) are removed, keeping the cache small and bounded.
Returning home after finishing a read now forces a fresh carousel render, so updated progress / last-read stats appear immediately.
General
Added a full e-ink refresh when exiting the Library back to Home, preventing leftover ghosting on the display.
