Skip to content

feat: Display file extensions in File Browser (#1019)#13

Merged
uxjulia merged 1 commit into
uxjulia:release/v1.2.1from
crosspoint-reader:master
Apr 9, 2026
Merged

feat: Display file extensions in File Browser (#1019)#13
uxjulia merged 1 commit into
uxjulia:release/v1.2.1from
crosspoint-reader:master

Conversation

@uxjulia

@uxjulia uxjulia commented Apr 9, 2026

Copy link
Copy Markdown
Owner

Summary

IMG_8136 Medium IMG_8137 Medium IMG_8138 Medium

Additional Context

Do we want a setting to toggle this?


AI Usage

Did you use AI tools to help write this code? NO

Summary

  • What changes are included?

## Summary

![IMG_8136
Medium](https://github.com/user-attachments/assets/e33a8a71-4126-4bdc-8d3a-32132acba712)
![IMG_8137
Medium](https://github.com/user-attachments/assets/2289fbee-71e8-446c-ad28-9dd4a9a21396)
![IMG_8138
Medium](https://github.com/user-attachments/assets/0e912f72-9be1-4708-a909-4dab192d1aea)


## Additional Context

Do we want a setting to toggle this?

---

### AI Usage

Did you use AI tools to help write this code? _**NO**_
@uxjulia
uxjulia merged commit 06f70d8 into uxjulia:release/v1.2.1 Apr 9, 2026
3 checks passed
uxjulia pushed a commit that referenced this pull request May 26, 2026
…point-reader#2106)

Tiled grayscale rendering to drop the storeBwBuffer peak largest
contiguous free block (the value that actually drives OOM on the C3)
from ~114 KB to ~82-90 KB.

This renders each grayscale plane band-by-band into a small (~8 KB)
scratch and
streams each band straight to controller RAM (community-sdk
writeGrayscalePlaneStrip), leaving the BW framebuffer intact. No save,
no
restore; controller RAM is re-synced for the next differential turn
directly
from the live framebuffer.

Three writers honor the active band target so per-band re-rendering
stays cheap
and correct:

- drawPixel (text) redirects writes to the band scratch and clips to it.
- renderCharImpl skips glyphs whose physical y-extent is outside the
band before
the bitmap decode (glyphIntersectsStrip), so the per-band re-render
doesn't
  pay N x glyph decode.
- DirectPixelWriter (images) writes the band scratch via getWriteTarget
instead
  of the framebuffer. Without this, image pixels wrote the live BW frame
directly and cleanup re-synced that corruption, leaving thin outlines
after
  navigating away from an image.

Controller specifics live in the SDK (X4 setRamArea windowing, X3 PTL);
the
reader checks supportsStripGrayscale() and is otherwise
controller-agnostic.

Measured on hardware (X4 and X3, text and images, visually correct):

- Grayscale scratch ~8 KB vs ~50 KB save; largest contiguous free block
held at
  full size during grayscale instead of dropping ~25-32 KB.
- X4 text page about +25 ms/page; X3 page time is dominated by its
intrinsic
  grayscale refresh, not tiling.

Depends on community-sdk #13 (the writeGrayscalePlaneStrip API). The
submodule
bump here points at that branch, so until #13 merges the submodule won't
resolve
from upstream and CI will fail there; keeping this a draft until then.
Will
rebase onto master and re-point the submodule to the merged SDK commit
once #13
lands.

Did you use AI tools to help write this code? partial
uxjulia added a commit that referenced this pull request Jun 5, 2026
Re-applies the X3 row-band grayscale work that was temporarily reverted in
06ef4ca, now that open-x4-sdk is on 26648d6 (which includes the #13 row-band
plane streaming the path depends on).

Restores the strip render pipeline end to end:
- GfxRenderer strip target (beginStripTarget/endStripTarget, getWriteTarget/
  getWriteOriginY/getWriteRows), real glyphIntersectsStrip, and
  writeGrayscalePlaneStrip/supportsStripGrayscale
- HalDisplay passthrough to EInkDisplay
- DirectPixelWriter band-clipping writePixel
- EpubReaderActivity tiled grayscale pass, gated on supportsStripGrayscale with
  a BW-snapshot fallback when unsupported or under memory pressure

Also drops the temporary glyphIntersectsStrip stub that kept call sites
compiling while the feature was reverted.

Builds for the simulator. Needs on-device X3 verification that the current SDK
AA path is fast enough and that grayscale image pages render without banding.
uxjulia added a commit that referenced this pull request Jun 10, 2026
* docs: update changelog

* fix: avoid settings list stack overflow on boot

* fix: prevent recents long-press from auto-confirming

* chore: merge upstream crosspoint

* fix: improve minimal theme's cover thumbnails (crop image before dithering)

* fix: adapt minimal cover thumbnails for unusual ratios

* fix: use pinned input manager held-time API

* fix: improve lyra carousel thumbnails

* feat: add additional long-press options in recent books view

* fix: move reader footnotes menu item above chapter selector #170

* fix: change label to "Download Font Size Range"

* fix(fonts): combine downloaded font ranges by family

* docs: update changelog

* fix: use stable EPUB cache path when moving finished books

* feat(settings): change "Page as Sleep Screen" feature to "Quick Resume"

* fix: address cppcheck diagnostics

* fix(epub): bump section cache for layout changes

* docs: update changelog

* ci: clean up github workflows

* fix: add translations for STR_QUICK_RESUME

* chore(i18n): refine quick resume translations

* chore(i18n): refine quick resume translations

* fix: show wifi connected status from settings

* fix: constrain status bar settings in landscape

* feat: auto inject build info into sleep screen for debug enviroment

* fix(settings): preserve quick resume timeout preference

* chore: fix the Italian translation (crosspoint-reader#2095)

* refactor: unify book cache clearing for epub, txt, and xtc files (crosspoint-reader#1875)

fix(settings): mirror quick resume timeout behavior on web settings

fix(settings): compare quick resume sleep screen by enum

* fix: wrap book title in long-press menu

* feat(opds): allow cancelling book downloads

* fix: validate saved credential payloads (#177)

* feat: add OPDS cancellation and better retry visual feedback (#178)

* fix: show loading state before opds retry
* feat: add more debugging wifi connection diagnostics
* fix: make opds download cancellation more responsive
* docs: update changelog

* docs: update changelog for next release

* docs: update readme

* fix: lyra carousel popups missing

* correctly draw status bar preview while editing in non portrait orientation

With CW, CCW, Inverted orientations

When in Reader

If you open Book menu > Reader Options > Customize Status Bar

The preview is drawn in the incorrect location due to a hardcoded offset, this commit sets this to change based on orientation

* feat(reader): add adjustable line height setting

* style: run clang-format

* fix: improve font download timeout diagnostics

* ci: run firmware build on self-hosted runner

* fix: improve OPDS and font download speeds and reliability (#195)

* fix(opds): show more specific opds errors for low memory scenario

* fix(opds): free sd font before catalog loading

* fix: improve font download timeout diagnostics

* fix(opds): show more specific opds errors for low memory scenario

* fix(opds): free sd font before catalog loading

* fix: increase opds transfer buffer back up to 4096 and increase font buffer to 2048kb

* ci: build only tiny firmware in CI

* feat(stats): sync and aggregate global reading stats between devices

* feat: save auto page turn interval per book (#192)

* fix: harden epub progress saves during sync (#193)

* fix: harden epub progress saves during sync
* fix: clamp KOReader remote progress page counts

* correctly draw status bar preview while editing in non portrait orientation

With CW, CCW, Inverted orientations

When in Reader

If you open Book menu > Reader Options > Customize Status Bar

The preview is drawn in the incorrect location due to a hardcoded offset, this commit sets this to change based on orientation

* fix: store only peer stats in synced stats folder

* docs: update documentation for synced reading stats

* docs: update readme

* feat(reader): anchor epub bookmarks to paragraphs

* feat(reader): split synced reading stats totals

* feat: show bookmark text snippets

* feat: add tilt-to-turn direction setting

* docs: update readme

* fix: translate tilt direction label

* fix: preserve epub sections when css cache rebuild fails

* fix: show loading popup before reader startup work

* fix: preserve partial epub css cache on low memory

* fix: clean up cppcheck warnings

* fix: preserve epub section caches after partial css rebuilds

* fix(epub): release table fallback memory before layout abort

* fix(epub): reduce sd font memory pressure during indexing

* fix(epub): fallback to built-in font on sd font layout OOM

* fix: keep inverted button hint outlines upright

* docs: update docs

* feat: add OPDS download filename format setting

* fix(epub): harden pagination page allocation

* fix(epub): clarify low-memory image warning

* fix: preserve book progress during web uploads

* feat: add time left in chapter/book

* feat: move reader clock to top status bar

* fix: clean up cppcheck style warnings

* chore: bump version

* docs: clean up unreleased changelog

* chore: merge upstream crosspoint

* feat: add Next/Next side button layout

* feat: add preview for top bar when customizing status bar

* fix: revert book cache bump

* fix: restore tiled grascale render path

* Revert "feat: tiled grayscale rendering to drop the storeBwBuffer peak (crosspoint-reader#2106)"

This reverts commit 4ee4068.

* fix: hide missing word-joiner glyphs in epub text

* feat: consolidate settings menu items

* fix: improve EPUB book time-left estimates

* fix: stabilize displayed wifi mac address

* fix: update clock padding

* fix: adjust finished-book prompt timing

* fix: SD font pre-indexing guard

* feat: add ability to display publisher page numbers when present

* fix: align reader clock padding

* docs: match cache versions with code

* fix: make publisher page marker scratch buffers const

* fix: expose disabled side button layout

* docs: sync book.bin/section.bin version refs to source (crosspoint-reader#2169)

* feat: add RTL support in epub and txt readers (crosspoint-reader#1700)

Co-authored-by: Zach Nelson <zach@zdnelson.com>

* fix: swedish translation for strings added by crosspoint-reader#1337 and crosspoint-reader#2105 (crosspoint-reader#2197)

* fix: complete Spanish, Catalan and Valencian strings (crosspoint-reader#2203)

* chore: remove feature requests from issue types

* fix: EPUB skip-depth handling for image alt fallback

* refactor: finalize EPUB publisher page markers once

* feat: add RTL support in epub and txt readers (crosspoint-reader#1700)

Co-authored-by: Zach Nelson <zach@zdnelson.com>

* fix: add missing swedish translation for disabled

* fix: complete Spanish, Catalan and Valencian strings (crosspoint-reader#2203)

Co-authored-by: Leopoldo Pla Sempere <leopoldo.pla@treelogic.com>

* fix(home): harden Lyra Carousel under low heap

* fix: make clock UTC offset picker easier to use

* fix: compute max width of minutes based on all allowable values

* fix: correct Vietnamese i18n string offsets

* fix: add missing settings menu translations

* fix: redesign X3's UTC offset picker so it is easier to use (crosspoint-reader#2205)

## Summary

* **What is the goal of this PR?**
Improve the X3 clock UTC offset picker so it is clearer which part of
the offset will change when the user presses up/down.

* **What changes are included?**
Replaces the single underlined `UTC +/- H:MM` string with separate
editable fields for the sign, hour, and minutes.
The editable fields are spaced out, outlined, and the currently selected
field is highlighted with a light gray background.

## Additional Context

* This is a render-only UI change in `ClockOffsetActivity`; it does not
change how UTC offsets are stored, clamped, saved, or applied.
* The selected field still cycles with Confirm, and up/down still
adjusts the active sign/hour/minute value.

Screenshot of **current design** showing the sign (+/-) highlighted:
<img width="264" height="396" alt="old utc offset"
src="https://github.com/user-attachments/assets/c88d69ea-089c-47da-b5b3-ed0ebda5b112"
/>


Screenshot of **new design** showing the sign (+/-) highlighted:
<img width="264" height="396" alt="utc offset fix"
src="https://github.com/user-attachments/assets/f51da8b3-9aab-4f48-a9d1-21c828c01499"
/>

---

### 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 >**_

* fix: inaccurate KOReader sync when syncing at chapter start

* feat: add custom sleep timer picker (crosspoint-reader#2206)

## Summary

* **What is the goal of this PR?**
Mainly fixes crosspoint-reader#2196, but also allows users to set a sleep time of 1~30
min or to never sleep.

* **What changes are included?**

1. Revert changes from crosspoint-reader#1948 and crosspoint-reader#2137 (Sorry @Uri-Tauber)
2. Cherrypick changes from
0cb91c3
and
4e6bd63
for a timeout interval picker UI, the custom sleep time feature, and
migrate the existing setting in v1.3.0, `sleepTimeout`, to
`sleepTimeoutMinutes` (Thanks! @uxjulia)
3. Add a "Never" at the far right of the timeout interval picker

---

### 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**_

---------

Co-authored-by: Julia <julia@uxj.io>

* fix: automatically attempt to sync clock

* fix: stop counting backward page turns in reading stats

* fix: only count page turns after 2 seconds

* feat: display date for x3

* docs: add Claude Code contributor skills for firmware code quality (crosspoint-reader#2212)

* fix(docs): Section numbering in USER_GUIDE.md (crosspoint-reader#2195)

* chore: update the Italian translation (crosspoint-reader#2207)

* fix(lang): Russian translate for new strings (crosspoint-reader#2217)

* feat: Hebrew localization (crosspoint-reader#2068)

* chore: new Italian fixes (crosspoint-reader#2218)

* fix: recover bookmarks from legacy epub hash filenames

* chore: bump version

* chore: remove unused sleep timer interval strings (crosspoint-reader#2223)

* fix: bookmark percentage always 0% and page number starts at 0 (crosspoint-reader#2188)

## Summary

* Fix the issue described in crosspoint-reader#2176 where bookmark percentages are always
0%
* Also fixed the page number rendering to +1 because they are 0 index
based, but should be rendered starting from 1

---

### AI Usage

Did you use AI tools to help write this code? _**< NO >**_

* fix: update German translation (crosspoint-reader#2224)

* fix: avoid zip-wide css scan for large epubs (crosspoint-reader#2213)

## Summary

* **What is the goal of this PR?** 
* This PR ports over Crossink's handling of large EPUBs that helps
prevent crashes during open after the book metadata cache is built.

* **What changes are included?**
* Removes the post-indexing ZIP-wide CSS discovery pass that built an
in-memory map of every ZIP entry.
* Reuses `content.opf` parsing to collect declared CSS files without
writing spine entries again.
* Temporarily releases the loaded book metadata cache while rebuilding
CSS for cached books.
* Parses CSS before reloading `book.bin` after a fresh cache build,
leaving more heap available during CSS rule parsing.

## Additional Context

* User reported their EPUB opening fine on Crossink but would crash on
Crosspoint. Verified this claim on my own devices.
* The crash this addresses happened after `book.bin` was successfully
built, when CSS discovery allocated a large `unordered_map` for ~3k EPUB
ZIP entries.
* Tradeoff: CSS files not declared in `content.opf` are no longer
discovered by scanning the full ZIP. This avoids the high-risk memory
allocation but improperly formatted EPUBs (ones that don't declare their
CSS styles in `content.opf` will render without styling and fallback to
inline styles.
* User provided epub that was crashing prior to this change:
https://www.mediafire.com/file/g57ea4mj13iunvh/Quang+%C3%82m+Chi+Ngo%E1%BA%A1i+-+Nh%C4%A9+C%C4%83n.epub/file

---

### 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 >**_

* Fix ghosting on pages following images in grayscale (crosspoint-reader#2226)

* chore: Move opendyslexic from flash to SD (crosspoint-reader#2231)

* fix: add more explicit KOReader sync error messaging

* fix: improve book time-left estimates after quick navigations

* fix: remove 'Go to Home' from in-reader menu

* fix: Skip Underline Calculations During Font Cache Scan Pass (crosspoint-reader#2237)

## Summary

This PR optimizes the text rendering process by skipping underline style
calculations and measurements during the initial font cache scanning
phase. This prevents excessive and unnecessary SD card reads on pages
with heavy use of underlines (e.g., Table of Contents pages).

### **The Problem**

During the first rendering pass (the font cache scan pass used to
collect text for prewarming), `GfxRenderer::drawText()` early-returns
after recording text as expected. However, `TextBlock::render()`
continued past this point to execute the underline decoration logic.

Because underline calculation calls `getTextWidth()` and
`getTextAdvanceX()`, it triggered immediate glyph lookups via
`EpdFont::getGlyph()`. Since the SD card font had not been prewarmed yet
at this stage, the lookups fell back to the `glyphMissHandler`,
resulting in hundreds of individual, slow SD card reads into a limited
8-slot ring buffer.

### **The Fix**

1. **Exposed Scan State:** Added `GfxRenderer::isFontCacheScanning()` to
safely check if the font cache manager is currently in
text-collection/scan mode.
2. **Bypassed Underline Logic:** Modified `TextBlock::render()` to check
this state and skip underline measurement and drawing entirely while
scanning is active.

> [!NOTE]
> The text itself is still properly captured for prewarming via
`drawText()`. The underlines will be safely and efficiently calculated
and drawn during the actual render pass after the fonts have been
completely prewarmed.

---

### 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 >**_

* fix: make clock and battery top padding consistent

* docs: Fix section numbering and table of contents in USER_GUIDE.md (crosspoint-reader#2244)

* chore: small Italian fixes (crosspoint-reader#2252)

* fix: remove duplicate nearby stats sync label

* fix: lyra and lyra extended home menu icon alignment

* feat: allow selecting a custom sleep folder (#227)

* feat: allow selecting a custom sleep folder

* fix: KOReader sync drift when syncing at chapter start (crosspoint-reader#2245)

* fix: long-press back should move to the start of chapter (crosspoint-reader#2243)

Co-authored-by: Julia <julia@uxj.io>

* fix: Crash on invalid font filename (crosspoint-reader#2253)

Co-authored-by: Julia <julia@uxj.io>

* fix: Replace full-image cache buffer with streaming band buffer to reduce memory usage (crosspoint-reader#2230)

* fix: apply progress bar offset from top instead of bottom edge (crosspoint-reader#2250)

* feat: reapply tiled grayscale row-band rendering on X3

Re-applies the X3 row-band grayscale work that was temporarily reverted in
06ef4ca, now that open-x4-sdk is on 26648d6 (which includes the #13 row-band
plane streaming the path depends on).

Restores the strip render pipeline end to end:
- GfxRenderer strip target (beginStripTarget/endStripTarget, getWriteTarget/
  getWriteOriginY/getWriteRows), real glyphIntersectsStrip, and
  writeGrayscalePlaneStrip/supportsStripGrayscale
- HalDisplay passthrough to EInkDisplay
- DirectPixelWriter band-clipping writePixel
- EpubReaderActivity tiled grayscale pass, gated on supportsStripGrayscale with
  a BW-snapshot fallback when unsupported or under memory pressure

Also drops the temporary glyphIntersectsStrip stub that kept call sites
compiling while the feature was reverted.

Builds for the simulator. Needs on-device X3 verification that the current SDK
AA path is fast enough and that grayscale image pages render without banding.

* feat: skip loading popup for cached EPUB opens

* perf: Minimize string allocations in CSS parsing (crosspoint-reader#2263)

## Summary

Use `std::string_view` and case-insensitive comparisons to avoid string
allocations during CSS parsing.

**Hot path:** `resolveStyle` (called per HTML start tag during chapter
rendering) now does zero heap allocations. Previously it allocated a
normalized tag string, a vector of class strings, and a composite key
per class. For a chapter with ~2000 tags × 2 classes each, that's ~12
000 small short-lived allocations eliminated per page render — primarily
a heap-fragmentation win on the ESP32-C3's ~380KB RAM.

**Cold path:** CSS load no longer allocates per-rule selector vectors or
per-token strings; `splitOnChar`/`splitWhitespace` are gone, replaced
with callback-based tokenization (`forEachDelimitedToken`).

**Behavioral notes:**
- The selector `unordered_map` now uses an ASCII-case-insensitive
hash/equal. Selectors are stored with their original case rather than
pre-lowercased; the observable lookup result is unchanged.
- `stripTrailingImportant` is now case-insensitive (per CSS spec;
previously matched only lowercase `!important`).

**Cache compatibility:** `CSS_CACHE_VERSION` unchanged. Old caches
(lowercase selectors) load correctly under the new lookup; new caches
will contain verbatim-case selectors — both forms work.

---

### AI Usage

Did you use AI tools to help write this code? _**PARTIALLY**_

* feat: add more reading stats for X3 and add minimal stats sleep screen

* fix: correct minimal stats streak wording

* feat: add global stats backup

* fix: add explicit error when syncing with older version of crossink

* feat: update web interface and improve development workflow

* feat: add dark reader mode

* docs: minor formatting update to readme

* fix: localize minimal stats streak label

* fix: reposition stats and swap 'new reader' icon

* fix: alignment and spacing fixes

* Update german.yaml

Fix crosspoint-reader#2266

* Revert "Update german.yaml" (crosspoint-reader#2267)

* fix: german translation for STR_INVERTED (crosspoint-reader#2269)

* fix: adjust reading stats padding again

* fix(epub): decode percent-encoded internal asset paths so assets render correctly (crosspoint-reader#2249)

## Summary

* **What is the goal of this PR?** 
* Fix EPUBs where internal file references are written in URL-style
escaped form, like spaces appearing as `%20`, so the reader can find the
right files instead of treating those references as missing.
* **What changes are included?**
* Added a small shared helper that converts those escaped EPUB-internal
paths back into their normal filenames before we try to look them up.
* Applied that cleanup step across the EPUB parsing flow wherever we
resolve internal references, including cover images, manifest items, TOC
links, spine entries, and inline HTML images.
* Kept the change narrowly focused on EPUB-internal asset resolution
rather than changing broader URL or networking behavior.

## Additional Context

* The user-facing bug here is that some books package their internal
filenames in an escaped form, so a file like `Chapter 1.xhtml` may be
referenced more like `Chapter%201.xhtml`. The reader was treating that
escaped text as the literal filename, which means otherwise-valid books
could lose images, covers, or chapter targets because the lookup no
longer matched the real file inside the EPUB.
* Risk is intentionally low. The helper only rewrites valid `%XX` escape
sequences and leaves malformed input alone, so it should improve
compatibility with escaped filenames without broadening the parser’s
behavior in unrelated cases.

## Local Testing Performed
* This was tested on my device with the user-provided optimized epub
that was not rendering images within the text prior to this fix (cover
image and chapter headers were rendering fine):

[orv_main_baseline.epub.zip](https://github.com/user-attachments/files/28529545/orv_main_baseline.epub.zip)
* This was also tested by the user with a local build and the affected
epub and confirmed to be working

## Steps for Testing
* Try to open the affected epub (linked above) or any epub that has
similar percent-encoding on a build prior to this fix.
* Apply this fix, clear book cache, and re-open the affected book.
* Images should render properly.
---

### 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 >**_

* feat: improve rendering of controls menu

* chore: add t5s3 fork (crosspoint-reader#2268)

* feat: improve rendering of display menu

* feat: improve rendering of reader menu

* fix: reduce emoji coverage to more popular ones to reduce firmware size

* feat: add hebrew support to UI fonts

* fix: invert tilt-page-turn confirmation pop up in dark mode

* fix: gate minimal stats to x3 devices only

* fix: align book time-left with displayed progress

* feat: show reader font sizes as point sizes

* fix: tighten reading pace sample cutoff

* fix(epub): decode footnote href path before spine lookup (crosspoint-reader#2271)

* fix: filter out reading pace samples greater than twice the average

* fix: german translation for STR_INVERTED (crosspoint-reader#2269)

* fix(epub): decode percent-encoded internal asset paths so assets render correctly (crosspoint-reader#2249)

* **What is the goal of this PR?**
* Fix EPUBs where internal file references are written in URL-style
escaped form, like spaces appearing as `%20`, so the reader can find the
right files instead of treating those references as missing.
* **What changes are included?**
* Added a small shared helper that converts those escaped EPUB-internal
paths back into their normal filenames before we try to look them up.
* Applied that cleanup step across the EPUB parsing flow wherever we
resolve internal references, including cover images, manifest items, TOC
links, spine entries, and inline HTML images.
* Kept the change narrowly focused on EPUB-internal asset resolution
rather than changing broader URL or networking behavior.

* The user-facing bug here is that some books package their internal
filenames in an escaped form, so a file like `Chapter 1.xhtml` may be
referenced more like `Chapter%201.xhtml`. The reader was treating that
escaped text as the literal filename, which means otherwise-valid books
could lose images, covers, or chapter targets because the lookup no
longer matched the real file inside the EPUB.
* Risk is intentionally low. The helper only rewrites valid `%XX` escape
sequences and leaves malformed input alone, so it should improve
compatibility with escaped filenames without broadening the parser’s
behavior in unrelated cases.
* This was tested on my device with the user-provided optimized epub
that was not rendering images within the text prior to this fix (cover
image and chapter headers were rendering fine):

[orv_main_baseline.epub.zip](https://github.com/user-attachments/files/28529545/orv_main_baseline.epub.zip)
* This was also tested by the user with a local build and the affected
epub and confirmed to be working
* Try to open the affected epub (linked above) or any epub that has
similar percent-encoding on a build prior to this fix.
* Apply this fix, clear book cache, and re-open the affected book.
* Images should render properly.
---

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 >**_

* fix(epub): decode footnote href path before spine lookup (crosspoint-reader#2271)

* docs: changelog cleanups

* fix: clarify global reading stats backup label

* feat: add dark mode shortcut actions

* fix: prefer pace for epub book time-left

* docs: readme cleanup

* fix: scale SUP/SUB underline to match 50%-scaled glyphs (crosspoint-reader#2255)

* refactor: Dedupe wifi scan in-place without std::map (crosspoint-reader#2262)

## Summary

`std::map` heap-allocates each node. Avoid using it for wifi SSID
dedupe, and instead just dedupe in-place with the existing `networks`
vector. Removed dead `ipAddress` member in `WifiNetworkInfo` struct.

---

### AI Usage

Did you use AI tools to help write this code? _**PARTIALLY**_

* fix: free font catalog before SD font downloads; fixes #236

* fix: honor inverted side-button navigation in reader menus; fixes #235

* feat: improve calculations for reading time left

* feat: reorganize reading stats backup settings
feat: add all-time stats reset action

* feat: add new menu and settings for reading stats including idle time threshold and reset all-time stats

* fix: add missing translations for minimal stats sleep screen reader type and reading streak

* fix: release SD fonts before wifi activities and release wifi memory on cancelled selection

* fix: clean up preserved cache return condition

* docs: refresh cache formats and web server workflows (crosspoint-reader#2233)

## Summary

* **What is the goal of this PR?** Update project documentation to match
the current master implementation for cache formats, i18n, file
transfer/web server workflows, SD-card fonts, and root user-facing docs.
* **What changes are included?** Refreshes `book.bin`/`section.bin` docs
for v6/v25, updates File Transfer/Calibre/WebDAV/API docs, documents 24
UI languages and JSON language persistence, updates root
README/USER_GUIDE cache and network details, and syncs the tracked
CLAUDE skill doc cache-version notes.

## Additional Context

* Docs-only change. Verified with `git diff --check origin/master..HEAD`
and stale-reference greps for old cache versions, removed i18n APIs, old
WiFi screen wording, and raw `Serial.printf` examples. No firmware build
was run.

---

### 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**_

* fix: invert quick resume markers in dark mode

* fix: sync quick resume timeout from sleep screen picker

* fix: replace crosspoint versions with crossink's

* fix: update German translations

Co-authored-by: Robert Janus<hallo@robertjanus.de>

* fix: translate minimal home button labels

* feat: add power button short press for quick access to footnotes (crosspoint-reader#1658)

* fix: use versioned s3 font downloads

* fix: preserve heading alignment after inline images

* fix: skip `<span>` anchors (crosspoint-reader#2303)

## Summary

* **What is the goal of this PR?** Prevent heap memory exhaustion caused
by thousands of machine-generated anchor IDs injected by epub converters
like Kobo KePub.
* Fix crosspoint-reader#2292.

* **What changes are included?**
* **Element-type filter (Layer 1):** Introduced the
`isNonNavigableInlineElement()` function in `ChapterHtmlSlimParser.cpp`
to automatically skip recording IDs on `<span>` elements, as they are
purely inline wrappers used for tracking and lack navigable meaning.
* **Hard cap (Layer 2):** Added the `MAX_ANCHORS_PER_CHAPTER = 1024`
constant to act as a fallback safety net against unbounded heap growth
from unknown future ID-injection patterns on non-span elements.
* **TOC Safety net:** Ensured that IDs matching known Table of Contents
(TOC) entries explicitly bypass both the `<span>` filter and the
1024-anchor cap, guaranteeing that chapter page-break and core
navigation logic are never compromised.


---

### 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 >**_

* fix: update spanish translations

Co-authored-by: PlatinumPOST <PlatinumPOST@users.noreply.github.com>

* fix: update translations for nearby stats sync

* fix(lang): russian.yaml new string (crosspoint-reader#2309)

* fix: german traslation for STR_INVERTED (crosspoint-reader#2315)

* docs: update agents.md

* fix: add missing translations for 'quick return from footnotes'

* fix: show quick return from footnotes setting in web controls

* docs: update readme

---------

Co-authored-by: Matteo Scopel <matteo@scopel.email>
Co-authored-by: WuTofu <5987870+WuTofu@users.noreply.github.com>
Co-authored-by: Dudekahedron <49531350+StanleyDudek@users.noreply.github.com>
Co-authored-by: Angad Kandhari <angad729@gmail.com>
Co-authored-by: Uri Tauber <uritaube@gmail.com>
Co-authored-by: Zach Nelson <zach@zdnelson.com>
Co-authored-by: Stefan Blixten Karlsson <sbkarlsson@gmail.com>
Co-authored-by: Leopoldo Pla Sempere <leopoldo.pla@treelogic.com>
Co-authored-by: Jeremy Klein <jeremydk@gmail.com>
Co-authored-by: Matheus Martins <matheuscumth@gmail.com>
Co-authored-by: muhas <muhas@muhas.ru>
Co-authored-by: Wilhelm Schuster <dev@rot13.io>
Co-authored-by: Nathanael Maher <nathanael.maher@outlook.com>
Co-authored-by: Justin Mitchell <justin@jmitch.com>
Co-authored-by: Eloren1 <elorenn@bk.ru>
Co-authored-by: SurprisedDuck <jannik.theiss@googlemail.com>
Co-authored-by: Lorenzo Santini <37672504+santinilor@users.noreply.github.com>
Co-authored-by: PlatinumPOST <PlatinumPOST@users.noreply.github.com>
uxjulia added a commit that referenced this pull request Jun 13, 2026
* fix: improve minimal theme's cover thumbnails (crop image before dithering)

* fix: adapt minimal cover thumbnails for unusual ratios

* fix: use pinned input manager held-time API

* fix: improve lyra carousel thumbnails

* feat: add additional long-press options in recent books view

* fix: move reader footnotes menu item above chapter selector #170

* fix: change label to "Download Font Size Range"

* fix(fonts): combine downloaded font ranges by family

* docs: update changelog

* fix: use stable EPUB cache path when moving finished books

* feat(settings): change "Page as Sleep Screen" feature to "Quick Resume"

* fix: address cppcheck diagnostics

* fix(epub): bump section cache for layout changes

* docs: update changelog

* ci: clean up github workflows

* fix: add translations for STR_QUICK_RESUME

* chore(i18n): refine quick resume translations

* chore(i18n): refine quick resume translations

* fix: show wifi connected status from settings

* fix: constrain status bar settings in landscape

* feat: auto inject build info into sleep screen for debug enviroment

* fix(settings): preserve quick resume timeout preference

* chore: fix the Italian translation (crosspoint-reader#2095)

* refactor: unify book cache clearing for epub, txt, and xtc files (crosspoint-reader#1875)

fix(settings): mirror quick resume timeout behavior on web settings

fix(settings): compare quick resume sleep screen by enum

* fix: wrap book title in long-press menu

* feat(opds): allow cancelling book downloads

* fix: validate saved credential payloads (#177)

* feat: add OPDS cancellation and better retry visual feedback (#178)

* fix: show loading state before opds retry
* feat: add more debugging wifi connection diagnostics
* fix: make opds download cancellation more responsive
* docs: update changelog

* docs: update changelog for next release

* docs: update readme

* fix: lyra carousel popups missing

* correctly draw status bar preview while editing in non portrait orientation

With CW, CCW, Inverted orientations

When in Reader

If you open Book menu > Reader Options > Customize Status Bar

The preview is drawn in the incorrect location due to a hardcoded offset, this commit sets this to change based on orientation

* feat(reader): add adjustable line height setting

* style: run clang-format

* fix: improve font download timeout diagnostics

* ci: run firmware build on self-hosted runner

* fix: improve OPDS and font download speeds and reliability (#195)

* fix(opds): show more specific opds errors for low memory scenario

* fix(opds): free sd font before catalog loading

* fix: improve font download timeout diagnostics

* fix(opds): show more specific opds errors for low memory scenario

* fix(opds): free sd font before catalog loading

* fix: increase opds transfer buffer back up to 4096 and increase font buffer to 2048kb

* ci: build only tiny firmware in CI

* feat(stats): sync and aggregate global reading stats between devices

* feat: save auto page turn interval per book (#192)

* fix: harden epub progress saves during sync (#193)

* fix: harden epub progress saves during sync
* fix: clamp KOReader remote progress page counts

* correctly draw status bar preview while editing in non portrait orientation

With CW, CCW, Inverted orientations

When in Reader

If you open Book menu > Reader Options > Customize Status Bar

The preview is drawn in the incorrect location due to a hardcoded offset, this commit sets this to change based on orientation

* fix: store only peer stats in synced stats folder

* docs: update documentation for synced reading stats

* docs: update readme

* feat(reader): anchor epub bookmarks to paragraphs

* feat(reader): split synced reading stats totals

* feat: show bookmark text snippets

* feat: add tilt-to-turn direction setting

* docs: update readme

* fix: translate tilt direction label

* fix: preserve epub sections when css cache rebuild fails

* fix: show loading popup before reader startup work

* fix: preserve partial epub css cache on low memory

* fix: clean up cppcheck warnings

* fix: preserve epub section caches after partial css rebuilds

* fix(epub): release table fallback memory before layout abort

* fix(epub): reduce sd font memory pressure during indexing

* fix(epub): fallback to built-in font on sd font layout OOM

* fix: keep inverted button hint outlines upright

* docs: update docs

* feat: add OPDS download filename format setting

* fix(epub): harden pagination page allocation

* fix(epub): clarify low-memory image warning

* fix: preserve book progress during web uploads

* feat: add time left in chapter/book

* feat: move reader clock to top status bar

* fix: clean up cppcheck style warnings

* chore: bump version

* docs: clean up unreleased changelog

* chore: merge upstream crosspoint

* feat: add Next/Next side button layout

* feat: add preview for top bar when customizing status bar

* fix: revert book cache bump

* fix: restore tiled grascale render path

* Revert "feat: tiled grayscale rendering to drop the storeBwBuffer peak (crosspoint-reader#2106)"

This reverts commit 4ee4068.

* fix: hide missing word-joiner glyphs in epub text

* feat: consolidate settings menu items

* fix: improve EPUB book time-left estimates

* fix: stabilize displayed wifi mac address

* fix: update clock padding

* fix: adjust finished-book prompt timing

* fix: SD font pre-indexing guard

* feat: add ability to display publisher page numbers when present

* fix: align reader clock padding

* docs: match cache versions with code

* fix: make publisher page marker scratch buffers const

* fix: expose disabled side button layout

* chore: remove feature requests from issue types

* fix: EPUB skip-depth handling for image alt fallback

* refactor: finalize EPUB publisher page markers once

* feat: add RTL support in epub and txt readers (crosspoint-reader#1700)

Co-authored-by: Zach Nelson <zach@zdnelson.com>

* fix: add missing swedish translation for disabled

* fix: complete Spanish, Catalan and Valencian strings (crosspoint-reader#2203)

Co-authored-by: Leopoldo Pla Sempere <leopoldo.pla@treelogic.com>

* fix(home): harden Lyra Carousel under low heap

* fix: make clock UTC offset picker easier to use

* fix: compute max width of minutes based on all allowable values

* fix: correct Vietnamese i18n string offsets

* fix: add missing settings menu translations

* fix: inaccurate KOReader sync when syncing at chapter start

* fix: automatically attempt to sync clock

* fix: stop counting backward page turns in reading stats

* fix: only count page turns after 2 seconds

* feat: display date for x3

* fix: recover bookmarks from legacy epub hash filenames

* chore: bump version

* fix: add more explicit KOReader sync error messaging

* fix: improve book time-left estimates after quick navigations

* fix: remove 'Go to Home' from in-reader menu

* fix: make clock and battery top padding consistent

* fix: remove duplicate nearby stats sync label

* fix: lyra and lyra extended home menu icon alignment

* feat: allow selecting a custom sleep folder (#227)

* feat: allow selecting a custom sleep folder

* feat: reapply tiled grayscale row-band rendering on X3

Re-applies the X3 row-band grayscale work that was temporarily reverted in
06ef4ca, now that open-x4-sdk is on 26648d6 (which includes the #13 row-band
plane streaming the path depends on).

Restores the strip render pipeline end to end:
- GfxRenderer strip target (beginStripTarget/endStripTarget, getWriteTarget/
  getWriteOriginY/getWriteRows), real glyphIntersectsStrip, and
  writeGrayscalePlaneStrip/supportsStripGrayscale
- HalDisplay passthrough to EInkDisplay
- DirectPixelWriter band-clipping writePixel
- EpubReaderActivity tiled grayscale pass, gated on supportsStripGrayscale with
  a BW-snapshot fallback when unsupported or under memory pressure

Also drops the temporary glyphIntersectsStrip stub that kept call sites
compiling while the feature was reverted.

Builds for the simulator. Needs on-device X3 verification that the current SDK
AA path is fast enough and that grayscale image pages render without banding.

* feat: skip loading popup for cached EPUB opens

* feat: add more reading stats for X3 and add minimal stats sleep screen

* fix: correct minimal stats streak wording

* feat: add global stats backup

* fix: add explicit error when syncing with older version of crossink

* feat: update web interface and improve development workflow

* feat: add dark reader mode

* docs: minor formatting update to readme

* fix: localize minimal stats streak label

* fix: reposition stats and swap 'new reader' icon

* fix: alignment and spacing fixes

* fix: adjust reading stats padding again

* feat: improve rendering of controls menu

* feat: improve rendering of display menu

* feat: improve rendering of reader menu

* fix: reduce emoji coverage to more popular ones to reduce firmware size

* feat: add hebrew support to UI fonts

* fix: invert tilt-page-turn confirmation pop up in dark mode

* fix: gate minimal stats to x3 devices only

* fix: align book time-left with displayed progress

* feat: show reader font sizes as point sizes

* fix: tighten reading pace sample cutoff

* fix: filter out reading pace samples greater than twice the average

* fix: german translation for STR_INVERTED (crosspoint-reader#2269)

* fix(epub): decode percent-encoded internal asset paths so assets render correctly (crosspoint-reader#2249)

* **What is the goal of this PR?**
* Fix EPUBs where internal file references are written in URL-style
escaped form, like spaces appearing as `%20`, so the reader can find the
right files instead of treating those references as missing.
* **What changes are included?**
* Added a small shared helper that converts those escaped EPUB-internal
paths back into their normal filenames before we try to look them up.
* Applied that cleanup step across the EPUB parsing flow wherever we
resolve internal references, including cover images, manifest items, TOC
links, spine entries, and inline HTML images.
* Kept the change narrowly focused on EPUB-internal asset resolution
rather than changing broader URL or networking behavior.

* The user-facing bug here is that some books package their internal
filenames in an escaped form, so a file like `Chapter 1.xhtml` may be
referenced more like `Chapter%201.xhtml`. The reader was treating that
escaped text as the literal filename, which means otherwise-valid books
could lose images, covers, or chapter targets because the lookup no
longer matched the real file inside the EPUB.
* Risk is intentionally low. The helper only rewrites valid `%XX` escape
sequences and leaves malformed input alone, so it should improve
compatibility with escaped filenames without broadening the parser’s
behavior in unrelated cases.
* This was tested on my device with the user-provided optimized epub
that was not rendering images within the text prior to this fix (cover
image and chapter headers were rendering fine):

[orv_main_baseline.epub.zip](https://github.com/user-attachments/files/28529545/orv_main_baseline.epub.zip)
* This was also tested by the user with a local build and the affected
epub and confirmed to be working
* Try to open the affected epub (linked above) or any epub that has
similar percent-encoding on a build prior to this fix.
* Apply this fix, clear book cache, and re-open the affected book.
* Images should render properly.
---

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 >**_

* fix(epub): decode footnote href path before spine lookup (crosspoint-reader#2271)

* docs: changelog cleanups

* fix: clarify global reading stats backup label

* feat: add dark mode shortcut actions

* fix: prefer pace for epub book time-left

* docs: readme cleanup

* fix: free font catalog before SD font downloads; fixes #236

* fix: honor inverted side-button navigation in reader menus; fixes #235

* feat: improve calculations for reading time left

* feat: reorganize reading stats backup settings
feat: add all-time stats reset action

* feat: add new menu and settings for reading stats including idle time threshold and reset all-time stats

* fix: add missing translations for minimal stats sleep screen reader type and reading streak

* fix: release SD fonts before wifi activities and release wifi memory on cancelled selection

* fix: clean up preserved cache return condition

* fix: invert quick resume markers in dark mode

* fix: sync quick resume timeout from sleep screen picker

* fix: replace crosspoint versions with crossink's

* fix: update German translations

Co-authored-by: Robert Janus<hallo@robertjanus.de>

* fix: translate minimal home button labels

* fix: use versioned s3 font downloads

* fix: preserve heading alignment after inline images

* fix: update spanish translations

Co-authored-by: PlatinumPOST <PlatinumPOST@users.noreply.github.com>

* fix: update translations for nearby stats sync

* docs: update agents.md

* fix: add missing translations for 'quick return from footnotes'

* fix: show quick return from footnotes setting in web controls

* docs: update readme

* feat: Slovak translation add (crosspoint-reader#2251)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: invert clock settings

* fix: stop book settings back button from skipping submenus

* feat: long-press menu from home screen to swap between most recently open book (single cover themes)

* feat(i18n): add Vietnamese translation (crosspoint-reader#2279)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(fonts): add Vietnamese glyph coverage to the built-in UI font (crosspoint-reader#2280)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: Compile Error: Duplicate _order values found (crosspoint-reader#2323)

* fix: preview png files from file browser #251

* refactor: Drop redundant self-class prefix on applyDirectionToEntry (crosspoint-reader#2325)

## Summary

Non-functional cleanup: `ChapterHtmlSlimParser::` prefix is redundant
when calling `applyDirectionToEntry` within `ChapterHtmlSlimParser`
methods.

---

### AI Usage

Did you use AI tools to help write this code? _**NO**_

* fix: Hanging indent causes overlapping words (crosspoint-reader#2324)

* feat: add the Libre Baskerville font family (crosspoint-reader#2088)

## Summary

This PR adds the [Libre Baskerville
](https://github.com/impallari/Libre-Baskerville) font family to the
fonts available for download in CrossPoint.


## Additional Context

Baskerville is a classic font family, widely available in some form or
the other in most ereaders and widely used in publishing and in the
academy.

Libre Baskerville is a libre (SIL Open Font License v1) implementation
of it, which makes it possible for CrossPoint to ship it without issues.


![Vita-e-destino_ch30_p1_13pct_99220.bmp](https://github.com/user-attachments/files/28070672/Vita-e-destino_ch30_p1_13pct_99220.bmp)


---

### AI Usage

Did you use AI tools to help write this code? _**NO**_

* fix: generate sleep covers on demand #252

* feat: add custom device name; feat: hide OS metadata in file browser

* feat: add additional shortcut options #222

* fix: close hal files under storage lock

* fix: refresh carousel cache for dynamic home icons

* fix: png page overlays causing long re-indexing #255

* fix: use Noto Sans as punctuation fallback when generating downloadable SD fonts (crosspoint-reader#2331)

* fix: Restore first-line paragraph indentation (crosspoint-reader#2320)

* feat: add noto sans regular

* chore: merge upstream crosspoint

* fix: preserve reading stats when clearing cache #253

* fix: clean up KOReader sync failure return #257

* fix: update font download sources

* chore: bump version

* feat: lower long-press threshold to 200ms

* fix: guard file browser loads under low memory

* docs: update docs to reference optimizations

* fix: move boot order back

* fix: use current screen for page overlay sleep background #260

* fix: add confirmation screen before clearing bookmark list

* docs: update controls documentation

* fix: resolve downloadable sd font sources

* fix: prevent grayscale pass for page overlay images

* fix: namespace CrossInk settings file

* fix(koreader): resolve element XPath progress against visible body text (#261)

* fix: handle KOReader element XPath offsets closes crosspoint-reader#2307
* fix(koreader): ignore non-body text when resolving xpath progress
* fix: tighten KOReader anchor id parsing

* feat: add setting to hide file extension #248

* feat: add file browser display row setting

* fix: date overlapping the clock in roundedraff

* fix: show remove read books setting in files cache

* Update release catalog for v1.3.2

* fix: migrate epub state when moving finished books

* fix: minor typos

* fix: address release review regressions

---------

Co-authored-by: Matteo Scopel <matteo@scopel.email>
Co-authored-by: WuTofu <5987870+WuTofu@users.noreply.github.com>
Co-authored-by: Dudekahedron <49531350+StanleyDudek@users.noreply.github.com>
Co-authored-by: Zach Nelson <zach@zdnelson.com>
Co-authored-by: Leopoldo Pla Sempere <leopoldo.pla@treelogic.com>
Co-authored-by: Uri Tauber <uritaube@gmail.com>
Co-authored-by: PlatinumPOST <PlatinumPOST@users.noreply.github.com>
Co-authored-by: Martin <35097765+neresus@users.noreply.github.com>
Co-authored-by: Hoang Manh Linh <jetaudio.media@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
uxjulia added a commit that referenced this pull request Jun 25, 2026
* fix: correct Vietnamese i18n string offsets

* fix: add missing settings menu translations

* fix: inaccurate KOReader sync when syncing at chapter start

* fix: automatically attempt to sync clock

* fix: stop counting backward page turns in reading stats

* fix: only count page turns after 2 seconds

* feat: display date for x3

* fix: recover bookmarks from legacy epub hash filenames

* chore: bump version

* fix: add more explicit KOReader sync error messaging

* fix: improve book time-left estimates after quick navigations

* fix: remove 'Go to Home' from in-reader menu

* fix: make clock and battery top padding consistent

* fix: remove duplicate nearby stats sync label

* fix: lyra and lyra extended home menu icon alignment

* feat: allow selecting a custom sleep folder (#227)

* feat: allow selecting a custom sleep folder

* feat: reapply tiled grayscale row-band rendering on X3

Re-applies the X3 row-band grayscale work that was temporarily reverted in
06ef4ca, now that open-x4-sdk is on 26648d6 (which includes the #13 row-band
plane streaming the path depends on).

Restores the strip render pipeline end to end:
- GfxRenderer strip target (beginStripTarget/endStripTarget, getWriteTarget/
  getWriteOriginY/getWriteRows), real glyphIntersectsStrip, and
  writeGrayscalePlaneStrip/supportsStripGrayscale
- HalDisplay passthrough to EInkDisplay
- DirectPixelWriter band-clipping writePixel
- EpubReaderActivity tiled grayscale pass, gated on supportsStripGrayscale with
  a BW-snapshot fallback when unsupported or under memory pressure

Also drops the temporary glyphIntersectsStrip stub that kept call sites
compiling while the feature was reverted.

Builds for the simulator. Needs on-device X3 verification that the current SDK
AA path is fast enough and that grayscale image pages render without banding.

* feat: skip loading popup for cached EPUB opens

* feat: add more reading stats for X3 and add minimal stats sleep screen

* fix: correct minimal stats streak wording

* feat: add global stats backup

* fix: add explicit error when syncing with older version of crossink

* feat: update web interface and improve development workflow

* feat: add dark reader mode

* docs: minor formatting update to readme

* fix: localize minimal stats streak label

* fix: reposition stats and swap 'new reader' icon

* fix: alignment and spacing fixes

* fix: adjust reading stats padding again

* feat: improve rendering of controls menu

* feat: improve rendering of display menu

* feat: improve rendering of reader menu

* fix: reduce emoji coverage to more popular ones to reduce firmware size

* feat: add hebrew support to UI fonts

* fix: invert tilt-page-turn confirmation pop up in dark mode

* fix: gate minimal stats to x3 devices only

* fix: align book time-left with displayed progress

* feat: show reader font sizes as point sizes

* fix: tighten reading pace sample cutoff

* fix: filter out reading pace samples greater than twice the average

* fix: german translation for STR_INVERTED (crosspoint-reader#2269)

* fix(epub): decode percent-encoded internal asset paths so assets render correctly (crosspoint-reader#2249)

* **What is the goal of this PR?**
* Fix EPUBs where internal file references are written in URL-style
escaped form, like spaces appearing as `%20`, so the reader can find the
right files instead of treating those references as missing.
* **What changes are included?**
* Added a small shared helper that converts those escaped EPUB-internal
paths back into their normal filenames before we try to look them up.
* Applied that cleanup step across the EPUB parsing flow wherever we
resolve internal references, including cover images, manifest items, TOC
links, spine entries, and inline HTML images.
* Kept the change narrowly focused on EPUB-internal asset resolution
rather than changing broader URL or networking behavior.

* The user-facing bug here is that some books package their internal
filenames in an escaped form, so a file like `Chapter 1.xhtml` may be
referenced more like `Chapter%201.xhtml`. The reader was treating that
escaped text as the literal filename, which means otherwise-valid books
could lose images, covers, or chapter targets because the lookup no
longer matched the real file inside the EPUB.
* Risk is intentionally low. The helper only rewrites valid `%XX` escape
sequences and leaves malformed input alone, so it should improve
compatibility with escaped filenames without broadening the parser’s
behavior in unrelated cases.
* This was tested on my device with the user-provided optimized epub
that was not rendering images within the text prior to this fix (cover
image and chapter headers were rendering fine):

[orv_main_baseline.epub.zip](https://github.com/user-attachments/files/28529545/orv_main_baseline.epub.zip)
* This was also tested by the user with a local build and the affected
epub and confirmed to be working
* Try to open the affected epub (linked above) or any epub that has
similar percent-encoding on a build prior to this fix.
* Apply this fix, clear book cache, and re-open the affected book.
* Images should render properly.
---

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 >**_

* fix(epub): decode footnote href path before spine lookup (crosspoint-reader#2271)

* docs: changelog cleanups

* fix: clarify global reading stats backup label

* feat: add dark mode shortcut actions

* fix: prefer pace for epub book time-left

* docs: readme cleanup

* fix: free font catalog before SD font downloads; fixes #236

* fix: honor inverted side-button navigation in reader menus; fixes #235

* feat: improve calculations for reading time left

* feat: reorganize reading stats backup settings
feat: add all-time stats reset action

* feat: add new menu and settings for reading stats including idle time threshold and reset all-time stats

* fix: add missing translations for minimal stats sleep screen reader type and reading streak

* fix: release SD fonts before wifi activities and release wifi memory on cancelled selection

* fix: clean up preserved cache return condition

* fix: invert quick resume markers in dark mode

* fix: sync quick resume timeout from sleep screen picker

* fix: replace crosspoint versions with crossink's

* fix: update German translations

Co-authored-by: Robert Janus<hallo@robertjanus.de>

* fix: translate minimal home button labels

* fix: use versioned s3 font downloads

* fix: preserve heading alignment after inline images

* fix: update spanish translations

Co-authored-by: PlatinumPOST <PlatinumPOST@users.noreply.github.com>

* fix: update translations for nearby stats sync

* docs: update agents.md

* fix: add missing translations for 'quick return from footnotes'

* fix: show quick return from footnotes setting in web controls

* docs: update readme

* fix: invert clock settings

* fix: stop book settings back button from skipping submenus

* feat: long-press menu from home screen to swap between most recently open book (single cover themes)

* fix: preview png files from file browser #251

* fix: generate sleep covers on demand #252

* feat: add custom device name; feat: hide OS metadata in file browser

* feat: add additional shortcut options #222

* fix: close hal files under storage lock

* fix: refresh carousel cache for dynamic home icons

* fix: png page overlays causing long re-indexing #255

* feat: add noto sans regular

* chore: merge upstream crosspoint

* fix: preserve reading stats when clearing cache #253

* fix: clean up KOReader sync failure return #257

* fix: update font download sources

* chore: bump version

* feat: lower long-press threshold to 200ms

* fix: guard file browser loads under low memory

* docs: update docs to reference optimizations

* fix: move boot order back

* fix: use current screen for page overlay sleep background #260

* fix: add confirmation screen before clearing bookmark list

* docs: update controls documentation

* fix: resolve downloadable sd font sources

* fix: prevent grayscale pass for page overlay images

* fix: namespace CrossInk settings file

* fix(koreader): resolve element XPath progress against visible body text (#261)

* fix: handle KOReader element XPath offsets closes crosspoint-reader#2307
* fix(koreader): ignore non-body text when resolving xpath progress
* fix: tighten KOReader anchor id parsing

* feat: add setting to hide file extension #248

* feat: add file browser display row setting

* fix: date overlapping the clock in roundedraff

* fix: show remove read books setting in files cache

* Update release catalog for v1.3.2

* fix: migrate epub state when moving finished books

* ci: sign release catalog commits

* fix: lower roundedraff's battery icon #263

* fix: consume release after reader long-press shortcuts #265

* fix: redraw carousel header after restoring cached frames

* fix: suppress back release from reader settings screens

* fix: suppress back release from reader settings screens
* fix: avoid stale back suppression after font errors

* feat: index large file browser folders on SD

Co-authored-by: zgredex <112968378+zgredex@users.noreply.github.com>

* fix(i18n): localize home empty-state strings (crosspoint-reader#2342)

* fix: avoid oversized web multi-delete requests (fixes #269)

* fix: improve handling of invisible codepoints

* feat: add first pass for clipping support

* fix: anchor clipping highlights to text after relayout

* fix: clean clipping preview text
feat: add timestamps to X3 clipping exports

* ci: update release workflow for catalog publishing

* fix: swap reader menu navigation direction in CCW/inverted (crosspoint-reader#2321) (crosspoint-reader#2341)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: add missing HTML 4.01 named entities (crosspoint-reader#2352)

Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>

* fix(koreader): resolve element XPath progress against visible body text (crosspoint-reader#2308)

* fix: Ukrainian translation (crosspoint-reader#2354)

Co-authored-by: KymAndriy <test@notamail.ua>

* fix: lower memory guard to what jpeg decoder actually needs

* fix: preserve EPUB position across font-size reindex

* fix: add epub compatibility mode that falls back to upstream's parsing methods

* Add grayscale preconditioning for e-ink displays

Implements OEM-style settle pass between BW base frame and grayscale planes for X3 displays. The preconditioning can be applied to the full frame or windowed to a specific region in logical coordinates, which are then rotated to physical panel coordinates. This prevents particles from being set too firmly by the base refresh, allowing the weak X3 grayscale waveform to move them properly. No-op on X4 displays.

* Add displayGrayscaleBase method for differential refresh

Introduces a new display method that prepares the framebuffer as a base frame for grayscale overlays. On X3 panels, this uses the OEM differential base waveform (AA-pre-BW) without forcing a resync. Other panels fall back to normal display with configurable refresh mode.

* update sdk

* fix: regenerate fonts to handle strange codepoints

* fix: avoid overlapping Calibre transfer status

* feat: save EPUB reader settings per book

* fix: prewarm SD fonts for clipping selection

* feat: new in-reader menu

* fix: improve reader menu tab focus state

* fix: exit reader menu from focused tab row

* fix: align clipping highlights with SD font advances

* fix: enable Shift key for URL keyboard input (crosspoint-reader#2178) (crosspoint-reader#2357)

* feat: add drag-and-drop to upload modal (crosspoint-reader#2290)

Co-authored-by: Julia <julia@uxj.io>

* feat: long-press Confirm launches KOReader sync from EPUB (crosspoint-reader#1808)

## Summary
- Hold the menu (Confirm) button for ≥1s while reading an EPUB to launch
the existing `KOReaderSyncActivity` directly — replaces the three-step
path (open reader menu → scroll to Sync → confirm) with a single
gesture.
- Reuses `ReaderUtils::GO_HOME_MS` (same 1s threshold used by long-press
Back) and the existing `KOREADER_STORE.hasCredentials()` guard.
- Adds a Controls picker **"Long-press Menu"** (`longPressMenuFunction`,
default **Bookmark**) that **cycles through the available functions**
bound to the long-press gesture: `KOSync → Disabled → Bookmark`. The
field name and `LONG_PRESS_MENU_FUNCTION` enum are intentionally general
so future actions (dictionary lookup, table of contents, etc.) can be
appended without another schema migration. The setting is **not** a
binary toggle.
- Existing menu Sync entry still works — both call sites share one
extracted helper (`launchKOReaderSync`); no logic duplication.
- Short-press Confirm release is gated on duration so the reader menu
does not also open after a long press that *acts*, mirroring the
existing long-press Back pattern.
- **No-credentials fall-through:** `launchKOReaderSync()` now returns
whether it acted. When the function is set to KOSync but no KOReader
credentials are stored, the long-press is a no-op that **falls through
to open the reader menu** — so the menu stays reachable instead of the
hold silently swallowing the gesture. The release is only suppressed
when sync actually launched or surfaced a save error.

## Test plan
- [x] `pio run` succeeds clean for the `default` ESP32-C3 environment.
- [x] On-device, value **KOSync**, valid KOReader credentials:
long-press Confirm ≥1s → sync screen launches; get + update progress
return HTTP 200; release does **not** also open the reader menu; returns
to the same page.
- [x] On-device, value **KOSync**, **no** credentials: long-press
Confirm falls through and **opens the reader menu** (regression fix);
short-press also opens the menu.
- [x] On-device: menu → Sync still launches the same screen (shared
helper) and syncs (200/200).
- [x] On-device, value **Bookmark**: long-press drops a bookmark and
does **not** also open the menu.
- [x] On-device, value **Disabled**: long-press Confirm opens the menu
on release; no sync, no bookmark.
- [x] On-device: long-press Back still goes to the file browser
(unchanged path).
- [x] Heap: epub is released before the TLS handshake (frees ~16 KB);
min free heap stayed ~84 KB during sync, well above the safe floor. No
panics/OOM across the session.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: Support for Korean line breaks and glyph spacing (crosspoint-reader#2288)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: protect incompatible reading stats files

* chore: update docs for clippings/highlights

* fix(i18n): localize home empty-state strings (crosspoint-reader#2342)

* fix: add missing HTML 4.01 named entities (crosspoint-reader#2352)

Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>

* fix: enable Shift key for URL keyboard input (crosspoint-reader#2178) (crosspoint-reader#2357)

* feat: add drag-and-drop to upload modal (crosspoint-reader#2290)

Co-authored-by: Julia <julia@uxj.io>

* feat: Support for Korean line breaks and glyph spacing (crosspoint-reader#2288)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: persist reader time-left estimates for home stats

* fix: prepare SD font metrics for clipping selection

* fix: add stats.bin migration flow

* fix: clippings not highlighting correctly with SD card fonts

* fix: remove unlabeled clipping page number

* fix: keep txt reader open at file boundary

* feat: apply inverted filter to generated sleep screens

* fix: move roundedraff clock down on home screen

* fix: cppchecks

* fix: export clippings with selected page number

* v1.3.4 (#284)

* fix: suppress back release from reader settings screens

* fix: suppress back release from reader settings screens
* fix: avoid stale back suppression after font errors

* feat: index large file browser folders on SD

Co-authored-by: zgredex <112968378+zgredex@users.noreply.github.com>

* fix(i18n): localize home empty-state strings (crosspoint-reader#2342)

* fix: avoid oversized web multi-delete requests (fixes #269)

* fix: improve handling of invisible codepoints

* feat: add first pass for clipping support

* fix: anchor clipping highlights to text after relayout

* fix: clean clipping preview text
feat: add timestamps to X3 clipping exports

* ci: update release workflow for catalog publishing

* fix: swap reader menu navigation direction in CCW/inverted (crosspoint-reader#2321) (crosspoint-reader#2341)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: add missing HTML 4.01 named entities (crosspoint-reader#2352)

Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>

* fix(koreader): resolve element XPath progress against visible body text (crosspoint-reader#2308)

* fix: Ukrainian translation (crosspoint-reader#2354)

Co-authored-by: KymAndriy <test@notamail.ua>

* fix: lower memory guard to what jpeg decoder actually needs

* fix: preserve EPUB position across font-size reindex

* fix: add epub compatibility mode that falls back to upstream's parsing methods

* Add grayscale preconditioning for e-ink displays

Implements OEM-style settle pass between BW base frame and grayscale planes for X3 displays. The preconditioning can be applied to the full frame or windowed to a specific region in logical coordinates, which are then rotated to physical panel coordinates. This prevents particles from being set too firmly by the base refresh, allowing the weak X3 grayscale waveform to move them properly. No-op on X4 displays.

* Add displayGrayscaleBase method for differential refresh

Introduces a new display method that prepares the framebuffer as a base frame for grayscale overlays. On X3 panels, this uses the OEM differential base waveform (AA-pre-BW) without forcing a resync. Other panels fall back to normal display with configurable refresh mode.

* update sdk

* fix: regenerate fonts to handle strange codepoints

* fix: avoid overlapping Calibre transfer status

* feat: save EPUB reader settings per book

* fix: prewarm SD fonts for clipping selection

* feat: new in-reader menu

* fix: improve reader menu tab focus state

* fix: exit reader menu from focused tab row

* fix: align clipping highlights with SD font advances

* fix: enable Shift key for URL keyboard input (crosspoint-reader#2178) (crosspoint-reader#2357)

* feat: add drag-and-drop to upload modal (crosspoint-reader#2290)

Co-authored-by: Julia <julia@uxj.io>

* feat: long-press Confirm launches KOReader sync from EPUB (crosspoint-reader#1808)

## Summary
- Hold the menu (Confirm) button for ≥1s while reading an EPUB to launch
the existing `KOReaderSyncActivity` directly — replaces the three-step
path (open reader menu → scroll to Sync → confirm) with a single
gesture.
- Reuses `ReaderUtils::GO_HOME_MS` (same 1s threshold used by long-press
Back) and the existing `KOREADER_STORE.hasCredentials()` guard.
- Adds a Controls picker **"Long-press Menu"** (`longPressMenuFunction`,
default **Bookmark**) that **cycles through the available functions**
bound to the long-press gesture: `KOSync → Disabled → Bookmark`. The
field name and `LONG_PRESS_MENU_FUNCTION` enum are intentionally general
so future actions (dictionary lookup, table of contents, etc.) can be
appended without another schema migration. The setting is **not** a
binary toggle.
- Existing menu Sync entry still works — both call sites share one
extracted helper (`launchKOReaderSync`); no logic duplication.
- Short-press Confirm release is gated on duration so the reader menu
does not also open after a long press that *acts*, mirroring the
existing long-press Back pattern.
- **No-credentials fall-through:** `launchKOReaderSync()` now returns
whether it acted. When the function is set to KOSync but no KOReader
credentials are stored, the long-press is a no-op that **falls through
to open the reader menu** — so the menu stays reachable instead of the
hold silently swallowing the gesture. The release is only suppressed
when sync actually launched or surfaced a save error.

## Test plan
- [x] `pio run` succeeds clean for the `default` ESP32-C3 environment.
- [x] On-device, value **KOSync**, valid KOReader credentials:
long-press Confirm ≥1s → sync screen launches; get + update progress
return HTTP 200; release does **not** also open the reader menu; returns
to the same page.
- [x] On-device, value **KOSync**, **no** credentials: long-press
Confirm falls through and **opens the reader menu** (regression fix);
short-press also opens the menu.
- [x] On-device: menu → Sync still launches the same screen (shared
helper) and syncs (200/200).
- [x] On-device, value **Bookmark**: long-press drops a bookmark and
does **not** also open the menu.
- [x] On-device, value **Disabled**: long-press Confirm opens the menu
on release; no sync, no bookmark.
- [x] On-device: long-press Back still goes to the file browser
(unchanged path).
- [x] Heap: epub is released before the TLS handshake (frees ~16 KB);
min free heap stayed ~84 KB during sync, well above the safe floor. No
panics/OOM across the session.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: Support for Korean line breaks and glyph spacing (crosspoint-reader#2288)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: protect incompatible reading stats files

* chore: update docs for clippings/highlights

* fix(i18n): localize home empty-state strings (crosspoint-reader#2342)

* fix: add missing HTML 4.01 named entities (crosspoint-reader#2352)

Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>

* fix: enable Shift key for URL keyboard input (crosspoint-reader#2178) (crosspoint-reader#2357)

* feat: add drag-and-drop to upload modal (crosspoint-reader#2290)

Co-authored-by: Julia <julia@uxj.io>

* feat: Support for Korean line breaks and glyph spacing (crosspoint-reader#2288)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: persist reader time-left estimates for home stats

* fix: prepare SD font metrics for clipping selection

* fix: add stats.bin migration flow

* fix: clippings not highlighting correctly with SD card fonts

* fix: remove unlabeled clipping page number

* fix: keep txt reader open at file boundary

* feat: apply inverted filter to generated sleep screens

* fix: move roundedraff clock down on home screen

* fix: cppchecks

* fix: export clippings with selected page number

---------

Co-authored-by: zgredex <112968378+zgredex@users.noreply.github.com>
Co-authored-by: Mauvis Ledford <switchstatement@gmail.com>
Co-authored-by: Ronin <6971304+TheCyberRonin@users.noreply.github.com>
Co-authored-by: Uri Tauber <uritaube@gmail.com>
Co-authored-by: rafaelmsse <rafaelmsse@gmail.com>
Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>
Co-authored-by: KymAndriy <32357131+KymAndriy@users.noreply.github.com>
Co-authored-by: KymAndriy <test@notamail.ua>
Co-authored-by: Justin Mitchell <justin@jmitch.com>
Co-authored-by: Ankit <iankit17@gmail.com>
Co-authored-by: darkbublu <davidcyprianhicks@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: guide dots not showing up when bionic reading was on
fix: custom settings not loading correctly

* feat: add new EPUB rendering mode and fallback method

* fix: start clock UTC offset picker on the sign field

* fix: back button when viewing clippings goes back to menu as expected

* fix: render clipping highlights across pages when layout changes

* ci: remove no_emoji builds

* fix: add Portuguese hyphenation support

* feat: preserve epub publisher spacing

* fix: preserve css during epub fallback layout

* feat: serve OTA firmware from stable S3 manifest

* fix: stream OTA updates and verify sha-256 hash

* fix: route no_emoji OTA updates to tiny

* fix: reduce epub conversion heap pressure

* fix: revert rendering publisher's line-height settings

* fix: smooth progressive JPEG cover BMP upscales

* fix: refine progressive cover smoothing gate

* chore: update version

* feat: add CrossInk EPUB location metadata

* wire in crossink-locations.json

* feat: add stable epub reference pages

* chore(release): prepare v1.3.4

* fix: update tilt page turn labels

* fix: remove no_emoji references

* feat: add create clipping reader shortcuts

* fix: set sd file timestamps from x3 rtc

* fix(epub): NFC-normalize EPUB text so NFD diacritics render correctly (crosspoint-reader#2277)

Co-authored-by: Uri Tauber <uritaube@gmail.com>
Co-authored-by: Julia <julia@uxj.io>

* feat: add live font preview pane to font selection screen (crosspoint-reader#2349)
* Adds a live font preview pane to the font selection screen so users
can see how a font looks before committing to it.
* Changes
* A preview pane occupying the top 30% of the font selection screen,
rendering sample pangram text in the previewed font
* A two-step confirm flow: first press (enter button) previews the font,
second press selects it
* Back restores the original font settings, so browsing has no side
effects
* Layout dimensions cached in `onEnter()` to avoid redundant
recalculation between `loop()` and `render()`
* Preview sample text is hardcoded English; didn't want to use AI for
translation as I would not be able to verify the output in most
languages...
* The preview pane reduces visible list height; this is compensated by
passing the reserved height into `getNumberOfItemsPerPage`

---
Did you use AI tools to help write this code? **PARTIALLY**
AI use for assisting in coding and in writing the PR description.

* feat: add Spacing Modifier Letters range to font presets (crosspoint-reader#2194)

* fix: don't justify-stretch a leading no-break space (crosspoint-reader#2185) (crosspoint-reader#2298)

* fix: update generated location filename

* fix: epub crashes while indexing with bionic reading on

* fix: use epub render fallbacks for silent indexing and avoid null final page serialization

* fix: constrain EPUB clipping highlights

* fix: handle sync long-press select release

* fix: add guidance for bionic/guide dots during memory pressure

* fix: preserve authored hyphens in clipping text

* fix: align reader menu icons with orientation

* fix: reduce epub layout buffering for reading aids

* fix: avoid home cover refresh oom crash

* update sdk

* fix: preserve clipping highlights after relayout

* fix: in-reader menu icons

* fix: keep clipping highlights complete after font relayout

* fix: reduce epub reading aid layout tokens

* feat: add chained slab arena allocator

* perf: wire parse arena into EPUB chapter style stacks

Replace std::vector inlineStyleStack and blockStyleStack in
ChapterHtmlSlimParser with arena-backed fixed-size arrays allocated
from parseArena_ at the start of each chapter parse. The arena is
initialized once, used for the full parse, then released in one
shot instead of per-object frees.

* fix: use arena inline style stack for table labels

* fix: use arena scratch buffers for epub layout

* chore: update changelog

* fix: add epub safe mode fallback

* fix: bound epub footnote preview indexing

* fix(epub): flush displaced anchor before overwrite (crosspoint-reader#2336) (crosspoint-reader#2382)

* **What is the goal of this PR?** (e.g., Implements the new feature for
file uploading.)

Fixes footnote links landing in start section instead of the specific
foot note target.

* **What changes are included?**

ChapterHtmlSlimParser.cpp: call flushPendingAnchor() before overwriting
pendingAnchorId. First id got lost due to consecutive non-block elements
carry ids, the first id was lost and the reader had no page to jump to,
so it defaulted to page 0.

Tested with the epubs attached to to crosspoint-reader#2336. Need to clear .crosspoint/
cache after flashing so the anchor map gets rebuilt with the fix.

* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks,
  specific areas to focus on).

---

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 assisted with writing documentation.

* feat: footnote returns to original position on deep sleep to avoid losing reading position (crosspoint-reader#2394)

* chore(release): prepare v1.3.4

* fix: report EPUB clipping save failures

* fix: allow long EPUB section LUT growth and preserve section LUT low-memory fallback signal

---------

Co-authored-by: Uri Tauber <uritaube@gmail.com>
Co-authored-by: PlatinumPOST <PlatinumPOST@users.noreply.github.com>
Co-authored-by: zgredex <112968378+zgredex@users.noreply.github.com>
Co-authored-by: Mauvis Ledford <switchstatement@gmail.com>
Co-authored-by: Ronin <6971304+TheCyberRonin@users.noreply.github.com>
Co-authored-by: rafaelmsse <rafaelmsse@gmail.com>
Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>
Co-authored-by: KymAndriy <32357131+KymAndriy@users.noreply.github.com>
Co-authored-by: KymAndriy <test@notamail.ua>
Co-authored-by: Justin Mitchell <justin@jmitch.com>
Co-authored-by: Ankit <iankit17@gmail.com>
Co-authored-by: darkbublu <davidcyprianhicks@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: gershalfred <gersh.alfred@gmail.com>
Co-authored-by: Hoang Manh Linh <jetaudio.media@gmail.com>
Co-authored-by: Paul Delestrac <40175004+PaulDelestrac@users.noreply.github.com>
Co-authored-by: SurprisedDuck <jannik.theiss@googlemail.com>
Co-authored-by: kygia <hi@kygiaha.com>
Co-authored-by: Zeph <cloudedsprite@gmail.com>
uxjulia added a commit that referenced this pull request Jun 25, 2026
* fix: correct Vietnamese i18n string offsets

* fix: add missing settings menu translations

* fix: inaccurate KOReader sync when syncing at chapter start

* fix: automatically attempt to sync clock

* fix: stop counting backward page turns in reading stats

* fix: only count page turns after 2 seconds

* feat: display date for x3

* fix: recover bookmarks from legacy epub hash filenames

* chore: bump version

* fix: add more explicit KOReader sync error messaging

* fix: improve book time-left estimates after quick navigations

* fix: remove 'Go to Home' from in-reader menu

* fix: make clock and battery top padding consistent

* fix: remove duplicate nearby stats sync label

* fix: lyra and lyra extended home menu icon alignment

* feat: allow selecting a custom sleep folder (#227)

* feat: allow selecting a custom sleep folder

* feat: reapply tiled grayscale row-band rendering on X3

Re-applies the X3 row-band grayscale work that was temporarily reverted in
06ef4ca, now that open-x4-sdk is on 26648d6 (which includes the #13 row-band
plane streaming the path depends on).

Restores the strip render pipeline end to end:
- GfxRenderer strip target (beginStripTarget/endStripTarget, getWriteTarget/
  getWriteOriginY/getWriteRows), real glyphIntersectsStrip, and
  writeGrayscalePlaneStrip/supportsStripGrayscale
- HalDisplay passthrough to EInkDisplay
- DirectPixelWriter band-clipping writePixel
- EpubReaderActivity tiled grayscale pass, gated on supportsStripGrayscale with
  a BW-snapshot fallback when unsupported or under memory pressure

Also drops the temporary glyphIntersectsStrip stub that kept call sites
compiling while the feature was reverted.

Builds for the simulator. Needs on-device X3 verification that the current SDK
AA path is fast enough and that grayscale image pages render without banding.

* feat: skip loading popup for cached EPUB opens

* feat: add more reading stats for X3 and add minimal stats sleep screen

* fix: correct minimal stats streak wording

* feat: add global stats backup

* fix: add explicit error when syncing with older version of crossink

* feat: update web interface and improve development workflow

* feat: add dark reader mode

* docs: minor formatting update to readme

* fix: localize minimal stats streak label

* fix: reposition stats and swap 'new reader' icon

* fix: alignment and spacing fixes

* fix: adjust reading stats padding again

* feat: improve rendering of controls menu

* feat: improve rendering of display menu

* feat: improve rendering of reader menu

* fix: reduce emoji coverage to more popular ones to reduce firmware size

* feat: add hebrew support to UI fonts

* fix: invert tilt-page-turn confirmation pop up in dark mode

* fix: gate minimal stats to x3 devices only

* fix: align book time-left with displayed progress

* feat: show reader font sizes as point sizes

* fix: tighten reading pace sample cutoff

* fix: filter out reading pace samples greater than twice the average

* fix: german translation for STR_INVERTED (crosspoint-reader#2269)

* fix(epub): decode percent-encoded internal asset paths so assets render correctly (crosspoint-reader#2249)

* **What is the goal of this PR?**
* Fix EPUBs where internal file references are written in URL-style
escaped form, like spaces appearing as `%20`, so the reader can find the
right files instead of treating those references as missing.
* **What changes are included?**
* Added a small shared helper that converts those escaped EPUB-internal
paths back into their normal filenames before we try to look them up.
* Applied that cleanup step across the EPUB parsing flow wherever we
resolve internal references, including cover images, manifest items, TOC
links, spine entries, and inline HTML images.
* Kept the change narrowly focused on EPUB-internal asset resolution
rather than changing broader URL or networking behavior.

* The user-facing bug here is that some books package their internal
filenames in an escaped form, so a file like `Chapter 1.xhtml` may be
referenced more like `Chapter%201.xhtml`. The reader was treating that
escaped text as the literal filename, which means otherwise-valid books
could lose images, covers, or chapter targets because the lookup no
longer matched the real file inside the EPUB.
* Risk is intentionally low. The helper only rewrites valid `%XX` escape
sequences and leaves malformed input alone, so it should improve
compatibility with escaped filenames without broadening the parser’s
behavior in unrelated cases.
* This was tested on my device with the user-provided optimized epub
that was not rendering images within the text prior to this fix (cover
image and chapter headers were rendering fine):

[orv_main_baseline.epub.zip](https://github.com/user-attachments/files/28529545/orv_main_baseline.epub.zip)
* This was also tested by the user with a local build and the affected
epub and confirmed to be working
* Try to open the affected epub (linked above) or any epub that has
similar percent-encoding on a build prior to this fix.
* Apply this fix, clear book cache, and re-open the affected book.
* Images should render properly.
---

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 >**_

* fix(epub): decode footnote href path before spine lookup (crosspoint-reader#2271)

* docs: changelog cleanups

* fix: clarify global reading stats backup label

* feat: add dark mode shortcut actions

* fix: prefer pace for epub book time-left

* docs: readme cleanup

* fix: free font catalog before SD font downloads; fixes #236

* fix: honor inverted side-button navigation in reader menus; fixes #235

* feat: improve calculations for reading time left

* feat: reorganize reading stats backup settings
feat: add all-time stats reset action

* feat: add new menu and settings for reading stats including idle time threshold and reset all-time stats

* fix: add missing translations for minimal stats sleep screen reader type and reading streak

* fix: release SD fonts before wifi activities and release wifi memory on cancelled selection

* fix: clean up preserved cache return condition

* fix: invert quick resume markers in dark mode

* fix: sync quick resume timeout from sleep screen picker

* fix: replace crosspoint versions with crossink's

* fix: update German translations

Co-authored-by: Robert Janus<hallo@robertjanus.de>

* fix: translate minimal home button labels

* fix: use versioned s3 font downloads

* fix: preserve heading alignment after inline images

* fix: update spanish translations

Co-authored-by: PlatinumPOST <PlatinumPOST@users.noreply.github.com>

* fix: update translations for nearby stats sync

* docs: update agents.md

* fix: add missing translations for 'quick return from footnotes'

* fix: show quick return from footnotes setting in web controls

* docs: update readme

* fix: invert clock settings

* fix: stop book settings back button from skipping submenus

* feat: long-press menu from home screen to swap between most recently open book (single cover themes)

* fix: preview png files from file browser #251

* fix: generate sleep covers on demand #252

* feat: add custom device name; feat: hide OS metadata in file browser

* feat: add additional shortcut options #222

* fix: close hal files under storage lock

* fix: refresh carousel cache for dynamic home icons

* fix: png page overlays causing long re-indexing #255

* feat: add noto sans regular

* chore: merge upstream crosspoint

* fix: preserve reading stats when clearing cache #253

* fix: clean up KOReader sync failure return #257

* fix: update font download sources

* chore: bump version

* feat: lower long-press threshold to 200ms

* fix: guard file browser loads under low memory

* docs: update docs to reference optimizations

* fix: move boot order back

* fix: use current screen for page overlay sleep background #260

* fix: add confirmation screen before clearing bookmark list

* docs: update controls documentation

* fix: resolve downloadable sd font sources

* fix: prevent grayscale pass for page overlay images

* fix: namespace CrossInk settings file

* fix(koreader): resolve element XPath progress against visible body text (#261)

* fix: handle KOReader element XPath offsets closes crosspoint-reader#2307
* fix(koreader): ignore non-body text when resolving xpath progress
* fix: tighten KOReader anchor id parsing

* feat: add setting to hide file extension #248

* feat: add file browser display row setting

* fix: date overlapping the clock in roundedraff

* fix: show remove read books setting in files cache

* Update release catalog for v1.3.2

* fix: migrate epub state when moving finished books

* ci: sign release catalog commits

* fix: lower roundedraff's battery icon #263

* fix: consume release after reader long-press shortcuts #265

* fix: redraw carousel header after restoring cached frames

* fix: suppress back release from reader settings screens

* fix: suppress back release from reader settings screens
* fix: avoid stale back suppression after font errors

* feat: index large file browser folders on SD

Co-authored-by: zgredex <112968378+zgredex@users.noreply.github.com>

* fix(i18n): localize home empty-state strings (crosspoint-reader#2342)

* fix: avoid oversized web multi-delete requests (fixes #269)

* fix: improve handling of invisible codepoints

* feat: add first pass for clipping support

* fix: anchor clipping highlights to text after relayout

* fix: clean clipping preview text
feat: add timestamps to X3 clipping exports

* ci: update release workflow for catalog publishing

* fix: swap reader menu navigation direction in CCW/inverted (crosspoint-reader#2321) (crosspoint-reader#2341)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: add missing HTML 4.01 named entities (crosspoint-reader#2352)

Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>

* fix(koreader): resolve element XPath progress against visible body text (crosspoint-reader#2308)

* fix: Ukrainian translation (crosspoint-reader#2354)

Co-authored-by: KymAndriy <test@notamail.ua>

* fix: lower memory guard to what jpeg decoder actually needs

* fix: preserve EPUB position across font-size reindex

* fix: add epub compatibility mode that falls back to upstream's parsing methods

* Add grayscale preconditioning for e-ink displays

Implements OEM-style settle pass between BW base frame and grayscale planes for X3 displays. The preconditioning can be applied to the full frame or windowed to a specific region in logical coordinates, which are then rotated to physical panel coordinates. This prevents particles from being set too firmly by the base refresh, allowing the weak X3 grayscale waveform to move them properly. No-op on X4 displays.

* Add displayGrayscaleBase method for differential refresh

Introduces a new display method that prepares the framebuffer as a base frame for grayscale overlays. On X3 panels, this uses the OEM differential base waveform (AA-pre-BW) without forcing a resync. Other panels fall back to normal display with configurable refresh mode.

* update sdk

* fix: regenerate fonts to handle strange codepoints

* fix: avoid overlapping Calibre transfer status

* feat: save EPUB reader settings per book

* fix: prewarm SD fonts for clipping selection

* feat: new in-reader menu

* fix: improve reader menu tab focus state

* fix: exit reader menu from focused tab row

* fix: align clipping highlights with SD font advances

* fix: enable Shift key for URL keyboard input (crosspoint-reader#2178) (crosspoint-reader#2357)

* feat: add drag-and-drop to upload modal (crosspoint-reader#2290)

Co-authored-by: Julia <julia@uxj.io>

* feat: long-press Confirm launches KOReader sync from EPUB (crosspoint-reader#1808)

## Summary
- Hold the menu (Confirm) button for ≥1s while reading an EPUB to launch
the existing `KOReaderSyncActivity` directly — replaces the three-step
path (open reader menu → scroll to Sync → confirm) with a single
gesture.
- Reuses `ReaderUtils::GO_HOME_MS` (same 1s threshold used by long-press
Back) and the existing `KOREADER_STORE.hasCredentials()` guard.
- Adds a Controls picker **"Long-press Menu"** (`longPressMenuFunction`,
default **Bookmark**) that **cycles through the available functions**
bound to the long-press gesture: `KOSync → Disabled → Bookmark`. The
field name and `LONG_PRESS_MENU_FUNCTION` enum are intentionally general
so future actions (dictionary lookup, table of contents, etc.) can be
appended without another schema migration. The setting is **not** a
binary toggle.
- Existing menu Sync entry still works — both call sites share one
extracted helper (`launchKOReaderSync`); no logic duplication.
- Short-press Confirm release is gated on duration so the reader menu
does not also open after a long press that *acts*, mirroring the
existing long-press Back pattern.
- **No-credentials fall-through:** `launchKOReaderSync()` now returns
whether it acted. When the function is set to KOSync but no KOReader
credentials are stored, the long-press is a no-op that **falls through
to open the reader menu** — so the menu stays reachable instead of the
hold silently swallowing the gesture. The release is only suppressed
when sync actually launched or surfaced a save error.

## Test plan
- [x] `pio run` succeeds clean for the `default` ESP32-C3 environment.
- [x] On-device, value **KOSync**, valid KOReader credentials:
long-press Confirm ≥1s → sync screen launches; get + update progress
return HTTP 200; release does **not** also open the reader menu; returns
to the same page.
- [x] On-device, value **KOSync**, **no** credentials: long-press
Confirm falls through and **opens the reader menu** (regression fix);
short-press also opens the menu.
- [x] On-device: menu → Sync still launches the same screen (shared
helper) and syncs (200/200).
- [x] On-device, value **Bookmark**: long-press drops a bookmark and
does **not** also open the menu.
- [x] On-device, value **Disabled**: long-press Confirm opens the menu
on release; no sync, no bookmark.
- [x] On-device: long-press Back still goes to the file browser
(unchanged path).
- [x] Heap: epub is released before the TLS handshake (frees ~16 KB);
min free heap stayed ~84 KB during sync, well above the safe floor. No
panics/OOM across the session.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: Support for Korean line breaks and glyph spacing (crosspoint-reader#2288)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: protect incompatible reading stats files

* chore: update docs for clippings/highlights

* fix(i18n): localize home empty-state strings (crosspoint-reader#2342)

* fix: add missing HTML 4.01 named entities (crosspoint-reader#2352)

Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>

* fix: enable Shift key for URL keyboard input (crosspoint-reader#2178) (crosspoint-reader#2357)

* feat: add drag-and-drop to upload modal (crosspoint-reader#2290)

Co-authored-by: Julia <julia@uxj.io>

* feat: Support for Korean line breaks and glyph spacing (crosspoint-reader#2288)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: persist reader time-left estimates for home stats

* fix: prepare SD font metrics for clipping selection

* fix: add stats.bin migration flow

* fix: clippings not highlighting correctly with SD card fonts

* fix: remove unlabeled clipping page number

* fix: keep txt reader open at file boundary

* feat: apply inverted filter to generated sleep screens

* fix: move roundedraff clock down on home screen

* fix: cppchecks

* fix: export clippings with selected page number

* v1.3.4 (#284)

* fix: suppress back release from reader settings screens

* fix: suppress back release from reader settings screens
* fix: avoid stale back suppression after font errors

* feat: index large file browser folders on SD

Co-authored-by: zgredex <112968378+zgredex@users.noreply.github.com>

* fix(i18n): localize home empty-state strings (crosspoint-reader#2342)

* fix: avoid oversized web multi-delete requests (fixes #269)

* fix: improve handling of invisible codepoints

* feat: add first pass for clipping support

* fix: anchor clipping highlights to text after relayout

* fix: clean clipping preview text
feat: add timestamps to X3 clipping exports

* ci: update release workflow for catalog publishing

* fix: swap reader menu navigation direction in CCW/inverted (crosspoint-reader#2321) (crosspoint-reader#2341)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: add missing HTML 4.01 named entities (crosspoint-reader#2352)

Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>

* fix(koreader): resolve element XPath progress against visible body text (crosspoint-reader#2308)

* fix: Ukrainian translation (crosspoint-reader#2354)

Co-authored-by: KymAndriy <test@notamail.ua>

* fix: lower memory guard to what jpeg decoder actually needs

* fix: preserve EPUB position across font-size reindex

* fix: add epub compatibility mode that falls back to upstream's parsing methods

* Add grayscale preconditioning for e-ink displays

Implements OEM-style settle pass between BW base frame and grayscale planes for X3 displays. The preconditioning can be applied to the full frame or windowed to a specific region in logical coordinates, which are then rotated to physical panel coordinates. This prevents particles from being set too firmly by the base refresh, allowing the weak X3 grayscale waveform to move them properly. No-op on X4 displays.

* Add displayGrayscaleBase method for differential refresh

Introduces a new display method that prepares the framebuffer as a base frame for grayscale overlays. On X3 panels, this uses the OEM differential base waveform (AA-pre-BW) without forcing a resync. Other panels fall back to normal display with configurable refresh mode.

* update sdk

* fix: regenerate fonts to handle strange codepoints

* fix: avoid overlapping Calibre transfer status

* feat: save EPUB reader settings per book

* fix: prewarm SD fonts for clipping selection

* feat: new in-reader menu

* fix: improve reader menu tab focus state

* fix: exit reader menu from focused tab row

* fix: align clipping highlights with SD font advances

* fix: enable Shift key for URL keyboard input (crosspoint-reader#2178) (crosspoint-reader#2357)

* feat: add drag-and-drop to upload modal (crosspoint-reader#2290)

Co-authored-by: Julia <julia@uxj.io>

* feat: long-press Confirm launches KOReader sync from EPUB (crosspoint-reader#1808)

## Summary
- Hold the menu (Confirm) button for ≥1s while reading an EPUB to launch
the existing `KOReaderSyncActivity` directly — replaces the three-step
path (open reader menu → scroll to Sync → confirm) with a single
gesture.
- Reuses `ReaderUtils::GO_HOME_MS` (same 1s threshold used by long-press
Back) and the existing `KOREADER_STORE.hasCredentials()` guard.
- Adds a Controls picker **"Long-press Menu"** (`longPressMenuFunction`,
default **Bookmark**) that **cycles through the available functions**
bound to the long-press gesture: `KOSync → Disabled → Bookmark`. The
field name and `LONG_PRESS_MENU_FUNCTION` enum are intentionally general
so future actions (dictionary lookup, table of contents, etc.) can be
appended without another schema migration. The setting is **not** a
binary toggle.
- Existing menu Sync entry still works — both call sites share one
extracted helper (`launchKOReaderSync`); no logic duplication.
- Short-press Confirm release is gated on duration so the reader menu
does not also open after a long press that *acts*, mirroring the
existing long-press Back pattern.
- **No-credentials fall-through:** `launchKOReaderSync()` now returns
whether it acted. When the function is set to KOSync but no KOReader
credentials are stored, the long-press is a no-op that **falls through
to open the reader menu** — so the menu stays reachable instead of the
hold silently swallowing the gesture. The release is only suppressed
when sync actually launched or surfaced a save error.

## Test plan
- [x] `pio run` succeeds clean for the `default` ESP32-C3 environment.
- [x] On-device, value **KOSync**, valid KOReader credentials:
long-press Confirm ≥1s → sync screen launches; get + update progress
return HTTP 200; release does **not** also open the reader menu; returns
to the same page.
- [x] On-device, value **KOSync**, **no** credentials: long-press
Confirm falls through and **opens the reader menu** (regression fix);
short-press also opens the menu.
- [x] On-device: menu → Sync still launches the same screen (shared
helper) and syncs (200/200).
- [x] On-device, value **Bookmark**: long-press drops a bookmark and
does **not** also open the menu.
- [x] On-device, value **Disabled**: long-press Confirm opens the menu
on release; no sync, no bookmark.
- [x] On-device: long-press Back still goes to the file browser
(unchanged path).
- [x] Heap: epub is released before the TLS handshake (frees ~16 KB);
min free heap stayed ~84 KB during sync, well above the safe floor. No
panics/OOM across the session.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: Support for Korean line breaks and glyph spacing (crosspoint-reader#2288)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: protect incompatible reading stats files

* chore: update docs for clippings/highlights

* fix(i18n): localize home empty-state strings (crosspoint-reader#2342)

* fix: add missing HTML 4.01 named entities (crosspoint-reader#2352)

Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>

* fix: enable Shift key for URL keyboard input (crosspoint-reader#2178) (crosspoint-reader#2357)

* feat: add drag-and-drop to upload modal (crosspoint-reader#2290)

Co-authored-by: Julia <julia@uxj.io>

* feat: Support for Korean line breaks and glyph spacing (crosspoint-reader#2288)

Co-authored-by: Uri Tauber <uritaube@gmail.com>

* fix: persist reader time-left estimates for home stats

* fix: prepare SD font metrics for clipping selection

* fix: add stats.bin migration flow

* fix: clippings not highlighting correctly with SD card fonts

* fix: remove unlabeled clipping page number

* fix: keep txt reader open at file boundary

* feat: apply inverted filter to generated sleep screens

* fix: move roundedraff clock down on home screen

* fix: cppchecks

* fix: export clippings with selected page number

---------

Co-authored-by: zgredex <112968378+zgredex@users.noreply.github.com>
Co-authored-by: Mauvis Ledford <switchstatement@gmail.com>
Co-authored-by: Ronin <6971304+TheCyberRonin@users.noreply.github.com>
Co-authored-by: Uri Tauber <uritaube@gmail.com>
Co-authored-by: rafaelmsse <rafaelmsse@gmail.com>
Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>
Co-authored-by: KymAndriy <32357131+KymAndriy@users.noreply.github.com>
Co-authored-by: KymAndriy <test@notamail.ua>
Co-authored-by: Justin Mitchell <justin@jmitch.com>
Co-authored-by: Ankit <iankit17@gmail.com>
Co-authored-by: darkbublu <davidcyprianhicks@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: guide dots not showing up when bionic reading was on
fix: custom settings not loading correctly

* feat: add new EPUB rendering mode and fallback method

* fix: start clock UTC offset picker on the sign field

* fix: back button when viewing clippings goes back to menu as expected

* fix: render clipping highlights across pages when layout changes

* ci: remove no_emoji builds

* fix: add Portuguese hyphenation support

* feat: preserve epub publisher spacing

* fix: preserve css during epub fallback layout

* feat: serve OTA firmware from stable S3 manifest

* fix: stream OTA updates and verify sha-256 hash

* fix: route no_emoji OTA updates to tiny

* fix: reduce epub conversion heap pressure

* fix: revert rendering publisher's line-height settings

* fix: smooth progressive JPEG cover BMP upscales

* fix: refine progressive cover smoothing gate

* chore: update version

* feat: add CrossInk EPUB location metadata

* wire in crossink-locations.json

* feat: add stable epub reference pages

* chore(release): prepare v1.3.4

* fix: update tilt page turn labels

* fix: remove no_emoji references

* feat: add create clipping reader shortcuts

* fix: set sd file timestamps from x3 rtc

* fix(epub): NFC-normalize EPUB text so NFD diacritics render correctly (crosspoint-reader#2277)

Co-authored-by: Uri Tauber <uritaube@gmail.com>
Co-authored-by: Julia <julia@uxj.io>

* feat: add live font preview pane to font selection screen (crosspoint-reader#2349)
* Adds a live font preview pane to the font selection screen so users
can see how a font looks before committing to it.
* Changes
* A preview pane occupying the top 30% of the font selection screen,
rendering sample pangram text in the previewed font
* A two-step confirm flow: first press (enter button) previews the font,
second press selects it
* Back restores the original font settings, so browsing has no side
effects
* Layout dimensions cached in `onEnter()` to avoid redundant
recalculation between `loop()` and `render()`
* Preview sample text is hardcoded English; didn't want to use AI for
translation as I would not be able to verify the output in most
languages...
* The preview pane reduces visible list height; this is compensated by
passing the reserved height into `getNumberOfItemsPerPage`

---
Did you use AI tools to help write this code? **PARTIALLY**
AI use for assisting in coding and in writing the PR description.

* feat: add Spacing Modifier Letters range to font presets (crosspoint-reader#2194)

* fix: don't justify-stretch a leading no-break space (crosspoint-reader#2185) (crosspoint-reader#2298)

* fix: update generated location filename

* fix: epub crashes while indexing with bionic reading on

* fix: use epub render fallbacks for silent indexing and avoid null final page serialization

* fix: constrain EPUB clipping highlights

* fix: handle sync long-press select release

* fix: add guidance for bionic/guide dots during memory pressure

* fix: preserve authored hyphens in clipping text

* fix: align reader menu icons with orientation

* fix: reduce epub layout buffering for reading aids

* fix: avoid home cover refresh oom crash

* update sdk

* fix: preserve clipping highlights after relayout

* fix: in-reader menu icons

* fix: keep clipping highlights complete after font relayout

* fix: reduce epub reading aid layout tokens

* feat: add chained slab arena allocator

* perf: wire parse arena into EPUB chapter style stacks

Replace std::vector inlineStyleStack and blockStyleStack in
ChapterHtmlSlimParser with arena-backed fixed-size arrays allocated
from parseArena_ at the start of each chapter parse. The arena is
initialized once, used for the full parse, then released in one
shot instead of per-object frees.

* fix: use arena inline style stack for table labels

* fix: use arena scratch buffers for epub layout

* chore: update changelog

* fix: add epub safe mode fallback

* fix: bound epub footnote preview indexing

* fix(epub): flush displaced anchor before overwrite (crosspoint-reader#2336) (crosspoint-reader#2382)

* **What is the goal of this PR?** (e.g., Implements the new feature for
file uploading.)

Fixes footnote links landing in start section instead of the specific
foot note target.

* **What changes are included?**

ChapterHtmlSlimParser.cpp: call flushPendingAnchor() before overwriting
pendingAnchorId. First id got lost due to consecutive non-block elements
carry ids, the first id was lost and the reader had no page to jump to,
so it defaulted to page 0.

Tested with the epubs attached to to crosspoint-reader#2336. Need to clear .crosspoint/
cache after flashing so the anchor map gets rebuilt with the fix.

* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks,
  specific areas to focus on).

---

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 assisted with writing documentation.

* feat: footnote returns to original position on deep sleep to avoid losing reading position (crosspoint-reader#2394)

* chore(release): prepare v1.3.4

* fix: report EPUB clipping save failures

* fix: allow long EPUB section LUT growth and preserve section LUT low-memory fallback signal

---------

Co-authored-by: Uri Tauber <uritaube@gmail.com>
Co-authored-by: PlatinumPOST <PlatinumPOST@users.noreply.github.com>
Co-authored-by: zgredex <112968378+zgredex@users.noreply.github.com>
Co-authored-by: Mauvis Ledford <switchstatement@gmail.com>
Co-authored-by: Ronin <6971304+TheCyberRonin@users.noreply.github.com>
Co-authored-by: rafaelmsse <rafaelmsse@gmail.com>
Co-authored-by: Rafael Santos <rmsantos@applaudostudios.com>
Co-authored-by: KymAndriy <32357131+KymAndriy@users.noreply.github.com>
Co-authored-by: KymAndriy <test@notamail.ua>
Co-authored-by: Justin Mitchell <justin@jmitch.com>
Co-authored-by: Ankit <iankit17@gmail.com>
Co-authored-by: darkbublu <davidcyprianhicks@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: gershalfred <gersh.alfred@gmail.com>
Co-authored-by: Hoang Manh Linh <jetaudio.media@gmail.com>
Co-authored-by: Paul Delestrac <40175004+PaulDelestrac@users.noreply.github.com>
Co-authored-by: SurprisedDuck <jannik.theiss@googlemail.com>
Co-authored-by: kygia <hi@kygiaha.com>
Co-authored-by: Zeph <cloudedsprite@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants