Compare commits

...
Author SHA1 Message Date
Justin Mitchell 9cfdaa46a1 Reformat touch reader controls enum definition 2026-08-13 15:51:38 -04:00
Justin Mitchell 58b2f6d41e Move tap for reader menu setting to Controls category
Changed the category of the tapForReaderMenu setting from STR_CAT_READER to STR_CAT_CONTROLS for better organization in the settings UI.
2026-08-13 15:26:33 -04:00
Justin Mitchell 6bf0dd746a Add inverted tap mode for touch reader controls
Adds a new touch control mode that swaps the left/right tap zones, allowing users to navigate forward by tapping the left side and backward by tapping the right side. The inverted behavior is applied when the TOUCH_READER_INVERTED_TAP setting is selected.
2026-08-13 15:21:52 -04:00
Justin Mitchell c0b2d3c2ad Add toggle to disable tap-for-reader-menu gesture
Introduces a new setting 'tapForReaderMenu' that allows users to disable the center-third tap gesture for opening the reader menu. This option is only shown on devices with a capacitive Home key, since those devices can still access the menu via long-press. On devices without a Home key, the tap gesture remains the primary access method and cannot be disabled.
2026-08-13 15:14:41 -04:00
Justin Mitchell 8a4efefe25 Add Reader Menu option for long-press action on homekey boards
Adds a new long-press menu option that opens the reader menu. This option is conditionally available only on boards with a Home key. The new option allows users to configure long-press to open the reader menu directly, which is useful for devices with capacitive Home keys that provide long-press actions.
2026-08-13 03:25:38 -04:00
Justin Mitchell b26bc5d531 Avoid restart on WiFi exit for touch devices
On devices with capacitive touch, external power rails for touch and frontlight are not cycled during software reset. Instead of restarting, cleanly shut down WiFi and SNTP in place to preserve peripheral state. Also handle Home gesture alongside Back button for exit responsiveness in the web server activity.
2026-08-13 03:20:14 -04:00
Justin Mitchell 2b3379569a Add power button confirm action for capacitive touch
Adds PWR_CONFIRM option to short power button settings, allowing the power button to act as a confirm button on capacitive touch devices. Includes special handling for X4 Pro's frontlight double-click window to avoid conflicts.
2026-08-13 03:14:02 -04:00
Justin Mitchell 9ebb824dfd Add Home key long-press action support in reader
Implements long-press detection for the Home key on devices without a front Confirm button. The long-press triggers the user-configured action (bookmark, KOSync, dictionary, or disabled) similar to the Confirm button long-press behavior.
2026-08-13 03:10:11 -04:00
Justin Mitchell 8891d49669 Prevent light sleep when frontlight is active
Add frontlight state check to sleep exclusion conditions to avoid visible flashing caused by LEDC PWM suspension during light sleep cycles. This prevents the ESP from entering light sleep when the frontlight is on, similar to existing WiFi and USB exclusions.
2026-08-13 00:05:01 -04:00
Justin Mitchell 3c3e695340 Add X4 Pro support for recovery mode detection
X4 Pro uses a different button (DOWN instead of UP) and requires shorter debounce time (20ms vs 500ms) for recovery mode detection. The DOWN button is used to avoid GPIO0 boot-strap pin conflicts on X4 Pro hardware.
2026-08-12 23:47:17 -04:00
Justin Mitchell 2a3f08ddcd Add vertical bounds to reader menu tap zone
The tap zone for opening the reader menu now checks both horizontal and vertical bounds, restricting it to the center third of the screen in both dimensions. Previously only horizontal bounds were checked, allowing taps anywhere vertically in the middle third horizontally to open the menu.
2026-08-12 23:30:47 -04:00
Justin Mitchell 4ff215f4e1 Merge branch 'develop' into feat-x4-papermono-support
# Conflicts:
#	src/activities/settings/SettingsActivity.cpp
2026-08-12 23:16:56 -04:00
Justin Mitchell 9361115e46 Skip power button hold verification for X4 Pro
X4 Pro wakes on any power button press, so it should bypass the hold-duration verification like boards without a power button. This ensures the wake is treated as valid immediately.
2026-08-12 23:16:22 -04:00
Justin Mitchell 1020f66723 Merge remote-tracking branch 'origin/develop' into feat-x4-papermono-support 2026-08-12 21:13:26 -04:00
Justin Mitchell 144f5740db fix: install full penv_setup dependency set for espressif32 builds
platform-espressif32's own penv bootstrap isn't reliably installing
its required python packages in this runner image, so pin the full
list (littlefs-python, fatfs-ng, and friends) explicitly instead of
discovering missing modules one build at a time.
2026-08-12 18:50:17 -04:00
Justin Mitchell 7d15decbc6 fix: install littlefs-python for PlatformIO CI builds
pioarduino's espressif32 builder imports littlefs unconditionally,
which was never installed alongside platformio-core, breaking every
build and cppcheck job.
2026-08-12 18:42:25 -04:00
Justin Mitchell a30d59ef97 Downgrade CI Python version from 3.14 to 3.13
Update all GitHub Actions workflows to use Python 3.13 instead of 3.14, likely due to 3.14 not being available or stable yet.
2026-08-12 18:22:02 -04:00
Justin Mitchell af3fe731ca Add grayscale base display handling for e-ink panels
Introduce displayBaseWithRefreshCycle to handle B/W base layer display differently for panels that combine grayscale bases vs those that don't. Panels with combined bases defer activation to avoid visible flashing when grayscale pass re-drives text. Also add cleanup call to flush deferred activations for combined-base panels.
2026-08-12 18:10:30 -04:00
Justin Mitchell e9eb7b8d6d Add combined grayscale base rendering for Paper Mono
Implements a new rendering path for Paper Mono displays that defers base activation so grayscale planes can be combined with the base in a single waveform. This prevents visible flashing that occurs when the base is displayed separately and the gray pass re-drives the text body. The feature is controlled by combinesGrayscaleBase() checks throughout the rendering pipeline.
2026-08-12 18:04:02 -04:00
Justin Mitchell a97e850279 Add matrix build for multiple board variants
Consolidates duplicate build jobs into a single matrix-based job that builds firmware for default, sticky, x4pro, and papermono boards. Adds a new release workflow that builds all board variants with release-specific environments when tags are pushed. Artifacts are named to match OtaUpdater's expected format (firmware.bin for C3, firmware-<board>.bin for others).
2026-08-12 17:59:47 -04:00
Justin Mitchell 4af91daaee Remove manual row height scaling for wrapped labels
The list() function now handles per-row sizing for wrapped items automatically, so manual scaling of row height by line count is no longer needed. Updated comments to reflect that wrapped labels grow only their own row while dense height is preserved for other rows.
2026-08-12 17:01:05 -04:00
Justin Mitchell 595edde489 Add back-to-file-browser setting to settings list
Include STR_BACK_SHORT_TO_FILE_BROWSER in the settings condition check alongside the existing sunlight fading fix setting.
2026-08-12 16:39:44 -04:00
Justin Mitchell 788e1d5901 Merge branch 'feat-x4-papermono-support' of https://github.com/crosspoint-reader/crosspoint-reader into feat-x4-papermono-support 2026-08-12 16:35:13 -04:00
Justin Mitchell 1c4ded42ff Scale list row height by label line count
When a list label can wrap to multiple lines, scale the entire row height by the label's maxLines instead of flooring against the raw font line-height. This preserves the theme's proportional padding for dense rows and prevents wrapped text from bleeding into the next row. Applied to UiListActivity, UiTabListActivity, and WifiSelectionActivity (list/tab/wifi selection screens) replacing the previous wrappedMin floor logic with rowHeight *= maxLines for labelText.maxLines > 1.
2026-08-12 16:34:29 -04:00
Justin Mitchell 6c2be7bb1e Reformat multi-line expressions for consistency
Adjust line breaks in WifiSelectionActivity and FrontlightPanelActivity to improve code formatting consistency. No functional changes.
2026-08-12 16:04:56 -04:00
Justin Mitchell a6db9c7bab Persist frontlight 'on' only if user changed
Add a lightOnChanged flag to FrontlightPanelActivity (src/activities/util/FrontlightPanelActivity.h) and initialize it in onEnter. Set the flag whenever the user toggles the light or adjustments implicitly turn it on. onExit now only updates SETTINGS.frontlightOn when lightOnChanged is true; brightness/warmth continue to be persisted as before. This avoids overwriting the saved "was on" preference with the live hardware state when the user didn't interact with the control.
2026-08-12 16:04:21 -04:00
Justin Mitchell 30a3137a69 Ensure list rows accommodate wrapped labels
Floor list row heights to the label's required lines where labels may wrap. UiListActivity, UiTabListActivity and WifiSelectionActivity now compute a wrappedMin = lineHeight * maxLines and increase rowHeight if needed to prevent the second wrapped line from bleeding into the next row. Also update SettingsActivity's language selection flow to save settings and rebuild the settings lists on return so row labels reflect the new language immediately.
2026-08-12 15:37:16 -04:00
Justin Mitchell f55580888f Add XteinkX3Uc8279 board to GPIO configuration
Include XteinkX3Uc8279 board in the active board check condition for GPIO handling.
2026-08-12 14:34:40 -04:00
Justin Mitchell 96dd6f6d6e Add bounds check before accessing recent books list
Clear rowItems before bounds checking to prevent accessing stale row indices. The interaction table can deliver row indices captured before list modifications, so validate the index is within current list bounds before proceeding.
2026-08-12 14:30:59 -04:00
Justin Mitchell 6953859576 Merge remote-tracking branch 'origin/develop' into feat-x4-papermono-support
# Conflicts:
#	freeink-sdk
#	src/MappedInputManager.cpp
#	src/MappedInputManager.h
#	src/activities/reader/EpubReaderMenuActivity.cpp
#	src/activities/reader/EpubReaderMenuActivity.h
#	src/activities/reader/ReaderUtils.h
#	src/activities/settings/OpdsServerListActivity.cpp
#	src/activities/settings/OpdsSettingsActivity.cpp
#	src/components/OptionPopup.h
#	src/components/UiAppHelpers.h
#	src/components/UiAppHost.cpp
#	src/components/UiAppHost.h
#	src/components/themes/BaseTheme.cpp
2026-08-12 13:51:39 -04:00
Justin Mitchell 35be6872a2 Remove duplicate screenInverted setting 2026-08-12 00:45:51 -04:00
Justin Mitchell 4baa19f05a Remove setInverted method from HalDisplay
Removes the setInverted method that was wrapping einkDisplay.setInverted. Callers should use the underlying einkDisplay method directly if needed.
2026-08-12 00:29:51 -04:00
Justin Mitchell fd281a5351 Remove duplicate night mode translation string 2026-08-12 00:21:11 -04:00
Justin Mitchell 55fe65e06b Merge remote-tracking branch 'origin/develop' into feat-x4-papermono-support 2026-08-12 00:19:27 -04:00
Justin Mitchell 72404c20af Update freeink-sdk submodule
Update freeink-sdk submodule from c1d96ba to 65d9eba.
2026-08-12 00:14:23 -04:00
Justin Mitchell ddc4c6a250 Add frontlight restore setting and X4 Pro toggle
Add optional setting to restore frontlight on/off state after wake (brightness/warmth always restored). Implement double-click power button to toggle frontlight on X4 Pro. Silent reboots preserve light state regardless of setting to avoid unexpected darkness.
2026-08-12 00:12:54 -04:00
Justin Mitchell b76b999266 Add frontlight control and display inversion support
Implements HalFrontlight wrapper around SDK frontlight manager with brightness, warmth, and on/off controls. Adds display inversion methods to HalDisplay. Includes special power management for PaperMono device using M5PM1 PMIC for shutdown. Adds corresponding UI strings for night mode and frontlight settings.
2026-08-12 00:10:53 -04:00
Justin Mitchell 2780802830 Add capacitive Home key support for X4 Pro
Implements Home key detection through the touch controller for X4 Pro hardware. The Home gesture now checks for a capacitive Home key tap if available, falling back to the bottom-edge swipe gesture on devices without the key. Also adds X4 Pro device detection and display controller probing.
2026-08-11 23:48:37 -04:00
Justin Mitchell 6b5600cd3b Return to reader menu when cancelling sub-screens
When users cancel (via Back button/gesture) from menu-launched sub-screens like text settings or footnotes, return them to the reader menu instead of the reading surface. This provides more intuitive navigation flow. Home gesture exits are unaffected as ActivityManager handles the stack.
2026-08-11 23:04:05 -04:00
Justin Mitchell cccdea96f4 Reformat array initializers for consistency
Adjust whitespace and line breaks in array initializer lists across settings activities to improve code formatting consistency. No functional changes.
2026-08-11 22:50:54 -04:00
Justin Mitchell 3c83f45f93 Cache list row data to avoid per-render allocations
Prebuild and cache ListItem/label buffers for list screens to eliminate repeated per-render heap allocations. Many activities were changed to build rowItems/rowLabels/rowValues once (on construction, onEnter(), or when data changes) and reuse them during paint: OpdsBookBrowser, RecentBooks, NetworkModeSelection, EndOfBookOptions, EpubReaderFootnotes, EpubReaderMenu, XtcReaderChapterSelection, FontDownload, KOReaderSettings, LanguageSelect, OpdsServerList, OpdsSettings, Settings, StatusBarSettings, and TextSettings. Added rebuildRowItems()/rowsDirty_ flags and fixed-capacity arrays where appropriate (NetworkModeSelection, KOReader, etc.). Behavior unchanged; this reduces CPU and heap churn during repaints.
2026-08-11 22:44:00 -04:00
Justin Mitchell ae478fb179 Clarify FUI row-cache guidance
Updates the touch/UI contribution guide to recommend activity-owned row caches for FUI list screens. It adds a concrete rebuildRows pattern, points contributors to FileBrowserActivity for the real-world implementation, and explains why per-render std::vector allocations are avoidable and harmful to steady-state rendering.
2026-08-11 22:13:48 -04:00
Justin Mitchell ee4db8e1fd Preserve denser list rows on non-touch devices
Restore the pre-FreeInkUI list density for non-touch hardware by selecting denser theme metrics where appropriate.

