e9120888fa8b0b454a1573765da6bcbf9c1d064d
17
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8a11f44571 | feat: Themed reader menus (#1072) | ||
|
|
7acc31bc34 |
fix: silent-reboot on wifi activity exit to clear heap fragmentation (#1908)
WiFi/LWIP/netif teardown scatters long-lived allocations across the heap, leaving ~50KB of contiguous space unrecoverable without a reboot. Reboot the SoC on exit from any wifi-using activity to guarantee a clean heap. An RTC_NOINIT flag survives the reboot and tells setup() to skip the boot splash and route the user back where they came from: - File transfer / Calibre / OPDS / Font download -> home - KOReader sync -> currently-open EPUB Activities check WiFi.getMode() before rebooting, so backing out of the network mode menu without joining doesn't trigger a cycle. KOSync also esp_wifi_stop()s after the sync result so the radio is off while the user reads it; full teardown happens at the reboot. ## Additional Context The silent reboot skips the booting splash screen - it visibly looks like a screen refresh. This does cause a disconnection/reconnection blip for developers actively pulling logs over serial, but `pio device monitor` and the like successfully reconnect and feed in the early boot serial. as an example: ``` [256676] [DBG] [ACT] Exiting activity: KOReaderSync [256706] [DBG] [MAIN] Silent restart (target=reader) ESP-ROM:esp32c3-api1-20210207 Build:Feb 7 2021 rst:0xc (RTC_SW_CPU_RST),boot:0xf (SPI_FAST_FLASH_BOOT) Saved PC:0x403872bc SPIWP:0xee mode:DIO, clock div:1 load:0x3fcd72a0,len:0x990 load:0x403cbf10,len:0xac8 load:0x403ce710,len:0x4d28 entry 0x403cbf10 [22] [INF] [MAIN] Hardware detect: X4 [29] [SD] SD card detected [43] [DBG] [CPS] Settings loaded from file [58] [DBG] [KRS] Loaded KOReader credentials for user: jeremydk [69] [DBG] [OPS] Loaded 1 OPDS servers from file [69] [DBG] [UI] Using Lyra theme [70] [DBG] [MAIN] Starting CrossPoint version 1.2.0-dev-detached-bde75787 ... [203] [DBG] [ACT] Entering activity: Reader [211] [DBG] [EBP] Loading ePub: /Halting State - Charles Stross.epub [221] [DBG] [BMC] Loaded cache data: 51 spine, 41 TOC entries [246] [DBG] [CSS] Loaded 41 rules from cache [247] [DBG] [EBP] Loaded ePub: /Halting State - Charles Stross.epub ``` --- ### 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_ |
||
|
|
bf894fd343 |
fix: improve KOSync bidirectional position matching accuracy (#1897)
## Summary **Goal:** Fix bidirectional KOSync position matching between CrossPoint and KOReader so that syncing in either direction lands on the correct page with character-level accuracy. **Changes included:** **Download — `toCrossPoint` (server XPath → CrossPoint page)** - **XPath ancestry mode for structured elements**: The previous `ParagraphStreamer` only tracked `<p>` elements. Replaced with a full ancestor-walking mode that correctly resolves XPaths pointing into `<li>`, `<ul>`, and other structured elements. Char offset within the target element is bounded to the matched element's content only. - **Slash-in-attribute-value corrupts depth tracking**: `processByteInTag()` treated every `/` byte as a self-closing tag marker, including `/` inside quoted attribute values (e.g. `xmlns="http://..."`, `src="Links/image.jpg"`). This drove `htmlDepth` to 0 prematurely, causing the ancestry search to exit far short of the target paragraph. Fixed with `inAttrQuote` tracking. - **Off-by-one in page formula**: `intra * totalPages` rounds up incorrectly for last-page positions. Changed to `intra * (totalPages - 1)` to map the `[0, 1]` intra fraction correctly onto the `[0, totalPages-1]` page range. Example: page 14 of 17 was returned as 15. **Upload — `toKOReader` (CrossPoint page → server XPath)** - **Off-by-one in page-to-intra formula**: Symmetric fix — `pageNumber / totalPages` changed to `pageNumber / (totalPages - 1)`, with the guard updated from `> 0` to `> 1` to avoid division by zero. - **`<li>`-based XPath generation**: When the current page starts on a list item, `findXPathForProgress` now generates `ul[N]/li[M]` XPaths rather than falling back to the preceding `<p>`. Requires the new `listItemIndex` field in `PageLutEntry` (section cache version bumped to 23). - **Text-node precision with correct `text()[N].M` format**: KOReader expects `text()[N].M` where `N` is the 1-based index of the specific text node within the element. The previous attempt generated `text().M` (no brackets), which caused KOReader to jump to the front of the book. Implements a per-element text-node index stack in `XPathProgressResolver` — parallel to the existing element path stack — that correctly tracks text node indices relative to each element. Empty text nodes from bare anchor elements (`<a id="anchor"/>`) are intentionally skipped, matching KOReader's own text node counting behavior. **Reviewer-caught bugs** - **Double `onCloseTag()` on malformed `</br/>`**: Both the `tagIsClose` path and the self-closing `/` check were firing, double-decrementing `htmlDepth`. Fixed with a `!tagIsClose` guard. - **Dangling pointer in `LOG_DBG`**: `std::to_string(*nextParagraphPage).c_str()` passed a pointer to a temporary destroyed before the variadic call. Fixed with `snprintf` into a stack `char[8]` buffer. ## Additional Context - Section cache version bumped from 22 → 23 due to the new `listItemIndex` field in `PageLutEntry`. Users upgrading will see a one-time re-render of all cached sections on first load — no data loss. - The `textNodeIndexStack` in `XPathProgressResolver` is a `std::vector<int>` that mirrors the existing `path` and `parentStates` stacks — same depth, same lifetime. No additional heap pressure beyond what was already present. - All fixes verified on device with *Gentle and Lowly* by Dane C. Ortlund (spine 21, 17 pages). Download syncs land on the correct page; upload syncs land at the correct paragraph with character-level offset. ## Test plan - [ ] Download: sync from KOReader → CrossPoint lands on correct page for `text()[N].M` XPaths - [ ] Download: ancestry correctly resolves `<li>` positions inbound from KOReader - [ ] Upload: sync from CrossPoint → KOReader lands within one page for mid-paragraph positions - [ ] Upload: sync from CrossPoint → KOReader correctly targets `<li>` elements when page starts on a list item - [ ] Upload: `text()[N].M` format XPaths do not cause KOReader to jump to front of book - [ ] Section cache version 23: delete `.crosspoint/` and verify clean re-parse with no crashes --- ### AI Usage Did you use AI tools to help write this code? **YES** — developed with Claude Code (Anthropic). --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
e64155ed63 |
fix: free Epub RAM and simplify KOSync navigation via ActivityManager (#1860)
## Summary * **What is the goal of this PR?** Fix KOSync failing with "Network error" on large/complex EPUBs, and simplify the sync navigation flow by removing the callback/result pattern. * **What changes are included?** This PR combines the approaches from #1855 and #1760 into a single, cleaner solution: **Memory fix (from #1855):** - `EpubReaderActivity` pre-computes the local KOReader position and chapter name, then explicitly releases `epub` and `section` before launching `KOReaderSyncActivity`. This frees ~65KB measured on device, giving the TLS handshake sufficient heap. The root cause was `MBEDTLS_ERR_X509_ALLOC_FAILED` (-0x2880) when a 3-cert chain consumed ~48KB during the handshake with only ~50KB available. - `KOReaderSyncActivity` no longer receives a `shared_ptr<Epub>` at construction — it lazy-loads the Epub after TLS only if remote progress is found (`ensureEpubLoaded()`). - Added `MIN_HEAP_FOR_TLS = 55000` guard in `KOReaderSyncClient` — returns `LOW_MEMORY` early if aggregate free heap is too low before attempting a TLS connection. **Navigation simplification (from #1760):** - Replaced `startActivityForResult` + callback with `activityManager.replaceActivity` / `activityManager.goToReader`. Progress is saved to `progress.bin` before the epub is released (cancel/upload paths) and in `saveProgressAndReturn` (apply remote path). The reader re-launches from the saved position naturally via `goToReader`, eliminating the need to reload the epub in a callback. - Extracted `ReaderUtils::saveProgress()` as a shared helper used by both `EpubReaderActivity` and `KOReaderSyncActivity`. - Added `STR_SAVE_PROGRESS_FAILED` to all 22 language files for the case where writing the synced position to SD fails. **Orientation fix (found during device testing):** - `EpubReaderActivity::onExit()` resets the renderer to portrait before destruction. With `replaceActivity` the reader is fully torn down before KOSync starts, so KOSync was always rendering in portrait even when reading in landscape. Fixed by calling `ReaderUtils::applyOrientation` in `KOReaderSyncActivity::onEnter()`. ## Additional Context Heap measurements on device (large EPUB with complex CSS): | Metric | Before | After | |---|---|---| | Heap before Epub release | 88,156 bytes | — | | Heap after Epub release | — | 153,892 bytes (+65,736) | | Heap at TLS handshake | ~50,000 bytes (fails) | ~116,384 bytes (passes) | | Min-free-ever during sync session | 2,600 bytes | 33,052 bytes | | TLS result | `MBEDTLS_ERR_X509_ALLOC_FAILED` | HTTP 200 | Tested on device: sync from inside a large EPUB in both portrait and landscape, cancel, apply remote progress, upload local progress. --- ### AI Usage Did you use AI tools to help write this code? _**YES**_ --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
302dea1eea |
fix: Switch to xpath map for paragraph level syncing in KOSync (#1686)
Switch KOReader sync progress mapping from chapter matching to XPath-based mapping. - resolves KOReader positions using real XHTML ancestry paths - supports paragraph-based upload mapping with text offsets where needed - passes the current paragraph index into sync so uploads map back to KOReader more accurately No HTTP client changes are included. No reader-state or resume-flow changes are included. --------- Co-authored-by: jpirnay <jens@pirnay.com> |
||
|
|
307a6608f0 |
chore: remove rendundant xTaskCreate (#1264)
## Summary Ref discussion: https://github.com/crosspoint-reader/crosspoint-reader/pull/1222#discussion_r2865402110 Important note that this is a bug-for-bug fix. In reality, this branch `WiFi.status() == WL_CONNECTED` is pretty much a dead code because the entry point of these 2 activities don't use wifi. It is better to refactor the management of network though, but it's better to be a dedicated PR. --- ### 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** |
||
|
|
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> |
||
|
|
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... |
||
|
|
00e25b1a90 |
fix: Fix kosync repositioning issue (#783)
## Summary * Original implementation had inconsistent positioning logic: - When XPath parsing succeeded: incorrectly set pageNumber = 0 (always beginning of chapter) - When XPath parsing failed: used percentage for positioning (worked correctly) - Result: Positions restored to wrong locations depending on XPath parsing success - Mentioned in Issue #581 * Solution - Unified ProgressMapper::toCrossPoint() to use percentage-based positioning exclusively for both spine identification and intra-chapter page calculation, eliminating unreliable XPath parsing entirely. ## Additional Context * ProgressMapper.cpp: Simplified toCrossPoint() to always use percentage for positioning, removed parseDocFragmentIndex() function * ProgressMapper.h: Updated comments and removed unused function declaration * Tests confirmed appropriate positioning * __Notabene: the syncing to another device will (most probably) end up at the current chapter of crosspoints reading position. There is not much we can do about it, as KOReader needs to have the correct XPath information - we can only provide an apporximate position (plus percentage) - the percentage information is not used in KOReaders current implementation__ --- ### 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 |
||
|
|
d02e21a48f |
fix: Added missing up/down button labels (#935)
## Summary **What is the goal of this PR?** In some places, button labels are omitted intentionally because the button has no purpose in the activity. I noticed a few obvious cases, like Home > File Transfer and Settings > System > Language, where the up and down button labels were missing. This change fixes those and all similar instances I could find. --- ### 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**_ |
||
|
|
7ba5978848 |
feat: User-Interface I18n System (#728)
## Summary **What is the goal of this PR?** This PR introduces Internationalization (i18n) support, enabling users to switch the UI language dynamically. **What changes are included?** - Core Logic: Added I18n class (`lib/I18n/I18n.h/cpp`) to manage language state and string retrieval. - Data Structures: - `lib/I18n/I18nStrings.h/cpp`: Static string arrays for each supported language. - `lib/I18n/I18nKeys.h`: Enum definitions for type-safe string access. - `lib/I18n/translations.csv`: single source of truth. - Documentation: Added `docs/i18n.md` detailing the workflow for developers and translators. - New Settings activity: `src/activities/settings/LanguageSelectActivity.h/cpp` ## Additional Context This implementation (building on concepts from #505) prioritizes performance and memory efficiency. The core approach is to store all localized strings for each language in dedicated arrays and access them via enums. This provides O(1) access with zero runtime overhead, and avoids the heap allocations, hashing, and collision handling required by `std::map` or `std::unordered_map`. The main trade-off is that enums and string arrays must remain perfectly synchronized—any mismatch would result in incorrect strings being displayed in the UI. To eliminate this risk, I added a Python script that automatically generates `I18nStrings.h/.cpp` and `I18nKeys.h` from a CSV file, which will serve as the single source of truth for all translations. The full design and workflow are documented in `docs/i18n.md`. ### Next Steps - [x] Python script `generate_i18n.py` to auto-generate C++ files from CSV - [x] Populate translations.csv with initial translations. Currently available translations: English, Español, Français, Deutsch, Čeština, Português (Brasil), Русский, Svenska. Thanks, community! **Status:** EDIT: ready to be merged. As a proof of concept, the SPANISH strings currently mirror the English ones, but are fully uppercased. --- ### AI Usage Did you use AI tools to help write this code? _**< PARTIALLY >**_ I used AI for the black work of replacing strings with I18n references across the project, and for generating the documentation. EDIT: also some help with merging changes from master. --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: yeyeto2788 <juanernestobiondi@gmail.com> |
||
|
|
3d47c081f2 |
fix: use RAII render lock everywhere (#916)
## Summary Follow-up to https://github.com/crosspoint-reader/crosspoint-reader/pull/774 --- ### 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** <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Refactor** * Modernized internal synchronization mechanisms across multiple components to improve code reliability and maintainability. All functionality remains unchanged. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
a616f42cb4 |
refactor: move render() to Activity super class, use freeRTOS notification (#774)
## Summary Currently, each activity has to manage their own `displayTaskLoop` which adds redundant boilerplate code. The loop is a wait loop which is also not the best practice, as the `updateRequested` boolean is not protected by a mutex. In this PR: - Move `displayTaskLoop` to the super `Activity` class - Replace `updateRequested` with freeRTOS's [direct to task notification](https://www.freertos.org/Documentation/02-Kernel/02-Kernel-features/03-Direct-to-task-notifications/01-Task-notifications) - For `ActivityWithSubactivity`, whenever a sub-activity is present, the parent's `render()` automatically goes inactive With this change, activities now only need to expose `render()` function, and anywhere in the code base can call `requestUpdate()` to request a new rendering pass. ## Additional Context In theory, this change may also make the battery life a bit better, since one wait loop is removed. Although the equipment in my home lab wasn't been able to verify it (the electric current is too noisy and small). Would appreciate if anyone has any insights on this subject. Update: I managed to hack [a small piece of code](https://github.com/ngxson/crosspoint-reader/tree/xsn/measure_cpu_usage) that allow tracking CPU idle time. The CPU load does decrease a bit (1.47% down to 1.39%), which make sense, because the display task is now sleeping most of the time unless notified. This should translate to a slightly increase in battery life in the long run. ``` PR: [40012] [MEM] Free: 185856 bytes, Total: 231004 bytes, Min Free: 123316 bytes [40012] [IDLE] Idle time: 98.61% (CPU load: 1.39%) [50017] [MEM] Free: 185856 bytes, Total: 231004 bytes, Min Free: 123316 bytes [50017] [IDLE] Idle time: 98.61% (CPU load: 1.39%) [60022] [MEM] Free: 185856 bytes, Total: 231004 bytes, Min Free: 123316 bytes [60022] [IDLE] Idle time: 98.61% (CPU load: 1.39%) master: [20012] [MEM] Free: 195016 bytes, Total: 231532 bytes, Min Free: 132460 bytes [20012] [IDLE] Idle time: 98.53% (CPU load: 1.47%) [30017] [MEM] Free: 195016 bytes, Total: 231532 bytes, Min Free: 132460 bytes [30017] [IDLE] Idle time: 98.53% (CPU load: 1.47%) [40022] [MEM] Free: 195016 bytes, Total: 231532 bytes, Min Free: 132460 bytes [40022] [IDLE] Idle time: 98.53% (CPU load: 1.47%) ``` --- ### 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** <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Streamlined rendering architecture by consolidating update mechanisms across all activities, improving efficiency and consistency. * Modernized synchronization patterns for display updates to ensure reliable, conflict-free rendering. * **Bug Fixes** * Enhanced rendering stability through improved locking mechanisms and explicit update requests. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: znelson <znelson@users.noreply.github.com> |
||
|
|
cb24947477 |
feat: Add central logging pragma (#843)
## Summary
* Definition and use of a central LOG function, that can later be
extended or completely be removed (for public use where debugging
information may not be required) to save flash by suppressing the
-DENABLE_SERIAL_LOG like in the slim branch
* **What changes are included?**
## Additional Context
* By using the central logger the usual:
```
#include <HardwareSerial.h>
...
Serial.printf("[%lu] [WCS] Obfuscating/deobfuscating %zu bytes\n", millis(), data.size());
```
would then become
```
#include <Logging.h>
...
LOG_DBG("WCS", "Obfuscating/deobfuscating %zu bytes", data.size());
```
You do have ``LOG_DBG`` for debug messages, ``LOG_ERR`` for error
messages and ``LOG_INF`` for informational messages. Depending on the
verbosity level defined (see below) soe of these message types will be
suppressed/not-compiled.
* The normal compilation (default) will create a firmware.elf file of
42.194.356 bytes, the same code via slim will create 42.024.048 bytes -
170.308 bytes less
* Firmware.bin : 6.469.984 bytes for default, 6.418.672 bytes for slim -
51.312 bytes less
### 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: Xuan Son Nguyen <son@huggingface.co>
|
||
|
|
f34d7d2aac |
fix(ui): Add Back label in KOReader Sync screen (#770)
## Summary - Remove duplicate Cancel option - Add Back label <img width="435" height="613" alt="image" src="https://github.com/user-attachments/assets/a3af4133-46fa-46e6-8360-a15dd7c4fe2a" /> ## Result <img width="575" height="431" alt="image" src="https://github.com/user-attachments/assets/6ccdac89-43df-45bf-bcfa-3a7cc4bd88e4" /> --- ### AI Usage Did you use AI tools to help write this code? _**< PARTIALLY >**_ Closes #754 |
||
|
|
bf87a7dc60 |
feat: UI themes, Lyra (#528)
## Summary ### What is the goal of this PR? - Visual UI overhaul - UI theme selection ### What changes are included? - Added a setting "UI Theme": Classic, Lyra - The classic theme is the current Crosspoint theme - The Lyra theme implements these mockups: https://www.figma.com/design/UhxoV4DgUnfrDQgMPPTXog/Lyra-Theme?node-id=2003-7596&t=4CSOZqf0n9uQMxDt-0 by Discord users yagofarias, ruby and gan_shu - New functions in GFXRenderer to render rounded rectangles, greyscale fills (using dithering) and thick lines - Basic UI components are factored into BaseTheme methods which can be overridden by each additional theme. Methods that are not overridden will fallback to BaseTheme behavior. This means any new features/components in CrossPoint only need to be developed for the "Classic" BaseTheme. - Additional themes can easily be developed by the community using this foundation    ## Additional Context - Only the Home, Library and main Settings screens have been implemented so far, this will be extended to the transfer screens and chapter selection screen later on, but we need to get the ball rolling somehow :) - Loading extra covers on the home screen in the Lyra theme takes a little more time (about 2 seconds), I added a loading bar popup (reusing the Indexing progress bar from the reader view, factored into a neat UI component) but the popup adds ~400ms to the loading time. - ~~Home screen thumbnails will need to be generated separately for each theme, because they are displayed in different sizes. Because we're using dithering, displaying a thumb with the wrong size causes the picture to look janky or dark as it does on the screenshots above. No worries this will be fixed in a future PR.~~ Thumbs are now generated with a size parameter - UI Icons will need to be implemented in a future PR. --- ### 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**_ This is not a vibe coded PR. Copilot was used for autocompletion to save time but I reviewed, understood and edited all generated code. --------- Co-authored-by: Dave Allie <dave@daveallie.com> |
||
|
|
f69cddf2cc |
Adds KOReader Sync support (#232)
## Summary - Adds KOReader progress sync integration, allowing CrossPoint to sync reading positions with other KOReader-compatible devices - Stores credentials securely with XOR obfuscation - Uses KOReader's partial MD5 document hashing for cross-device book matching - Syncs position via percentage with estimated XPath for compatibility # Features - Settings: KOReader Username, Password, and Authenticate options - Sync from chapters menu: "Sync Progress" option appears when credentials are configured - Bidirectional sync: Can apply remote progress or upload local progress --------- Co-authored-by: Dave Allie <dave@daveallie.com> |