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



---
### 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>
## Summary
**What is the goal of this PR?**
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**_
Small edits of the French translation.
## Summary
* **What is the goal of this PR?**
Small fixes of the French translation : fixes on missing/unclear rows,
usage of technical terms better suited for an e-reader GUI, shorter
sentences.
* **What changes are included?**
See above and in the .yaml files; only translations have changed, no
code edit.
## Additional Context
* Nothing else
---
### 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>
## Summary
**What is the goal of this PR?**
I18nKeys.h and I18nStrings.h are generated by gen_i18n.py prior to each
build, so we do not need to maintain a checked-in copy of these 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**_
## Summary
* **What is the goal of this PR?**
Add Vietnamese glyphs support for the reader's built-in fonts, enabling
proper rendering of Vietnamese text in EPUB content.
* **What changes are included?**
- Added 3 new Unicode intervals to `fontconvert.py` covering Vietnamese
characters:
- **Latin Extended-B** (Vietnamese subset only): `U+01A0–U+01B0` — Ơ/ơ,
Ư/ư
- **Vietnamese Extended**: `U+1EA0–U+1EF9` — All precomposed Vietnamese
characters with tone marks (Ả, Ấ, Ầ, Ẩ, Ẫ, Ậ, Ắ, …, Ỹ)
- Re-generated all 54 built-in font header files (Bookerly, Noto Sans,
OpenDyslexic, Ubuntu across all sizes and styles) to include the new
Vietnamese glyphs.
## Additional Context
* **Scope**: This PR only covers the **reader** fonts. The outer UI
still uses the Ubuntu font which does not fully support Vietnamese — UI
and i18n will be addressed in a follow-up PR (per discussion in PR
#1124).
* **Memory impact**:
| Metric | Before | After | Delta |
|---|---|---|---|
| Flash Data (`.rodata`) | 2,971,028 B | 3,290,748 B | **+319,720 B
(+10.8%)** |
| Total image size | 4,663,235 B | 4,982,955 B | **+319,720 B (+6.9%)**
|
| Flash usage | 69.1% | 74.0% | **+4.9 pp** |
| RAM usage | 29.0% | 29.0% | **No change** |
* **Risk**: Low — this is a data-only change (font glyph tables in
`.rodata`). No logic changes, no RAM impact. Flash headroom remains
comfortable at 74%.
---
### AI Usage
Did you use AI tools to help write this code? _**PARTIALLY**_
AI was used to identify the minimal set of Unicode ranges needed for
Vietnamese support and to assist with the PR description.
---------
Co-authored-by: danoooob <danoooob@example.com>
## Summary
* **What is the goal of this PR?** Implements the Italian language
translation for CrossPoint Reader.
* **What changes are included?**
* Added [lib/I18n/translations/italian.yaml] with Italian translations
for all strings.
* Generated the necessary C++ files by running the [gen_i18n.py] script.
* Added myself to the [docs/translators.md] file under the Italian
section.
## 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 >**_
---------
Co-authored-by: Zach Nelson <zach@zdnelson.com>
## Summary
* **What is the goal of this PR?**
Add missing `STR_SCREENSHOT_BUTTON`
## Additional Context
After the screenshot feature was added, a new translation line was
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 **_
## Summary
**What is the goal of this PR?**
Improved typesetting, including
[kerning](https://en.wikipedia.org/wiki/Kerning) and
[ligatures](https://en.wikipedia.org/wiki/Ligature_(writing)#Latin_alphabet).
**What changes are included?**
- The script to convert built-in fonts now adds kerning and ligature
information to the generated font headers.
- Epub page layout calculates proper kerning spaces and makes ligature
substitutions according to the selected font.



## Additional Context
- I am not a typography expert.
- The implementation has been reworked from the earlier version, so it
is no longer necessary to omit Open Dyslexic, and kerning data now
covers all fonts, styles, and codepoints for which we include bitmap
data.
- Claude Opus 4.6 helped with a lot of this.
- There's an included test epub document with lots of kerning and
ligature examples, shown in the photos.
**_After some time to mature, I think this change is in decent shape to
merge and get people testing._**
After opening this PR I came across #660, which overlaps in adding
ligature support.
---
### 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.6**_
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary
Bookerly's native TrueType hinting is effectively a no-op at the sizes
used here, causing FreeType to place stems at inconsistent sub-pixel
positions. This results in the 'k' stem (8-bit fringe: 0x38=56) falling
just below the 2-bit quantization threshold while 'l' and 'h' stems
(fringes: 0x4C=76, 0x40=64) land above it --- making 'k' visibly
narrower (2.00px vs 2.33px effective width).
FreeType's auto-hinter snaps all stems to consistent grid positions,
normalizing effective stem width to 2.67px across all glyphs.
Adds --force-autohint flag to fontconvert.py and applies it to Bookerly
only. NotoSans, OpenDyslexic, and Ubuntu fonts are unaffected.
Here is an example of before/after. Take notice of the vertical stems on
characters like `l`, `k`, `n`, `i`, etc. The font is Bookerly 12pt
regular:
**BEFORE**:

**AFTER**:

Claude generated this script to quantitatively determine that this
change makes the vertical stems on a variety of characters more
consistent for Bookerly _only_.
<details>
<summary>Python script</summary>
```python
#!/usr/bin/env python3
"""Compare stem consistency across all font families with and without
auto-hinting.
Run from repo root:
python3 compare_all_fonts.py
"""
import freetype
DPI = 150
CHARS = ["k", "l", "h", "i", "b", "d"]
SIZES = [12, 14, 16, 18]
FONTS = {
"Bookerly":
"lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Regular.ttf",
"NotoSans":
"lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Regular.ttf",
"OpenDyslexic":
"lib/EpdFont/builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf",
"Ubuntu": "lib/EpdFont/builtinFonts/source/Ubuntu/Ubuntu-Regular.ttf",
}
MODES = {
"default": freetype.FT_LOAD_RENDER,
"autohint": freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT,
}
def q4to2(v):
if v >= 12:
return 3
elif v >= 8:
return 2
elif v >= 4:
return 1
else:
return 0
def get_stem_eff(face, char, flags):
gi = face.get_char_index(ord(char))
if gi == 0:
return None
face.load_glyph(gi, flags)
bm = face.glyph.bitmap
w, h = bm.width, bm.rows
if w == 0 or h == 0:
return None
p2 = []
for y in range(h):
row = []
for x in range(w):
row.append(q4to2(bm.buffer[y * bm.pitch + x] >> 4))
p2.append(row)
# Measure leftmost stem in stable middle rows
mid_start, mid_end = h // 4, h - h // 4
widths = []
for y in range(mid_start, mid_end):
first = next((x for x in range(w) if p2[y][x] > 0), -1)
if first < 0:
continue
last = first
for x in range(first, w):
if p2[y][x] > 0:
last = x
else:
break
eff = sum(p2[y][x] for x in range(first, last + 1)) / 3.0
widths.append(eff)
return round(sum(widths) / len(widths), 2) if widths else None
def main():
for font_name, font_path in FONTS.items():
try:
freetype.Face(font_path)
except Exception:
print(f"\n {font_name}: SKIPPED (file not found)")
continue
print(f"\n{'=' * 80}")
print(f" {font_name}")
print(f"{'=' * 80}")
for size in SIZES:
print(f"\n {size}pt:")
print(f" {'':6s}", end="")
for c in CHARS:
print(f" '{c}' ", end="")
print(" | spread")
for mode_name, flags in MODES.items():
face = freetype.Face(font_path)
face.set_char_size(size << 6, size << 6, DPI, DPI)
vals = []
print(f" {mode_name:6s}", end="")
for c in CHARS:
v = get_stem_eff(face, c, flags)
vals.append(v)
print(f" {v:5.2f}" if v else " N/A", end="")
valid = [v for v in vals if v is not None]
spread = max(valid) - min(valid) if len(valid) >= 2 else 0
marker = " <-- inconsistent" if spread > 0.5 else ""
print(f" | {spread:.2f}{marker}")
if __name__ == "__main__":
main()
```
</details>
Here are the results. The table compares how the font-generation
`autohint` flag affects the range of widths of various characters. Lower
`spread` mean that glyph stroke widths should appear more consistent.
```
Spread = max stem width - min stem width across glyphs (lower = more consistent):
┌──────────────┬──────┬─────────┬──────────┬──────────┐
│ Font │ Size │ Default │ Autohint │ Winner │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ Bookerly │ 12pt │ 1.49 │ 1.12 │ autohint │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 14pt │ 1.39 │ 1.13 │ autohint │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 16pt │ 1.38 │ 1.16 │ autohint │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 18pt │ 1.90 │ 1.58 │ autohint │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ NotoSans │ 12pt │ 1.16 │ 0.94 │ mixed │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 14pt │ 0.83 │ 1.14 │ default │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 16pt │ 1.41 │ 1.51 │ default │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 18pt │ 1.74 │ 1.63 │ mixed │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ OpenDyslexic │ 12pt │ 2.22 │ 1.44 │ autohint │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 14pt │ 2.57 │ 3.29 │ default │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 16pt │ 3.13 │ 2.60 │ autohint │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 18pt │ 3.21 │ 3.23 │ ~tied │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ Ubuntu │ 12pt │ 1.25 │ 1.31 │ default │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 14pt │ 1.41 │ 1.64 │ default │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 16pt │ 2.21 │ 1.71 │ autohint │
├──────────────┼──────┼─────────┼──────────┼──────────┤
│ │ 18pt │ 1.80 │ 1.71 │ autohint │
└──────────────┴──────┴─────────┴──────────┴──────────┘
```
---
### 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? I used AI to make sure I'm
not doing something stupid, since I'm not a typography expert. I made
the changes though.
## Summary
Fix redefinition of `FILE_*` macro.
Note that there will still be 2 warning:
```
.pio/libdeps/default/WebSockets/src/WebSocketsClient.cpp: In member function 'void WebSocketsClient::clientDisconnect(WSclient_t*, const char*)':
.pio/libdeps/default/WebSockets/src/WebSocketsClient.cpp:573:31: warning: 'virtual void NetworkClient::flush()' is deprecated: Use clear() instead. [-Wdeprecated-declarations]
573 | client->tcp->flush();
| ~~~~~~~~~~~~~~~~~~^~
```
--> I assume the upstream library need to fix it
And:
```
src/activities/Activity.cpp:8:1: warning: 'noreturn' function does return
8 | }
| ^
```
Will be fixed in #1016
---
### 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**
## Summary
* **What is the goal of this PR?**
Fix inconsistent WiFi strings in Czech translation.
* **What changes are included?**
Only a few `Wi-Fi` strings changed to `WiFi` to maintain consistency.
---
### 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**_
## Summary
* **What is the goal of this PR?** (e.g., Implements the new feature for
file uploading.)
Added Romanian translations for newly addded strings
* **What changes are included?**
Just the translations in the localisation 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 >**_
## Summary
* **What is the goal of this PR?** Address expected hyphenation issue
from
https://github.com/crosspoint-reader/crosspoint-reader/issues/998#issuecomment-3940533510
* Closes#998
* **What changes are included?** Add `„` (U+201E, _Double Low-9
Quotation Mark_), `‚` (U+201A, _Single Low-9 Quotation Mark_) and `‹`
(U+2039, _Single Left-pointing Angle Quotation Mark_) exceptions, other
quote types were handled correctly.
**Before**
<img width="480" height="155" alt="hyph3"
src="https://github.com/user-attachments/assets/e06b4071-2c8c-4814-965d-96fbe302a450"
/>
**After**
<img width="480" height="154" alt="hyph3-fix"
src="https://github.com/user-attachments/assets/4f7f5406-e200-451c-8bee-3f410cc84bbe"
/>
## 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**_
## Summary
**What is the goal of this PR?**
Consolidated repeated logic to fall back to REPLACEMENT_GLYPH.
---
### 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**_
## Summary
* **What is the goal of this PR?**
A Ukrainian translation for the GUI
* **What changes are included?**
Everything according to
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).
Nope
---
### 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 a
consistency validation
## Summary
* Remove miniz and move completely to uzlib
* Move uzlib interfacing to InflateReader to better modularise inflation
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? Yes, Claude helped with
the extraction and refactor
## Summary
* Resolve several build warnings
---
### 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
## Summary
* This PR introduces a migration from binary file storage to JSON-based
storage for application settings, state, and various credential stores.
This improves readability, maintainability, and allows for easier manual
configuration editing.
* Benefits:
- Settings files are now JSON and can be easily read/edited manually
- Easier to inspect application state and settings during development
- JSON structure is more flexible for future changes
* Drawback: around 15k of additional flash usage
* Compatibility: Seamless migration preserves existing user data
## Additional Context
1. New JSON I/O Infrastructure files:
- JsonSettingsIO: Core JSON serialization/deserialization logic using
ArduinoJson library
- ObfuscationUtils: XOR-based password obfuscation for sensitive data
2. Migrated Components (now use JSON storage with automatic binary
migration):
- CrossPointSettings (settings.json): Main application settings
- CrossPointState (state.json): Application state (open book, sleep
mode, etc.)
- WifiCredentialStore (wifi.json): WiFi network credentials (Password
Obfuscation: Sensitive data like WiFi passwords, uses XOR encryption
with fixed keys. Note: This is obfuscation, not cryptographic security -
passwords can be recovered with the key)
- KOReaderCredentialStore (koreader.json): KOReader sync credentials
- RecentBooksStore (recent.json): Recently opened books list
3. Migration Logic
- Forward Compatibility: New installations use JSON format
- Backward Compatibility: Existing binary files are automatically
migrated to JSON on first load
- Backup Safety: Original binary files are renamed with .bak extension
after successful migration
- Fallback Handling: If JSON parsing fails, system falls back to binary
loading
4. Infrastructure Updates
- HalStorage: Added rename() method for backup operations
---
### 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: Dave Allie <dave@daveallie.com>
## Summary
_Revision to @blindbat's #802. Description comes from the original PR._
- Replace `std::list` with `std::vector` for word storage in `TextBlock`
and `ParsedText`
- Use index-based access (`words[i]`) instead of iterator advancement
(`std::advance(it, n)`)
- Remove the separate `continuesVec` copy that was built from
`wordContinues` for O(1) access — now unnecessary since
`std::vector<bool>` already provides O(1) indexing
## Why
`std::list` allocates each node individually on the heap with 16 bytes
of prev/next pointer overhead per node. For text layout with many small
words, this means:
- Scattered heap allocations instead of contiguous memory
- Poor cache locality during iteration (each node can be anywhere in
memory)
- Per-node malloc/free overhead during construction and destruction
`std::vector` stores elements contiguously, giving better cache
performance during the tight rendering and layout loops. The
`extractLine` function also benefits: list splice was O(1) but required
maintaining three parallel iterators, while vector range construction
with move iterators is simpler and still efficient for the small
line-sized chunks involved.
## Files changed
- `lib/Epub/Epub/blocks/TextBlock.h` / `.cpp`
- `lib/Epub/Epub/ParsedText.h` / `.cpp`
## AI Usage
YES
## Test plan
- [ ] Open an EPUB with mixed formatting (bold, italic, underline) —
verify text renders correctly
- [ ] Open a book with justified text — verify word spacing is correct
- [ ] Open a book with hyphenation enabled — verify words break
correctly at hyphens
- [ ] Navigate through pages rapidly — verify no rendering glitches or
crashes
- [ ] Open a book with long paragraphs — verify text layout matches
pre-change behavior
---------
Co-authored-by: Kuanysh Bekkulov <kbekkulov@gmail.com>