Commit Graph
673 Commits
Author SHA1 Message Date
Zach Nelson ea55e6ec47 fix: remove empty-block restore that wiped deposited bottom margins 2026-04-16 00:44:56 -05:00
Zach Nelson 8b940db781 Combine approaches with #1454 2026-04-16 00:39:35 -05:00
Zach Nelson 206bfe760e Merge branch 'master' into fix/nested-block-styles 2026-04-15 23:36:13 -05:00
jpirnayandGitHub 40e4c96906 refactor: replace picojpeg with JPEGDEC for cover art conversion (#1517)
## Summary

- Removes the vendored `picojpeg` library and rewrites
`JpegToBmpConverter` to use the already-present `JPEGDEC` (bitbank2)
dependency
- Eliminates the redundancy of having two JPEG decoders in the firmware
- All BMP output (headers, fixed-point scaling, Atkinson/Floyd-Steinberg
dithering) is identical to before — cached cover BMPs are unaffected

## Size impact

| | Before | After | Delta |
|---|---|---|---|
| Flash | 5,754,089 bytes (87.8%) | 5,744,777 bytes (87.7%) | **−9,312
bytes** |
| RAM | 95,212 bytes (29.1%) | 92,852 bytes (28.3%) | **−2,360 bytes** |

## Implementation notes

- `bmpDrawCallback` receives MCU-sized blocks from JPEGDEC (up to 16
rows × MCU-width), accumulates them into a pre-allocated `mcuBuf`, and
applies the same scaling + dithering logic once each MCU row is complete
- File I/O uses a file-scope static `FsFile*` (safe in single-threaded
embedded context) via JPEGDEC's open/read/seek callbacks — same pattern
as `JpegToFramebufferConverter`
- Added a 52 KB free-heap guard before allocating the JPEGDEC object
(~17 KB)
- `lib/picojpeg/` deleted (2,087 lines of C removed)

## Test plan

- [ ] Build compiles without warnings
- [ ] Cover art BMP cache regenerates correctly for EPUB books
- [ ] Home screen thumbnails (1-bit BMP path) render correctly
- [ ] Custom-size thumbnails (`jpegFileToBmpStreamWithSize`) render
correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-15 23:20:24 -05:00
Stefan Blixten KarlssonandGitHub 80772ff6b8 fix: footnote link text (#1666)
## Summary

Previouls where ALL whitespace (and square brackes) removed from the
footnote link text, however some link texts are multiworded, like "`turn
to 252`" which were truncated into "`turnto252`", (an example from the
first book "Flight from the Dark" of the Lone Wolf book series by Joe
Dever, see [link](https://www.projectaon.org/en/Main/FlightFromTheDark))

* This change will only remove whitespaces from the beginning and end of
the string
so "` [ 12 ] `" will become "`12`" just like before, and "` turn to 252
`" will become "`turn to 252`".

---

### 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-04-15 21:47:10 -05:00
Stefan Blixten KarlssonandGitHub 57fc6555f2 fix: missing swedish translations (#1667)
## Summary

* Add missing swedish translations

---

### 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-04-15 19:05:09 -05:00
jpirnayandGitHub ed54f97909 fix: Fix ghosting on exit of BMPViewer (#1432)
## Summary

* **What is the goal of this PR?** After displaying an image via the
filebrowser ghosting artifacts remained on the screen
* **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-04-16 00:52:29 +02:00
jpirnayandGitHub 45cd00889e chore: clang-format.fix.ps1 script: Add .venv to list of path exclusions (#1515)
## Summary

* **What is the goal of this PR?** Dont format files in .venv directory
* **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 | PARTIALLY | NO
>**_
2026-04-14 18:50:37 -05:00
Егор МартыновandGitHub cced77783f feat: add orientation-aware popups for reader activities (#1428)
## Summary

Make popups (like "Going to sleep") respect the current screen
orientation when shown from reader activities.

**What changes are included?**

- Apply reader orientation in SleepActivity before showing popup when
`lastSleepFromReader` is true
- Make popup Y-position proportional to screen height (7.5% for
BaseTheme, 16.5% for LyraTheme) instead of hardcoded pixel values,
ensuring correct positioning in both portrait and landscape modes.
- Add `isReaderActivity()` override to all reader sub-screens (menu,
chapter selection, percent selection, footnotes, QR display, KOReader
sync), so sleep popups rotate correctly when entering sleep from any
reader context.

## Additional Context

<img
src="https://github.com/user-attachments/assets/47d88c2c-ffc5-41a7-b3f2-af272ea0150e"
width="400" height="240">

---

### 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**_ (Claude Opus
4.5)
2026-04-14 17:21:55 -05:00
Zach NelsonandGitHub 1bd7a1de67 refactor: Deduplicate battery drawing code and fix Lyra charging indicator (#1437)
## Summary

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

Following up on #1427:
- Extracted shared battery drawing logic, including lightning bolt, to
reduce duplication.
- In Lyra with segmented battery the lightning bolt was hard to see, so
when charging Lyra now uses a solid battery fill.

---

### 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-04-14 17:05:06 -05:00
Zach NelsonandGitHub 23aad213fc refactor: Removed redundant FsFile close() calls (#1434)
## Summary

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

`DESTRUCTOR_CLOSES_FILE=1` is set in platformio.ini, which makes SdFat's
FsBaseFile destructor call close() automatically when a file goes out of
scope.

Three categories of file close calls remain untouched:
1. Close before Storage.remove() on the same path: ScreenshotUtil.cpp
closes the file before deleting it on write error. The remove might fail
if the file is still open.
2. Close before reopening the same variable: Epub.cpp writes a temp
NCX/nav file, closes it, then reopens it for reading. The
RecentBooksStore.cpp close before saveToFile() is the same pattern, it
rewrites the same file.
3. Close on member variables: BookMetadataCache.cpp (bookFile,
spineFile, tocFile), Section.cpp (file), XtcParser.cpp (m_file),
ZipFile.cpp (file). These persist beyond any single function scope, so
the destructor timing doesn't match the intended close point.

---

### 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-04-14 16:41:05 -05:00
075ad7d021 fix: Use font metrics for combining mark positioning (#1310)
## Summary

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

Combining diacritical marks (U+0300–U+036F) were positioned using a
heuristic that centered them at the midpoint of the base glyph's
**advance width**. This worked acceptably for Bookerly but produced
visibly off-center marks for Noto Sans due to a fundamental difference
in how the two fonts design their combining mark metrics.

Builds on the work of #1037.

## The problem

The two built-in body fonts encode combining mark `left` offsets with
very different conventions:

| Mark | Bookerly `left` | Noto Sans `left` |
|---|---|---|
| U+0301 (acute) | -2 | -10 |
| U+0300 (grave) | -5 | -15 |
| U+0302 (circumflex) | -5 | -5 |
| U+0323 (dot below) | -2 | -11 |

Noto Sans uses large negative `left` values because its marks are
designed for placement at the post-advance cursor position, with `left`
pulling the bitmap back over the base glyph. Bookerly uses small offsets
because its marks sit closer to the glyph origin. The old `advance/2`
centering split the difference poorly — it happened to land close to
correct for Bookerly but placed Noto Sans marks roughly 6px left of
center on a typical lowercase letter.

There was also a bug in the vertical gap heuristic. It unconditionally
computed a `raiseBy` value to prevent above-baseline marks from
colliding with tall base glyphs, but it applied the same logic to
**below-baseline** marks like cedilla (U+0327), dot below (U+0323), and
ogonek (U+0328). For those marks, the math produced a large positive
raise (e.g., 24px for dot-below on 'a'), launching them above the
x-height instead of keeping them below the baseline.

## The fix

**Horizontal positioning**: Instead of centering at `advance/2`, align
the mark bitmap's visual midpoint directly over the base glyph bitmap's
visual midpoint. This uses the base glyph's actual `left` and `width`
rather than its advance width, producing correct results regardless of
how the font encodes its mark offsets.

**Vertical positioning**: The raise heuristic now checks `markTop -
markHeight > 0` and skips below-baseline marks entirely, leaving them at
their font-designed position.

**Consolidation**: The shared math is extracted into two `constexpr`
helpers (`combiningMark::centerOver` and
`combiningMark::raiseAboveBase`) in `EpdFontData.h`, eliminating the
previously triplicated inline calculations across `drawText`,
`drawTextRotated90CW`, and `getTextBounds`. The `MIN_COMBINING_GAP_PX`
constant is also centralized as `combiningMark::MIN_GAP_PX`.

| Before | After |
| -- | -- |
| <img
src="https://github.com/user-attachments/files/25752257/before-noto.bmp"
width="250" /> | <img
src="https://github.com/user-attachments/files/25752258/after-noto.bmp"
width="250" /> |
| <img
src="https://github.com/user-attachments/files/25752259/before-bookerly.bmp"
width="250" /> | <img
src="https://github.com/user-attachments/files/25752260/after-bookerly.bmp"
width="250" /> |

---

### 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
differences between Noto Sans and Bookerly font metrics**_

---------

Co-authored-by: Uri Tauber <142022451+Uri-Tauber@users.noreply.github.com>
2026-04-14 14:35:50 -05:00
Xuan-Son NguyenandGitHub 243ae8b408 feat: show crash reason on boot (#1453)
## Summary

If the system reboots from crash, display the reason and tell user to
include `crash_report.txt` file.

To test this, simply add an `assert(false)` somewhere inside the code.


![screenshot-74453.bmp](https://github.com/user-attachments/files/26160373/screenshot-74453.bmp)

---

### 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-04-13 15:23:45 -05:00
4e9c7a787f feat: show full path bar in file browser (#1411)
![obraz](https://github.com/user-attachments/assets/f848a381-7c45-4724-912b-56168791bcf3)


## Summary

Adds a full path display at the bottom of the file browser with a
separator line matching the header style. Path uses the small font,
left-truncates to always show the deepest folder when path is too long.
Toggleable via Settings > System > Show Full Path (default 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 >**_

---------

Co-authored-by: Patryk Radtke <patryk@Patryks-MacBook-Pro.local>
2026-04-13 15:12:49 -05:00
Russell NechesandGitHub cc23aaa9c2 docs: Update README with firmware flashing instructions (#1654)
Added instructions for flashing firmware using esptool.

## Summary

Instructions for flashing a specific firmware from the terminal using
`esptool.py`.

## Additional Context

Not everyone has Chrome or Chromium installed. An alternative to the
web-based firmware utility shouldn't be hard to find.

---

### AI Usage

Did you use AI tools to help write this code? _**PARTIALLY**_ : `dmesg`
command analog for MacOS
2026-04-13 13:50:31 -05:00
DianaandGitHub 05f8e6e12d fix: webserver /delete API backward compatibility (#1475)
## Summary

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

This fixes #682 by restoring API compatibility for external users, eg
deleting on-device books in bulk via calibre using the crosspoint plugin
works now.

* **What changes are included?**

The `/delete` webserver API now accepts the old `path` argument and maps
it to a JSON array element. It is made an error to provide both
arguments.

## Additional Context

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

I have compiled, flashed, and tested this on master at commit
0245972132. Before this change, calibre
cannot delete books, either individually or in bulk.

After this change, it can do so successfully.

---

### 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-04-13 08:59:07 +03:00
Ian ChasseandGitHub 405ce0c3c8 feat: Rework "Cover + Custom" sleep screens to show covers only when currently reading (#1256)
## Summary

The cover/custom setting was a bit misleading to me. Usually after you
start reading a book you never see your customs again unless a cover
fails to render for some reason. With this, you can easily show your
custom images by just sleeping from the menus instead of the reader

## 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-04-12 21:03:23 -04:00
CSCMeandGitHub 9bc5111c77 fix: increase loadable epub size (#1638)
## Summary

* **What is the goal of this PR?** Slightly increase the OOM limit when
loading epubs
* **What changes are included?** Switched vectors for parsing epubs to
deques, allowing use of more memory

## Additional Context

* Increases loadable epub size from 2000+ chapter/ToC entries loadable
to 5000+ chapter/ToC entries
* #1574, but without the complicated stuff

---

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

### Testing
| Commit | Book | Time |
|----------|------|-------|
| 83cd96bc2f | 1000.epub | ~30 sec |
| 83cd96bc2f | 5000.epub | crash |
| PR | 1000.epub | ~29 sec |
| PR | 5000.epub | ~2 min 20 sec |

=> No actual loading time regressions

[tested_epubs.zip](https://github.com/user-attachments/files/26645243/tested_epubs.zip)
2026-04-12 18:41:28 -05:00
bdeshiandGitHub 9c11f3e4a2 feat: enable manual screen refresh on power button short press (#1626)
## Summary

Adds an option to allow manual screen refresh on power button short
press.

## Additional Context

there's an option to refresh the screen after a set number of pages. but
sometimes a manual refresh is needed to clear up stale ink pixels. this
works everywhere both in and out of reading mode.

resolves #550 

---

### 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
understand the project structure.
2026-04-12 22:31:26 +03:00
fa2a3d2539 feat: add OPDS search support & next/prev page navigation (#1462)
## Summary

**What is the goal of this PR?**
Adds OPDS search support, allowing users to search a catalog directly
from the book browser when the server exposes an OpenSearch template.

**What changes are included?**
- `OpdsParser`: parses the OpenSearch template URL from feed-level
`<link rel="search">` elements and exposes it via `getSearchTemplate()`
- `OpdsBookBrowserActivity`: fetches and stores the search template
after each feed load; shows a Search hint on the Left button when a
template is available; launches the existing `KeyboardEntryActivity` for
query input; URL-encodes the query and fetches the result feed
- Absolute search result URLs are handled correctly in `fetchFeed`
(skips prepending the server base URL)
- A `consumeConfirm` guard prevents the Confirm release that submits the
keyboard from immediately triggering a book download on the first
browsing frame after search results load

## Additional Context

- Search is silently unavailable if the server does not advertise an
OpenSearch template — no UI change in that case
- Tested against a Calibre-Web OPDS endpoint which exposes `<link
rel="search" type="application/opensearchdescription+xml">`
- The inline URL encoder in `performSearch` was necessary as
`StringUtils` has no such utility; worth considering extracting to
`StringUtils` in a follow-up
- No new dependencies introduced

---

### 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: kira <rammah@tuta.io>
Co-authored-by: Justin Mitchell <justin@jmitch.com>
2026-04-12 12:24:27 -04:00
MraulioandGitHub 5c12f2f01e fix: avoid skipping chapter after screenshot (#1625)
## Summary

* **What is the goal of this PR?** 
Fixes skipping chapter when it's enabled in Settings and you take a
Screenshot.
* **What changes are included?**
A simple return if Power and Down were released before the skipChapter.

## Additional Context

* There is an Issue related #1595.
* Checked that it kept the Power button funcionality for Next page and
Suspend.

---

### 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-04-11 20:28:00 +03:00
8d6b35b8e7 fix: back navigation from BMPViewer (#1597)
## Summary

This fixes navigating back from the BMP Viewer to the FileBrowser which
was broken when moving to the new ActivityManager

This is fixed by making FileBrowserActivity able to take a full file
path on enter and splitting the basePath and fileName from it and
navigating to the correct place.

fixes:
https://github.com/crosspoint-reader/crosspoint-reader/issues/1553

duplicates:
https://github.com/crosspoint-reader/crosspoint-reader/pull/910 to some
extend but mine has the file cursor at the correct file instead of the
first one in the folder

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

---------

Co-authored-by: Jan Ivanov <jan.ivanov@sirma.com>
2026-04-11 20:20:46 +03:00
Justin MitchellandGitHub 83cd96bc2f fix: Wild pointer crash in JPEGDEC MCU_SKIP handling (#1627)
Adds a PlatformIO pre-build script to patch JPEGDEC library. When
decoding progressive JPEGs with AC coefficients, MCU_SKIP (-8) causes
array index 0xFFFFF8, creating a wild pointer ~33MB past the sMCUs
array. The patch redirects pMCU to sMCUs[0] when MCU_SKIP is active,
preventing store-access faults while maintaining correct behavior for
JPEG_SCALE_EIGHTH decoding. Devices with larger framebuffers (like the
x3) (792×528 = 52,272 bytes vs 800×480 = 48,000 bytes) have less free
heap, shifting the allocation and changing where the wild pointer lands.

Commit 8628297 guarded the DC coefficient write (pMCU[0]) with if (iMCU
>= 0), which prevents crashes for progressive JPEGs whose first scan is
DC-only (iScanEnd == 0). However, if the first scan includes AC
coefficients (iScanEnd > 0), the AC decode loop still writes through the
wild pointer and crashes.
2026-04-10 21:13:59 +01:00
14ec53a335 feat: Added Slovenian translation (#1551)
Adde

## Summary

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

Adding Slovenian translation

* **What changes are included?**

Just new slovenian.yaml file with translated strings

## Additional Context

I kindly ask to include it in next release.

---

### 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: Andrej Kralj <andrej.kralj@gmail.com>
Co-authored-by: Uri Tauber <142022451+Uri-Tauber@users.noreply.github.com>
2026-04-10 11:00:32 -05:00
Zach NelsonandGitHub 5ba85290ab refactor: Deduplicated BMP header writing in Xtc (#1439)
## Summary

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

Replaced manual 1-bit BMP header logic in `Xtc::generateCoverBmp()` and
`Xtc::generateThumbBmp()` with calls to the existing `createBmpHeader()`
utility. Added a `BmpRowOrder` enum and param to support the top-down
row order of XTC cover images.

---

### 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-04-10 00:35:43 +03:00