Commit Graph

623 Commits

Author SHA1 Message Date
ariel-lindemann
34484300e4 chore: update RO translation for release v1.2.0 (#1504) 2026-03-26 08:49:20 +02:00
Spigaw
831144e737 chore: Add missing French translations for UI controls and settings (#1493)
Added missing strings for the French translation.

## Summary

Adding the missing French translated strings before the next PR.
No modification done to the preexisting strings, only added new ones.



## Additional Context

N/A

---

### 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.

No AI usage.
2026-03-25 21:03:24 -05:00
Mirus
42c33528f9 feat: Add Ukrainian translations for image-related strings (#1491)
## Summary

Prep for RC 1.2.0
https://github.com/crosspoint-reader/crosspoint-reader/pull/1483
2026-03-25 20:59:18 -05:00
Егор Мартынов
6969950cd7 feat: update Russian translation (#1489)
## Summary

Adds new Russian strings for recently merged features, yay! 😃 

---

### AI Usage

Did you use AI tools to help write this code? _**NO**_
2026-03-25 11:35:10 -05:00
jpirnay
bc6f6daeb5 chore: Update German translation strings (#1495)
## Summary

* **What is the goal of this PR?** Updating German language file
* **What changes are included?**

## Additional Context

- None

---

### 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 >**_
2026-03-25 11:34:53 -05:00
Jonasz Potoniec
8352e1f08f chore: Polish localization for STR_SHOW_HIDDEN_FILES (#1490)
## Summary

Polish localization for `STR_SHOW_HIDDEN_FILES`

---

### 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**_
2026-03-25 11:34:40 -05:00
Àngel
dfc38cca4c chore: Catalan localization for STR_SHOW_HIDDEN_FILES (#1494)
## Summary

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

Adds the missing Catalan translation for STR_SHOW_HIDDEN_FILES in
lib/I18n/translations/catalan.yaml.

* **What changes are included?**

Only modified catalan.yaml file

## Additional Context

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

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? NO
2026-03-25 11:34:17 -05:00
Stefan Blixten Karlsson
3856348ee6 fix: swedish translation (#1476)
## Summary

* **What is the goal of this PR?** 
  fix swedish translation
* **What changes are included?**
  lib\I18n\translations\swedish.yaml
## Additional Context

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

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-25 11:33:11 -05:00
Baris Albayrak
0e228324e6 chore: Turkish localization for STR_SHOW_HIDDEN_FILES (#1487)
Adds the missing Turkish translation for STR_SHOW_HIDDEN_FILES in
lib/I18n/translations/turkish.yaml.

- Added: STR_SHOW_HIDDEN_FILES: "Gizli Dosyaları Göster"
- Scope: Turkish only (single-key micro-fix)

This follows up the missing-translations callout in #1483.

Co-authored-by: Barış Albayrak <barisa@pop-os.lan>
2026-03-25 08:29:03 +02:00
Dani Poveda
8e091609f7 chore: Spanish localization for STR_SHOW_HIDDEN_FILES (#1486)
## Summary

* Adding Spanish translation for string `STR_SHOW_HIDDEN_FILES`

---

### 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**_
2026-03-25 08:25:55 +02:00
jpirnay
710055f02c feat: Make directories stand out more in local file browser: "[dir]" instead of "dir" (#1339)
## Summary

* **What is the goal of this PR?** It's difficult to distinguish
directory names from normal file entries, so they are displayed now as
"[dir]" instead of "dir" for classic theme
* **What changes are included?**

## Additional Context

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

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-24 19:47:42 -05:00
jpirnay
0245972132 chore: Add powershell script for clang-formatting (#1472)
## Summary

* **What is the goal of this PR?** Add a windows equivalent for the
linux clang-format-fix script
* **What changes are included?**

## Additional Context
```
.SYNOPSIS
    Runs clang-format -i on project *.cpp and *.h files.

.DESCRIPTION
    Formats all C/C++ source and header files in the repository, excluding
    generated, vendored, and build directories (open-x4-sdk, builtinFonts,
    hyphenation tries, uzlib, .pio, *.generated.h).

    The clang-format binary path is resolved once and cached in
    .local/clang-format-fix.local. On first run it checks a default path,
    then PATH, then common install locations. Edit the .local file to
    override manually.

.PARAMETER g
    Format only git-modified files (git diff --name-only HEAD) instead of
    the full tree.

.PARAMETER h
    Show this help text.
```
---

### 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 >**_
2026-03-23 18:04:59 -05:00
Zach Nelson
0cbfaa007d fix: Overlapping battery percentage on image pages with anti-aliasing (#1452)
## Summary

**What is the goal of this PR?**

When viewing a page with images and anti-aliasing enabled, the
`imagePageWithAA` path renders the page twice with fast refreshes (blank
image area, then restore). Both passes called `renderStatusBar()`, which
reads the battery percentage live. If the value changed between the two
renders (e.g. 88% -> 87%), the digits would overlap on screen.
Fix: Removed the redundant `renderStatusBar()` from the second BW
render. The status bar is already drawn and displayed in the first pass,
and only the image area needs restoration.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-23 22:05:15 +00:00
jpirnay
ceb6acc8d7 fix: Fix img layout issue / support CSS display:none for elements and images (#1443)
## Summary
- Add CSS `display: none` support to the EPUB rendering pipeline (fixes
#1431)
- Parse `display` property in stylesheets and inline styles, with full
cascade resolution (element, class, element.class, inline)
- Skip hidden elements and all their descendants in
`ChapterHtmlSlimParser`
- Separate display:none check for `<img>` tags (image code path is
independent of the general element handler)
- Flush pending text blocks before placing images to fix layout ordering
(text preceding an image now correctly renders above it)
- Bump CSS cache version to 4 to invalidate stale caches
- Add test EPUB (`test_display_none.epub`) covering class selectors,
element selectors, combined selectors, inline styles, nested hidden
content, hidden images, style priority/override, and realistic use cases
2026-03-23 13:51:02 -05:00
pablohc
7d56810ee6 feat: integrated epub optimizer (#1224)
## Problem

Many e-ink readers have limited image decoder support natively.
EPUBs with images in other formats than **baseline JPEG** frequently
cause:

- **Broken images**: pages render as blank, corrupted noise, or never
load
- **Slow rendering**: unoptimized images cause severe delays on e-ink
hardware, up to 7 seconds per page turn, with cover images taking up to
59 seconds to render
- **Broken covers**: the book thumbnail never generates

Fixing this today requires external tools before uploading.

---

## What this PR does

Adds an **optional, on-demand EPUB optimizer** to the file upload flow.
When enabled,
it converts all images to baseline JPEG directly in the browser — no
server, no internet,
no external tools needed.

**Conversion is opt-in. The standard upload flow is unchanged.**

---

## Real-world impact

The optimizer was applied in batch to **61 EPUBs**:
- 60 standard EPUBs: 198 MB → 55 MB (**−72.2%**, 143 MB saved)
- Text-dominant books: 8–46% smaller (covers and inline images
converted)
  - Image-heavy / illustrated books: 65–93% smaller
- 1 Large manga volume (594 MB): 594 MB → 72 MB (**−87.8%**, 522 MB
saved)
- EPUB structural integrity fully maintained — zero new validation
issues introduced across all 61 books

*Size and integrity analysis:
[epub-comparator](https://github.com/pablohc/epub-comparator)*

From that set, **17 books were selected** as a representative sample
covering different content
types: image-heavy novels, pure manga, light novels with broken images,
and text-dominant books.
Each was benchmarked on two devices running in parallel, one on `master`
and one
on `PR#1224` — measuring render time across ~30 pages per book on
average.

### Rendering bugs fixed

| Book | Problem (original) | After optimization |
|------|--------------------|--------------------|
| Fairy Tale — Stephen King | Cover took **59.7 s** to render | 2.1 s
(−96%) |
| Cycle of the Werewolf — Stephen King | Cover took **23.3 s** to render
| 1.7 s (−93%) |
| Tomie: Complete Deluxe Ed. — Junji Ito | Cover took **18.3 s** to
render | 2.0 s (−89%) |
| Joel Dicker — El tigre (Ed. Ilustrada) | Cover took **14.5 s** to
render | 1.4 s (−90%) |
| Jackson, Holly — Asesinato para principiantes | Cover failed
completely (blank) | 2.0 s ✓ |
| Sentenced to Be a Hero — Yen Press | Cover failed, **8 images failed
to load** | All fixed ✓ |
| Flynn, Gillian — Perdida | Cover failed completely (blank) | 1.6 s ✓ |
| Chandler, Raymond — Asesino en la lluvia | Cover failed completely
(blank) | 2.0 s ✓ |

### Page render times — image-heavy EPUBs (avg per page)

| Book | Pages | Avg original | Avg optimized | Improvement | File size
|
|------|-------|-------------|---------------|-------------|-----------|
| Fairy Tale — Stephen King | 30 | 3,028 ms | 1,066 ms | **−64.8%** |
32.4 MB → 9.1 MB (−72%) |
| Cycle of the Werewolf — Stephen King | 33 | 3,026 ms | 1,558 ms |
**−48.5%** | 35.1 MB → 2.9 MB (−92%) |
| Joel Dicker — El tigre (Ed. Ilustrada) | 16 | 1,846 ms | 1,051 ms |
**−43.1%** | 5.3 MB → 0.4 MB (−93%) |
| Tomie: Complete Deluxe Ed. — Junji Ito | 30 | 4,817 ms | 2,802 ms |
**−41.8%** | 593.8 MB → 72.2 MB (−87.8%) |
| Sentenced to Be a Hero — Yen Press | 30 | 1,719 ms | 1,388 ms |
**−19.2%** | 15.2 MB → 1.6 MB (−90%) |

### Text-heavy EPUBs — no regression

| Book | Pages | Avg original | Avg optimized | Delta |
|------|-------|-------------|---------------|-------|
| Christie — Asesinato en el Orient Express | 30 | 1,672 ms | 1,646 ms |
−1.6% |
| Flynn — Perdida | 30 | 1,327 ms | 1,291 ms | −2.7% |
| Dicker — La verdad sobre el caso Harry Quebert | 30 | 1,132 ms | 1,084
ms | −4.2% |
| Hammett — El halcón maltés | 30 | 1,009 ms | 966 ms | −4.3% |
| Chandler — Asesino en la lluvia | 30 | 989 ms | 1,007 ms | +1.8% |

*Differences within ±5% — consistent with device measurement noise.*

*Render time benchmark:
[epub-optimization-benchmark](https://github.com/pablohc/epub-optimization-benchmark)*

---
## How to use it

**Single file:**
1. Click **Upload** (top of the page) — a modal opens. Use **Choose
files** to select one EPUB from your device.
2. Check **Optimize**.
- *(Optional)* Expand **Advanced Mode** — adjust quality, rotation, or
overlap; set individual images to H-Split / V-Split / Rotate.
3. Click **Optimize & Upload**.

**Batch (2+ files):**
1. Click **Upload** (top of the page) — a modal opens. Use **Choose
files** to select multiple EPUBs from your device.
2. Check **Optimize**.
   - *(Optional)* Expand **Advanced Mode** — adjust quality.
3. Click **Upload** — all files are converted and uploaded sequentially.

Upload a batch of files, without optimization:
<img width="810" height="671" alt="image"
src="https://github.com/user-attachments/assets/d892ae13-0b87-4ea4-b6b8-340d56efc763"
/>

Batch file upload, with standard optimization:
<img width="809" height="707" alt="image"
src="https://github.com/user-attachments/assets/d32dbc88-1208-4555-bfcf-330ab91d2174"
/>

Optimization Phase (1/2):
<img width="807" height="1055" alt="image"
src="https://github.com/user-attachments/assets/fd4cd5f9-e56e-4ca1-9777-6926b9baf2bb"
/>

Upload Phase (2/2):
<img width="805" height="1065" alt="image"
src="https://github.com/user-attachments/assets/483294f0-02f0-4569-ae11-c10b3581d747"
/>

Batch upload successfully confirmed:
<img width="812" height="1043" alt="image"
src="https://github.com/user-attachments/assets/80c135bf-05c3-4c80-8755-2a04c68235bc"
/>

---

## Options

**Always active when the converter is enabled:**
- Converts PNG, WebP, BMP, GIF → baseline JPEG
- Smart downscaling to 480×800 px max (preserves aspect ratio)
- True grayscale for e-ink (BT.709 luminance, always on)
- SVG cover fix + OPF/NCX compliance repairs

**Advanced Mode (opt-in) — single file:**
- JPEG quality presets: 30% / 45% / 60% / 75% / **85%** (default) / 95%
- Rotation direction for split images: CW (default) / CCW
- Min overlap when splitting: 5% (default) / 10% / 15%
- Auto-download conversion log toggle (detailed stats per image)
- Per-image picker: set Normal / H-Split / V-Split / Rotate per image
individually,
  with "Apply to all" for bulk assignment

**Advanced Mode (opt-in) — batch (2+ files):**
- JPEG quality presets: 30% / 45% / 60% / 75% / **85%** (default) / 95%
- Auto-download conversion log toggle (aggregated stats for all files)

---

## ⚠️ Known limitations

**KoReader hash-based sync will break** for converted files. The file
content changes,
so the hash no longer matches the original. Filename-based sync is
unaffected.

If you rely on KoReader hash sync, use the Calibre plugin or the web
tool instead.

---
## Build size impact

| Metric | master (53beeee) | PR #1224 (a2ba5db) | Delta |

|---------------|------------------|--------------------|----------------|
| Flash used | 5,557 KB | 5,616 KB | +59 KB (+1.1%) |
| Flash free | 843 KB | 784 KB | −59 KB |
| Flash usage | 86.8% | 87.7% | +0.9 pp |
| RAM used | 95,156 B | 95,156 B | no change |

> Both builds compiled with `gh_release` environment in release mode
(ESP32-C3, 6,400 KB Flash).
> The +59 KB increase is entirely due to `jszip.min.js` embedded as a
> gzipped static asset served from Flash. RAM usage is identical,
> confirming no runtime overhead — the library runs in the browser,
> not on the ESP32. ~784 KB of Flash remain available.

---

## Alternatives considered

| Approach | Friction |
|----------|---------|
| **This PR** — integrated in upload flow | Zero: convert + upload in
one step, offline, any browser |
| Calibre plugin (in parallel development) | Requires a computer with
Calibre installed, same network |
| Web converters | Requires extra upload / download / transfer steps |

---

## Credits

Based on the converter algorithm developed by @zgredex.
Co-authored-by: @zgredex

---

### AI Usage

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

---------

Co-authored-by: zgredex <zgredex@users.noreply.github.com>
2026-03-22 19:53:15 +00:00
Xuan-Son Nguyen
526c8a5e7a fix: use sleep routine from the original firmware (#1298)
## Summary

Fixes #1263

I spent half of my day(-off) reverse engineering the stock english
firmware V3.1.1, it's more or less like solving a sudoku with some known
pieces (like debug strings, known static addresses, known compiled
function, etc) and then the task is to guess the rest.

Long story short, this is the sleep routine that they use:

<img width="674" height="604" alt="image"
src="https://github.com/user-attachments/assets/6d53ce44-7bae-40c7-b4fb-24f898dbcc05"
/>

From the code above:
- They pull down GPIO13 (value = 0xd) before sleep
- They verify that power button is released by doing a delay loop of
50ms, similar to what we're doing
- `esp_sleep_config_gpio_isolate` is called but I'm not 100% sure why
- Pull up power button, note that it's likely redundant because power
button should already pulled up by `InputManager`
- `param1` and `param2` means enabling front/side buttons for wake up,
but it doesn't used in the code in reality. But I think it's physically
impossible, see the explanation below
- `param3` means "wake up from power button"
- `esp_sleep_start` is used; there is a logic to handle if it fails to
sleep, then retry recursively (no idea why!)

My observation is that they use GPIO13 so that it will be on HIGH state
when the chip is powered on, without any user space code to keep it on
that state. And once going to deep sleep, it goes into FLOATING by
default. That may explain why it need to be in LOW state before going to
sleep. (Nice trick btw)

Looking again at the circuit diagram provided
[here](https://github.com/sunwoods/Xteink-X4/blob/main/readme-img/sch.jpg)
(note: it's not official):

<img width="705" height="384" alt="image"
src="https://github.com/user-attachments/assets/b98d59fd-47ca-4d3d-a24a-94bf999e957b"
/>

It kinda make sense as the GPIO13 and VBUS (USB VCC) have the same role,
they are part of a simple "battery protection" cirtuit

Now, we may wonder, how the device wake up when there is no battery at
all?

<img width="440" height="323" alt="image"
src="https://github.com/user-attachments/assets/2981c411-239b-49a7-b9f7-9a75b6c1b6d3"
/>

It seems like power button is not just a simple switch between GPIO3 and
ground, but it also linked the POWER_CTRL, which leads to nowhere on the
diagram, but I suppose it connects the battery back for a short amount
of time, just enough for the MCU to wake up, and GPIO13 goes HIGH again.
It may also explain why power button becomes non-responsive for ~1
second after power on, as it's being pulled up by the current from
battery (remind: high = not pressed, low = pressed)

To test the theory above, I simply **comment out** the
`esp_deep_sleep_enable_gpio_wakeup`:
- On battery, power button works as nothing happen
- On USB, it doesn't wake up, I need to press RST

---

Important things about my analysis:
1. I had to name every function on the code above **manually**, but I'm
99% confident about it. The only function that I'm not sure is
`esp_wifi_bt_power_domain_off` ; Edit: it was indeed mislabeled, see
https://github.com/crosspoint-reader/crosspoint-reader/pull/1298#discussion_r2879670852
2. Some logic inside the stock firmware looks very strange, there is
almost no mention to "arduino" in the hardware, suggesting that they may
just call esp-idf functions directly, bypassing the arduino abstraction.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

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

---------

Co-authored-by: Zach Nelson <zach@zdnelson.com>
2026-03-21 13:35:38 -05:00
Adrian Wilkins-Caruana
0c9e8b3ece fix: Fix prewarm perf when a page contains many styles (#1451)
## Summary

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

Fix prewarm perf when a page contains many styles.

The prewarm page buffer was a single slot, so each `prewarmCache` call
for a new font style freed the previous style's glyphs. On pages with
multiple styles (regular + bold + italic), only the last style was
prewarmed. The others fell through to the hot-group compaction path at
~2-3ms per glyph.

This was most visible on rich formatting (e.g. this [Czech prayer
book](https://stahuj.kancional.cz/e-kniha/kancional.epub) with bold
headings, italic liturgical text, and regular body), where page renders
took 3-5 seconds instead of ~700ms.

Fix: use up to 4 page buffer slots (one per font style) so all styles
stay prewarmed simultaneously.

Fixes #1450.

---

### 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: to diagnose and
brainstorm solutions.
2026-03-21 12:10:41 -05:00
Zach Nelson
53beeeed2b chore: Removed unused PlatformIO include directory placeholder (#1417)
## Summary

**What is the goal of this PR?**

This change deletes include/README, which is a PlatformIO boilerplate
placeholder file explaining what header files are. The include/
directory isn't used by this project (headers live in lib/ and src/), so
this is just cleanup.

### 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**_
2026-03-19 23:20:50 -05:00
LSTAR
8dd365b4da feat: Implement silent pre-indexing for the next chapter in EpubReaderActivity (#979)
## Summary

* A simple tweak to pre-index the next chapter silently during normal
reading.
* Triggers silent pre-indexing of the next chapter when the penultimate
page of a chapter is rendered to reduce visible interruptions.
* Keeps existing indexing with popup when a reader jumps directly into
an unindexed chapter.

## Additional Context

* Reader input is temporarily blocked during silent indexing to avoid
navigation/index state conflicts.
* The penultimate page is used because readers typically spend longer
there than on the final page.
* This change optimizes linear reading flow while preserving reliable
indexing for non-linear navigation.

## Possible Improvements

* Add a setting for First Page Indexing vs Penultimate Page Pre-indexing
* Display an indexing icon in the status bar instead of using a popup
that overlaps book text.

Tested on device:

https://www.dropbox.com/scl/fi/29g5kjqgsi5e4hgujv38u/Silent-Indexing.MOV?rlkey=yemi4mosmev5vicaa7gpe49qw&dl=0

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

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

---------

Co-authored-by: Jake Kenneally <jakekenneally@gmail.com>
2026-03-19 23:20:26 -05:00
Zach Nelson
9665dd7473 chore: Update SKILL.md to reflect generated i18n files are gitignored (#1423)
## Summary

**What is the goal of this PR?**

Update SKILL.md to stop instructing contributors to commit `I18nKeys.h`
and `I18nStrings.h`. All three generated i18n files have been gitignored
since ff577540 and are regenerated at build time.

---

### 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**_
2026-03-19 23:19:54 -05:00
jpirnay
71719e1d94 feat: battery charging indicator (mirroring PR #537) (#1427)
## Summary

* **What is the goal of this PR?** All praise goes to @didacta for his
PR #537. Just picked up the reviewer comments to contain the changes as
suggested (there was no response for more than 6 weeks, so I wanted to
reanimate this feature).

Just one addition: should recognize usb cable plug ins / retractions and
update the icon immediately

* **What changes are included?**

## Additional Context

see #537 

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**< NO >**_
2026-03-19 22:33:29 -05:00
Zach Nelson
d6951f81b7 fix: Build with -fno-exceptions (#1412)
## Summary

**What is the goal of this PR?**

Until today, I sincerely thought we were building without exception
support. The codebase is not set up with any exception handling
infrastructure. The SKILL.md file specifies no exceptions.

I just learned that we actually were building with exceptions enabled,
with `-fexceptions` coming from
~/.platformio/packages/framework-arduinoespressif32-libs/esp32c3/pioarduino-build.py.

This change removes the `-fexceptions` flag and adds `-fno-exceptions`.
The result is **53,670 bytes in flash savings**.

---

### 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**_
2026-03-18 11:41:18 -05:00
Stefan Blixten Karlsson
99721c081b fix: Reduce flash usage by cleaning up I18n translations (#1401)
## Summary

* **What is the goal of this PR?** 
Removing no longer used i18n keys/string, to reduce (~28k) used flash
space.
To correct to swedish translations for `STR_FONT_SIZE` and
`STR_KOREADER_SYNC`.

* **What changes are included?**
   `lib\I18n\translations\*`

## Additional Context

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

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-18 09:59:03 -05:00
jpirnay
f9286709d1 feat: Show hidden directories in browser (#1288)
## Summary

* **What is the goal of this PR?** Add setting to display hidden files /
directories in filebrowser / web file browser
* **What changes are included?**

## Additional Context

-

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**< NO >**_
2026-03-18 09:57:58 -05:00
Zach Nelson
dc39480349 fix: Prevent line breaks on common English contractions (#1405) 2026-03-16 20:04:06 -04:00
jpirnay
b5df6cb2b5 fix: jpeg resource cleanup (#1320)
## Summary

* **What is the goal of this PR?** Fix leak on decode error path in JPEG
converter
* **What changes are included?**
Unif resource cleanup

## Additional Context

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**PARTIALLY**_
Identification of the issue by AI
2026-03-13 17:45:42 -05:00
fsocietyipa
16b73744c5 feat: Add Kazakh (kk) language support (#1377)
## Summary

* **What is the goal of this PR?** Implements Kazakh language
* **What changes are included?**

## Additional Context

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

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

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

---------

Co-authored-by: Okzhetpes <okhzetpes.20@gmail.com>
2026-03-11 18:40:14 -05:00
jpirnay
79b54b3a75 fix: Init lastSleepImage (edge case) (#1360)
## Summary

* **What is the goal of this PR?** fix edge case for definition

## Additional Context

If loadFromFile() returns false (no state file exists — first boot, or
SD missing), lastSleepImage is never set and contains garbage.
[SleepActivity.cpp:83] then uses it in a while comparison to avoid
repeating the same image. The JSON path (doc["lastSleepImage"] |
(uint8_t)0) handles it, but only if the file exists.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _** NO **_
2026-03-11 18:37:13 -05:00
jpirnay
11ca208ec2 chore: change label while on settings tab actions (#1325)
## Summary

* **What is the goal of this PR?** The "Toggle" label while on the "tab"
actions of settings screen was misleading. Will show "Select" now ,
while "Toggle" remains in place for all 'real' settings

* **What changes are included?**

## Additional Context
<img width="240" alt="1"
src="https://github.com/user-attachments/assets/dc198716-0aad-4c75-96fe-52595625e69d"
/>
<img width="240" alt="2"
src="https://github.com/user-attachments/assets/85ce5368-801c-489d-aa94-51f126c3ddc8"
/>


---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO **_
2026-03-11 18:36:34 -05:00
Cache8063
7a28f90dad fix: back button in settings returns to tab bar first (#1354)
## Summary
- Pressing Back while browsing settings within a category now jumps
focus to the category tab bar
- Pressing Back again from the tab bar exits settings to home
- Previously, Back always exited directly to home regardless of scroll
position

Closes #797

## Test plan
- [ ] Scroll deep into a settings category → press Back → tab bar is
focused
- [ ] Press Back again from tab bar → exits to home screen
- [ ] Use category switching (continuous hold) → still works as before
- [ ] Settings are saved on exit (not on tab-bar jump)

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

Co-authored-by: bkb <bkb@arcnode.xyz>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 18:35:48 -05:00
jpirnay
3dabd30287 fix: Add special handling for apostrophe hyphenation (#1318)
## Summary

* **What is the goal of this PR?** Fixing / extending the hyphenation
logic to deal with words containing an apostophe as raised in #1186
* **What changes are included?**

## Additional Context

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**PARTIALLY**_ (as the
user provided a thorough analysis that I followed)
2026-03-11 18:35:23 -05:00
Adrian Wilkins-Caruana
f1e9dc7f30 perf: font-compression improvements (#1056)
## Purpose

This PR includes some preparatory changes that are needed for an
upcoming performant CJK font feature. The changes have no impact on
render time and heap allocation for latin text. **Despite this, I think
these changes stand on their own as a better font
compression/decompression implementation.**

## Summary

- Font decompressor rewrite: Replaced the 4-slot LRU group cache with a
two-tier system — a page buffer (glyphs prewarmed before rendering
begins) and a hot-group fallback (last decompressed group retained for
non-prewarmed
  glyphs). 
- Byte-aligned compressed bitmap format: Glyph bitmaps within compressed
groups are now stored row-padded rather than tightly packed before
DEFLATE compression, improving compression ratios by making identical
pixel rows produce
identical byte patterns. Glyphs are compacted back to packed format on
demand at render time. Reduces flash size by 155 KB.
- Page prewarm system: Added `Page::collectText` and
`Page::getDominantStyle` to extract per-style glyph requirements before
rendering, and `GfxRenderer::prewarmFontCache` to pre-decompress only
the groups needed for the dominant style
   — eliminating mid-render decompression for the common case.
- UTF-8 robustness fixes: `utf8NextCodepoint` now validates continuation
bytes and returns a replacement glyph on malformed input;
`ChapterHtmlSlimParser` correctly preserves incomplete multi-byte
sequences across word-buffer flush
  boundaries rather than splitting them.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**YES**_ Architecture and
design was done by me, refined a bit by Claude. Code mostly by Claude,
but not entirely.
2026-03-11 21:05:46 +01:00
Dani Poveda
b467ea7973 fix: Improve and add Spanish translations (#1338)
## Summary

* **What is the goal of this PR?** 
    - Improve and add the latest missing Spanish translations

* **What changes are included?**
    - Replaced `Der.` with `Dcha.`, as it's a more common abbreviation
- Replaced `Selec.` with `Selecc.` (same reason as in the previous case)
- Added missing strings `STR_IMAGES`, `STR_IMAGES_DISPLAY`,
`STR_IMAGES_PLACEHOLDER` and `STR_IMAGES_SUPPRESS`
    - Rewording certain translations to make them clearer

---

### 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**_
2026-03-11 23:02:22 +03:00
Zach Nelson
32a5c1c358 fix: Fix inter-word spacing rounding error in text layout (#1311)
## Summary

**What is the goal of this PR?**

### Problem

Inter-word gap widths were computed as two separately-snapped integers:

```cpp
gap = getSpaceWidth(fontId, style);                        // fp4::toPixel(spaceAdvance)
gap += getSpaceKernAdjust(fontId, leftCp, rightCp, style); // fp4::toPixel(kern1 + kern2)
```

Because `fp4::toPixel(a) + fp4::toPixel(b)` can differ from
`fp4::toPixel(a + b)` by +/-1 pixel when the fractional parts straddle a
rounding boundary, each inter-word space could be one pixel wider or
narrower than the correct value. This affected line-break width
decisions and word-position accumulation across the whole paragraph
layout pipeline.

### Fix

Replaces `getSpaceKernAdjust()` with `getSpaceAdvance(fontId, leftCp,
rightCp, style)`, which combines the space glyph advance and both
flanking kern values (`kern(leftCp, ' ')` + `kern(' ', rightCp)`) into a
single fixed-point sum before the snap:

```cpp
return fp4::toPixel(spaceAdvanceFP + kern(leftCp, ' ') + kern(' ', rightCp));
```

This is the same single-snap pattern already used by `getTextAdvanceX`
for word widths.

### Changes

- **`GfxRenderer`**: Replaces `getSpaceKernAdjust()` with
`getSpaceAdvance()`. `getSpaceWidth()` is retained for the
single-space-word case in `measureWordWidth` where no adjacent-word kern
context is available.
- **`ParsedText`**: All four call sites (`computeLineBreaks`,
`computeHyphenatedLineBreaks`, and both loops in `extractLine`) updated
to use `getSpaceAdvance()`. The now-redundant `spaceWidth`
pre-computation and parameter are removed from all three internal layout
functions.

---

### 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 to analyze for
correctness**_
2026-03-10 22:55:23 -05:00
Uri Tauber
a95a63b753 fix: load access fault crash (#1370)
## Summary

Fixes a crash (load access fault) when opening EPUB chapters whose first
text block exceeds 750 words.

## Changes

* **Crash fix (`addLineToPage`)**: Added a null guard for `currentPage`.
If `makePages()` hasn't run yet (which can happen when the first block
triggers the "text block too long" split path), the page is now created
on demand.
* **Layout fix (`characterData`)**: The early-split path previously used
`viewportWidth`, ignoring CSS margins and padding. It now computes
`effectiveWidth` using `totalHorizontalInset()`, consistent with
`makePages()`.

## Additional Context

* Crash signature: `MCAUSE=0x5` (load access fault), `A0=0x0` (`Page*`
null), `MTVAL=0x4 / 0x8` (offsets into `Page::elements`).
* Confirmed in two user reports reported in #1328
* Tested on PR #1357 (not on `master`).

---

### 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 >**_
2026-03-09 16:57:40 -05:00
jpirnay
4104fa8102 fix: Fix bootloop logging crash (#1357)
## Summary

* **What is the goal of this PR?** On a cold boot (or after a crash that
corrupts RTC RAM), logHead contains garbage. Then addToLogRingBuffer
does: ``strncpy(logMessages[logHead], message, MAX_ENTRY_LEN - 1); ``
With garbage logHead, this computes a completely invalid address. The %
MAX_LOG_LINES guard on line 16 only runs after the bad store, which is
too late. The fix is to clamp logHead before use.

## Additional Context

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

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_ (did use claude
for the magic hash value)
2026-03-09 21:53:38 +01:00
jpirnay
e60ba7620d chore: micro-optimisation: early exit on fillUncompressedSizes (#1322)
## Summary

* **What is the goal of this PR?** Avoid repeated full central-directory
scans by using early stop when all requested targets are already
matched.
* **What changes are included?**

## Additional Context

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

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _** PARTIALLY **_
Identified by AI
2026-03-08 14:15:51 -05:00
Uri Tauber
cd508d27d5 refactor: reader utils (#1329)
## Summary

Extract shared reader utilities (`ReaderUtils.h`) to reduce duplication
across `EpubReaderActivity`, `TxtReaderActivity`, and (upcoming)
`MarkdownReaderActivity`.

  Utilities extracted:

   - `applyOrientation()` — orientation switch logic
   - `detectPageTurn()` — page navigation input detection
   - `renderAntiAliased()` — grayscale anti-aliasing pass
   - `displayWithRefreshCycle()` — refresh mode cadence
   - `GO_HOME_MS` — back button timing constant

  ## Impact

Flash: 32 bytes saved (6006441 → 6006409 bytes). Minimal immediate gain,
but meaningful once markdown reader and future reader types share these
functions.

Code quality: Eliminates ~100 lines of duplicated logic spread across
multiple files. All readers now follow the same patterns for
orientation, input handling, and rendering.

  ## Rationale

This refactor is preparation for markdown support, which requires
identical input and rendering logic. Instead of copy-pasting these
patterns a third time, all readers now share a single, tested
implementation. Future reader types can reuse `ReaderUtils` without
duplication.

  ---

  ## AI Usage

Did you use AI tools to help write this code? YES Claude extracted the
code, under my guidance. Tested on my device and seems to work fine.
2026-03-08 11:45:54 -05:00
Jonasz Potoniec
170cc25774 chore: Polish localization for STR_DELETE (#1323) 2026-03-06 21:22:52 -05:00
Xuan-Son Nguyen
c40e92e4d1 fix: dump crash log without usb plugged, bump release log to INFO (#1332)
## Summary

Follow-up
https://github.com/crosspoint-reader/crosspoint-reader/pull/1145

- Fix log not being record without USB connected
- Bump release log to INFO for more logging details

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

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

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-06 22:05:23 +01:00
Uri Tauber
4d22256745 feat: footnote anchor navigation (#1245)
## Summary: Enable footnote anchor navigation in EPUB reader

This PR extracts the core anchor-to-page mapping mechanism from PR #1143
(TOC fragment navigation) to provide immediate footnote navigation
support. By merging this focused subset first, users get a complete
footnote experience now while simplifying the eventual review and merge
of the full #1143 PR.

  ---

## What this extracts from PR #1143

PR #1143 implements comprehensive TOC fragment navigation for EPUBs with
multi-chapter spine files. This PR takes only the anchor resolution
infrastructure:

- Anchor-to-page mapping in section cache: During page layout,
ChapterHtmlSlimParser records which page each HTML id attribute lands
on, serializing the map into the .bin cache file.
- Anchor resolution in `EpubReaderActivity`: When navigating to a
footnote link with a fragment (e.g., `chapter2.xhtml#note1`), the reader
resolves the anchor to a page number and jumps directly to it.
- Section file format change: Bumped to version 15, adds anchor map
offset in header.

  ---

## Simplified scope vs. PR #1143

To minimize conflicts and complexity, this PR differs from #1143 in key
ways:

* **Anchors tracked**
  * **Origin:** Only TOC anchors (passed via `std::set`)
  * **This branch:** All `id` attributes

* **Page breaks**
  * **Origin**: Forces new page at TOC chapter boundaries
  * **This branch:** None — natural flow

* **TOC integration**
  * **Origin**: `tocBoundaries`, `getTocIndexForPage()`, chapter skip
  * **This branch:** None — just footnote links

* **Bug fix**
  * **This branch:** Fixed anchor page off-by-1/2 bug


The anchor recording bug (recording page number before `makePages()`
flushes previous block) was identified and fixed during this extraction.
The fix uses a deferred `pendingAnchorId` pattern that records the
anchor after page completion.

  ---

## Positioning for future merge

Changes are structured to minimize conflicts when #1143 eventually
merges:

- `ChapterHtmlSlimParser.cpp` `startElement()`: Both branches rewrite
the same if `(!idAttr.empty())` block. The merged version will combine
both approaches (TOC anchors get page breaks + immediate recording;
footnote anchors get deferred recording).
- `EpubReaderActivity.cpp` `render()`: The `pendingAnchor` resolution
block is positioned at the exact same insertion point where #1143 places
its `pendingTocIndex` block (line 596, right after `nextPageNumber`
assignment). During merge, both blocks will sit side-by-side.
   
  ---

## Why merge separately?

1. Immediate user value: Footnote navigation works now without waiting
for the full TOC overhaul
   2. Easier review: ~100 lines vs. 500+ lines in #1143 
3. Bug fix included: The page recording bug is fixed here and will carry
into #1143
4. Minimal conflicts: Structured for clean merge — both PRs touch the
same files but in complementary ways
---

### AI Usage

Did you use AI tools to help write this code? _**< YES >**_ Done by
Claude Opus 4.6
2026-03-06 21:10:45 +03:00
Xuan-Son Nguyen
18b36efbae feat: dump crash report to sdcard (#1145)
## Summary

This allow dumping crash message (i.e. assertion fail) and stack trace
to `crash_report.txt` file on sdcard. The stack trace can then be
decoded using https://esphome.github.io/esp-stacktrace-decoder/

Could be useful to debug things like
https://github.com/crosspoint-reader/crosspoint-reader/issues/1137 where
error doesn't always happen.

May also be useful to show a screen to tell what happen (show on next
boot after crash), similar to [flipper zero crash
message](https://www.reddit.com/r/flipperzero/comments/10f8m3f/anyone_who_can_tell_me_why_this_message_pops_up/)
, but this is better to be a dedicated PR (I'm missing the
`drawTextWrapped` function, too lazy to code it ; update: exactly what I
need in
https://github.com/crosspoint-reader/crosspoint-reader/pull/1141)

To test this:
- Option 1: add an `assert(false)` somewhere in the code
- Option 2: try dereferencing a nullptr
- Option 3: try `throw` an exception

Example of a crash report:

```
CrossPoint version: 1.1.0-dev

Panic reason: abort() was called at PC 0x4214585b on core 0

Recent logs:
[196] [DBG] [GFX] Time = 2 ms from clearScreen to displayBuffer
[1831] [DBG] [RBS] Recent books loaded from file (7 entries)
[1832] [DBG] [ACT] Exiting activity: Boot
[1832] [DBG] [ACT] Entering activity: Home
[1891] [DBG] [GFX] Time = 54 ms from clearScreen to displayBuffer
[2521] [DBG] [GFX] Time = 46 ms from clearScreen to displayBuffer
[4839] [DBG] [PWR] Going to low-power mode
[10048] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes
[20060] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes
[30072] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes
[34453] [DBG] [PWR] Restoring normal CPU frequency
[34485] [DBG] [GFX] Time = 30 ms from clearScreen to displayBuffer
[35182] [DBG] [GFX] Time = 31 ms from clearScreen to displayBuffer
[36675] [DBG] [GFX] Time = 30 ms from clearScreen to displayBuffer
[38800] [DBG] [GFX] Time = 30 ms from clearScreen to displayBuffer
[40079] [INF] [MEM] Free: 134164 bytes, Total: 232372 bytes, Min Free: 133664 bytes


Stack memory:
0x3FCB0650: 0x00000000 0x00000000 0x3FCB0668 0x4038DBB6 0x00000000 0x00000000 0x3FCA0030 0x3FC936D0 
0x3FCB0670: 0x3FCB067C 0x3FC936EC 0x3FCB0668 0x34313234 0x62353835 0x00000000 0x726F6261 0x20292874 
0x3FCB0690: 0x20736177 0x6C6C6163 0x61206465 0x43502074 0x34783020 0x35343132 0x20623538 0x63206E6F 
0x3FCB06B0: 0x2065726F 0x00000030 0x3FCA0000 0xB37A603F 0x00000001 0x3FCA7000 0x3FCABCDC 0x4214585E 
0x3FCB06D0: 0x3FCA7000 0x3FCA7000 0x3FCABCDC 0x421458AA 0x3FCABCDC 0x3FCA7000 0x3FCABCDC 0x421459CC 
0x3FCB06F0: 0x3FCA7000 0x3FCA7000 0x42145D5A 0x3C205624 0x40388560 0x3FCA7000 0x3FCABCFC 0x42079866 
0x3FCB0710: 0x3FCA7000 0x3FCA7000 0x00009C9A 0x4207B7F6 0x3FCA7000 0x42090000 0x001B7740 0x00000001 
0x3FCB0730: 0x3FCA7000 0x3FCA7000 0x00000001 0x600C0028 0x00000001 0x3FCA1000 0x00000000 0x00000000 
0x3FCB0750: 0x00000000 0x00000000 0x00000000 0xB37A603F 0x00000000 0x00000000 0x00000000 0x00000000 
0x3FCB0770: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x42090000 0x3FCA7000 0x4208F9C4 
0x3FCB0790: 0x00000000 0x00000000 0x00000000 0x40388368 0x00000000 0x00000000 0x00000000 0x00000000 
0x3FCB07B0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0xA5A5A5A5 0xA5A5A5A5 0xA5A5A5A5 
0x3FCB07D0: 0xA5A5A5A5 0xA5A5A5A5 0xA5A5A5A5 0xA5A5A5A5 0xBAAD5678 0xDA6D3601 0x5EB5B9C5 0x2602E480 
0x3FCB07F0: 0x2BCDD33F 0x15556D4A 0x1F2140A0 0x5D59BEE3 0x8E76449F 0x6FB2D0CE 0xF5F46FAC 0x0112946A 
0x3FCB0810: 0x3B0B32E0 0x7A52B537 0x46801DB4 0xDA85DF9F 0x37E83D20 0x12861028 0x47A702BB 0x287A3C8A 
0x3FCB0830: 0x03632209 0xD44C5489 0x5E258453 0xFDA77529 0xE6748E23 0xADCF1394 0x67AD6778 0x2C208663 
0x3FCB0850: 0xC7985786 0xD4AA3AB2 0x312E1760 0xEC7AEAAE 0x1857020E 0x48003E7E 0xD6CB8763 0x9B4A3F66 
0x3FCB0870: 0x4B79E9F6 0xCBF739F0 0x3794C641 0xD0DBA3CB 0x95B9BE15 0x581C9983 0xDE62EFB6 0x20C67C5B 
0x3FCB0890: 0x1E4A3DF3 0xFB317C74 0xC0D86103 0x1D79ED56 0x72FE0862 0x3D38B0C8 0xD27EB587 0x0E0A4C40 
0x3FCB08B0: 0xF643ADC0 0x56D114D7 0x703AF879 0xAC7F3075 0x89C78C23 0xEDA86814 0xF767B3E3 0x0528838F 
0x3FCB08D0: 0x50ED4662 0x11FD38E7 0x8A5A83BB 0x658159BD 0x781AF696 0x8A700F79 0x526DDE23 0xC8472505 
0x3FCB08F0: 0x21AACC02 0xCB89369E 0xB82E5BE2 0x4C6C9D7D 0x9E724D9B 0xDC1067F7 0x84478FBC 0x4E89C444 
0x3FCB0910: 0x973F4229 0x49F93DA8 0xE30200F6 0xD1B5C391 0x8363A89F 0x2409E74C 0x3AFF7B52 0xCBEC2349 
0x3FCB0930: 0xD38F6695 0xBC3EA980 0xF067EBB1 0x7F87D167 0x92B3823B 0x9F0617D7 0xA7537C57 0x12CAB3D4 
0x3FCB0950: 0xC82EEE37 0x84D4B4BC 0xE1E2261C 0x488F0ADA 0x96EAF2FF 0x0BC493A0 0xCE614467 0x3829053D 
0x3FCB0970: 0xA41156BE 0x2747B77D 0x64DEA90B 0xE704AB0A 0xE4B01006 0x8D51903C 0x56CD3CF2 0x07E0A8E8 
0x3FCB0990: 0xD1DE05CE 0x33368522 0xD1889988 0x3A3097F4 0xB0796D09 0xC78948AA 0x6DEFC56E 0xD5C2E1D9 
0x3FCB09B0: 0xFD6DD8FA 0xA957B675 0xC202D80D 0x733FF8F4 0xA1484913 0x0B9AFBA6 0x330C07EA 0x2C09AD4C 
0x3FCB09D0: 0x3B1E08F7 0x3FCAE7D0 0x00000170 0xABBA1234 0x0000015C 0x3FCB00E0 0x00009C93 0x3FCA13C4 
0x3FCB09F0: 0x3FCA13C4 0x3FCB09E4 0x3FCA13BC 0x00000018 0x00000000 0x00000000 0x3FCB09E4 0x00000000 
0x3FCB0A10: 0x00000001 0x3FCAE7E0 0x706F6F6C 0x6B736154 0x00000000 0x00000000 0x3FCB07D0 0x00000005 
0x3FCB0A30: 0x00000000 0x00000001 0x00000000 0x3FCAB444 0x4209AFF0 0x0017E38F 0x00000000 0x3FCA7BD0 

```

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

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

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-06 17:46:13 +01:00
jpirnay
a35f372e1b fix: avoid zip filename overflow (#1321)
## Summary

* **What is the goal of this PR?** Potential stack buffer overflow from
untrusted ZIP entry name length
* **What changes are included?** If nameLen >= 256 , this writes past
the stack buffer. Risk: memory corruption/crash on malformed EPUB/ZIP.

## Additional Context

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

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _** PARTIALLY **_ Issue
identified by AI
2026-03-05 21:25:17 -06:00
Baris Albayrak
4ef433e373 feat: add turkish translation (#1192)
Description
  This Pull Request introduces Turkish language support to CrossPoint
  Reader firmware.


  Key Changes:
- Translation File: Added lib/I18n/translations/turkish.yaml with 315
translated
     string keys, covering all system UI elements.
- I18N Script Update: Modified scripts/gen_i18n.py to include the "TR"
     abbreviation mapping for Turkish.
- System Integration: Regenerated I18N C++ files to include the new
Language::TR
     enum and STRINGS_TR array.
- UI Availability: The language is now selectable in the Settings menu
and
     correctly handles Turkish-specific characters (ç, ğ, ı, ö, ş, ü).
- Documentation: Updated docs/i18n.md to include Turkish in the list of
     supported languages.

  Testing:
   - Verified the build locally with PlatformIO.
- Flashed the firmware to an Xteink X4 device and confirmed the Turkish
UI
     renders correctly.
---

### AI Usage

Did you use AI tools to help write this code?  Yes Gemini

---------

Co-authored-by: Baris Albayrak <baris@Bariss-MacBook-Pro.local>
Co-authored-by: Barış Albayrak <barisa@pop-os.lan>
2026-03-05 18:24:44 -06:00
Stefan Blixten Karlsson
a5d7e03f54 fix: improve and add Swedish translations (#1317)
## Summary

* **What is the goal of this PR?**
  * Improve and add the latest missing Swedish translations.

* **What changes are included?**
* Added missing Swedish translations in
`lib\I18n\translations\swedish.yaml`
  
## Additional Context

* (none)

---

### 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**_
2026-03-05 14:25:29 -06:00
ariel-lindemann
047b0029c9 chore: add missing translations for Romanian (#1265)
## Summary

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

added Romanian ranslations from recent commits.

---

### 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 >**_
2026-03-05 10:19:17 -06:00
Zach Nelson
c3f1dbfa09 perf: Avoid creating strings for file extension checks (#1303)
## Summary

**What is the goal of this PR?**

This change avoids the pattern of creating a `std::string` using
`.substr` in order to compare against a file extension literal.
```c++
std::string path;
if (path.length() >= 4 && path.substr(path.length() - 4) == ".ext")
```

The `checkFileExtension` utility has moved from StringUtils to
FsHelpers, to be available to code in lib/. The signature now accepts a
`std::string_view` instead of `std::string`, which makes the single
implementation reusable for Arduino `String`.

Added utility functions for commonly repeated extensions.

These changes **save about 2 KB of flash (5,999,427 to 5,997,343)**.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_
2026-03-05 10:12:22 -06:00
Zach Nelson
ea88797c8e chore: Image settings Polish localization (#1299)
## Summary

**What is the goal of this PR?**

Quick follow up to #1291, adding Polish translations suggested by
@th0m4sek

---

### 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**_
2026-03-05 19:08:36 +03:00
pablohc
218201bd1f fix: Correct relative file paths in SKILL.md documentation (#1304)
## Summary

* **What is the goal of this PR?**
Update relative paths to correctly navigate from .skills/ directory to
project root by adding ../ prefix to file references.

* **What changes are included?**
.skills/SKILL.md

---

### 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 >**_
2026-03-05 08:36:53 -06:00
Àngel
6ee05b08a1 chore: add missing Catalan strings (#1302)
## Summary

* **What is the goal of this PR?**
Add missing Catalan strings.

* **What changes are included?**
Changes on catalan.yaml file only.


### 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
2026-03-05 09:28:25 -05:00