- Added optional hasSubtitle parameter to UiListActivity::syncListViewport and UiTabListActivity::syncTabListViewport so callers can choose subtitle-aware row heights.
- When mappedInput/gpio reports no touch, activities now override props.rowHeight with UITheme metrics (listRowHeight or listWithSubtitleRowHeight) so lists show more rows on X3/X4 devices.
- Updated callers across activities (RecentBooks, Network/WiFi screens, bookmarks, font/opds lists, reader actions, etc.) and added necessary includes.

This keeps touch-target sizing for touch devices while restoring denser layouts on non-touch hardware.
2026-08-11 22:08:19 -04:00
Justin Mitchell 3702925755 Cache list rows/strings for list screens
Introduce cached row buffers to avoid composing strings and allocating ListItems on every repaint. Added networkStatuses/networkRowItems + rebuildNetworkRowItems() (WifiSelectionActivity.cpp/.h), bookmarkSubtitles/bookmarkRowItems + rebuildBookmarkRowItems() (EpubReaderBookmarksActivity.cpp/.h), and tocLabels/tocRowItems + buildTocRowItems() (EpubReaderChapterSelectionActivity.cpp/.h). buildScreen() now reuses these cached arrays; caches are rebuilt when underlying data changes (scan results, bookmark delete, onEnter for TOC). Reduces per-frame allocations and CPU work during cursor moves/taps.
2026-08-11 18:09:14 -04:00
Justin Mitchell a4edce3961 Cache file-list rows to avoid per-render allocs
Add cached per-row buffers (rowNames, rowExtensions, rowItems) and rebuildRowItems() to FileBrowserActivity. loadFiles() now populates/clears the cache and error paths call rebuildRowItems(); buildScreen() reuses cached rowItems and invalidates them on theme change. Caches are cleared in onExit(). Changes in src/activities/home/FileBrowserActivity.h and .cpp. This prevents allocating hundreds of strings/ListItem objects on every repaint for large directories, reducing heap churn and improving UI responsiveness.
2026-08-11 17:58:06 -04:00
Justin Mitchell 07b27ff6df Restore popup borders in option dialogs
Explicitly apply themed popup border styles in the Wi‑Fi prompt and generic option popup dialogs. This restores the missing frame around option dialogs by setting the same border color, thickness, and corner radius used by the theme metrics, matching the prior OptionPopup rendering and keeping the UI consistent.
2026-08-11 16:50:54 -04:00
Justin Mitchell 3198b293f3 Clarify list data flow with improved comments
Rename 'items' to 'entries' to distinguish activity data from transient render items. Add comments explaining that 'entries' holds loaded data while 'rows' is the per-render vector of ListItems passed to the UI component.
2026-08-10 15:33:28 -04:00
Justin Mitchell bba8c21b1a Use UI font for titles in all builds
Remove OMIT_FONTS conditional and always use UI_FONT_ID for titles instead of NOTOSANS_14_FONT_ID. UI fonts provide better script coverage (Hebrew, CJK) for book and directory titles, matching the font used in develop's drawHeader.
2026-08-10 15:26:41 -04:00
Justin Mitchell 6dea6b31f4 Deprecate touch bridge helpers in favor of FreeInkUI
Mandate FreeInkUI components for all new screens. The old touch bridge helpers (rowTouch, colTouch, wasTapInRect, manual rect contains checks) are now legacy-only and must not appear in new code. Document the four supported host patterns: UiListActivity, UiTabListActivity, UiAppHost, and OptionPopup.
2026-08-10 15:16:36 -04:00
Justin Mitchell fc6d11fdd8 Fix input handling race conditions and edge cases
Add assertions for tab navigation bounds checking. Fix confirm button handling to only swallow release when button is actually pressed, preventing touch input from being incorrectly consumed. Add fromButton parameter to distinguish physical button presses from touch taps. Hide action hints when recent books list is empty. Add atomic synchronization for end-of-book options menu to prevent race conditions. Handle case where section is dropped during pending page turn.
2026-08-10 14:29:09 -04:00
Justin Mitchell daf7937b68 Refactor UiListActivity to inherit from UiAppHost
Extract common UI app hosting logic into UiAppHost base class. UiListActivity now inherits from UiAppHost instead of duplicating the render target, FreeInkApp, and uiReady handshake logic. Simplifies touch routing by delegating to parent class and renames routeTouch to routeListTouch to avoid name hiding.
2026-08-10 13:54:09 -04:00
Justin Mitchell 502335693d Replace custom touch handling with ConfirmPopup
Refactor OtaUpdateActivity to use the standard ConfirmPopup component instead of custom touch rectangle handling and button rendering. Also configure WifiSelectionActivity to use vertical options layout with multi-line text wrapping to prevent label truncation.
2026-08-10 13:19:37 -04:00
Justin Mitchell 9e6578f61c Replace custom prompt rendering with dialog component
Refactor WiFi save and forget prompts to use the FreeInkApp dialog system instead of custom touch handling and rendering. Moves prompt logic into event handlers that interact with the dialog action system, simplifying the code and improving consistency with the UI framework.
2026-08-10 00:48:06 -04:00
Justin Mitchell 36085d80db Convert all lists and tabs to FUI 2026-08-09 23:31:47 -04:00
53 changed files with 1339 additions and 176 deletions

