mirror of
https://github.com/crosspoint-reader/crosspoint-reader.git
synced 2026-04-29 10:26:52 -07:00
fix/image-block-style-bleed
328
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9b3885135f |
feat: Initial support for the x3 (#875)
## Summary Adds Xteink X3 hardware support to CrossPoint Reader. The X3 uses the same SSD1677 e-ink controller as the X4 but with a different panel (792x528 vs 800x480), different button layout, and an I2C fuel gauge (BQ27220) instead of ADC-based battery reading. All X3-specific behavior is gated by runtime device detection — X4 behavior is unchanged. Depends on community-sdk X3 support: open-x4-epaper/community-sdk#19 (merged). ## Changes ### HAL Layer **HalGPIO** (`lib/hal/HalGPIO.cpp/.h`) - I2C-based device fingerprinting at boot: probes for BQ27220 fuel gauge, DS3231 RTC, and QMI8658 IMU to distinguish X3 from X4 - Detection result cached in NVS for fast subsequent boots - Exposes `deviceIsX3()` / `deviceIsX4()` helpers used throughout the codebase - X3 button mapping (7 GPIOs vs X4's layout) - USB connection detection and wake classification for X3 **HalDisplay** (`lib/hal/HalDisplay.cpp/.h`) - Calls `einkDisplay.setDisplayX3()` before init when X3 is detected - Requests display resync after power button / flash wake events - Runtime display dimension accessors (`getDisplayWidth()`, `getDisplayHeight()`, `getBufferSize()`) - Exposed as global `display` instance for use by image converters **HalPowerManager** (`lib/hal/HalPowerManager.cpp/.h`) - X3 battery reading via I2C fuel gauge (BQ27220 at 0x55, SOC register) - X3 power button uses GPIO hold for deep sleep ### Display & Rendering **GfxRenderer** (`lib/GfxRenderer/GfxRenderer.cpp/.h`) - Buffer size and display dimensions are now runtime values (not compile-time constants) to support both panel sizes - X3 anti-aliasing tuning: only the darker grayscale level is applied to avoid washed-out text on the X3 panel. X4 retains both levels via `deviceIsX4()` gate **Image Converters** (`lib/JpegToBmpConverter`, `lib/PngToBmpConverter`) - Cover image prescale target uses runtime display dimensions from HAL instead of hardcoded 800x480 ### UI Themes **BaseTheme / LyraTheme** (`src/components/themes/`) - X3 button position mapping for the different physical layout - Adjusted UI element positioning for 792x528 viewport ### Boot & Init **main.cpp** - X3 hardware detection logging - Adjusted init sequence for X3 (no `HalSystem::begin()` dependency on X3 path) **HomeActivity** - Uses runtime `renderer.getBufferSize()` instead of static `GfxRenderer::getBufferSize()` FYI I did not add support for the gyro page turner. That can be it's own PR. |
||
|
|
710055f02c |
feat: Make directories stand out more in local file browser: "[dir]" instead of "dir" (#1339)
## Summary * **What is the goal of this PR?** It's difficult to distinguish directory names from normal file entries, so they are displayed now as "[dir]" instead of "dir" for classic theme * **What changes are included?** ## Additional Context * Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on). --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**NO**_ |
||
|
|
0cbfaa007d |
fix: Overlapping battery percentage on image pages with anti-aliasing (#1452)
## Summary **What is the goal of this PR?** When viewing a page with images and anti-aliasing enabled, the `imagePageWithAA` path renders the page twice with fast refreshes (blank image area, then restore). Both passes called `renderStatusBar()`, which reads the battery percentage live. If the value changed between the two renders (e.g. 88% -> 87%), the digits would overlap on screen. Fix: Removed the redundant `renderStatusBar()` from the second BW render. The status bar is already drawn and displayed in the first pass, and only the image area needs restoration. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**NO**_ |
||
|
|
7d56810ee6 |
feat: integrated epub optimizer (#1224)
## Problem Many e-ink readers have limited image decoder support natively. EPUBs with images in other formats than **baseline JPEG** frequently cause: - **Broken images**: pages render as blank, corrupted noise, or never load - **Slow rendering**: unoptimized images cause severe delays on e-ink hardware, up to 7 seconds per page turn, with cover images taking up to 59 seconds to render - **Broken covers**: the book thumbnail never generates Fixing this today requires external tools before uploading. --- ## What this PR does Adds an **optional, on-demand EPUB optimizer** to the file upload flow. When enabled, it converts all images to baseline JPEG directly in the browser — no server, no internet, no external tools needed. **Conversion is opt-in. The standard upload flow is unchanged.** --- ## Real-world impact The optimizer was applied in batch to **61 EPUBs**: - 60 standard EPUBs: 198 MB → 55 MB (**−72.2%**, 143 MB saved) - Text-dominant books: 8–46% smaller (covers and inline images converted) - Image-heavy / illustrated books: 65–93% smaller - 1 Large manga volume (594 MB): 594 MB → 72 MB (**−87.8%**, 522 MB saved) - EPUB structural integrity fully maintained — zero new validation issues introduced across all 61 books *Size and integrity analysis: [epub-comparator](https://github.com/pablohc/epub-comparator)* From that set, **17 books were selected** as a representative sample covering different content types: image-heavy novels, pure manga, light novels with broken images, and text-dominant books. Each was benchmarked on two devices running in parallel, one on `master` and one on `PR#1224` — measuring render time across ~30 pages per book on average. ### Rendering bugs fixed | Book | Problem (original) | After optimization | |------|--------------------|--------------------| | Fairy Tale — Stephen King | Cover took **59.7 s** to render | 2.1 s (−96%) | | Cycle of the Werewolf — Stephen King | Cover took **23.3 s** to render | 1.7 s (−93%) | | Tomie: Complete Deluxe Ed. — Junji Ito | Cover took **18.3 s** to render | 2.0 s (−89%) | | Joel Dicker — El tigre (Ed. Ilustrada) | Cover took **14.5 s** to render | 1.4 s (−90%) | | Jackson, Holly — Asesinato para principiantes | Cover failed completely (blank) | 2.0 s ✓ | | Sentenced to Be a Hero — Yen Press | Cover failed, **8 images failed to load** | All fixed ✓ | | Flynn, Gillian — Perdida | Cover failed completely (blank) | 1.6 s ✓ | | Chandler, Raymond — Asesino en la lluvia | Cover failed completely (blank) | 2.0 s ✓ | ### Page render times — image-heavy EPUBs (avg per page) | Book | Pages | Avg original | Avg optimized | Improvement | File size | |------|-------|-------------|---------------|-------------|-----------| | Fairy Tale — Stephen King | 30 | 3,028 ms | 1,066 ms | **−64.8%** | 32.4 MB → 9.1 MB (−72%) | | Cycle of the Werewolf — Stephen King | 33 | 3,026 ms | 1,558 ms | **−48.5%** | 35.1 MB → 2.9 MB (−92%) | | Joel Dicker — El tigre (Ed. Ilustrada) | 16 | 1,846 ms | 1,051 ms | **−43.1%** | 5.3 MB → 0.4 MB (−93%) | | Tomie: Complete Deluxe Ed. — Junji Ito | 30 | 4,817 ms | 2,802 ms | **−41.8%** | 593.8 MB → 72.2 MB (−87.8%) | | Sentenced to Be a Hero — Yen Press | 30 | 1,719 ms | 1,388 ms | **−19.2%** | 15.2 MB → 1.6 MB (−90%) | ### Text-heavy EPUBs — no regression | Book | Pages | Avg original | Avg optimized | Delta | |------|-------|-------------|---------------|-------| | Christie — Asesinato en el Orient Express | 30 | 1,672 ms | 1,646 ms | −1.6% | | Flynn — Perdida | 30 | 1,327 ms | 1,291 ms | −2.7% | | Dicker — La verdad sobre el caso Harry Quebert | 30 | 1,132 ms | 1,084 ms | −4.2% | | Hammett — El halcón maltés | 30 | 1,009 ms | 966 ms | −4.3% | | Chandler — Asesino en la lluvia | 30 | 989 ms | 1,007 ms | +1.8% | *Differences within ±5% — consistent with device measurement noise.* *Render time benchmark: [epub-optimization-benchmark](https://github.com/pablohc/epub-optimization-benchmark)* --- ## How to use it **Single file:** 1. Click **Upload** (top of the page) — a modal opens. Use **Choose files** to select one EPUB from your device. 2. Check **Optimize**. - *(Optional)* Expand **Advanced Mode** — adjust quality, rotation, or overlap; set individual images to H-Split / V-Split / Rotate. 3. Click **Optimize & Upload**. **Batch (2+ files):** 1. Click **Upload** (top of the page) — a modal opens. Use **Choose files** to select multiple EPUBs from your device. 2. Check **Optimize**. - *(Optional)* Expand **Advanced Mode** — adjust quality. 3. Click **Upload** — all files are converted and uploaded sequentially. Upload a batch of files, without optimization: <img width="810" height="671" alt="image" src="https://github.com/user-attachments/assets/d892ae13-0b87-4ea4-b6b8-340d56efc763" /> Batch file upload, with standard optimization: <img width="809" height="707" alt="image" src="https://github.com/user-attachments/assets/d32dbc88-1208-4555-bfcf-330ab91d2174" /> Optimization Phase (1/2): <img width="807" height="1055" alt="image" src="https://github.com/user-attachments/assets/fd4cd5f9-e56e-4ca1-9777-6926b9baf2bb" /> Upload Phase (2/2): <img width="805" height="1065" alt="image" src="https://github.com/user-attachments/assets/483294f0-02f0-4569-ae11-c10b3581d747" /> Batch upload successfully confirmed: <img width="812" height="1043" alt="image" src="https://github.com/user-attachments/assets/80c135bf-05c3-4c80-8755-2a04c68235bc" /> --- ## Options **Always active when the converter is enabled:** - Converts PNG, WebP, BMP, GIF → baseline JPEG - Smart downscaling to 480×800 px max (preserves aspect ratio) - True grayscale for e-ink (BT.709 luminance, always on) - SVG cover fix + OPF/NCX compliance repairs **Advanced Mode (opt-in) — single file:** - JPEG quality presets: 30% / 45% / 60% / 75% / **85%** (default) / 95% - Rotation direction for split images: CW (default) / CCW - Min overlap when splitting: 5% (default) / 10% / 15% - Auto-download conversion log toggle (detailed stats per image) - Per-image picker: set Normal / H-Split / V-Split / Rotate per image individually, with "Apply to all" for bulk assignment **Advanced Mode (opt-in) — batch (2+ files):** - JPEG quality presets: 30% / 45% / 60% / 75% / **85%** (default) / 95% - Auto-download conversion log toggle (aggregated stats for all files) --- ## ⚠️ Known limitations **KoReader hash-based sync will break** for converted files. The file content changes, so the hash no longer matches the original. Filename-based sync is unaffected. If you rely on KoReader hash sync, use the Calibre plugin or the web tool instead. --- ## Build size impact | Metric | master ( |
||
|
|
8dd365b4da |
feat: Implement silent pre-indexing for the next chapter in EpubReaderActivity (#979)
## Summary * A simple tweak to pre-index the next chapter silently during normal reading. * Triggers silent pre-indexing of the next chapter when the penultimate page of a chapter is rendered to reduce visible interruptions. * Keeps existing indexing with popup when a reader jumps directly into an unindexed chapter. ## Additional Context * Reader input is temporarily blocked during silent indexing to avoid navigation/index state conflicts. * The penultimate page is used because readers typically spend longer there than on the final page. * This change optimizes linear reading flow while preserving reliable indexing for non-linear navigation. ## Possible Improvements * Add a setting for First Page Indexing vs Penultimate Page Pre-indexing * Display an indexing icon in the status bar instead of using a popup that overlaps book text. Tested on device: https://www.dropbox.com/scl/fi/29g5kjqgsi5e4hgujv38u/Silent-Indexing.MOV?rlkey=yemi4mosmev5vicaa7gpe49qw&dl=0 --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ --------- Co-authored-by: Jake Kenneally <jakekenneally@gmail.com> |
||
|
|
71719e1d94 |
feat: battery charging indicator (mirroring PR #537) (#1427)
## Summary * **What is the goal of this PR?** All praise goes to @didacta for his PR #537. Just picked up the reviewer comments to contain the changes as suggested (there was no response for more than 6 weeks, so I wanted to reanimate this feature). Just one addition: should recognize usb cable plug ins / retractions and update the icon immediately * **What changes are included?** ## Additional Context see #537 --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**< NO >**_ |
||
|
|
f9286709d1 |
feat: Show hidden directories in browser (#1288)
## Summary * **What is the goal of this PR?** Add setting to display hidden files / directories in filebrowser / web file browser * **What changes are included?** ## Additional Context - --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**< NO >**_ |
||
|
|
79b54b3a75 |
fix: Init lastSleepImage (edge case) (#1360)
## Summary * **What is the goal of this PR?** fix edge case for definition ## Additional Context If loadFromFile() returns false (no state file exists — first boot, or SD missing), lastSleepImage is never set and contains garbage. [SleepActivity.cpp:83] then uses it in a while comparison to avoid repeating the same image. The JSON path (doc["lastSleepImage"] | (uint8_t)0) handles it, but only if the file exists. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _** NO **_ |
||
|
|
11ca208ec2 |
chore: change label while on settings tab actions (#1325)
## Summary * **What is the goal of this PR?** The "Toggle" label while on the "tab" actions of settings screen was misleading. Will show "Select" now , while "Toggle" remains in place for all 'real' settings * **What changes are included?** ## Additional Context <img width="240" alt="1" src="https://github.com/user-attachments/assets/dc198716-0aad-4c75-96fe-52595625e69d" /> <img width="240" alt="2" src="https://github.com/user-attachments/assets/85ce5368-801c-489d-aa94-51f126c3ddc8" /> --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**NO **_ |
||
|
|
7a28f90dad |
fix: back button in settings returns to tab bar first (#1354)
## Summary - Pressing Back while browsing settings within a category now jumps focus to the category tab bar - Pressing Back again from the tab bar exits settings to home - Previously, Back always exited directly to home regardless of scroll position Closes #797 ## Test plan - [ ] Scroll deep into a settings category → press Back → tab bar is focused - [ ] Press Back again from tab bar → exits to home screen - [ ] Use category switching (continuous hold) → still works as before - [ ] Settings are saved on exit (not on tab-bar jump) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: bkb <bkb@arcnode.xyz> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
f1e9dc7f30 |
perf: font-compression improvements (#1056)
## Purpose This PR includes some preparatory changes that are needed for an upcoming performant CJK font feature. The changes have no impact on render time and heap allocation for latin text. **Despite this, I think these changes stand on their own as a better font compression/decompression implementation.** ## Summary - Font decompressor rewrite: Replaced the 4-slot LRU group cache with a two-tier system — a page buffer (glyphs prewarmed before rendering begins) and a hot-group fallback (last decompressed group retained for non-prewarmed glyphs). - Byte-aligned compressed bitmap format: Glyph bitmaps within compressed groups are now stored row-padded rather than tightly packed before DEFLATE compression, improving compression ratios by making identical pixel rows produce identical byte patterns. Glyphs are compacted back to packed format on demand at render time. Reduces flash size by 155 KB. - Page prewarm system: Added `Page::collectText` and `Page::getDominantStyle` to extract per-style glyph requirements before rendering, and `GfxRenderer::prewarmFontCache` to pre-decompress only the groups needed for the dominant style — eliminating mid-render decompression for the common case. - UTF-8 robustness fixes: `utf8NextCodepoint` now validates continuation bytes and returns a replacement glyph on malformed input; `ChapterHtmlSlimParser` correctly preserves incomplete multi-byte sequences across word-buffer flush boundaries rather than splitting them. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ Architecture and design was done by me, refined a bit by Claude. Code mostly by Claude, but not entirely. |
||
|
|
cd508d27d5 |
refactor: reader utils (#1329)
## Summary Extract shared reader utilities (`ReaderUtils.h`) to reduce duplication across `EpubReaderActivity`, `TxtReaderActivity`, and (upcoming) `MarkdownReaderActivity`. Utilities extracted: - `applyOrientation()` — orientation switch logic - `detectPageTurn()` — page navigation input detection - `renderAntiAliased()` — grayscale anti-aliasing pass - `displayWithRefreshCycle()` — refresh mode cadence - `GO_HOME_MS` — back button timing constant ## Impact Flash: 32 bytes saved (6006441 → 6006409 bytes). Minimal immediate gain, but meaningful once markdown reader and future reader types share these functions. Code quality: Eliminates ~100 lines of duplicated logic spread across multiple files. All readers now follow the same patterns for orientation, input handling, and rendering. ## Rationale This refactor is preparation for markdown support, which requires identical input and rendering logic. Instead of copy-pasting these patterns a third time, all readers now share a single, tested implementation. Future reader types can reuse `ReaderUtils` without duplication. --- ## AI Usage Did you use AI tools to help write this code? YES Claude extracted the code, under my guidance. Tested on my device and seems to work fine. |
||
|
|
4d22256745 |
feat: footnote anchor navigation (#1245)
## Summary: Enable footnote anchor navigation in EPUB reader This PR extracts the core anchor-to-page mapping mechanism from PR #1143 (TOC fragment navigation) to provide immediate footnote navigation support. By merging this focused subset first, users get a complete footnote experience now while simplifying the eventual review and merge of the full #1143 PR. --- ## What this extracts from PR #1143 PR #1143 implements comprehensive TOC fragment navigation for EPUBs with multi-chapter spine files. This PR takes only the anchor resolution infrastructure: - Anchor-to-page mapping in section cache: During page layout, ChapterHtmlSlimParser records which page each HTML id attribute lands on, serializing the map into the .bin cache file. - Anchor resolution in `EpubReaderActivity`: When navigating to a footnote link with a fragment (e.g., `chapter2.xhtml#note1`), the reader resolves the anchor to a page number and jumps directly to it. - Section file format change: Bumped to version 15, adds anchor map offset in header. --- ## Simplified scope vs. PR #1143 To minimize conflicts and complexity, this PR differs from #1143 in key ways: * **Anchors tracked** * **Origin:** Only TOC anchors (passed via `std::set`) * **This branch:** All `id` attributes * **Page breaks** * **Origin**: Forces new page at TOC chapter boundaries * **This branch:** None — natural flow * **TOC integration** * **Origin**: `tocBoundaries`, `getTocIndexForPage()`, chapter skip * **This branch:** None — just footnote links * **Bug fix** * **This branch:** Fixed anchor page off-by-1/2 bug The anchor recording bug (recording page number before `makePages()` flushes previous block) was identified and fixed during this extraction. The fix uses a deferred `pendingAnchorId` pattern that records the anchor after page completion. --- ## Positioning for future merge Changes are structured to minimize conflicts when #1143 eventually merges: - `ChapterHtmlSlimParser.cpp` `startElement()`: Both branches rewrite the same if `(!idAttr.empty())` block. The merged version will combine both approaches (TOC anchors get page breaks + immediate recording; footnote anchors get deferred recording). - `EpubReaderActivity.cpp` `render()`: The `pendingAnchor` resolution block is positioned at the exact same insertion point where #1143 places its `pendingTocIndex` block (line 596, right after `nextPageNumber` assignment). During merge, both blocks will sit side-by-side. --- ## Why merge separately? 1. Immediate user value: Footnote navigation works now without waiting for the full TOC overhaul 2. Easier review: ~100 lines vs. 500+ lines in #1143 3. Bug fix included: The page recording bug is fixed here and will carry into #1143 4. Minimal conflicts: Structured for clean merge — both PRs touch the same files but in complementary ways --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ Done by Claude Opus 4.6 |
||
|
|
18b36efbae |
feat: dump crash report to sdcard (#1145)
## Summary This allow dumping crash message (i.e. assertion fail) and stack trace to `crash_report.txt` file on sdcard. The stack trace can then be decoded using https://esphome.github.io/esp-stacktrace-decoder/ Could be useful to debug things like https://github.com/crosspoint-reader/crosspoint-reader/issues/1137 where error doesn't always happen. May also be useful to show a screen to tell what happen (show on next boot after crash), similar to [flipper zero crash message](https://www.reddit.com/r/flipperzero/comments/10f8m3f/anyone_who_can_tell_me_why_this_message_pops_up/) , but this is better to be a dedicated PR (I'm missing the `drawTextWrapped` function, too lazy to code it ; update: exactly what I need in https://github.com/crosspoint-reader/crosspoint-reader/pull/1141) To test this: - Option 1: add an `assert(false)` somewhere in the code - Option 2: try dereferencing a nullptr - Option 3: try `throw` an exception Example of a crash report: ``` CrossPoint version: 1.1.0-dev Panic reason: abort() was called at PC 0x4214585b on core 0 Recent logs: [196] [DBG] [GFX] Time = 2 ms from clearScreen to displayBuffer [1831] [DBG] [RBS] Recent books loaded from file (7 entries) [1832] [DBG] [ACT] Exiting activity: Boot [1832] [DBG] [ACT] Entering activity: Home [1891] [DBG] [GFX] Time = 54 ms from clearScreen to displayBuffer [2521] [DBG] [GFX] Time = 46 ms from clearScreen to displayBuffer [4839] [DBG] [PWR] Going to low-power mode [10048] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes [20060] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes [30072] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes [34453] [DBG] [PWR] Restoring normal CPU frequency [34485] [DBG] [GFX] Time = 30 ms from clearScreen to displayBuffer [35182] [DBG] [GFX] Time = 31 ms from clearScreen to displayBuffer [36675] [DBG] [GFX] Time = 30 ms from clearScreen to displayBuffer [38800] [DBG] [GFX] Time = 30 ms from clearScreen to displayBuffer [40079] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes Stack memory: 0x3FCB0650: 0x00000000 0x00000000 0x3FCB0668 0x4038DBB6 0x00000000 0x00000000 0x3FCA0030 0x3FC936D0 0x3FCB0670: 0x3FCB067C 0x3FC936EC 0x3FCB0668 0x34313234 0x62353835 0x00000000 0x726F6261 0x20292874 0x3FCB0690: 0x20736177 0x6C6C6163 0x61206465 0x43502074 0x34783020 0x35343132 0x20623538 0x63206E6F 0x3FCB06B0: 0x2065726F 0x00000030 0x3FCA0000 0xB37A603F 0x00000001 0x3FCA7000 0x3FCABCDC 0x4214585E 0x3FCB06D0: 0x3FCA7000 0x3FCA7000 0x3FCABCDC 0x421458AA 0x3FCABCDC 0x3FCA7000 0x3FCABCDC 0x421459CC 0x3FCB06F0: 0x3FCA7000 0x3FCA7000 0x42145D5A 0x3C205624 0x40388560 0x3FCA7000 0x3FCABCFC 0x42079866 0x3FCB0710: 0x3FCA7000 0x3FCA7000 0x00009C9A 0x4207B7F6 0x3FCA7000 0x42090000 0x001B7740 0x00000001 0x3FCB0730: 0x3FCA7000 0x3FCA7000 0x00000001 0x600C0028 0x00000001 0x3FCA1000 0x00000000 0x00000000 0x3FCB0750: 0x00000000 0x00000000 0x00000000 0xB37A603F 0x00000000 0x00000000 0x00000000 0x00000000 0x3FCB0770: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x42090000 0x3FCA7000 0x4208F9C4 0x3FCB0790: 0x00000000 0x00000000 0x00000000 0x40388368 0x00000000 0x00000000 0x00000000 0x00000000 0x3FCB07B0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0xA5A5A5A5 0xA5A5A5A5 0xA5A5A5A5 0x3FCB07D0: 0xA5A5A5A5 0xA5A5A5A5 0xA5A5A5A5 0xA5A5A5A5 0xBAAD5678 0xDA6D3601 0x5EB5B9C5 0x2602E480 0x3FCB07F0: 0x2BCDD33F 0x15556D4A 0x1F2140A0 0x5D59BEE3 0x8E76449F 0x6FB2D0CE 0xF5F46FAC 0x0112946A 0x3FCB0810: 0x3B0B32E0 0x7A52B537 0x46801DB4 0xDA85DF9F 0x37E83D20 0x12861028 0x47A702BB 0x287A3C8A 0x3FCB0830: 0x03632209 0xD44C5489 0x5E258453 0xFDA77529 0xE6748E23 0xADCF1394 0x67AD6778 0x2C208663 0x3FCB0850: 0xC7985786 0xD4AA3AB2 0x312E1760 0xEC7AEAAE 0x1857020E 0x48003E7E 0xD6CB8763 0x9B4A3F66 0x3FCB0870: 0x4B79E9F6 0xCBF739F0 0x3794C641 0xD0DBA3CB 0x95B9BE15 0x581C9983 0xDE62EFB6 0x20C67C5B 0x3FCB0890: 0x1E4A3DF3 0xFB317C74 0xC0D86103 0x1D79ED56 0x72FE0862 0x3D38B0C8 0xD27EB587 0x0E0A4C40 0x3FCB08B0: 0xF643ADC0 0x56D114D7 0x703AF879 0xAC7F3075 0x89C78C23 0xEDA86814 0xF767B3E3 0x0528838F 0x3FCB08D0: 0x50ED4662 0x11FD38E7 0x8A5A83BB 0x658159BD 0x781AF696 0x8A700F79 0x526DDE23 0xC8472505 0x3FCB08F0: 0x21AACC02 0xCB89369E 0xB82E5BE2 0x4C6C9D7D 0x9E724D9B 0xDC1067F7 0x84478FBC 0x4E89C444 0x3FCB0910: 0x973F4229 0x49F93DA8 0xE30200F6 0xD1B5C391 0x8363A89F 0x2409E74C 0x3AFF7B52 0xCBEC2349 0x3FCB0930: 0xD38F6695 0xBC3EA980 0xF067EBB1 0x7F87D167 0x92B3823B 0x9F0617D7 0xA7537C57 0x12CAB3D4 0x3FCB0950: 0xC82EEE37 0x84D4B4BC 0xE1E2261C 0x488F0ADA 0x96EAF2FF 0x0BC493A0 0xCE614467 0x3829053D 0x3FCB0970: 0xA41156BE 0x2747B77D 0x64DEA90B 0xE704AB0A 0xE4B01006 0x8D51903C 0x56CD3CF2 0x07E0A8E8 0x3FCB0990: 0xD1DE05CE 0x33368522 0xD1889988 0x3A3097F4 0xB0796D09 0xC78948AA 0x6DEFC56E 0xD5C2E1D9 0x3FCB09B0: 0xFD6DD8FA 0xA957B675 0xC202D80D 0x733FF8F4 0xA1484913 0x0B9AFBA6 0x330C07EA 0x2C09AD4C 0x3FCB09D0: 0x3B1E08F7 0x3FCAE7D0 0x00000170 0xABBA1234 0x0000015C 0x3FCB00E0 0x00009C93 0x3FCA13C4 0x3FCB09F0: 0x3FCA13C4 0x3FCB09E4 0x3FCA13BC 0x00000018 0x00000000 0x00000000 0x3FCB09E4 0x00000000 0x3FCB0A10: 0x00000001 0x3FCAE7E0 0x706F6F6C 0x6B736154 0x00000000 0x00000000 0x3FCB07D0 0x00000005 0x3FCB0A30: 0x00000000 0x00000001 0x00000000 0x3FCAB444 0x4209AFF0 0x0017E38F 0x00000000 0x3FCA7BD0 ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> |
||
|
|
c3f1dbfa09 |
perf: Avoid creating strings for file extension checks (#1303)
## Summary **What is the goal of this PR?** This change avoids the pattern of creating a `std::string` using `.substr` in order to compare against a file extension literal. ```c++ std::string path; if (path.length() >= 4 && path.substr(path.length() - 4) == ".ext") ``` The `checkFileExtension` utility has moved from StringUtils to FsHelpers, to be available to code in lib/. The signature now accepts a `std::string_view` instead of `std::string`, which makes the single implementation reusable for Arduino `String`. Added utility functions for commonly repeated extensions. These changes **save about 2 KB of flash (5,999,427 to 5,997,343)**. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**NO**_ |
||
|
|
ce0b439aa3 |
feat: User setting for image display (#1291)
## Summary **What is the goal of this PR?** Add a user setting to decide image support: display, show placeholder instead, supress fully Fixes #1289 --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**< NO >**_ |
||
|
|
307a6608f0 |
chore: remove rendundant xTaskCreate (#1264)
## Summary Ref discussion: https://github.com/crosspoint-reader/crosspoint-reader/pull/1222#discussion_r2865402110 Important note that this is a bug-for-bug fix. In reality, this branch `WiFi.status() == WL_CONNECTED` is pretty much a dead code because the entry point of these 2 activities don't use wifi. It is better to refactor the management of network though, but it's better to be a dedicated PR. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **NO** |
||
|
|
ef02737c89 |
feat: Prefer ".sleep" over "sleep" for custom image directory (#948)
## Summary * Custom sleep screen images now load from /.sleep directory (preferred), falling back to /sleep for backwards compatibility. The dot-prefix keeps the directory hidden from the file browser. * Rewrote User Guide section 3.6 to document all six sleep screen modes, cover settings, and the updated custom image setup. ## Additional Context * The sleep directoy entry while browsing files was distracting. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _NO_ |
||
|
|
f0a549b680 |
refactor: rename MyLibrary to FileBrowser (#1260)
## Summary * Renames MyLibrary component to FileBrowser, as it better reflects what it is, in my opinion ## Additional Context * Frees the Library name for possible future library component that can cache metadata, provide other ways of browsing than filesystem structure, etc --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ |
||
|
|
80d1856330 |
perf: Removed unused ConfirmationActivity member (#1234)
## Summary **What is the goal of this PR?** Small follow up to #909, removing an unused member variable and some temporary debug logging. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**NO**_ |
||
|
|
76681201bf |
fix: Hide unusable button hints when viewing empty directory (#1253)
## Summary * **What is the goal of this PR?** Increase accuracy of button hints and text description in the file browser when viewing empty directory. * **What changes are included?** Adjusted button label hint rendering logic in file browser to hide the "Open", "Up", and "Down" hints when the they are not available due to an empty directory. I also changed the NO_BOOKS_FOUND string to NO_FILES_FOUND and updated translations. File browser shows more than just books so seeing "No Books Found" really doesn't make sense. ## Additional Context Very Simple change, here is what that looks like on my device. <img width="1318" height="879" alt="Untitled (7)" src="https://github.com/user-attachments/assets/6416c8c8-795d-41a5-9b9f-28d2c26666a0" /> --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**NO**_ |
||
|
|
04242fa221 |
refactor: Simplify new setting introduction (#1086)
## Summary
* **What is the goal of this PR?** Eliminate the 3-file / 4-location
overhead for adding a new setting. Previously, every new setting
required manually editing JsonSettingsIO.cpp in two places (save +
load), duplicating knowledge already present in SettingsList.h. After
this PR, JsonSettingsIO.cpp never needs to be touched again for standard
settings.
* **What changes are included?**
* `SettingInfo` (in `SettingsActivity.h`) gains one new field: `bool
obfuscated` (base64 save/load for passwords), with a fluent builder
method `.withObfuscated()`. The previously proposed
`defaultValue`/`withDefault()` approach was dropped in favour of reading
the struct field's own initializer value as the fallback (see below).
* `SettingsList.h` entries are annotated with `.withObfuscated()` on the
OPDS password entry. The list is now returned as a `static const`
singleton (`const std::vector<SettingInfo>&`), so it is constructed
exactly once. A missing `key`/`category` on the
`statusBarProgressBarThickness` entry was also fixed — it was previously
skipped by the generic save loop, so changes were silently lost on
restart.
* `JsonSettingsIO::saveSettings` and `loadSettings` replace their ~90
lines of manual per-field code with a single generic loop over
`getSettingsList()`. The loop uses `info.key`,
`info.valuePtr`/`info.stringOffset`+`info.stringMaxLen` (for char-array
string fields), `info.enumValues.size()` (for enum clamping), and
`info.obfuscated`.
* **Default values**: instead of a duplicated `defaultValue` field in
`SettingInfo`, `loadSettings` reads `s.*(info.valuePtr)` *before*
overwriting it. Because `CrossPointSettings` is default-constructed
before `loadSettings` is called, this captures each field's struct
initializer value as the JSON-absent fallback. The single source of
truth for defaults is `CrossPointSettings.h`.
* One post-loop special case remains explicitly: the four `frontButton*`
remap fields (managed by the RemapFrontButtons sub-activity, not in
SettingsList) and `validateFrontButtonMapping()`.
* One pre-loop migration guard handles legacy settings files that
predate the status bar refactor: if `statusBarChapterPageCount` is
absent from the JSON, `applyLegacyStatusBarSettings()` is called first
so the generic loop picks up the migrated values as defaults and applies
its normal clamping.
* OPDS password backward-compat migration (plain `opdsPassword` →
obfuscated `opdsPassword_obf`) is preserved inside the generic
obfuscated-string path.
## Additional Context
Say we want to add a new `bookmarkStyle` enum setting with options
`DOT`, `LINE`, `NONE` and a default of `DOT`:
1. `src/CrossPointSettings.h` — add enum and member:
```cpp
enum BOOKMARK_STYLE { BOOKMARK_DOT = 0, BOOKMARK_LINE = 1, BOOKMARK_NONE = 2 };
uint8_t bookmarkStyle = BOOKMARK_DOT;
```
2. `lib/I18n/translations/english.yaml` — add display strings:
```yaml
STR_BOOKMARK_STYLE: "Bookmark Style"
STR_BOOKMARK_DOT: "Dot"
STR_BOOKMARK_LINE: "Line"
```
(Other language files will fall back to English if not translated. Run
`gen_i18n.py` to regenerate `I18nKeys.h`.)
3. `src/SettingsList.h` — add one entry in the appropriate category:
```cpp
SettingInfo::Enum(StrId::STR_BOOKMARK_STYLE, &CrossPointSettings::bookmarkStyle,
{StrId::STR_BOOKMARK_DOT, StrId::STR_BOOKMARK_LINE, StrId::STR_NONE_OPT},
"bookmarkStyle", StrId::STR_CAT_READER),
```
That's it — no default annotation needed anywhere, because
`bookmarkStyle = BOOKMARK_DOT` in the struct already provides the
fallback. The setting will automatically persist to JSON on save, load
with clamping on boot, appear in the device settings UI under the Reader
category, and be exposed via the web API — all with no further changes.
---
### AI Usage
While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.
Did you use AI tools to help write this code? _**< PARTIALLY>**_
|
||
|
|
a57c62f0b4 |
fix: properly implement requestUpdateAndWait() (#1218)
## Summary Properly implement `requestUpdateAndWait()` using freeRTOS direct task notification. FWIW, I think most of the current use cases of `requestUpdateAndWait()` are redundant, better to be replaced by `requestUpdate(true)`. But just keeping them in case we can find a proper use case for it in the future. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **YES**, it's trivial, so I asked an AI to write the code --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> |
||
|
|
5e95d9a36f |
feat: Long Click for File Deletion through File Browser (#909)
## Summary * **What is the goal of this PR?** (e.g., Implements the new feature for file uploading.) Allow users to better manage their epub library by offloading unwanted or finished books and other files. Resolves #893 * **What changes are included?** Added Delete Book shortcut in the fil browser. Delete function implements the new ConfirmationActivity to show file name and solicit user interaction before either returning to the file browser on a press of the back button, or proceeding to delete. Delete function then deletes the file and returns user to the file browser menu at the current directory. Video of it working on my machine attached here: https://github.com/user-attachments/assets/329b0198-9e97-45ad-82aa-c39894351667 ## Additional Context * Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on). Certainly potential risks associated with file deletion. Please let me know if there are any concerns that need to be better addressed. I think this is a very good feature to have to go along with the new screenshots so you don't get stuck with a bunch of extra files on your device. Also I did add this to the user guide. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Егор Мартынов <martynovegorOF@yandex.ru> Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com> Co-authored-by: Zach Nelson <zach@zdnelson.com> |
||
|
|
45a228a645 |
fix: use HTTPClient::writeToStream for downloading files from OPDS (#1207)
## Summary * Refactored `HttpDownloader::downloadToFile` to use `FileWriteStream` and `HTTPClient::writeToStream`, removing manual chunked downloading logic, which was error-prone. * Fixes https://github.com/crosspoint-reader/crosspoint-reader/issues/632 ## Additional Context * Tested downloading files from OPDS with a size up to 10 mb. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**< YES >**_ |