Add skip notification and delay before action

This commit is contained in:
Yaroslav 2026-01-21 21:57:19 +03:00
parent eae951a286
commit e3b0c924c6
4 changed files with 91 additions and 4 deletions

View File

@ -186,11 +186,13 @@ void EpubReaderActivity::loop() {
if (skipChapter) {
// We don't want to delete the section mid-render, so grab the semaphore
xSemaphoreTake(renderingMutex, portMAX_DELAY);
nextPageNumber = 0;
currentSpineIndex = nextReleased ? currentSpineIndex + 1 : currentSpineIndex - 1;
section.reset();
// Show immediate feedback for long-press skip, then schedule delayed action (500ms)
showSkipPopup("Skipping");
delayedSkipPending = true;
delayedSkipDir = nextReleased ? +1 : -1;
delayedSkipExecuteAtMs = millis() + 500;
xSemaphoreGive(renderingMutex);
updateRequired = true;
// Do not perform the skip immediately; it will be executed in display loop after delay
return;
}
@ -229,11 +231,21 @@ void EpubReaderActivity::loop() {
void EpubReaderActivity::displayTaskLoop() {
while (true) {
const uint32_t now = millis();
if (updateRequired) {
updateRequired = false;
xSemaphoreTake(renderingMutex, portMAX_DELAY);
renderScreen();
xSemaphoreGive(renderingMutex);
} else if (delayedSkipPending && now >= delayedSkipExecuteAtMs) {
// Execute the delayed chapter skip now
xSemaphoreTake(renderingMutex, portMAX_DELAY);
nextPageNumber = 0;
currentSpineIndex += delayedSkipDir;
section.reset();
delayedSkipPending = false;
xSemaphoreGive(renderingMutex);
updateRequired = true;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
@ -385,6 +397,19 @@ void EpubReaderActivity::renderScreen() {
}
}
void EpubReaderActivity::showSkipPopup(const char* text) {
constexpr int boxMargin = 20;
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, text);
const int boxWidth = textWidth + boxMargin * 2;
const int boxHeight = renderer.getLineHeight(UI_12_FONT_ID) + boxMargin * 2;
const int boxX = (renderer.getScreenWidth() - boxWidth) / 2;
constexpr int boxY = 50;
renderer.fillRect(boxX, boxY, boxWidth, boxHeight, false);
renderer.drawText(UI_12_FONT_ID, boxX + boxMargin, boxY + boxMargin, text);
renderer.drawRect(boxX + 5, boxY + 5, boxWidth - 10, boxHeight - 10);
renderer.displayBuffer(EInkDisplay::FAST_REFRESH);
}
void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int orientedMarginTop,
const int orientedMarginRight, const int orientedMarginBottom,
const int orientedMarginLeft) {

View File

@ -16,6 +16,9 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
int nextPageNumber = 0;
int pagesUntilFullRefresh = 0;
bool updateRequired = false;
bool delayedSkipPending = false;
int delayedSkipDir = 0;
uint32_t delayedSkipExecuteAtMs = 0;
const std::function<void()> onGoBack;
const std::function<void()> onGoHome;
@ -25,6 +28,7 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
void renderContents(std::unique_ptr<Page> page, int orientedMarginTop, int orientedMarginRight,
int orientedMarginBottom, int orientedMarginLeft);
void renderStatusBar(int orientedMarginRight, int orientedMarginBottom, int orientedMarginLeft) const;
void showSkipPopup(const char* text);
public:
explicit EpubReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr<Epub> epub,

View File

@ -132,6 +132,16 @@ void XtcReaderActivity::loop() {
const int skipAmount = skipPages ? 10 : 1;
if (prevReleased) {
if (skipPages) {
xSemaphoreTake(renderingMutex, portMAX_DELAY);
showSkipPopup("Skipping");
delayedSkipPending = true;
delayedSkipDir = -1;
delayedSkipAmount = skipAmount;
delayedSkipExecuteAtMs = millis() + 500;
xSemaphoreGive(renderingMutex);
return;
}
if (currentPage >= static_cast<uint32_t>(skipAmount)) {
currentPage -= skipAmount;
} else {
@ -139,6 +149,16 @@ void XtcReaderActivity::loop() {
}
updateRequired = true;
} else if (nextReleased) {
if (skipPages) {
xSemaphoreTake(renderingMutex, portMAX_DELAY);
showSkipPopup("Skipping");
delayedSkipPending = true;
delayedSkipDir = +1;
delayedSkipAmount = skipAmount;
delayedSkipExecuteAtMs = millis() + 500;
xSemaphoreGive(renderingMutex);
return;
}
currentPage += skipAmount;
if (currentPage >= xtc->getPageCount()) {
currentPage = xtc->getPageCount(); // Allow showing "End of book"
@ -149,11 +169,29 @@ void XtcReaderActivity::loop() {
void XtcReaderActivity::displayTaskLoop() {
while (true) {
const uint32_t now = millis();
if (updateRequired) {
updateRequired = false;
xSemaphoreTake(renderingMutex, portMAX_DELAY);
renderScreen();
xSemaphoreGive(renderingMutex);
} else if (delayedSkipPending && now >= delayedSkipExecuteAtMs) {
xSemaphoreTake(renderingMutex, portMAX_DELAY);
if (delayedSkipDir < 0) {
if (currentPage >= delayedSkipAmount) {
currentPage -= delayedSkipAmount;
} else {
currentPage = 0;
}
} else {
currentPage += delayedSkipAmount;
if (currentPage >= xtc->getPageCount()) {
currentPage = xtc->getPageCount();
}
}
delayedSkipPending = false;
xSemaphoreGive(renderingMutex);
updateRequired = true;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
@ -177,6 +215,19 @@ void XtcReaderActivity::renderScreen() {
saveProgress();
}
void XtcReaderActivity::showSkipPopup(const char* text) {
constexpr int boxMargin = 20;
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, text);
const int boxWidth = textWidth + boxMargin * 2;
const int boxHeight = renderer.getLineHeight(UI_12_FONT_ID) + boxMargin * 2;
const int boxX = (renderer.getScreenWidth() - boxWidth) / 2;
constexpr int boxY = 50;
renderer.fillRect(boxX, boxY, boxWidth, boxHeight, false);
renderer.drawText(UI_12_FONT_ID, boxX + boxMargin, boxY + boxMargin, text);
renderer.drawRect(boxX + 5, boxY + 5, boxWidth - 10, boxHeight - 10);
renderer.displayBuffer(EInkDisplay::FAST_REFRESH);
}
void XtcReaderActivity::renderPage() {
const uint16_t pageWidth = xtc->getPageWidth();
const uint16_t pageHeight = xtc->getPageHeight();
@ -359,6 +410,8 @@ void XtcReaderActivity::renderPage() {
bitDepth);
}
// scheduleSkipMessage removed: delayed skip now handled via delayedSkip* fields
void XtcReaderActivity::saveProgress() const {
FsFile f;
if (SdMan.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) {

View File

@ -21,6 +21,10 @@ class XtcReaderActivity final : public ActivityWithSubactivity {
uint32_t currentPage = 0;
int pagesUntilFullRefresh = 0;
bool updateRequired = false;
bool delayedSkipPending = false;
int delayedSkipDir = 0;
uint32_t delayedSkipExecuteAtMs = 0;
uint32_t delayedSkipAmount = 0;
const std::function<void()> onGoBack;
const std::function<void()> onGoHome;
@ -30,6 +34,7 @@ class XtcReaderActivity final : public ActivityWithSubactivity {
void renderPage();
void saveProgress() const;
void loadProgress();
void showSkipPopup(const char* text);
public:
explicit XtcReaderActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::unique_ptr<Xtc> xtc,