Commit Graph

125 Commits

Author SHA1 Message Date
Dave Allie
46fa186b82
Make extension checks case-insensitive (#273)
## Summary

* Implement new `StringUtils::checkFileExtension` which does case
insensitive checking
* Move all checks over to this
2026-01-07 21:07:23 +11:00
Stanislav Khromov
1f956e972b
Allow disabling anti-aliasing via a setting (#241)
## Summary

Fixes https://github.com/daveallie/crosspoint-reader/issues/233

## Additional Context

By disabling the Text Anti-Aliasing in the settings, you can get faster
black-and-white page turns that work exactly like the stock firmware,
instead of having an additional flash after rendering (see issue linked
above for example).

Tested on the X4 and confirmed working.

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-07 20:14:35 +11:00
Justin
0edb2baced
feat: remember parent folder index in menu when ascending folders (#260)
## Summary

Adds feature to file selection activity for better user navigation when
ascending folders. The activity now remembers the index of the parent
folder instead of always resetting to the first element.

I don't have any means of testing this, so if someone could test it
that'd be great

Resolves #259
2026-01-07 19:58:49 +11:00
Justin Mitchell
b792b792bf
Calibre Web Epub Downloading + Calibre Wireless Device Syncing (#219)
## Summary

Adds support for browsing and downloading books from a Calibre-web
server via OPDS.
How it works
1. Configure server URL in Settings → Calibre Web URL (e.g.,
https://myserver.com:port I use Cloudflare tunnel to make my server
accessible anywhere fwiw)
2. "Calibre Library" will now show on the the home screen
3. Browse the catalog - navigate through categories like "By Newest",
"By Author", "By Series", etc.
4. Download books - select a book and press Confirm to download the EPUB
to your device
Navigation
- Up/Down - Move through entries
- Confirm - Open folder or download book
- Back - Go to parent catalog, or exit to home if at root
- Navigation entries show with > prefix, books show title and author
- Button hints update dynamically ("Open" for folders, "Download" for
books)
Technical details
- Fetches OPDS catalog from {server_url}/opds
- Parses both navigation feeds (catalog links) and acquisition feeds
(downloadable books)
- Maintains navigation history stack for back navigation
- Handles absolute paths in OPDS links correctly (e.g.,
/books/opds/navcatalog/...)
- Downloads EPUBs directly to the SD card root
Note
The server URL should be typed to include https:// if the server
requires it - HTTP→HTTPS redirects may cause SSL errors on ESP32.

## Additional Context

* I also changed the home titles to use uppercase for each word and
added a setting to change the size of the side margins

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-07 19:58:37 +11:00
Jonas Diemer
afe9672156
Feature/cover crop mode (#225)
Some checks failed
CI / build (push) Has been cancelled
Added a setting to select `fit` or `crop` for cover image on sleep
screen.

Might add a `expand` feature in the future that does not crop but rather
fills the blank space with a mirror of the image.

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-05 21:07:27 +11:00
David Fischer
9f95b31de5
add settings for reader screen margin (#223)
## Summary

* **What is the goal of this PR?** 
* This PR adds a setting to control the top left and right margins of
the reader screen in 4 sizes (5, 10, 20, 40 pt?) and defaults to `SMALL`
which is equivalent to the fixed margin of 5 that was already in use
before.
* **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).

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-05 20:29:08 +11:00
Stanislav Khromov
c76507c937
Add blank sleep screen option (#242)
## Summary

Very small change to add a blank ("None") sleep screen option, for those
who prefer a clean aesthetic.

Tested on X4 device.
2026-01-05 20:08:39 +11:00
Justin
881aa2e005
Fix scrolling wrap-around in settings menu (#249)
## Summary

Fixes a bug in the settings menu, where previously wrap-around only
worked when scrolling upwards. Now, scrolling downwards on the last list
element wraps around to the top as expected.

Resolves #236.
2026-01-05 19:25:27 +11:00
Dave Allie
14972b34cb
Remove authentication type from hotspot QR code (#235)
Some checks are pending
CI / build (push) Waiting to run
## Summary

* Remove the `T` parameter (authentication type), and `P` parameter
(password) for the SoftAP wifi config QR code

## Additional Context

* It is optional according to the spec:
https://www.wi-fi.org/system/files/WPA3%20Specification%20v3.2.pdf#page=25
so should either be omitted or set to nopass
* Fixes https://github.com/daveallie/crosspoint-reader/issues/229
2026-01-04 16:08:32 +11:00
Justinian
2fb417ee90
Feat/sleep and refresh settings (#209)
## Summary

* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module, Implements the new feature for
  file uploading.)
* **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).

---------

Co-authored-by: ratedcounsel <hello@ratedcounsel.com>
Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-03 19:33:42 +11:00
Brendan O'Leary
8e4484cd22
Add buton hints to keyboard screen (#205)
## Summary

This adds the correctly styled button hints to the keyboard screen as
well as the ability to add hints to the side buttons (and up/down hints
to that screen)

## Additional Context

N/A
2026-01-03 19:17:53 +11:00
Maeve Andrews
5e9626eb2a
Add paragraph alignment setting (justify/left/center/right) (#191)
## Summary

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

Add a new user setting for paragraph alignment, instead of hard-coding
full justification.

* **What changes are included?**

One new line in the settings screen, with 4 options
(justify/left/center/right). Default is justified since that's what it
was already. I personally only wanted to disable justification and use
"left", but I included the other options for completeness since they
were already supported.

## Additional Context

Tested on my X4 and looks as expected for each alignment.

Co-authored-by: Maeve Andrews <maeve@git.mail.maeveandrews.com>
2026-01-02 18:21:48 +11:00
Jonas Diemer
00e83af4e8
Show "Entering Sleep" on black, so it's quicker to notice (in book). (#181)
Black popup is easier to notice at higher contrast.
2026-01-02 17:55:21 +11:00
Brendan O'Leary
9e59a5106b
Fix race condition with keyboard and Wifi entry (#204)
## Summary

* **What is the goal of this PR?** Fixes a bug -
https://github.com/daveallie/crosspoint-reader/issues/187 - where the
screen would freeze after entering a WiFi password, causing the device
to appear hung.

* **What changes are included?**
- Fixed a race condition in `WifiSelectionActivity::displayTaskLoop()`
that caused rendering of an empty screen when transitioning from the
keyboard subactivity
- Added `vTaskDelay()` when a subactivity is active to prevent CPU
starvation from a tight `continue` loop
- Added a check to skip rendering when in `PASSWORD_ENTRY` state,
allowing the state machine to properly transition to `CONNECTING` before
the display updates

## Additional Context

* **Root cause:** When the keyboard subactivity exited after password
entry, the display task would wake up and attempt to render. However,
the `state` was still `PASSWORD_ENTRY` (before `attemptConnection()`
changed it to `CONNECTING`), and since there was no render case for
`PASSWORD_ENTRY`, the display would show a cleared/empty buffer,
appearing frozen.

* **Performance implications:** The added `vTaskDelay(10)` calls when
subactivity is active or in `PASSWORD_ENTRY` state actually improve
performance by preventing CPU starvation - previously the display task
would spin in a tight loop with `continue` while a subactivity was
present.

* **Testing focus:** Test the full WiFi connection flow:
  1. Enter network selection
  2. Select a network requiring a password
  3. Enter password and press OK
  4. Verify "Connecting..." screen appears
  5. Verify connection completes and prompts to save password
2026-01-02 17:49:16 +11:00
Pavel Liashkov
a922e553ed
Prevent device sleep during WiFi file transfer and OTA updates (#203)
## Summary

* **What is the goal of this PR?** Fixes #199 - Device falls asleep
during WiFi file transfer after 10 minutes of inactivity, disconnecting
the web server.

  * **What changes are included?**
    - Add `preventAutoSleep()` virtual method to `Activity` base class
- Modify main loop to reset inactivity timer when `preventAutoSleep()`
returns true
- Override `preventAutoSleep()` in `CrossPointWebServerActivity`
(returns true when web server running)
- Override `preventAutoSleep()` in `OtaUpdateActivity` (returns true
during update check/download)

  ## Additional Context

* The existing `skipLoopDelay()` method controls loop timing (yield vs
delay) for HTTP responsiveness. The new `preventAutoSleep()` method is
semantically separate - it explicitly signals that an activity should
keep the device awake.
* `CrossPointWebServerActivity` uses both methods: `skipLoopDelay()` for
responsive HTTP handling, `preventAutoSleep()` for staying awake.
* `OtaUpdateActivity` only needs `preventAutoSleep()` since the OTA
library handles HTTP internally.
2026-01-02 17:44:17 +11:00
Dave Allie
6e9ba1006a
Use sane smaller data types for data in section.bin (#188)
Some checks are pending
CI / build (push) Waiting to run
## Summary

* Update EpdFontFamily::Style to be u8 instead of u32 (saving 3 bytes
per word)
* Update layout width/height to be u16 from int
* Update page element count to be u16 from u32
* Update text block element count to be u16 from u32
* Bumped section bin version to version 8
2025-12-31 13:11:36 +11:00
Dave Allie
026733a4fe
Hide "System Volume Information" folder (#184)
## Summary

* Hide "System Volume Information" folder
* It's a FAT filesystem folder, shouldn't be used

## Additional Context

* Fixes https://github.com/daveallie/crosspoint-reader/issues/177
2025-12-31 09:27:17 +11:00
dangson
648c688642
Update button hints on OTA update screen and update user guide to reflect current settings (#183)
## Summary

- Update the button hints on the OTA update screen to reflect the
current front button layout.
- Update user guide to reflect current available settings. A lot has
been added recently!
2025-12-31 09:15:40 +11:00
Jonas Diemer
06065dfd8b
Show book title instead of "Select Chapter". (#169)
I think this is nicer ;)
2025-12-31 09:10:41 +11:00
Eunchurn Park
93226c9fbb
Fix file browser navigation for non-ASCII folder names (#178)
## Summary

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

Fix file browser failing to navigate into subdirectories with non-ASCII
(Korean/Unicode) folder names.

* **What changes are included?**

- Enable UTF-8 long file names in SdFat (`USE_UTF8_LONG_NAMES=1`)
- Add directory validation before iterating files
- Add `rewindDirectory()` call for stability

## Additional Context
2025-12-31 09:08:31 +11:00
Dave Allie
9bba41ed96
Move home screen battery indicator to avoid clashing with button hints (#174)
## Summary

* Move home screen battery indicator to avoid clashing with button hints
* Default button mapping was fine, but others clashes with the indicator
2025-12-31 02:46:46 +11:00
Dave Allie
34cf5f0636
Add button mapping for Left, Back, Confirm, Right (#173)
## Summary

* Add button mapping for Left, Back, Confirm, Right for front buttons

## Additional Context

* Asked for in
https://github.com/daveallie/crosspoint-reader/discussions/78#discussioncomment-15375326
2025-12-31 02:46:35 +11:00
Dave Allie
f2ca65d752
Swap from Aleo to Bookerly for wider glyph support (#172)
## Summary

* Swap from Aleo to Bookerly for wider glyph support
* Swap from Space Grotesk to a small Noto Sans

## Additional Context

* 0.11.0 swapped to Aleo which has a few issues (things like Cyrillic
support for eg)
2025-12-31 02:28:25 +11:00
Dave Allie
e2cba5be83
Show battery percentage on home screen (#167)
## Summary

* Show battery percentage on home screen
  * Moved battery rendering logic into shared ScreenComponents class
* As discussed
https://github.com/daveallie/crosspoint-reader/discussions/155
2025-12-30 23:41:47 +11:00
Dave Allie
3abcd0d05d
Redesign home screen (#166)
## Summary

* Redesigned home screen with big option to continue reading and
slightly nicer options to navigate to core sections
* Attempt to use the cached EPUB details (title, author) if they exist,
otherwise fall back to file name
* Adjusted button hints on home screen, removed Back option and changed
left/right to up/down

## Additional Context

* Core of this work comes from @ChandhokTannay in
1d36a86ef1
2025-12-30 23:18:10 +11:00
Jonas Diemer
03f0ce04cc
Feature: go to text/start reference in epub guide section at first start (#156)
This parses the guide section in the content.opf for text/start
references and jumps to this on first open of the book.

Currently, this behavior will be repeated in case the reader manually
jumps to Chapter 0 and then re-opens the book. IMO, this is an
acceptable edge case (for which I couldn't see a good fix other than to
drag a "first open" boolean around).

---------

Co-authored-by: Sam Davis <sam@sjd.co>
Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-30 23:02:46 +11:00
Dave Allie
3dd52f30fa
Adjust screen title position 2025-12-30 22:06:57 +11:00
Dave Allie
e43fec79be
Add setting for line spacing to adjust space between lines (#164)
Some checks are pending
CI / build (push) Waiting to run
## Summary

* Add setting for line spacing to adjust space between lines
* Aleo is already a bit tighter than Noto Sans and Open Dyslexic, so
have adjusted the values to match, this can be tweaked in the future
2025-12-30 19:34:46 +11:00
Dave Allie
bf7bffd506
Aleo, Noto Sans, Open Dyslexic fonts (#163)
## Summary

* Swap out Bookerly font due to licensing issues, replace default font
with Aleo
* I did a bunch of searching around for a nice replacement font, and
this trumped several other like Literata, Merriwether, Vollkorn, etc
* Add Noto Sans, and Open Dyslexic as font options
  * They can be selected in the settings screen
* Add font size options (Small, Medium, Large, Extra Large)
  * Adjustable in settings
* Swap out uses of reader font in headings and replaced with slightly
larger Ubuntu font
* Replaced PixelArial14 font as it was difficult to track down, replace
with Space Grotesk
* Remove auto formatting on generated font files
* Massively speeds up formatting step now that there is a lot more CPP
font source
* Include fonts with their licenses in the repo

## Additional Context

Line compression setting will follow

| Font | Small | Medium | Large | X Large |
| --- | --- | --- | --- | --- |
| Aleo |
![IMG_5704](https://github.com/user-attachments/assets/7acb054f-ddef-4080-b3c8-590cfaf13115)
|
![IMG_5705](https://github.com/user-attachments/assets/d4819036-5c89-486e-92c3-86094fa4d89a)
|
![IMG_5706](https://github.com/user-attachments/assets/35caf622-d126-4396-9c3e-f927eba1e1f4)
|
![IMG_5707](https://github.com/user-attachments/assets/af32370a-6244-400f-bea9-5c27db040b5b)
|
| Noto Sans |
![IMG_5708](https://github.com/user-attachments/assets/1f9264a5-c069-4e22-9099-a082bfcaabc5)
|
![IMG_5709](https://github.com/user-attachments/assets/ef6b07fe-8d87-403a-b152-05f50b69b78e)
|
![IMG_5710](https://github.com/user-attachments/assets/112a5d20-262c-4dc0-b67d-980b237e4607)
|
![IMG_5711](https://github.com/user-attachments/assets/d25e0e1d-2ace-450d-96dd-618e4efd4805)
|
| Open Dyslexic |
![IMG_5712](https://github.com/user-attachments/assets/ead64690-f261-4fae-a4a2-0becd1162e2d)
|
![IMG_5713](https://github.com/user-attachments/assets/59d60f7d-5142-4591-96b0-c04e0a4c6436)
|
![IMG_5714](https://github.com/user-attachments/assets/bb6652cd-1790-46a3-93ea-2b8f70d0d36d)
|
![IMG_5715](https://github.com/user-attachments/assets/496e7eb4-c81a-4232-83e9-9ba9148fdea4)
|
2025-12-30 19:21:47 +11:00
Dave Allie
9f31f80c80
Show previous title for unnamed spines (#158)
## Summary

* Show previous title for unnamed spines
* The spec is a little unclear, but there are plenty of cases where
chapters are split up in parts and should show the previous chapter's
title
* List TOC items instead of spine items in chapter select
* Bump `BOOK_CACHE_VERSION` to `2` to force regeneration of spine item's
TOC indexes
2025-12-30 18:52:42 +11:00
Dave Allie
fb5fc32c5d
Add exFAT support (#150)
## Summary

* Swap to updated SDCardManager which uses SdFat
* Add exFAT support
  * Swap to using FsFile everywhere
* Use newly exposed `SdMan` macro to get to static instance of
SDCardManager
* Move a bunch of FsHelpers up to SDCardManager
2025-12-30 16:09:30 +11:00
Sam Davis
278b056bd0
Add chapter select support to XTC files (#145)
Some checks are pending
CI / build (push) Waiting to run
## Summary

- **What is the goal of this PR?** Add chapter selection support to the
XTC reader activity, including parsing chapter metadata from XTC files.
- **What changes are included?** Implemented XTC chapter parsing and
exposure in the XTC library, added a chapter selection activity for XTC,
integrated it into XtcReaderActivity, and normalized chapter page
indices by shifting them to 0-based.

  ## Additional Context

- The reader uses 0-based page indexing (first page = 0), but the XTC
chapter table appears to be 1-based (first page = 1), so chapter
start/end pages are shifted down by 1 during parsing.
2025-12-30 12:49:18 +11:00
Jonas Diemer
b01eb50325
Shorten continueLabel to actual screen width. (#151)
Some checks are pending
CI / build (push) Waiting to run
2025-12-29 23:18:23 +11:00
Jonas Diemer
1bfe694807
Improvement/settings selection by inversion (#152)
Style in settings like everywhere else. Also improved the alignment of
the settings value.
2025-12-29 23:18:16 +11:00
Yona
d7f4bd54f5
Add side button layout configuration while on reader (#147)
## Summary

Allow swapping the side button layout between *next page - prev page*
and *prev page - next page* while reading
2025-12-29 21:17:10 +11:00
dangson
140d8749a6
Support swapping the functionality of the front buttons (#133)
Some checks are pending
CI / build (push) Waiting to run
## Summary

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

Adds a setting to swap the front buttons. The default functionality are:
Back/Confirm/Left/Right. When this setting is enabled they become:
Left/Right/Back/Confirm. This makes it more comfortable to use when
holding in your right hand since your thumb can more easily rest on the
next button. The original firmware has a similar setting.

**What changes are included?**

- Add the new setting.
- Create a mapper to dynamically switch the buttons based on the
setting.
- Use mapper on the various activity screens.
- Update the button hints to reflect the swapped buttons.

## Additional Context

Full disclosure: I used Codex CLI to put this PR together, but did
review it to make sure it makes sense.

Also tested on my device:
https://share.cleanshot.com/k76891NY
2025-12-29 14:59:14 +11:00
Dave Allie
534504cf7a
Consolidate chapter page data into single file (#144)
## Summary

* Consolidate chapter page data into single file
* Header structure of the file stays the same, following the page count,
we now put a LUT offset
   * The page data is all then appended to this file
* Finally the LUT is appended to the end of the file, and the page count
is updated
* This will also significantly improve the duration of cache cleanup
which takes a while to scan the directory and cleanup content
* Remove page file version as it's all tied up into the section file now
* Bumped section file version to 7
* Moved section content into sub directory
* Updated docs

## Additional Context

* Benchmarks:
  * Generating 74 pages of content from a chapter in Jade Legacy took:
    * master: 6,229ms
    * this PR: 1,305ms
    * Speedup of 79%
  * Generating 207 pages of content from Livesuit book:
    * With progress bar UI updates:
      * master: 24,250ms
      * this PR: 8,063ms
      * Speedup of 67%
    * Without progress bar UI updates:
      * master: 13,055ms
      * this PR: 3,600ms
      * Speedup of 72%
2025-12-29 13:19:54 +11:00
Dave Allie
f8c0b1acea
Use confirmation release on home screen to detect action 2025-12-29 02:00:42 +11:00
Eunchurn Park
f9b604f04e
Add XTC/XTCH ebook format support (#135)
## Summary

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

Add support for XTC (XTeink X4 native) ebook format, which contains
pre-rendered 480x800 1-bit bitmap pages optimized for e-ink displays.

* **What changes are included?**

- New `lib/Xtc/` library with XtcParser for reading XTC files
- XtcReaderActivity for displaying XTC pages on e-ink display
- XTC file detection in FileSelectionActivity
- Cover BMP generation from first XTC page
- Correct XTG page header structure (22 bytes) and bit polarity handling

## Additional Context

- XTC files contain pre-rendered bitmap pages with embedded status bar
(page numbers, progress %)
- XTG page header: 22 bytes (magic + dimensions + reserved fields +
bitmap size)
- Bit polarity: 0 = black, 1 = white
- No runtime text rendering needed - pages display directly on e-ink
- Faster page display compared to EPUB since no parsing/rendering
required
- Memory efficient: loads one page at a time (48KB per page)
- Tested with XTC files generated from https://x4converter.rho.sh/
- Verified correct page alignment and color rendering
- Please report any issues if you test with XTC files from other
sources.

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-29 01:56:05 +11:00
Dave Allie
3dc5f6fec4
Avoid jumping straight into chapter selection screen 2025-12-28 23:49:51 +11:00
Dave Allie
41c93e4eba
Use font ascender height for baseline offset (#139)
## Summary

* Use font ascender height for baseline offset
* Previously was using font height, but when rendering the font (even
from y = 0), there would be a lot of top margin
* Font would also go below the "bottom of the line" as we were using the
full font height as the baseline

## Additional Context

* This caused some text to move around, I've fixed everything I can
* Notably it moves the first line of font a little closer to the top of
the page
2025-12-28 22:30:01 +11:00
Dave Allie
1c33162368
Fix rendering issue with entering keyboard from wifi screen 2025-12-28 21:50:45 +11:00
Dave Allie
27d42fbef3
Allow entering into chapter select screen correctly 2025-12-28 21:50:36 +11:00
Tannay
dd280bdc97
Rotation Support (#77)
•  What is the goal of this PR?  
Implement a horizontal EPUB reading mode so books can be read in
landscape orientation (both 90° and 270°), while keeping the rest of the
UI in portrait.

•  What changes are included?
◦  Rendering / Display
▪ Added an orientation model to GfxRenderer (Portrait, LandscapeNormal,
LandscapeFlipped) and made:
▪ drawPixel, drawImage, displayWindow map logical coordinates
differently depending on orientation.
▪ getScreenWidth() / getScreenHeight() return orientation‑aware logical
dimensions (480×800 in portrait, 800×480 in landscape).
◦  Settings / Configuration
▪  Extended CrossPointSettings with:
▪  landscapeReading (toggle for portrait vs. landscape EPUB reading).
▪ landscapeFlipped (toggle to flip landscape 180° so both horizontal
holding directions are supported).
▪ Updated settings serialization/deserialization to persist these fields
while remaining backward‑compatible with existing settings files.
▪  Updated SettingsActivity to expose two new toggles:
▪  “Landscape Reading”
▪  “Flip Landscape (swap top/bottom)”
◦  EPUB Reader
▪  In EpubReaderActivity:
▪ On onEnter, set GfxRenderer orientation based on the new settings
(Portrait, LandscapeNormal, or LandscapeFlipped).
▪ On onExit, reset orientation back to Portrait so Home, WiFi, Settings,
etc. continue to render as before.
▪ Adjusted renderStatusBar to position the status bar and battery
indicator relative to GfxRenderer::getScreenHeight() instead of
hard‑coded Y coordinates, so it stays correctly at the bottom in both
portrait and landscape.
◦  EPUB Caching / Layout
▪ Extended Section cache metadata (section.bin) to include the logical
screenWidth and screenHeight used when pages were generated; bumped
SECTION_FILE_VERSION.
▪  Updated loadCacheMetadata to compare:
▪ font/margins/line compression/extraParagraphSpacing and screen
dimensions; mismatches now invalidate and clear the cache.
▪ Updated persistPageDataToSD and all call sites in EpubReaderActivity
to pass the current GfxRenderer::getScreenWidth() / getScreenHeight() so
portrait and landscape caches are kept separate and correctly sized.



Additional Context

•  Cache behavior / migration
◦ Existing section.bin files (old SECTION_FILE_VERSION) will be detected
as incompatible and their caches cleared and rebuilt once per chapter
when first opened after this change.
◦ Within a given orientation, caches will be reused as before. Switching
orientation (portrait ↔ landscape) will cause a one‑time re‑index of
each chapter in the new orientation.
•  Scope and risks
◦ Orientation changes are scoped to the EPUB reader; the Home screen,
Settings, WiFi selection, sleep screens, and web server UI continue to
assume portrait orientation.
◦ The renderer’s orientation is a static/global setting; if future code
uses GfxRenderer outside the reader while a reader instance is active,
it should be aware that orientation is no longer implicitly fixed.
◦ All drawing primitives now go through orientation‑aware coordinate
transforms; any code that previously relied on edge‑case behavior or
out‑of‑bounds writes might surface as logged “Outside range” warnings
instead.
•  Testing suggestions / areas to focus on
◦  Verify in hardware:
▪ Portrait mode still renders correctly (boot, home, settings, WiFi,
reader).
▪  Landscape reading in both directions:
▪  Landscape Reading = ON, Flip Landscape = OFF.
▪  Landscape Reading = ON, Flip Landscape = ON.
▪ Status bar (page X/Y, % progress, battery icon) is fully visible and
aligned at the bottom in all three combinations.
◦  Open the same book:
▪  In portrait first, then switch to landscape and reopen it.
▪  Confirm that:
▪ Old portrait caches are rebuilt once for landscape (you should see the
“Indexing…” page).
▪ Progress save/restore still works (resume opens to the correct page in
the current orientation).
◦ Ensure grayscale rendering (the secondary pass in
EpubReaderActivity::renderContents) still looks correct in both
orientations.

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-28 21:33:20 +11:00
Dave Allie
bf031fd999
Fix exiting WifiSelectionActivity renderer early
Some checks are pending
CI / build (push) Waiting to run
2025-12-28 19:27:00 +11:00
Dave Allie
02350c6a9f
Fix underscore on keyboard and standardize activity (#138)
## Summary

* Fix underscore on keyboard
  * Remove special handling of special row characters
* Fix navigating between special row items
* Standardize keyboard activity to use standard loop
  * Fix issue with rendering keyboard non-stop

Fixes https://github.com/daveallie/crosspoint-reader/issues/131
2025-12-28 18:57:06 +11:00
Dave Allie
9023b262a1
Fix issue where pressing back from chapter select would leave book (#137)
## Summary

* Fix issue where pressing back from chapter select would leave book
* Rely on `wasReleased` checks instead
2025-12-28 17:06:18 +11:00
Eunchurn Park
eabd149371
Add retry logic and progress bar for chapter indexing (#128)
## Summary

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

Improve reliability and user experience during chapter indexing by
adding retry logic for SD card operations and a visual progress bar.

* **What changes are included?**

- **Retry logic**: Add 3 retry attempts with 50ms delay for ZIP to SD
card streaming to handle timing issues after display refresh
- **Progress bar**: Display a visual progress bar (0-100%) during
chapter indexing based on file read progress, updating every 10% to
balance responsiveness with e-ink display limitations

## Additional Context

* **Problem observed**: When navigating quickly through books with many
chapters (before chapter titles finish rendering), the "Indexing..."
screen would appear frozen. Checking the serial log revealed the
operation had silently failed, but the UI showed no indication of this.
Users would likely assume the device had crashed. Pressing the next
button again would resume operation, but this behavior was confusing and
unexpected.

* **Solution**:
- Retry logic handles transient SD card timing failures automatically,
so users don't need to manually retry
- Progress bar provides visual feedback so users know indexing is
actively working (not frozen)

* **Why timing issues occur**: After display refresh operations, there
can be timing conflicts when immediately starting SD card write
operations. This is more likely to happen when rapidly navigating
through chapters.

* **Progress bar design**: Updates every 10% to avoid excessive e-ink
refreshes while still providing meaningful feedback during long indexing
operations (especially for large chapters with CJK characters).

* **Performance**: Minimal overhead - progress calculation is simple
byte counting, and display updates use `FAST_REFRESH` mode.
2025-12-28 15:59:44 +11:00
1991AcuraLegend
838246d147
Add setting to enable status bar display options (#111)
Some checks are pending
CI / build (push) Waiting to run
Add setting toggle that allows status bar display options in EpubReader.

Supported options would be as follows: 

- FULL: display as is today
- PROGRESS: display progress bar only
- BATTERY: display battery only
- NONE: hide status bar

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-28 10:48:27 +11:00
Brendan O'Leary
e3d0201365
Add 'Open' button hint to File Selection page (#136)
## Summary

In using my build of
https://github.com/daveallie/crosspoint-reader/pull/130 I realized that
we need a "open" button hint above the second button in the File browser

## Additional Context

* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
2025-12-28 10:36:26 +11:00
Dave Allie
aff4dc6628
Fix QRCode import attempt 2
Some checks failed
CI / build (push) Has been cancelled
2025-12-26 11:33:41 +10:00
Dave Allie
98a39374e8
Fix QRCode import 2025-12-26 11:29:27 +10:00
Jonas Diemer
e8c0fb42d4
Network details QR code (#113)
Using QRCode library from pio to generate the QR code.

Done:
- Display QR code for URL in network mode
- minor fixes of layout
- Display QR for URL in AP mode
- Display QR for AP in AP mode

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-26 12:13:40 +11:00
Eunchurn Park
b77af16caa
Add Continue Reading menu and remember last book folder (#129)
## Summary

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

Add a "Continue Reading" feature to improve user experience when
returning to a previously opened book.

* **What changes are included?**

- Add dynamic "Continue: <book name>" menu item in Home screen when a
book was previously opened

- File browser now starts from the folder of the last opened book
instead of always starting from root directory
- Menu dynamically shows 3 or 4 items based on reading history:
  - Without history: `Browse`, `File transfer`, `Settings`
- With history: `Continue: <book>`, `Browse`, `File transfer`,
`Settings`

## Additional Context

* This feature leverages the existing `APP_STATE.openEpubPath` which
already persists the last opened book path
* The Continue Reading menu only appears if the book file still exists
on the SD card
* Book name in the menu is truncated to 25 characters with "..." suffix
if too long
* If the last book's folder was deleted, the file browser gracefully
falls back to root directory
* No new dependencies or significant memory overhead - reuses existing
state management
2025-12-26 11:55:23 +11:00
Brendan O'Leary
e3c1e28b8f
Normalize button hints (#130)
## Summary

This creates a `renderer.drawButtonHints` to make all of the "hints"
over buttons to match the home screen.

## Additional Context

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

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-26 11:54:02 +11:00
Dave Allie
b6bc1f7ed3
New book.bin spine and table of contents cache (#104)
## Summary

* Use single unified cache file for book spine, table of contents, and
core metadata (title, author, cover image)
* Use new temp item store file in OPF parsing to store items to be
rescaned when parsing spine
  * This avoids us holding these items in memory
* Use new toc.bin.tmp and spine.bin.tmp to build out partial toc / spine
data as part of parsing content.opf and the NCX file
  * These files are re-read multiple times to ultimately build book.bin

## Additional Context

* Spec for file format included below as an image
* This should help with:
  * #10 
  * #60 
  * #99
2025-12-24 22:36:13 +11:00
Dave Allie
1107590b56
Standardize File handling with FsHelpers (#110)
Some checks failed
CI / build (push) Has been cancelled
## Summary

* Standardize File handling with FsHelpers
* Better central place to manage to logic of if files exist/open for
reading/writing
2025-12-23 14:14:10 +11:00
Brendan O'Leary
9f4f71fabe
Add AP mode option for file transfers (#98)
Some checks are pending
CI / build (push) Waiting to run
## Summary

* **What is the goal of this PR?** Adds WiFi Access Point (AP) mode
support for File Transfer, allowing the device to create its own WiFi
network that users can connect to directly - useful when no existing
WiFi network is available. And in my experience is faster when the
device is right next to your laptop (but maybe further from your wifi)

* **What changes are included?**
- New `NetworkModeSelectionActivity` - an interstitial screen asking
users to choose between:
- "Join a Network" - connects to an existing WiFi network (existing
behavior)
- "Create Hotspot" - creates a WiFi access point named
"CrossPoint-Reader"
  - Modified `CrossPointWebServerActivity` to:
    - Launch the network mode selection screen before proceeding
- Support starting an Access Point with mDNS (`crosspoint.local`) and
DNS server for captive portal behavior
    - Display appropriate connection info for both modes
- Modified `CrossPointWebServer` to support starting when WiFi is in AP
mode (not just STA connected mode)

## Additional Context

* **AP Mode Details**: The device creates an open WiFi network named
"CrossPoint-Reader". Once connected, users can access the file transfer
page at `http://crosspoint.local/` or `http://192.168.4.1/`
* **DNS Captive Portal**: A DNS server redirects all domain requests to
the device's IP, enabling captive portal behavior on some devices
* **mDNS**: Hostname resolution via `crosspoint.local` is enabled for
both AP and STA modes
* **No breaking changes**: The "Join a Network" option preserves the
existing WiFi connection flow
* **Memory impact**: Minimal - the AP mode uses roughly the same
resources as STA mode
2025-12-22 17:24:14 +11:00
Dave Allie
d23020e268
OTA updates (#96)
## Summary

* Adds support for OTA
  * Gets latest firmware bin from latest GitHub release
* I have noticed it be a little flaky unpacking the JSON and
occasionally failing to start
2025-12-22 17:16:46 +11:00
Dave Allie
b39ce22e54
Cleanup of activities 2025-12-22 00:48:16 +11:00
Dave Allie
77c655fcf5
Give activities names and log when entering and exiting them (#92)
Some checks are pending
CI / build (push) Waiting to run
## Summary

* Give activities name and log when entering and exiting them
* Clearer logs when attempting to debug, knowing where users are coming
from/going to helps
2025-12-21 21:17:00 +11:00
Dave Allie
955c78de64
Book cover sleep screen (#89)
## Summary

* Fix issue with 2-bit bmp rendering
* Add support generate book cover BMP from JPG and use as sleep screen

## Additional Context

* It does not support other image formats beyond JPG at this point
* Something is cooked with my JpegToBmpConverter logic, it generates
weird interlaced looking images for some JPGs

| Book 1 | Book 2|
| --- | --- |
|
![IMG_5653](https://github.com/user-attachments/assets/49bbaeaa-b171-44c7-a68d-14cbe42aef03)
|
![IMG_5652](https://github.com/user-attachments/assets/7db88d70-e09a-49b0-a9a0-4cc729b4ca0c)
|
2025-12-21 18:42:06 +11:00
Dave Allie
958508eb6b
Prevent boot loop if last open epub crashes on load (#87)
## Summary

* Unset openEpubPath on boot and set once epub fully loaded

## Additional Context

* If an epub was crashing when loading, it was possible to get the
device stuck into a loop. There was no way to get back to the home
screen as we'd always load you back into old epub
* Break this loop by clearing the stored value when we boot, still
jumping to the last open epub, but only resetting that value once the
epub has been fully loaded
2025-12-21 18:41:52 +11:00
Dave Allie
b73ae7fe74
Paginate book list and avoid out of bounds rendering (#86)
## Summary

* Paginate book list
* Avoid out of bounds rendering of long book titles, truncate with
ellipsis instead

## Additional Context

* Should partially help with
https://github.com/daveallie/crosspoint-reader/issues/75 as it was
previously rendering a lot of content off screen, will need to test with
a large directory
2025-12-21 17:12:53 +11:00
Dave Allie
0d32d21d75
Small code cleanup (#83)
Some checks are pending
CI / build (push) Waiting to run
## Summary

* Fix cppcheck low violations
* Remove teardown method on parsers, use destructor
* Code cleanup
2025-12-21 15:43:53 +11:00
Dave Allie
9b4dfbd180
Allow any file to be uploaded (#84)
## Summary

- Allow any file to be uploaded
- Removes .epub restriction

## Additional Context

- Fixes #74
2025-12-21 15:43:17 +11:00
Brendan O'Leary
d41d539435
Add connect to Wifi and File Manager Webserver (#41)
## Summary

- **What is the goal of this PR?**  
Implements wireless EPUB file management via a built-in web server,
enabling users to upload, browse, organize, and delete EPUB files from
any device on the same WiFi network without needing a computer cable
connection.

- **What changes are included?**
- **New Web Server**
([`CrossPointWebServer.cpp`](src/CrossPointWebServer.cpp),
[`CrossPointWebServer.h`](src/CrossPointWebServer.h)):
    - HTTP server on port 80 with a responsive HTML/CSS interface
    - Home page showing device status (version, IP, free memory)
    - File Manager with folder navigation and breadcrumb support
    - EPUB file upload with progress tracking
    - Folder creation and file/folder deletion
    - XSS protection via HTML escaping
- Hidden system folders (`.` prefixed, "System Volume Information",
"XTCache")
  
- **WiFi Screen** ([`WifiScreen.cpp`](src/screens/WifiScreen.cpp),
[`WifiScreen.h`](src/screens/WifiScreen.h)):
    - Network scanning with signal strength indicators
    - Visual indicators for encrypted (`*`) and saved (`+`) networks
- State machine managing: scanning, network selection, password entry,
connecting, save/forget prompts
    - 15-second connection timeout handling
    - Integration with web server (starts on connect, stops on exit)
  
- **WiFi Credential Storage**
([`WifiCredentialStore.cpp`](src/WifiCredentialStore.cpp),
[`WifiCredentialStore.h`](src/WifiCredentialStore.h)):
    - Persistent storage in `/sd/.crosspoint/wifi.bin`
- XOR obfuscation for stored passwords (basic protection against casual
reading)
    - Up to 8 saved networks with add/remove/update operations
  
- **On-Screen Keyboard**
([`OnScreenKeyboard.cpp`](src/screens/OnScreenKeyboard.cpp),
[`OnScreenKeyboard.h`](src/screens/OnScreenKeyboard.h)):
    - Reusable QWERTY keyboard component with shift support
    - Special keys: Shift, Space, Backspace, Done
    - Support for password masking mode
  
- **Settings Screen Integration**
([`SettingsScreen.h`](src/screens/SettingsScreen.h)):
    - Added WiFi action to navigate to the new WiFi screen
  
  - **Documentation** ([`docs/webserver.md`](docs/webserver.md)):
- Comprehensive user guide covering WiFi setup, web interface usage,
file management, troubleshooting, and security notes
    - See this for more screenshots!
- Working "displays the right way in GitHub" on my repo:
https://github.com/olearycrew/crosspoint-reader/blob/feature/connect-to-wifi/docs/webserver.md

**Video demo**


https://github.com/user-attachments/assets/283e32dc-2d9f-4ae2-848e-01f41166a731

## Additional Context

- **Security considerations**: The web server has no
authentication—anyone on the same WiFi network can access files. This is
documented as a limitation, recommending use only on trusted private
networks. Password obfuscation in the credential store is XOR-based, not
cryptographically secure.

- **Memory implications**: The web server and WiFi stack consume
significant memory. The implementation properly cleans up (stops server,
disconnects WiFi, sets `WIFI_OFF` mode) when exiting the WiFi screen to
free resources.

- **Async operations**: Network scanning and connection use async
patterns with FreeRTOS tasks to prevent blocking the UI. The display
task handles rendering on a dedicated thread with mutex protection.

- **Browser compatibility**: The web interface uses standard
HTML5/CSS3/JavaScript and is tested to work with all modern browsers on
desktop and mobile.

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-20 01:05:43 +11:00
Dave Allie
cf6fec78dc
Cleanup indexing layout string 2025-12-20 00:33:55 +11:00
Jonas Diemer
10d76dde12
Randomly load Sleep Screen from /sleep/*bmp (if exists). (#71)
Load a random sleep screen. 

Only works for ".bmp" (not ".BMP"), but I think that's OK (we do the
same for EPUBs).
2025-12-20 00:17:26 +11:00
Jonas Diemer
7b5a63d220
Option to short-press power button. (#56)
Some checks are pending
CI / build (push) Waiting to run
Adresses #53 

Please check if we still need the code to "Give the user up to 1000ms to
start holding the power button, and must hold for
SETTINGS.getPowerButtonDuration()" - the power button should be pressed
already when waking up...

Also, decided to return before the delay to wait more to make the
behavior more immediate.

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-19 23:37:34 +11:00
IFAKA
2d3928ed81
Validate file handle when reading progress.bin (#66)
## Problem
Reading progress.bin used `SD.exists()` then `SD.open()` without
checking if open succeeded. Race conditions or SD errors could cause
file handle to be invalid.

## Fix
- Removed redundant `SD.exists()` check
- Check if file opened successfully before reading
- Verify correct number of bytes were read

## Testing
- Builds successfully with `pio run`
- Affects: `src/activities/reader/EpubReaderActivity.cpp`
2025-12-19 23:27:08 +11:00
IFAKA
1a53dccebd
Fix title truncation crash for short titles (#63)
## Problem
The status bar title truncation loop crashes when the chapter title is
shorter than 8 characters.

```cpp
// title.length() - 8 underflows when length < 8 (size_t is unsigned)
title = title.substr(0, title.length() - 8) + "...";
```

## Fix
Added a length guard to skip truncation for titles that are too short to
truncate safely.

## Testing
- Builds successfully with `pio run`
- Affects: `src/activities/reader/EpubReaderActivity.cpp`
2025-12-19 23:23:43 +11:00
Dave Allie
1a3d6b125d
Custom sleep screen support with BMP reading (#57)
## Summary

* Builds on top of
https://github.com/daveallie/crosspoint-reader/pull/16 - adresses
https://github.com/daveallie/crosspoint-reader/discussions/14
* This PR adds the ability for the user to supply a custom `sleep.bmp`
image at the root of the SD card that will be shown instead of the
default sleep screen if present.
* Supports:
  * Different BPPs:
    * 1bit
    * 2bit
    * 8bit
    * 24bit
    * 32bit (with alpha-channel ignored)
  * Grayscale rendering

---------

Co-authored-by: Sam Davis <sam@sjd.co>
2025-12-19 08:45:14 +11:00
Dave Allie
57fdb1c0fb
Rendering "Indexing..." on white screen to avoid partial update 2025-12-18 22:13:24 +11:00
Dave Allie
d429966dd4
Rename Screens to Activities and restructure files (#44)
## Summary

* This PR drastically reshapes the structure of the codebase, moving
from the concept of "Screens" to "Activities", restructing the files and
setting up the concept of subactivities.
* This should help with keep the main file clean and containing all
functional logic in the relevant activity.
* CrossPointState is now also a global singleton which should help with
accessing it from within activities.

## Additional Context

* This is probably going to be a bit disruptive for people with open
PRs, sorry 😞
2025-12-17 23:32:18 +11:00