No files matched your search

+45 -62
View File
@@ -18,7 +18,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
python-version: '3.13'
- name: Install clang-format-21
run: |
@@ -42,7 +42,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -51,7 +51,15 @@ jobs:
enable-cache: false
- name: Install PlatformIO Core
run: uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
run: |
uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
# platform-espressif32's builder/main.py imports these unconditionally; its own
# penv bootstrap (builder/penv_setup.py) is supposed to install them automatically
# but isn't picking them up reliably in this runner image, so pin them explicitly.
uv pip install --system -U "littlefs-python>=0.16.0" "fatfs-ng>=0.1.14" "pyyaml>=6.0.2" \
"rich-click>=1.8.6" "zopfli>=0.2.2" "intelhex>=2.3.0" "rich>=14.0.0" "urllib3<2" \
"cryptography>=45.0.3" "certifi>=2025.8.3" "ecdsa>=0.19.1" "bitstring>=4.3.1" \
"reedsolo>=1.5.3,<1.8" "esp-idf-size>=2.0.0" "esp-coredump>=1.14.0"
- name: Cache PlatformIO packages
uses: actions/cache@v4
@@ -63,9 +71,24 @@ jobs:
- name: Run cppcheck
run: pio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high
build-default:
name: Build default
build:
name: Build ${{ matrix.env }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Artifact names match the release asset names OtaUpdater requests:
# plain firmware.bin for the C3 X4/X3 binary, firmware-<board>.bin for
# the S3 boards.
include:
- env: default
asset: firmware.bin
- env: sticky
asset: firmware-sticky.bin
- env: x4pro
asset: firmware-x4pro.bin
- env: papermono
asset: firmware-papermono.bin
steps:
- uses: actions/checkout@v6
with:
@@ -73,7 +96,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -82,7 +105,15 @@ jobs:
enable-cache: false
- name: Install PlatformIO Core
run: uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
run: |
uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
# platform-espressif32's builder/main.py imports these unconditionally; its own
# penv bootstrap (builder/penv_setup.py) is supposed to install them automatically
# but isn't picking them up reliably in this runner image, so pin them explicitly.
uv pip install --system -U "littlefs-python>=0.16.0" "fatfs-ng>=0.1.14" "pyyaml>=6.0.2" \
"rich-click>=1.8.6" "zopfli>=0.2.2" "intelhex>=2.3.0" "rich>=14.0.0" "urllib3<2" \
"cryptography>=45.0.3" "certifi>=2025.8.3" "ecdsa>=0.19.1" "bitstring>=4.3.1" \
"reedsolo>=1.5.3,<1.8" "esp-idf-size>=2.0.0" "esp-coredump>=1.14.0"
- name: Cache PlatformIO packages
uses: actions/cache@v4
@@ -91,13 +122,12 @@ jobs:
key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini') }}
restore-keys: pio-${{ runner.os }}-
- name: Build default firmware
- name: Build ${{ matrix.env }} firmware
run: |
set -euo pipefail
pio run -e default | tee pio.log
pio run -e ${{ matrix.env }} | tee pio.log
- name: Extract firmware stats
run: |
set -euo pipefail
ram_line="$(grep -E "RAM:\\s" -m1 pio.log || true)"
@@ -105,64 +135,18 @@ jobs:
echo "ram_line=${ram_line}" >> "$GITHUB_OUTPUT"
echo "flash_line=${flash_line}" >> "$GITHUB_OUTPUT"
{
echo "## Firmware build stats"
echo "## ${{ matrix.env }} firmware build stats"
if [ -n "$ram_line" ]; then echo "- ${ram_line}"; else echo "- RAM: not found"; fi
if [ -n "$flash_line" ]; then echo "- ${flash_line}"; else echo "- Flash: not found"; fi
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload firmware.bin artifact
- name: Upload firmware artifact
uses: actions/upload-artifact@v6
with:
name: firmware.bin
path: .pio/build/default/firmware.bin
name: ${{ matrix.asset }}
path: .pio/build/${{ matrix.env }}/firmware.bin
if-no-files-found: error
build-sticky:
name: Build sticky
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: "latest"
enable-cache: false
- name: Install PlatformIO Core
run: uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
- name: Cache PlatformIO packages
uses: actions/cache@v4
with:
path: ~/.platformio
key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini') }}
restore-keys: pio-${{ runner.os }}-
- name: Build sticky firmware
run: |
set -euo pipefail
pio run -e sticky | tee pio.log
- name: Extract firmware stats
run: |
set -euo pipefail
ram_line="$(grep -E "RAM:\\s" -m1 pio.log || true)"
flash_line="$(grep -E "Flash:\\s" -m1 pio.log || true)"
echo "ram_line=${ram_line}" >> "$GITHUB_OUTPUT"
echo "flash_line=${flash_line}" >> "$GITHUB_OUTPUT"
{
echo "## Sticky firmware build stats"
if [ -n "$ram_line" ]; then echo "- ${ram_line}"; else echo "- RAM: not found"; fi
if [ -n "$flash_line" ]; then echo "- ${flash_line}"; else echo "- Flash: not found"; fi
} >> "$GITHUB_STEP_SUMMARY"
unit-tests:
runs-on: ubuntu-latest
steps:
@@ -195,8 +179,7 @@ jobs:
test-status:
name: Test Status
needs:
- build-default
- build-sticky
- build
- clang-format
- cppcheck
- unit-tests
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
python-version: '3.13'
- name: Install font tools
run: pip install freetype-py fonttools pyyaml
+83
View File
@@ -0,0 +1,83 @@
name: Compile Release
# Builds every board's release firmware on tag push, with the .bin named
# exactly as OtaUpdater requests it from the GitHub release: plain
# firmware.bin for the C3 X4/X3 binary, firmware-<board>.bin for every other
# board. Attach the artifacts' .bin files to the release as-is.
on:
push:
tags:
- '*'
permissions:
contents: read
jobs:
build-release:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- pio_env: gh_release
asset: firmware.bin
- pio_env: sticky-gh_release
asset: firmware-sticky.bin
- pio_env: x4pro-gh_release
asset: firmware-x4pro.bin
- pio_env: papermono-gh_release
asset: firmware-papermono.bin
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: "latest"
enable-cache: false
- name: Install PlatformIO Core
run: |
uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
# platform-espressif32's builder/main.py imports these unconditionally; its own
# penv bootstrap (builder/penv_setup.py) is supposed to install them automatically
# but isn't picking them up reliably in this runner image, so pin them explicitly.
uv pip install --system -U "littlefs-python>=0.16.0" "fatfs-ng>=0.1.14" "pyyaml>=6.0.2" \
"rich-click>=1.8.6" "zopfli>=0.2.2" "intelhex>=2.3.0" "rich>=14.0.0" "urllib3<2" \
"cryptography>=45.0.3" "certifi>=2025.8.3" "ecdsa>=0.19.1" "bitstring>=4.3.1" \
"reedsolo>=1.5.3,<1.8" "esp-idf-size>=2.0.0" "esp-coredump>=1.14.0"
- name: Cache PlatformIO packages
uses: actions/cache@v4
with:
path: ~/.platformio
key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini') }}
restore-keys: pio-${{ runner.os }}-
- name: Build CrossPoint
run: pio run -e ${{ matrix.pio_env }} -j1
- name: Name release asset
run: |
if [ "${{ matrix.asset }}" != "firmware.bin" ]; then
cp ".pio/build/${{ matrix.pio_env }}/firmware.bin" \
".pio/build/${{ matrix.pio_env }}/${{ matrix.asset }}"
fi
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset }}
path: |
.pio/build/${{ matrix.pio_env }}/bootloader.bin
.pio/build/${{ matrix.pio_env }}/${{ matrix.asset }}
.pio/build/${{ matrix.pio_env }}/firmware.elf
.pio/build/${{ matrix.pio_env }}/firmware.map
.pio/build/${{ matrix.pio_env }}/partitions.bin
+10 -2
View File
@@ -14,7 +14,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -23,7 +23,15 @@ jobs:
enable-cache: false
- name: Install PlatformIO Core
run: uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
run: |
uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
# platform-espressif32's builder/main.py imports these unconditionally; its own
# penv bootstrap (builder/penv_setup.py) is supposed to install them automatically
# but isn't picking them up reliably in this runner image, so pin them explicitly.
uv pip install --system -U "littlefs-python>=0.16.0" "fatfs-ng>=0.1.14" "pyyaml>=6.0.2" \
"rich-click>=1.8.6" "zopfli>=0.2.2" "intelhex>=2.3.0" "rich>=14.0.0" "urllib3<2" \
"cryptography>=45.0.3" "certifi>=2025.8.3" "ecdsa>=0.19.1" "bitstring>=4.3.1" \
"reedsolo>=1.5.3,<1.8" "esp-idf-size>=2.0.0" "esp-coredump>=1.14.0"
- name: Cache PlatformIO packages
uses: actions/cache@v4
+2 -2
View File
@@ -1,6 +1,6 @@
# Touch and UI Development
CrossPoint runs on touch devices (Seeed Sticky, M5Paper, LilyGo T5) alongside the button-only Xteink X3/X4. Every screen must work with both input styles.
CrossPoint runs on touch devices (Seeed Sticky, M5Paper, M5Stack PaperMono, LilyGo T5, Xteink X4 Pro) alongside the button-only Xteink X3/X4. Every screen must work with both input styles.
**There is one supported way to build a new screen: FreeInkUI, hosted through the firmware base classes below.** Touch hit-testing, tap highlighting, long-press, swipe scrolling, and button focus navigation all come from the shared stack; you never hand-roll coordinate math.
@@ -18,7 +18,7 @@ The old bridge helpers (`rowTouch`, `colTouch`, `wasTapInRect`, manual rect `con
| A modal picker or confirm inside a legacy activity | `OptionPopup` (or push `ConfirmationActivity`) | [`OtaUpdateActivity`](../../src/activities/settings/OtaUpdateActivity.cpp) |
| A Yes/No prompt inside a FUI screen | build `fui::optionDialog` into the screen | `WifiSelectionActivity::buildPromptDialog` |
All four paths route input through the same SDK interaction table, so touch and physical buttons fire the same actions with no per-screen coordinate code.
All of these paths route input through the same SDK interaction table, so touch and physical buttons fire the same actions with no per-screen coordinate code.
## The hosting stack
+2
View File
@@ -2138,6 +2138,8 @@ void GfxRenderer::writeGrayscalePlaneStrip(bool lsbPlane, const uint8_t* scratch
bool GfxRenderer::supportsStripGrayscale() const { return display.supportsStripGrayscale(); }
bool GfxRenderer::combinesGrayscaleBase() const { return display.combinesGrayscaleBase(); }
void GfxRenderer::freeBwBufferChunks() {
for (auto& bwBufferChunk : bwBufferChunks) {
if (bwBufferChunk) {
+3
View File
@@ -293,6 +293,9 @@ class GfxRenderer {
// numRows)), bypassing the framebuffer. supportsStripGrayscale() gates use.
void writeGrayscalePlaneStrip(bool lsbPlane, const uint8_t* scratch, int yStart, int numRows) const;
bool supportsStripGrayscale() const;
// Paper Mono: the base activation is deferred so base + gray planes go out
// as one waveform. Route the base through displayGrayscaleBase() when true.
bool combinesGrayscaleBase() const;
bool storeBwBuffer(); // Returns true if buffer was stored successfully
void restoreBwBuffer(); // Restore and free the stored buffer
void cleanupGrayscaleWithFrameBuffer() const;
+9
View File
@@ -95,6 +95,7 @@ STR_SHORT_PWR_BTN: "Short Power Button Click"
STR_ORIENTATION: "Reading Orientation"
STR_SIDE_BTN_LAYOUT: "Side Button Layout (reader)"
STR_TOUCH_READER_CONTROLS: "Touch Reader Controls"
STR_TAP_FOR_READER_MENU: "Tap For Reader Menu"
STR_FRONT_BTN_FOLLOW_ORIENTATION: "Orient front buttons"
STR_LONG_PRESS_BEHAVIOR: "Long-press button behavior"
STR_LONG_PRESS_BEHAVIOR_OFF: "OFF"
@@ -184,6 +185,7 @@ STR_NEXT_PREV: "Next/Prev"
STR_KOSYNC: "KOSync"
STR_BOOKMARK_OPTION: "Bookmark"
STR_DICTIONARY: "Dictionary"
STR_READER_MENU: "Reader Menu"
STR_DISABLED: "Disabled"
STR_NOTO_SERIF: "Noto Serif"
STR_NOTO_SANS: "Noto Sans"
@@ -247,6 +249,13 @@ STR_SHOW: "Show"
STR_HIDE: "Hide"
STR_STATE_ON: "ON"
STR_STATE_OFF: "OFF"
STR_STATE_TAP: "Tap"
STR_STATE_SWIPE: "Swipe"
STR_STATE_INVERTED_TAP: "Inverted Tap"
STR_FRONTLIGHT: "Frontlight"
STR_BRIGHTNESS: "Brightness"
STR_WARMTH: "Warmth"
STR_RESTORE_LIGHT_ON_WAKE: "Restore Light on Wake"
STR_NOT_SET: "Not Set"
STR_DIR_LEFT: "Left"
STR_DIR_RIGHT: "Right"
+6 -1
View File
@@ -16,9 +16,14 @@ void safeCopy(char* dst, size_t dstSize, const char* src, size_t srcLen) {
ReleaseJsonParser::ReleaseJsonParser()
: parser(JsonCallbacks{this, sOnKey, sOnString, sOnNumber, sOnBool, sOnNull, sOnObjectStart, sOnObjectEnd,
sOnArrayStart, sOnArrayEnd}) {
safeCopy(firmwareAssetName, sizeof(firmwareAssetName), "firmware.bin", sizeof("firmware.bin") - 1);
reset();
}
void ReleaseJsonParser::setFirmwareAssetName(const char* name) {
safeCopy(firmwareAssetName, sizeof(firmwareAssetName), name, strlen(name));
}
void ReleaseJsonParser::reset() {
parser.reset();
position = Position::TOP_LEVEL;
@@ -44,7 +49,7 @@ const char* ReleaseJsonParser::getFirmwareUrl() const { return firmwareUrl; }
size_t ReleaseJsonParser::getFirmwareSize() const { return firmwareSize; }
void ReleaseJsonParser::commitAsset() {
if (strcmp(currentAssetName, "firmware.bin") == 0) {
if (strcmp(currentAssetName, firmwareAssetName) == 0) {
memcpy(firmwareUrl, currentAssetUrl, sizeof(firmwareUrl));
firmwareSize = currentAssetSize;
firmwareFound = true;
+7
View File
@@ -15,6 +15,11 @@ class ReleaseJsonParser {
void reset();
void feed(const char* data, size_t len);
// Release-asset filename to match (default "firmware.bin"). Boards with
// their own release binaries pass e.g. "firmware-papermono.bin". Survives
// reset(); truncated silently if longer than the internal buffer.
void setFirmwareAssetName(const char* name);
bool foundTag() const;
bool foundFirmware() const;
const char* getTagName() const;
@@ -65,4 +70,6 @@ class ReleaseJsonParser {
char currentAssetName[32];
char currentAssetUrl[512];
size_t currentAssetSize;
char firmwareAssetName[32];
};
+2
View File
@@ -143,6 +143,8 @@ void HalDisplay::writeGrayscalePlaneStrip(bool lsbPlane, const uint8_t* rows, ui
bool HalDisplay::supportsStripGrayscale() const { return einkDisplay.supportsStripGrayscale(); }
bool HalDisplay::combinesGrayscaleBase() const { return einkDisplay.combinesGrayscaleBase(); }
uint16_t HalDisplay::getDisplayWidth() const { return einkDisplay.getDisplayWidth(); }
uint16_t HalDisplay::getDisplayHeight() const { return einkDisplay.getDisplayHeight(); }
+7
View File
@@ -102,6 +102,13 @@ class HalDisplay {
void writeGrayscalePlaneStrip(bool lsbPlane, const uint8_t* rows, uint16_t yStart, uint16_t numRows);
bool supportsStripGrayscale() const;
// True when displayGrayscaleBase() defers the base activation so the gray
// planes join it in a single waveform (Paper Mono). Callers should then route
// the base of a grayscale page through displayGrayscaleBase() instead of
// displayBuffer(): a separate B/W refresh first makes the gray pass re-drive
// the whole text body (a visible flash).
bool combinesGrayscaleBase() const;
// Runtime geometry passthrough
uint16_t getDisplayWidth() const;
uint16_t getDisplayHeight() const;
+31
View File
@@ -0,0 +1,31 @@
#include "HalFrontlight.h"
#include <Logging.h>
HalFrontlight HalFrontlight::instance;
void HalFrontlight::begin(const uint8_t brightness, const uint8_t warmth, const bool on) {
if (!manager.present()) return;
manager.begin();
lastBrightness = brightness > 100 ? 100 : brightness;
manager.setColorTemperature(warmth > 100 ? 100 : warmth);
lit = on;
manager.setBrightness(lit ? lastBrightness : 0);
LOG_INF("LIGHT", "Frontlight up: %u%% warm=%u%% %s", lastBrightness, manager.colorTemperature(), lit ? "on" : "off");
}
void HalFrontlight::setBrightness(const uint8_t percent) {
lastBrightness = percent > 100 ? 100 : percent;
if (lit) manager.setBrightness(lastBrightness);
}
void HalFrontlight::setWarmth(const uint8_t warmPercent) {
manager.setColorTemperature(warmPercent > 100 ? 100 : warmPercent);
}
void HalFrontlight::setOn(const bool on) {
if (on == lit) return;
lit = on;
manager.setBrightness(lit ? lastBrightness : 0);
}
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include <FrontlightManager.h>
// Thin firmware HAL over the SDK frontlight manager. It is inert on boards
// without a frontlight, so callers do not need board-specific conditionals.
class HalFrontlight {
public:
static HalFrontlight& getInstance() { return instance; }
void begin(uint8_t brightness, uint8_t warmth, bool on);
bool present() const { return manager.present(); }
bool hasColorTemperature() const { return manager.hasColorTemperature(); }
void setBrightness(uint8_t percent);
void setWarmth(uint8_t warmPercent);
void setOn(bool on);
uint8_t brightness() const { return lastBrightness; }
uint8_t warmth() const { return manager.colorTemperature(); }
bool isOn() const { return lit; }
private:
HalFrontlight() = default;
FrontlightManager manager;
// The SDK represents off as brightness 0. Keep the selected brightness so
// toggling back on restores it.
uint8_t lastBrightness = 60;
bool lit = false;
static HalFrontlight instance;
};
#define Frontlight HalFrontlight::getInstance()
+10 -3
View File
@@ -199,6 +199,12 @@ unsigned long HalGPIO::getPowerButtonHeldTime() const { return inputMgr.getPower
bool HalGPIO::hasTouch() const { return inputMgr.hasTouch(); }
bool HalGPIO::hasHomeKey() const { return BoardConfig::hasHomeKey(); }
bool HalGPIO::wasHomeKeyTapped() const { return inputMgr.wasHomeKeyTapped(); }
bool HalGPIO::wasHomeKeyLongPressed() const { return inputMgr.wasHomeKeyLongPressed(); }
bool HalGPIO::wasTouchTap(float& nx, float& ny) const { return inputMgr.wasTouchTap(nx, ny); }
bool HalGPIO::wasTouchDown(float& nx, float& ny) const { return inputMgr.wasTouchPressedAt(nx, ny); }
@@ -229,6 +235,7 @@ void HalGPIO::setSharedConfirmPowerShortPressEmitsPower(const bool enabled) {
bool HalGPIO::hasEdgeSideButtons() const {
return BoardConfig::ACTIVE.board == BoardConfig::Board::XteinkX3 ||
BoardConfig::ACTIVE.board == BoardConfig::Board::XteinkX3Uc8279 ||
BoardConfig::ACTIVE.board == BoardConfig::Board::XteinkX4Pro;
}
@@ -239,9 +246,9 @@ bool HalGPIO::isXteinkDevice() const {
}
bool HalGPIO::verifyPowerButtonWakeup(uint16_t requiredDurationMs, bool shortPressAllowed) {
// Boards without a power button (or M5Paper's latch circuit) cannot verify a
// hold; treat the wake as valid.
if (BoardConfig::ACTIVE.input.power < 0) {
// X4 Pro wakes on any power-button press; other boards retain the configured
// hold-duration verification below.
if (BoardConfig::isX4Pro() || BoardConfig::ACTIVE.input.power < 0) {
return true;
}
#if defined(FREEINK_DEVICE_M5PAPER) && FREEINK_DEVICE_M5PAPER
+5
View File
@@ -113,6 +113,11 @@ class HalGPIO {
unsigned long getHeldTime() const;
unsigned long getPowerButtonHeldTime() const;
bool hasTouch() const;
// Capacitive Home key reported by the touch controller (X4 Pro). The tap
// event fires on release and excludes a long hold.
bool hasHomeKey() const;
bool wasHomeKeyTapped() const;
bool wasHomeKeyLongPressed() const;
bool wasTouchTap(float& nx, float& ny) const;
bool wasTouchDown(float& nx, float& ny) const;
// Raw release edge, reported even when the contact was not a tap (swipe end,
+20 -4
View File
@@ -10,8 +10,13 @@
#include <cassert>
#include "HalFrontlight.h"
#include "HalGPIO.h"
#if FREEINK_DEVICE_PAPERMONO
#include <M5Pm1.h>
#endif
HalPowerManager powerManager; // Singleton instance
// GPIO13 must stay high during light sleep on the C3 Xteink boards: it controls
@@ -101,6 +106,15 @@ void HalPowerManager::startDeepSleep(HalGPIO& gpio) const {
// guarantees that ordering).
freeink::PowerManager::powerDownRailsForSleep();
#if FREEINK_DEVICE_PAPERMONO
// Its power button is behind the M5PM1 PMIC rather than an ESP GPIO, so
// normal GPIO deep sleep would have no wake source. Ask the PMIC to shut the
// device down; a button click then restarts it through a cold boot.
if (freeink::m5pm1::requestShutdown()) {
delay(1000); // allow the PMIC firmware time to drop power
}
#endif
// Waits for the power button to be physically released (so holding it doesn't
// immediately wake the device again), then arms the wake source and sleeps.
freeink::PowerManager::deepSleepUntilPowerButton();
@@ -118,7 +132,9 @@ bool HalPowerManager::lightSleep(const HalGPIO& gpio) const {
return false;
}
// Light sleep drops a WiFi association and kills an enumerated USB-CDC link.
if (WiFi.getMode() != WIFI_MODE_NULL || gpio.isUsbConnectedCached()) {
// It also stops the default LEDC PWM output, visibly flashing ESP-driven
// frontlights as the idle loop enters repeated sleep slices.
if (WiFi.getMode() != WIFI_MODE_NULL || gpio.isUsbConnectedCached() || (Frontlight.present() && Frontlight.isOn())) {
return false;
}
@@ -181,9 +197,9 @@ bool HalPowerManager::lightSleep(const HalGPIO& gpio) const {
}
bool HalPowerManager::onEinkBusyWaitSlice(const int8_t busyPin, const uint8_t busyLevel) {
// Same exclusions as lightSleep(): light sleep drops a WiFi association and
// kills an enumerated USB-CDC link. No LOG here — this runs ~50x/s mid-refresh.
if (WiFi.getMode() != WIFI_MODE_NULL || gpio.isUsbConnectedCached()) {
// Same exclusions as lightSleep(): light sleep drops WiFi/USB and suspends
// frontlight PWM. No LOG here — this runs ~50x/s mid-refresh.
if (WiFi.getMode() != WIFI_MODE_NULL || gpio.isUsbConnectedCached() || (Frontlight.present() && Frontlight.isOn())) {
return false;
}
+39
View File
@@ -132,6 +132,7 @@ lib_deps =
BoardConfig=symlink://freeink-sdk/libs/hardware/BoardConfig
XteinkDetect=symlink://freeink-sdk/libs/hardware/XteinkDetect
PowerManager=symlink://freeink-sdk/libs/hardware/PowerManager
FrontlightManager=symlink://freeink-sdk/libs/hardware/FrontlightManager
Rtc=symlink://freeink-sdk/libs/hardware/Rtc
Imu=symlink://freeink-sdk/libs/hardware/Imu
SecureNet=symlink://freeink-sdk/libs/network/SecureNet
@@ -224,3 +225,41 @@ build_flags =
-DCROSSPOINT_VERSION=\"${crosspoint.version}-rc+${sysenv.CROSSPOINT_RC_HASH}\"
-DENABLE_SERIAL_LOG
-DLOG_LEVEL=1 ; Set log level to info for release candidate builds
; --- Xteink X4 Pro — ESP32-S3, 16MB flash / 8MB PSRAM, SSD1677 + GT911 --------
; Minimal X4 Pro target: the SDK profile supplies the board pinout, display,
; touch controller, and capacitive Home key.
; pio run -e x4pro -t upload
[env:x4pro]
extends = base
board = esp32-s3-devkitc1-n16r8
board_build.mcu = esp32s3
build_flags =
${base.build_flags}
-DFREEINK_DEVICE_X4PRO=1
-DBOARD_HAS_PSRAM
-DCROSSPOINT_VERSION=\"${crosspoint.version}-x4pro\"
-DENABLE_SERIAL_LOG
-DLOG_LEVEL=2
; X4 Pro SD is native SDMMC (1-bit), mounted through SdFat's block-device API.
-DUSE_BLOCK_DEVICE_INTERFACE=1
; --- M5Stack Paper Mono — ESP32-S3, SSD1683 800x480 + FT6336 touch + frontlight
; Power/reset plumbing runs through the M5PM1 PMIC and M5IOE1 expander; the SDK
; sequences them itself. Touch, frontlight, RTC, and other capabilities are
; selected by the Paper Mono BoardConfig profile.
; pio run -e papermono -t upload
[env:papermono]
extends = base
board = esp32-s3-devkitc1-n16r8
board_build.mcu = esp32s3
build_flags =
${base.build_flags}
-DFREEINK_DEVICE_PAPERMONO=1
; The SSD1683 grayscale target planes are batched in PSRAM.
-DBOARD_HAS_PSRAM
-DCROSSPOINT_VERSION=\"${crosspoint.version}-papermono\"
-DENABLE_SERIAL_LOG
-DLOG_LEVEL=2
; Native 1-bit SDMMC is mounted through SdFat's block-device interface.
-DUSE_BLOCK_DEVICE_INTERFACE=1
+28 -2
View File
@@ -130,7 +130,15 @@ class CrossPointSettings : public PersistableStore<CrossPointSettings> {
};
// Short power button press actions
enum SHORT_PWRBTN { IGNORE = 0, SLEEP = 1, PAGE_TURN = 2, FORCE_REFRESH = 3, FOOTNOTES = 4, SHORT_PWRBTN_COUNT };
enum SHORT_PWRBTN {
IGNORE = 0,
SLEEP = 1,
PAGE_TURN = 2,
FORCE_REFRESH = 3,
FOOTNOTES = 4,
PWR_CONFIRM = 5,
SHORT_PWRBTN_COUNT
};
// Long-press Confirm action while reading an EPUB. The setting cycles through these values.
// Persisted in settings.json by index: any new function (e.g. dictionary, bookmark) MUST use a
@@ -141,6 +149,7 @@ class CrossPointSettings : public PersistableStore<CrossPointSettings> {
LP_MENU_DISABLED = 1,
LP_MENU_BOOKMARK = 2,
LP_MENU_DICTIONARY = 3,
LP_MENU_READER_MENU = 4,
LONG_PRESS_MENU_FUNCTION_COUNT
};
@@ -163,7 +172,13 @@ class CrossPointSettings : public PersistableStore<CrossPointSettings> {
enum TILT_PAGE_TURN { TILT_OFF = 0, TILT_NORMAL = 1, TILT_NVERTED = 2, TILT_PAGE_TURN_COUNT };
enum TOUCH_READER_CONTROLS { TOUCH_READER_OFF = 0, TOUCH_READER_ON = 1, TOUCH_READER_CONTROLS_COUNT };
enum TOUCH_READER_CONTROLS {
TOUCH_READER_OFF = 0,
TOUCH_READER_ON = 1,
TOUCH_READER_SWIPE = 2,
TOUCH_READER_INVERTED_TAP = 3,
TOUCH_READER_CONTROLS_COUNT
};
enum QUICK_RESUME_SLEEP_SCREEN {
QUICK_RESUME_NEVER = 0,
@@ -279,6 +294,17 @@ class CrossPointSettings : public PersistableStore<CrossPointSettings> {
uint8_t tiltPageTurn = TILT_OFF;
// Touch screen reader zones/gestures on boards with a touch controller.
uint8_t touchReaderControls = TOUCH_READER_ON;
// Center-third tap opens the reader menu (0 = disabled, 1 = enabled). Only
// surfaced on home-key boards, where the menu stays reachable without it.
uint8_t tapForReaderMenu = 1;
// Frontlight quick-panel state. Category-less SettingsList entries persist
// these without adding them to the regular Settings screen.
uint8_t frontlightBrightness = 60;
uint8_t frontlightWarmth = 50; // 0 = cool .. 100 = warm
uint8_t frontlightOn = 0;
// Restore the saved on/off state after a normal boot or wake. Brightness and
// warmth are always remembered even when this is disabled.
uint8_t frontlightRestoreOnWake = 0;
// Language setting (Language enum index, default 0 = EN)
uint8_t language = 0;
// Quick Resume: keep current content visible with moon icon instead of showing a static sleep screen.
Loaded 20 of 53 files, more files were not shown because too many files have changed in this diff. Show more