Detect long-press and skip chapter immediately

This commit is contained in:
Yaroslav 2026-01-21 23:33:26 +03:00
parent 4824247137
commit de92710627
4 changed files with 66 additions and 40 deletions

View File

@ -162,6 +162,28 @@ void EpubReaderActivity::loop() {
return;
}
// Detect long-press and schedule skip immediately
const bool prevPressed = mappedInput.isPressed(MappedInputManager::Button::PageBack) ||
mappedInput.isPressed(MappedInputManager::Button::Left);
const bool nextPressed = mappedInput.isPressed(MappedInputManager::Button::PageForward) ||
(SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::PAGE_TURN &&
mappedInput.isPressed(MappedInputManager::Button::Power)) ||
mappedInput.isPressed(MappedInputManager::Button::Right);
if (SETTINGS.longPressChapterSkip && (prevPressed || nextPressed) &&
mappedInput.getHeldTime() >= SETTINGS.getLongPressDurationMs() && !delayedSkipPending &&
!awaitingReleaseAfterSkip) {
xSemaphoreTake(renderingMutex, portMAX_DELAY);
showSkipPopup("Skipping");
delayedSkipPending = true;
delayedSkipDir = nextPressed ? +1 : -1;
delayedSkipExecuteAtMs = millis() + 500;
xSemaphoreGive(renderingMutex);
// Block release-based page change until unpressed
awaitingReleaseAfterSkip = true;
return;
}
const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::PageBack) ||
mappedInput.wasReleased(MappedInputManager::Button::Left);
const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) ||
@ -173,6 +195,12 @@ void EpubReaderActivity::loop() {
return;
}
if (awaitingReleaseAfterSkip) {
awaitingReleaseAfterSkip = false;
skipUnpressed = true;
return;
}
// any botton press when at end of the book goes back to the last page
if (currentSpineIndex > 0 && currentSpineIndex >= epub->getSpineItemsCount()) {
currentSpineIndex = epub->getSpineItemsCount() - 1;
@ -181,20 +209,6 @@ void EpubReaderActivity::loop() {
return;
}
const bool skipChapter = SETTINGS.longPressChapterSkip && mappedInput.getHeldTime() > SETTINGS.getLongPressDurationMs();
if (skipChapter) {
// We don't want to delete the section mid-render, so grab the semaphore
xSemaphoreTake(renderingMutex, portMAX_DELAY);
// 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);
// Do not perform the skip immediately; it will be executed in display loop after delay
return;
}
// No current section, attempt to rerender the book
if (!section) {

View File

@ -19,6 +19,8 @@ class EpubReaderActivity final : public ActivityWithSubactivity {
bool delayedSkipPending = false;
int delayedSkipDir = 0;
uint32_t delayedSkipExecuteAtMs = 0;
bool awaitingReleaseAfterSkip = false;
bool skipUnpressed = false;
const std::function<void()> onGoBack;
const std::function<void()> onGoHome;

View File

@ -110,6 +110,29 @@ void XtcReaderActivity::loop() {
return;
}
// Detect long-press and schedule skip immediately
const bool prevPressed = mappedInput.isPressed(MappedInputManager::Button::PageBack) ||
mappedInput.isPressed(MappedInputManager::Button::Left);
const bool nextPressed = mappedInput.isPressed(MappedInputManager::Button::PageForward) ||
(SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::PAGE_TURN &&
mappedInput.isPressed(MappedInputManager::Button::Power)) ||
mappedInput.isPressed(MappedInputManager::Button::Right);
if (SETTINGS.longPressChapterSkip && (prevPressed || nextPressed) &&
mappedInput.getHeldTime() >= SETTINGS.getLongPressDurationMs() && !delayedSkipPending &&
!awaitingReleaseAfterSkip) {
xSemaphoreTake(renderingMutex, portMAX_DELAY);
showSkipPopup("Skipping");
delayedSkipPending = true;
delayedSkipDir = nextPressed ? +1 : -1;
delayedSkipAmount = 10; // long-press skip amount
delayedSkipExecuteAtMs = millis() + 500;
xSemaphoreGive(renderingMutex);
// Block release-based page change until unpressed
awaitingReleaseAfterSkip = true;
return;
}
const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::PageBack) ||
mappedInput.wasReleased(MappedInputManager::Button::Left);
const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::PageForward) ||
@ -121,6 +144,12 @@ void XtcReaderActivity::loop() {
return;
}
if (awaitingReleaseAfterSkip) {
awaitingReleaseAfterSkip = false;
skipUnpressed = true;
return;
}
// Handle end of book
if (currentPage >= xtc->getPageCount()) {
currentPage = xtc->getPageCount() - 1;
@ -128,38 +157,17 @@ void XtcReaderActivity::loop() {
return;
}
const bool skipPages = SETTINGS.longPressChapterSkip && mappedInput.getHeldTime() > SETTINGS.getLongPressDurationMs();
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;
// Short press: single page back
if (currentPage >= 1) {
currentPage -= 1;
} else {
currentPage = 0;
}
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;
// Short press: single page forward
currentPage += 1;
if (currentPage >= xtc->getPageCount()) {
currentPage = xtc->getPageCount(); // Allow showing "End of book"
}

View File

@ -25,6 +25,8 @@ class XtcReaderActivity final : public ActivityWithSubactivity {
int delayedSkipDir = 0;
uint32_t delayedSkipExecuteAtMs = 0;
uint32_t delayedSkipAmount = 0;
bool awaitingReleaseAfterSkip = false;
bool skipUnpressed = false;
const std::function<void()> onGoBack;
const std::function<void()> onGoHome;