Commit Graph
695 Commits
Author SHA1 Message Date
GenesiaWandGitHub 3b4f2a1129 feat: Auto Page Turn for Epub Reader (#1219)
## Summary

* **What is the goal of this PR?** (e.g., Implements the new feature for
file uploading.)
- Implements auto page turn feature for epub reader in the reader
submenu

* **What changes are included?**
  - added auto page turn feature in epub reader in the submenu
  - currently there are 5 settings, `OFF, 1, 3, 6, 12` pages per minute

## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks,
  specific areas to focus on).
  - Replacement PR for #723 
- when auto turn is enabled, space reserved for chapter title will be
used to indicate auto page turn being active
  - Back and Confirm button is used to disable it

---

### 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 (mainly code
reviews)**_
2026-02-27 22:42:41 +03:00
09cef70709 fix: clarity issue with ambiguous string SET (#1169)
## Summary

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

Fixes a clarity issue regarding the translation string `STR_SET`. The
issue lies in the fact that the english word can have different
meanings.

The only time the string is used is in the language selectio screen,
where it has the meaning of _selected_. (As in _The language has been
**set** to French_).

Another meaning can be _configured_. (As in _The KOReader username has
been __set__). This is the meaning many of the translations have taken.
The reason that the string is right above `STR_NOT_SET` (which is meant
as _not configured_).

With this PR I propose to explicitly use the term "_Selected_". There
are two good reasons for this:
+ it removes the confusion and the misleading translations
+ it is consistent with the button label `Select`, communicating the
link between the two (the row will be marked `Selected` if you press the
buttpn `Select`. Much clearer than now)

* **What changes are included?**

Removed the unused strings and added translations for the new string
`STR_SELECTED` for the languages I know.

tagging the translators for feedback:
fr: @Spigaw @CaptainFrito 
de: @DavidOrtmann
cs: @brbla 
pt: @yagofarias
it: @andreaturchet @fargolinux
ru: @madebykir @mrtnvgr 
es: @yeyeto2788 @Skrzakk @pablohc 
sv: @dawiik
ca: @angeldenom 
uj: @mirus-ua 
be: @dexif 

## Additional Context

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

the Issue was introduced in #1020. Previously, if a language was
selected it was marked with `[ON]` (`STR_ON_MARKER`). I considered
reverting it back to that, but the solution I described above seemed
superior.

---

### 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: Егор Мартынов <martynovegorOF@yandex.ru>
Co-authored-by: Mirus <mirusim@gmail.com>
2026-02-27 11:45:05 -06:00
Willy HardyandGitHub 4fb785af82 docs: add quick KOReader sync setup guide (#1181)
## Summary

* **What is the goal of this PR?**
Improve KOReader Sync documentation so new users can self-host and
configure sync quickly, with clear references in both README and
USER_GUIDE.

* **What changes are included?**
- Add a KOReader Sync feature mention in `README.md` and link to a
quick-setup section in the guide.
- Add `3.6.5 KOReader Sync Quick Setup` to `USER_GUIDE.md` with:
- Docker Compose-first setup instructions (plus Podman compose
alternative)
  - healthcheck verification
  - one-time user registration example using `curl`
- device-side setup steps (`Settings -> System -> KOReader Sync` and
`Authenticate`)
  - in-reader usage via `Sync Progress` in the reader menu
- Update reading mode navigation wording from "Chapter Menu" to "Reader
Menu" so it reflects current UI behavior.

Closes #1032.

## Additional Context

* This is documentation-only and does not change firmware behavior.
* The quick-setup flow is intentionally short and focused on getting
sync working quickly for typical home-network setups.

---

### 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-02-27 09:59:53 -06:00
74c7205967 feat: add Dutch translation (#1204)
## Summary

* **Added Dutch translation** 
* **(Added dutch.yaml translation 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? _**< PARTIALLY>**_

---------

Co-authored-by: Bas van der Ploeg <bas@MBP-M2-Max-3.localdomain>
2026-02-27 09:10:18 -06:00
Victor DomingosandGitHub 93d4a34c37 chore: Add Portuguese (Portugal) translator to the list (#1211)
## Summary

* **What is the goal of this PR?** (e.g., Implements the new feature for
file uploading.)
* **What changes are included?**
Added translator name for Portuguese (Portugal)

---

### AI Usage



Did you use AI tools to help write this code? _**<  NO >**_
2026-02-27 14:10:22 +03:00
c4fc4effbd refactor: implement ActivityManager (#1016)
## Summary

Ref comment:
https://github.com/crosspoint-reader/crosspoint-reader/pull/1010#pullrequestreview-3828854640

This PR introduces `ActivityManager`, which mirrors the same concept of
Activity in Android, where an activity represents a single screen of the
UI. The manager is responsible for launching activities, and ensuring
that only one activity is active at a time.

Main differences from Android's ActivityManager:
- No concept of Bundle or Intent extras
- No onPause/onResume, since we don't have a concept of background
activities
- onActivityResult is implemented via a callback instead of a separate
method, for simplicity

## Key changes

- Single `renderTask` shared across all activities
- No more sub-activity, we manage them using a stack; Results can be
passed via `startActivityForResult` and `setResult`
- Activity can call `finish()` to destroy themself, but the actual
deletion will be handled by `ActivityManager` to avoid `delete this`
pattern

As a bonus: the manager will automatically call `requestUpdate()` when
returning from another activity

## Example usage

**BEFORE**:

```cpp
// caller
    enterNewActivity(new WifiSelectionActivity(renderer, mappedInput,
                                               [this](const bool connected) { onWifiSelectionComplete(connected); }));

// subactivity
  onComplete(true); // will eventually call exitActivity(), which deletes the caller instance (dangerous behavior)
``` 

**AFTER**: (mirrors the `startActivityForResult` and `setResult` from
android)

```cpp
// caller
  startActivityForResult(new NetworkModeSelectionActivity(renderer, mappedInput),
                         [this](const ActivityResult& result) { onNetworkModeSelected(result.selectedNetworkMode); });

// subactivity
  ActivityResult result;
  result.isCancelled = false;
  result.selectedNetworkMode = mode;
  setResult(result);
  finish(); // signals to ActivityManager to go back to last activity AFTER this function returns
```

TODO:
- [x] Reconsider if the `Intent` is really necessary or it should be
removed (note: it's inspired by
[Intent](https://developer.android.com/guide/components/intents-common)
from Android API) ==> I decided to keep this pattern fr clarity
- [x] Verify if behavior is still correct (i.e. back from sub-activity)
- [x] Refactor the `ActivityWithSubactivity` to just simple `Activity`
--> We are using a stack for keeping track of sub-activity now
- [x] Use single task for rendering --> avoid allocating 8KB stack per
activity
- [x] Implement the idea of [Activity
result](https://developer.android.com/training/basics/intents/result)
--> Allow sub-activity like Wifi to report back the status (connected,
failed, etc)

---

### 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**, some
repetitive migrations are done by Claude, but I'm the one how ultimately
approve it

---------

Co-authored-by: Zach Nelson <zach@zdnelson.com>
2026-02-27 00:32:40 -06:00
pablohcandGitHub 5b11e45a36 fix: prevent infinite render loop in Calibre Wireless after file transfer (#1070)
## Summary

* **What is the goal of this PR?**
Fix an infinite render loop bug in CalibreConnectActivity that caused
the e-ink display to refresh continuously every ~421ms after a file
transfer completed.

* **What changes are included?**
- Added lastProcessedCompleteAt member variable to track which server
completion timestamp has already been processed
- Modified the completion status update logic to only accept new values
from the server, preventing re-processing of old timestamps
- Added clarifying comments explaining the fix

## Problem Description
After receiving a file via Calibre Wireless, the activity displays
"Received: [filename]" for 6 seconds, then clears the message. However,
the web server's wsLastCompleteAt timestamp persists indefinitely and is
never cleared.

This created a race condition:

After 6 seconds, lastCompleteAt is set to 0 (timeout)
In the next loop iteration, status.lastCompleteAt (still has the old
timestamp) ≠ lastCompleteAt (0)
The code restores lastCompleteAt from the server value
Immediately, the 6-second timeout condition is met again
This creates an infinite cycle causing unnecessary e-ink refreshes

## Solution
The fix introduces lastProcessedCompleteAt to track which server
timestamp value has already been processed:

Only accept a new status.lastCompleteAt if it differs from
lastProcessedCompleteAt
Update lastProcessedCompleteAt when processing a new value
Do NOT reset lastProcessedCompleteAt when the 6-second timeout clears
lastCompleteAt
This prevents re-processing the same old server value after the timeout.

## Testing
Tested on device with multiple file transfer scenarios:

 File received message appears correctly after transfer
 Message clears after 6 seconds as expected
 No infinite render loop after timeout
 Multiple consecutive transfers work correctly
 Exiting and re-entering Calibre Wireless works as expected

## Performance Impact
Before: Infinite refreshes every ~421ms after timeout (high battery
drain, display wear)
After: 2-3 refreshes after timeout, then stops (normal behavior)


## Additional Context
This is a targeted fix that only affects the Calibre Wireless file
transfer screen. The root cause is the architectural difference between
the persistent web server state (wsLastCompleteAt) and the per-activity
display state (lastCompleteAt).

An alternative fix would be to clear wsLastCompleteAt in the web server
after some timeout, but that would affect all consumers of the web
server status. The chosen solution keeps the fix localized to
CalibreConnectActivity.

---

### AI Usage

Did you use AI tools to help write this code? _**< YES >**_
2026-02-26 23:34:11 -06:00
d05cb220bb feat: Polish translation tweaks (#1193)
## Summary

* **What is the goal of this PR?** some tweaks to Polish translation
* **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
>**_

---------

Co-authored-by: Zach Nelson <zach@zdnelson.com>
Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-26 18:53:30 -06:00
Victor DomingosandGitHub 125e091d13 fix: Small typo in i18n.md regarding C++ identifiers (#1210)
## Summary

fixes just a small typo in docs.


---

### AI Usage
Did you use AI tools to help write this code? _**< NO >**_
2026-02-26 23:00:34 +00:00
jpirnayandGitHub 6b64a0a2d8 feat: aiagent context definition (#922)
## Summary

* As many of us have experienced, the use of AI coding agents (Claude,
Cursor, Copilot) in our daily workflows is no longer a hypothetical—it
is a reality. While these tools can significantly accelerate
development, they also pose a unique risk to a project like CrossPoint
Reader, where our hardware constraints (ESP32-C3 with ~380KB RAM) are
extremely tight.

* AI models often "hallucinate" APIs or suggest high-level C++ patterns
(like std::string or heavy heap usage) that are detrimental to our
memory-constrained environment.

* To address this, I am proposing the introduction of an AI Agent
Guidance File (.skills/SKILL.md recognized by many AI systems). This
file acts as a "Constitutional Document" for AI agents, forcing them to
adhere to our specific engineering rigors before they generate a single
line of code.

## 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**_ Asked
several Ai systems about their needs, added my own 5 cents of nuisances
I faced
2026-02-26 16:59:09 -06:00
1abe307f20 perf: Optimize HTML entities lookup to O(log(n)) (#1194)
## Summary

**What is the goal of this PR?** Replace the linear scan of
`lookupHtmlEntity` with a simple binary search to improve lookup
performance.

**What changes are included?**
`lib/Epub/Epub/Entities/htmlEntities.cpp`: 
 - Sorted the `ENTITY_LOOKUP` array.
 - Added a compile-time assertion to guarantee the array remains sorted.
 - Rewrote `lookupHtmlEntity` to use a binary search.

## Additional Context

Benchmarked on my x64 laptop (probably will be different on RISC-V)
```
=== Benchmark (53 entities x 10000 iterations) ===

Version           Total time   Avg per lookup
----------------------------------------------
linear          236.97 ms total     447.11 ns/lookup
binary search    22.09 ms total      41.68 ns/lookup

=== Summary ===

Binary search is 10.73x faster than linear scan.
```

This is a simplified alternative to #1180, focused on keeping the
implementation clean, and maintainable.

### AI Usage


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

---------

Co-authored-by: Zach Nelson <zach@zdnelson.com>
2026-02-26 12:55:31 -06:00
MirusandGitHub f7814cd139 chore: new Ukrainian translation lines (#1199)
## Summary

* **What is the goal of this PR?** 
Update translation after
https://github.com/crosspoint-reader/crosspoint-reader/pull/733

---

### 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-02-26 12:54:13 -06:00
madebyKirandGitHub 3f98a87709 chore: Update russian.yaml (#1198)
## Summary

Translation added russian.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? _**< YES | PARTIALLY | NO
>**_
NO
2026-02-26 09:15:34 -06:00
30d8a8d011 feat: slim footnotes support (#1031)
## Summary
**What is the goal of this PR?** Implement support for footnotes in epub
files.
It is based on #553, but simplified — removed the parts which
complicated the code and burden the CPU/RAM. This version supports basic
footnotes and lets the user jump from location to location inside the
epub.

**What changes are included?**
- `FootnoteEntry` struct — A small POD struct (number[24], href[64])
shared between parser, page storage, and UI.
- Parser: `<a href>` detection (`ChapterHtmlSlimParser`) — During a
single parsing pass, internal epub links are detected and collected as
footnotes. The link text is underlined to hint navigability.
Bracket/whitespace normalization is applied to the display label (e.g.
[1] → 1).
- Footnote-to-page assignment (`ChapterHtmlSlimParser`, `Page`) —
Footnotes are attached to the exact page where their anchor word
appears, tracked via a cumulative word counter during layout, surviving
paragraph splits and the 750-word mid-paragraph safety flush.
- Page serialization (`Page`, `Section`) — Footnotes are
serialized/deserialized per page (max 16 per page). Section cache
version bumped to 14 to force a clean rebuild.
- Href → spine resolution (`Epub`) — `resolveHrefToSpineIndex()` maps an
href (e.g. `chapter2.xhtml#note1`) to its spine index by filename
matching.
- Footnotes menu + activity (`EpubReaderMenuActivity`,
`EpubReaderFootnotesActivity`) — A new "Footnotes" entry in the reader
menu lists all footnote links found on the current page. The user
scrolls and selects to navigate.
- Navigate & restore (`EpubReaderActivity`) — `navigateToHref()` saves
the current spine index and page number, then jumps to the target. The
Back button restores the saved position when the user is done reading
the footnote.

  **Additional Context**

**What was removed vs #553:** virtual spine items
(`addVirtualSpineItem`, `isVirtualSpineItem`), two-pass parsing,
`<aside>` content extraction to temp HTML files, `<p class="note">`
paragraph note extraction, `replaceHtmlEntities` (master already has
`lookupHtmlEntity`), `footnotePages` / `buildFilteredChapterList`,
`noterefCallback` / `Noteref` struct, and the stack size increase from 8
KB to 24 KB (not needed without two-pass parsing and virtual file I/O on
the render task).
 
**Performance:** Single-pass parsing. No new heap allocations in the hot
path — footnote text is collected into fixed stack buffers (char[24],
char[64]). Active runtime memory is ~2.8 KB worst-case (one page × 16
footnotes × 88 bytes, mirrored in `currentPageFootnotes`). Flash usage
is unchanged at 97.4%; RAM stays at 31%.
   
**Known limitations:** When clicking a footnote, it jumps to the start
of the HTML file instead of the specific anchor. This could be
problematic for books that don't have separate files for each footnote.
(no element-id-to-page mapping yet - will be another PR soon).

---

### AI Usage

Did you use AI tools to help write this code? _**< PARTIALLY>**_
Claude Opus 4.6 was used to do most of the migration, I checked manually
its work, and fixed some stuff, but I haven't review all the changes
yet, so feedback is welcomed.

---------

Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-26 08:47:34 -06:00
ariel-lindemannandGitHub 451774ddf8 fix: broken translations in status bar settings (#1188)
## Summary

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

The strings for `Show` and `Hide` were always showing in English,
regardless of which language was selected.

* **What changes are included?**

Replace the variables in the lambda by direct calls to the `tr` macro

## 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-02-26 11:25:34 +03:00
ariel-lindemannandGitHub 8c27938979 fix: add missing romanian strings (#1187)
## Summary

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

Romanian translations for newly added strings.

* **What changes are included?**

Only the 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-02-26 11:22:30 +03:00
4a0ef05899 feat: add full Danish translation (#1146)
## Summary

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

* **What changes are included?**
Everything from
[`i18n.md`](https://github.com/crosspoint-reader/crosspoint-reader/blob/master/docs/i18n.md)

---

## Additional Context

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

No

---

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

Started translating myself, transitioned to having Claude Code do the
bulk of the translation. Read every translation myself and doubled
checked with a dictionary if I agreed with the translation made.

---------

Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-26 11:21:03 +03:00
c99a673e5b feat: Add Finnish translations (#1133)
## Summary

* **What is the goal of this PR?** (e.g., Implements the new feature for
file uploading.)
Adds Finnish language support
* **What changes are included?**
Created new translation yaml file, ran the translation script to
generate the C++ code

---

### 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: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-25 17:03:35 +00:00
cae8517235 feat: Add Polish Language (#1155)
## Summary

* **What is the goal of this PR?** Implements Polish 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 | PARTIALLY | NO
>**_

---------

Co-authored-by: Zach Nelson <zach@zdnelson.com>
Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-25 17:01:19 +00:00
ariel-lindemannandGitHub 7e214ea760 feat: sort languages in selection menu (#1071)
## Summary

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

Currently we are displaying the languages in the order they were added
(as in the `Language` enum). However, as new languages are coming in,
this will quickly be confusing to the users.

But we can't just change the ordering of the enum if we want to respect
bakwards compatibility.

So my proposal is to add a mapping of the alphabetical order of the
languages. I've made it so that it's generated by the `gen_i18n.py`
script, which will be used when a new language is added.


* **What changes are included?**

Added the array from the python script and changed
`LanguageSelectActivity` to use the indices from there. Also commited
the generated `I18nKeys.h`

## 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 was wondering if there is a better way to sort it. Currently, it's by
unicode value and Czech and Russian are last, which I don't know it it's
the most intuitive.

The current order is:
`Català, Deutsch, English, Español, Français, Português (Brasil),
Română, Svenska, Čeština, Русский`

---

### 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-02-25 19:44:17 +03:00
jpirnayandGitHub b695a48af6 fix: WiFi lifecycle and hyphenation heap defragmentation for KOReader sync (#1151)
## Summary

* **What is the goal of this PR?** KOReader sync on a German-language
book would fail with an out-of-memory error when trying to open the
destination chapter after applying remote progress. The root cause was a
chain of two independent bugs that combined to exhaust the contiguous
heap needed by the EPUB inflate pipeline.
* **What changes are included?**
## Fix 1 — Hyphenation heap defragmentation (LiangHyphenation.cpp)
### What was happening
AugmentedWord, the internal struct used during Liang pattern matching,
held three std::vector<> members (bytes, charByteOffsets,
byteToCharIndex) plus a separate scores vector — a total of 4 heap
allocations per word during page layout. For a German-language section
with hundreds of words, thousands of small malloc/free cycles fragmented
the heap. Total free memory was adequate (~108 KB) but the largest
contiguous block shrank well below the 32 KB needed for the INFLATE ring
buffer used during EPUB decompression. The failure was invisible with
hyphenation disabled, where MaxAlloc stayed at ~77 KB; enabling German
hyphenation silently destroyed the contiguity the allocator needed.

### What changed
The three std::vector<> members of AugmentedWord and the scores vector
are replaced with fixed-size C arrays on the render-task stack:
```
uint8_t bytes[160]           // was std::vector<uint8_t>
size_t  charByteOffsets[70]  // was std::vector<size_t>
int32_t byteToCharIndex[160] // was std::vector<int32_t>
uint8_t scores[70]           // was std::vector<uint8_t>  (local in liangBreakIndexes)
```
Sizing is based on the longest known German word (~63 codepoints × 2
UTF-8 bytes + 2 sentinel dots = 128 bytes); MAX_WORD_BYTES=160 and
MAX_WORD_CHARS=70 give comfortable headroom. The same analysis holds for
all seven supported languages (en, fr, de, es, it, ru, uk) — every
accepted letter encodes to at most 2 UTF-8 bytes after case-folding.
Words exceeding the limits are silently skipped (no hyphenation
applied), which is correct behaviour. The struct lives on the 8 KB
render-task stack so no permanent DRAM is consumed.

Verification: after the fix, MaxAlloc reads 77,812 bytes with German
hyphenation enabled — identical to the figure previously achievable only
with hyphenation off.

## Fix 2 — WiFi lifecycle in KOReaderSyncActivity
(KOReaderSyncActivity.cpp)
### What was happening

onEnter() called WiFi.mode(WIFI_STA) unconditionally before delegating
to WifiSelectionActivity. WifiSelectionActivity manages WiFi mode
internally (it calls WiFi.mode(WIFI_STA) again at scan start and at
connection attempt). The pre-emptive call from KOReaderSyncActivity
interfered with the sub-activity's own state machine, causing
intermittent connection failures that were difficult to reproduce.

Additionally, WiFi was only shut down in onExit(). If the user chose
"Apply remote progress" the activity exited without turning WiFi off
first, leaving the radio on and its memory allocated while the EPUB was
being decompressed — unnecessarily consuming the contiguous heap
headroom that inflate needed.

### What changed

* WiFi.mode(WIFI_STA) removed from onEnter(). WifiSelectionActivity owns
WiFi mode; KOReaderSyncActivity should not touch it before the
sub-activity runs.
* A wifiOff() helper (SNTP stop + disconnect + WIFI_OFF with settling
delays) is extracted into the anonymous namespace and called at every
web-session exit point:
  - "Apply remote" path in loop() — before onSyncComplete()
  - performUpload() success path
  - performUpload() failure path
  - onExit() (safety net for all other exit paths)

## 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**_ and two days of
blood, sweat and heavy swearing...
2026-02-25 08:27:18 -06:00
divinitycoveandGitHub a6c5d9aa7c fix: Change "UI Font Size" to "Reader Font Size" (#1171)
## Summary

* **What is the goal of this PR?** (e.g., Implements the new feature for
file uploading.)
Update "UI Font Size" to "Reader Font Size", to match the rest of the
"Reader" settings and clarify that the setting doesn't change the UI
font.

* **What changes are included?**
Changes the `english.yaml` string and USER_GUIDE.md entry.

## 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
>**_
NO
2026-02-25 08:22:59 -06:00
2d49c7b7b4 feat: split status bar setting (#733)
## Summary

This PR aims to reduce the complexity of the status bar by splitting the
setting into 5:
- Chapter Page Count
- Book Progress %
- Progress Bar
- Chapter Title
- Battery Indicator

These are located within the new StausBarSettings activity, which also
shows a preview of the bar the user has created

<img width="513" height="806" alt="image"
src="https://github.com/user-attachments/assets/cdf852fb-15d8-4da2-a74f-fd69294d7b05"
/>


<img width="483" height="797" alt="image"
src="https://github.com/user-attachments/assets/66fc0c0d-ee51-4d31-b70d-e2bc043205d1"
/>


When updating from a previous version, the user's past settings are
honoured.

## Additional Context

The PR aims to remove any duplication of status bar code where possible,
and extracts the status bar rendering into a new component - StatusBar

It also adds a new (optional) padding option to the progress bar to
allow the status bar to be shifted upwards - this is only intended for
use in the settings.

---

### 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 - although did help to decode some C++ errors

---------

Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-25 13:06:38 +03:00
Zach NelsonandGitHub cb72916397 feat: Latin Extended-B European glyphs (#1167)
## Summary

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

Correction to #1157, which (embarrassingly) failed to actually include
the updated font header files. (Maybe we should generate these at build
time?)

Add Latin Extended-B glyphs for Croatian, Romanian, Pinyin, and European
diacritical variants. Fixes #921.

---

### 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, confirmed
codepoint ranges with Claude**_
2026-02-25 12:56:11 +03:00
iandchasseGitHubcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
35988ada55 feat: wrapped text in GfxRender, implemented in themes so far (#1141)
## Summary

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


* **What changes are included?**
Conrgegate the changes of #1074 , #1013 , and extended upon #911 by
@lkristensen
New function implemented in GfxRenderer.cpp
```C++
std::vector<std::string> GfxRenderer::wrappedText(const int fontId, const char* text, const int maxWidth,
                                                  const int maxLines, const EpdFontFamily::Style style) const
```
Applied logic to all uses in Lyra, Lyra Extended, and base theme
(continue reading card as pointed out by @znelson


## Additional Context





![IMG_8604](https://github.com/user-attachments/assets/49da71c9-a44f-4cde-b3bf-6773d71601b6)

![IMG_8605](https://github.com/user-attachments/assets/5eab4293-65c1-47fb-b422-8ab53a6b50a2)

![IMG_8606](https://github.com/user-attachments/assets/e0f98d19-0e3f-4294-83a1-e49264378dca)


---

### AI Usage

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

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

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-25 10:24:35 +01:00