Compare commits

...

19 Commits

Author SHA1 Message Date
Luke Stein
52cc90eec0
Merge 4436e44666 into e5c0ddc9fa 2026-02-01 08:32:50 -05:00
Uri Tauber
4436e44666 feat: Debugging monitor script (#555)
## Summary

* **What is the goal of this PR?**
Add a debugging script to help developers monitor the ESP32 serial port
directly from a PC.

* **What changes are included?**
Added a new script: scripts/debugging_monitor.py

## Additional Context

While working on a new Crosspoint-Reader feature, it quickly became
clear that watching the ESP32 serial output without any visual cues was
inconvenient and easy to mess up.

This script improves the debugging experience by reading data from the
serial port and providing:

1. A timestamp prefix for every log line (instead of milliseconds since
power-up)
2. Color-coded output for different message types
3. A secondary window displaying a live graph of RAM usage, which is
especially useful for tracking the memory impact of new features

<img width="1916" height="1049" alt="Screenshot_20260126_183811"
src="https://github.com/user-attachments/assets/6291887f-ac17-43ac-9e43-f5dec8a7097e"
/>

---

### AI Usage

Did you use AI tools to help write this code? _**< PARTIALLY >**_
I wrote the initial version of the script. Gemini was used to help add
the Matplotlib-based graphing and threading logic.
2026-02-01 08:32:47 -05:00
Arthur Tazhitdinov
4bb8a869e7 fix: truncating chapter titles using UTF-8 safe function (#599)
## Summary

* Truncating chapter titles using utf8 safe functions (Cyrillic titles
were split mid codepoint)
* refactoring of lib/Utf8

---

### AI Usage

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

Did you use AI tools to help write this code? _**< PARTIALLY >**_
2026-02-01 08:32:47 -05:00
Arthur Tazhitdinov
cc2f125809 fix: don't wake up after USB connect (#644)
## Summary

* fixes problem that if short power button press is enabled, connecting
device to usb leads to waking up
2026-02-01 08:32:47 -05:00
Dave Allie
6228a9f14c Revert "fix: don't wake up after USB connect" (#643)
Reverts crosspoint-reader/crosspoint-reader#576

Causing a boot loop on master
2026-02-01 08:32:47 -05:00
Gaspar Fabrega Ragni
81f4770618 fix: custom sleep not showing image at index 0 (#639)
## Summary

* Fixing custom sleep behaviour where the first image in the /sleep
directory is not shown
* image at index 0 is not being rendered when more than 1 image is
stored in /sleep directory, because `APP_STATE.lastSleepImage` is always
0.

## Additional Context

* `APP_STATE.lastSleepImage` is reset to 0 when a epub is open, this
value is only used to compare it to the randomly selected one in
`renderCustomSleepScreen()` that should always be a valid index, since
the list of valid bmp images is colected from scratch. -> no need to
reset it and block image @ index 0 from being rendered

---

### 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: Oyster <Oyster@home>
2026-02-01 08:32:47 -05:00
Thomas Foskolos
c79fcac3ad docs: Update USER_GUIDE.md (#625)
Add Greek as not supported language atm on the use guide
2026-02-01 08:32:47 -05:00
nscheung
1b11e91932 fix: Hide button hints in landscape CW mode (#637)
## Summary

* This change hides the button hints from overlapping chapter titles
when in landscape CW mode.

Before

![Before](https://github.com/user-attachments/assets/3015a9b3-3fa5-443b-a641-3e65841a6fbc)
After

![After](https://github.com/user-attachments/assets/011de15d-5ae6-429c-8f91-d8f37abe52d9)

## Additional Context

* I initially considered implementing an offset fix, but with potential
UI changes on the horizon, hiding the button hints appears to be the
simplest solution for now.

---

### AI Usage

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

Did you use AI tools to help write this code? < Partially >
2026-02-01 08:32:47 -05:00
Luke Stein
2add1e63c0 fix: WiFi error screen text clarifications (#612)
## Summary

* Clarify strings on Wifi connection error screens
* I have confirmed on device that these are short enough not to overflow
screen margins

## Additional Context

* Several screens give duplicative text (e.g., header "Connection
Failed" with contents text "Connection failed") or slightly confusing
text (header "Forget Network?" with text "Remove saved password?")

---

### AI Usage

Did you use AI tools to help write this code? **No**
2026-02-01 08:32:47 -05:00
Arthur Tazhitdinov
9870c662c7 fix: don't wake up after USB connect (#576)
## Summary

* fixes problem that if short power button press is enabled, connecting
device to usb leads to waking up
2026-02-01 08:32:47 -05:00
Arthur Tazhitdinov
28fdbe0938 feat(ui): change popup logic (#442)
## Summary

* refactors Indexing popups into ScreenComponents (they had different
implementations in different files)
* removes Indexing popup for small chapters
* only show Indexing popup (without progress bar) for large chapters
(using same minimum file size condition as for progress bar before)

## Additional Context

* Having to show even single popup message and redraw the screen slows
down the flow significantly
* Testing results:
    * Opening large chapter with progress bar - 11 seconds
* Same chapter without progress bar, only single Indexing popup - 5
seconds

---

### AI Usage

Did you use AI tools to help write this code? _**< PARTIALLY>**_
2026-02-01 08:32:47 -05:00
Jonas Diemer
1eeea5459d feat: Add reading menu and delete cache function (#433)
## Summary

* Adds a menu in the Epub reader
* The Chapter selection is moved there to pos 1 (so it can be reached by
double tapping the confirm button)
* A Go Home is there, too
* Most significantly, a function "Delete Book Cache" is added. This
returns to main (to avoid directly rebuilding cached items, eg. if this
is used to debug/develop other areas - and it's also easier ;))

Probably, the Sync function could now be moved from the Chapter
selection to this menu, too.

---

### AI Usage

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

Did you use AI tools to help write this code? _**PARTIALLY**_
2026-02-01 08:32:47 -05:00
Luke Stein
0b9a2c77d7 Fix progress bar vertical alignment 2026-01-31 22:58:56 -05:00
copilot-swe-agent[bot]
547d1e4963 Fix text overlap with chapter progress bar by adjusting textY position
Co-authored-by: lukestein <44452336+lukestein@users.noreply.github.com>
2026-01-31 21:36:08 +00:00
copilot-swe-agent[bot]
7667935aed Remove accidentally added llvm.sh script
Co-authored-by: lukestein <44452336+lukestein@users.noreply.github.com>
2026-01-31 21:01:00 +00:00
copilot-swe-agent[bot]
8658786db5 Run clang-format on modified files
Co-authored-by: lukestein <44452336+lukestein@users.noreply.github.com>
2026-01-31 21:00:49 +00:00
Luke Stein
533a8f2eb4 Rename progress bar height variable and make 6 pixels 2026-01-31 15:52:07 -05:00
copilot-swe-agent[bot]
4d437032fb Add Chapter Progress Bar status bar option
Co-authored-by: lukestein <44452336+lukestein@users.noreply.github.com>
2026-01-31 20:39:38 +00:00
copilot-swe-agent[bot]
b000b42963 Initial plan 2026-01-31 20:34:52 +00:00
6 changed files with 70 additions and 18 deletions

View File

@ -31,6 +31,7 @@ class CrossPointSettings {
FULL = 2,
FULL_WITH_PROGRESS_BAR = 3,
ONLY_PROGRESS_BAR = 4,
CHAPTER_PROGRESS_BAR = 5,
STATUS_BAR_MODE_COUNT
};

View File

@ -80,9 +80,20 @@ void ScreenComponents::drawBookProgressBar(const GfxRenderer& renderer, const si
&vieweableMarginLeft);
const int progressBarMaxWidth = renderer.getScreenWidth() - vieweableMarginLeft - vieweableMarginRight;
const int progressBarY = renderer.getScreenHeight() - vieweableMarginBottom - BOOK_PROGRESS_BAR_HEIGHT;
const int progressBarY = renderer.getScreenHeight() - vieweableMarginBottom - PROGRESS_BAR_HEIGHT;
const int barWidth = progressBarMaxWidth * bookProgress / 100;
renderer.fillRect(vieweableMarginLeft, progressBarY, barWidth, BOOK_PROGRESS_BAR_HEIGHT, true);
renderer.fillRect(vieweableMarginLeft, progressBarY, barWidth, PROGRESS_BAR_HEIGHT, true);
}
void ScreenComponents::drawChapterProgressBar(const GfxRenderer& renderer, const size_t chapterProgress) {
int vieweableMarginTop, vieweableMarginRight, vieweableMarginBottom, vieweableMarginLeft;
renderer.getOrientedViewableTRBL(&vieweableMarginTop, &vieweableMarginRight, &vieweableMarginBottom,
&vieweableMarginLeft);
const int progressBarMaxWidth = renderer.getScreenWidth() - vieweableMarginLeft - vieweableMarginRight;
const int progressBarY = renderer.getScreenHeight() - vieweableMarginBottom - PROGRESS_BAR_HEIGHT;
const int barWidth = progressBarMaxWidth * chapterProgress / 100;
renderer.fillRect(vieweableMarginLeft, progressBarY, barWidth, PROGRESS_BAR_HEIGHT, true);
}
int ScreenComponents::drawTabBar(const GfxRenderer& renderer, const int y, const std::vector<TabInfo>& tabs) {

View File

@ -13,7 +13,14 @@ struct TabInfo {
class ScreenComponents {
public:
static const int BOOK_PROGRESS_BAR_HEIGHT = 4;
static const int PROGRESS_BAR_HEIGHT = 6;
struct PopupLayout {
int x;
int y;
int width;
int height;
};
struct PopupLayout {
int x;
@ -24,6 +31,11 @@ class ScreenComponents {
static void drawBattery(const GfxRenderer& renderer, int left, int top, bool showPercentage = true);
static void drawBookProgressBar(const GfxRenderer& renderer, size_t bookProgress);
static void drawChapterProgressBar(const GfxRenderer& renderer, size_t chapterProgress);
static PopupLayout drawPopup(const GfxRenderer& renderer, const char* message);
static void fillPopupProgress(const GfxRenderer& renderer, const PopupLayout& layout, int progress);
static PopupLayout drawPopup(const GfxRenderer& renderer, const char* message);

View File

@ -351,9 +351,10 @@ void EpubReaderActivity::renderScreen() {
if (SETTINGS.statusBar != CrossPointSettings::STATUS_BAR_MODE::NONE) {
// Add additional margin for status bar if progress bar is shown
const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR;
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR;
orientedMarginBottom += statusBarMargin - SETTINGS.screenMargin +
(showProgressBar ? (ScreenComponents::BOOK_PROGRESS_BAR_HEIGHT + progressBarMarginTop) : 0);
(showProgressBar ? (ScreenComponents::PROGRESS_BAR_HEIGHT + progressBarMarginTop) : 0);
}
if (!section) {
@ -493,16 +494,20 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in
const int orientedMarginLeft) const {
// determine visible status bar elements
const bool showProgressPercentage = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL;
const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR;
const bool showBookProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR;
const bool showChapterProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR;
const bool showProgressText = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR;
const bool showBookPercentage = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR;
const bool showBattery = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR;
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR;
const bool showChapterTitle = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR;
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR;
const bool showBatteryPercentage =
SETTINGS.hideBatteryPercentage == CrossPointSettings::HIDE_BATTERY_PERCENTAGE::HIDE_NEVER;
@ -515,7 +520,7 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in
const float sectionChapterProg = static_cast<float>(section->currentPage) / section->pageCount;
const float bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg) * 100;
if (showProgressText || showProgressPercentage) {
if (showProgressText || showProgressPercentage || showBookPercentage) {
// Right aligned text for progress counter
char progressStr[32];
@ -523,6 +528,8 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in
if (showProgressPercentage) {
snprintf(progressStr, sizeof(progressStr), "%d/%d %.0f%%", section->currentPage + 1, section->pageCount,
bookProgress);
} else if (showBookPercentage) {
snprintf(progressStr, sizeof(progressStr), "%.0f%%", bookProgress);
} else {
snprintf(progressStr, sizeof(progressStr), "%d/%d", section->currentPage + 1, section->pageCount);
}
@ -532,11 +539,18 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in
progressStr);
}
if (showProgressBar) {
if (showBookProgressBar) {
// Draw progress bar at the very bottom of the screen, from edge to edge of viewable area
ScreenComponents::drawBookProgressBar(renderer, static_cast<size_t>(bookProgress));
}
if (showChapterProgressBar) {
// Draw chapter progress bar at the very bottom of the screen, from edge to edge of viewable area
const float chapterProgress =
(section->pageCount > 0) ? (static_cast<float>(section->currentPage + 1) / section->pageCount) * 100 : 0;
ScreenComponents::drawChapterProgressBar(renderer, static_cast<size_t>(chapterProgress));
}
if (showBattery) {
ScreenComponents::drawBattery(renderer, orientedMarginLeft + 1, textY, showBatteryPercentage);
}

View File

@ -172,9 +172,10 @@ void TxtReaderActivity::initializeReader() {
if (SETTINGS.statusBar != CrossPointSettings::STATUS_BAR_MODE::NONE) {
// Add additional margin for status bar if progress bar is shown
const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR;
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR;
orientedMarginBottom += statusBarMargin - cachedScreenMargin +
(showProgressBar ? (ScreenComponents::BOOK_PROGRESS_BAR_HEIGHT + progressBarMarginTop) : 0);
(showProgressBar ? (ScreenComponents::PROGRESS_BAR_HEIGHT + progressBarMarginTop) : 0);
}
viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight;
@ -487,27 +488,34 @@ void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int
const bool showProgressPercentage = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL;
const bool showProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::ONLY_PROGRESS_BAR;
const bool showChapterProgressBar = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR;
const bool showProgressText = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR;
const bool showBookPercentage = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR;
const bool showBattery = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR;
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR;
const bool showTitle = SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::NO_PROGRESS ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR;
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::FULL_WITH_PROGRESS_BAR ||
SETTINGS.statusBar == CrossPointSettings::STATUS_BAR_MODE::CHAPTER_PROGRESS_BAR;
const bool showBatteryPercentage =
SETTINGS.hideBatteryPercentage == CrossPointSettings::HIDE_BATTERY_PERCENTAGE::HIDE_NEVER;
const auto screenHeight = renderer.getScreenHeight();
// Adjust text position upward when progress bar is shown to avoid overlap
const auto textY = screenHeight - orientedMarginBottom - 4;
int progressTextWidth = 0;
const float progress = totalPages > 0 ? (currentPage + 1) * 100.0f / totalPages : 0;
if (showProgressText || showProgressPercentage) {
if (showProgressText || showProgressPercentage || showBookPercentage) {
char progressStr[32];
if (showProgressPercentage) {
snprintf(progressStr, sizeof(progressStr), "%d/%d %.0f%%", currentPage + 1, totalPages, progress);
} else if (showBookPercentage) {
snprintf(progressStr, sizeof(progressStr), "%.0f%%", progress);
} else {
snprintf(progressStr, sizeof(progressStr), "%d/%d", currentPage + 1, totalPages);
}
@ -522,6 +530,11 @@ void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int
ScreenComponents::drawBookProgressBar(renderer, static_cast<size_t>(progress));
}
if (showChapterProgressBar) {
// For text mode, treat the entire book as one chapter, so chapter progress == book progress
ScreenComponents::drawChapterProgressBar(renderer, static_cast<size_t>(progress));
}
if (showBattery) {
ScreenComponents::drawBattery(renderer, orientedMarginLeft, textY, showBatteryPercentage);
}

View File

@ -18,8 +18,9 @@ const SettingInfo displaySettings[displaySettingsCount] = {
SettingInfo::Enum("Sleep Screen Cover Mode", &CrossPointSettings::sleepScreenCoverMode, {"Fit", "Crop"}),
SettingInfo::Enum("Sleep Screen Cover Filter", &CrossPointSettings::sleepScreenCoverFilter,
{"None", "Contrast", "Inverted"}),
SettingInfo::Enum("Status Bar", &CrossPointSettings::statusBar,
{"None", "No Progress", "Full w/ Percentage", "Full w/ Progress Bar", "Progress Bar"}),
SettingInfo::Enum(
"Status Bar", &CrossPointSettings::statusBar,
{"None", "No Progress", "Full w/ Percentage", "Full w/ Progress Bar", "Progress Bar", "Chapter Progress Bar"}),
SettingInfo::Enum("Hide Battery %", &CrossPointSettings::hideBatteryPercentage, {"Never", "In Reader", "Always"}),
SettingInfo::Enum("Refresh Frequency", &CrossPointSettings::refreshFrequency,
{"1 page", "5 pages", "10 pages", "15 pages", "30 pages"})};