diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 225d5102..e2fd673b 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -247,7 +247,9 @@ The Settings screen allows you to configure the device's behavior. There are a f - "Ignore" (default) - Require a long press to turn off the device - "Sleep" - A short press puts the device into sleep mode - "Page Turn" - A short press in reading mode turns to the next page; a long press turns the device off + - "Footnotes" - A short press in reading mode opens the footnotes submenu; if only one footnote is present on the page, the referenced page is opened directly. The short press on the power button can be used to select the footnote in the submenu, and to go back to the original page after finish reading the footnote (like the back button). - "Refresh" - A short press triggers a manual full-screen refresh, useful for clearing ghosting +- **Quick-return from footnotes**: Toggles on and off the quick return functionality from the footnotes. When the functionality it's active, a short press of the power button will act as the back button from the footnotes page. #### 3.6.4 System diff --git a/lib/I18n/translations/english.yaml b/lib/I18n/translations/english.yaml index 67021f31..2ad915ba 100644 --- a/lib/I18n/translations/english.yaml +++ b/lib/I18n/translations/english.yaml @@ -318,6 +318,7 @@ STR_BOOK_S_STYLE: "Book's Style" STR_EMBEDDED_STYLE: "Embedded Style" STR_FOCUS_READING: "Focus Reading" STR_OPDS_SERVER_URL: "OPDS Server URL" +STR_PWR_BTN_FOOTNOTE_BACK: "Quick-return from footnotes" STR_SET_SLEEP_COVER: "Set Cover" STR_FOOTNOTES: "Footnotes" STR_NO_FOOTNOTES: "No footnotes on this page" diff --git a/src/CrossPointSettings.h b/src/CrossPointSettings.h index 7df8c8ed..07413595 100644 --- a/src/CrossPointSettings.h +++ b/src/CrossPointSettings.h @@ -134,7 +134,7 @@ class CrossPointSettings { }; // Short power button press actions - enum SHORT_PWRBTN { IGNORE = 0, SLEEP = 1, PAGE_TURN = 2, FORCE_REFRESH = 3, SHORT_PWRBTN_COUNT }; + enum SHORT_PWRBTN { IGNORE = 0, SLEEP = 1, PAGE_TURN = 2, FORCE_REFRESH = 3, FOOTNOTES = 4, SHORT_PWRBTN_COUNT }; // Hide battery percentage enum HIDE_BATTERY_PERCENTAGE { HIDE_NEVER = 0, HIDE_READER = 1, HIDE_ALWAYS = 2, HIDE_BATTERY_PERCENTAGE_COUNT }; @@ -230,6 +230,8 @@ class CrossPointSettings { uint8_t uiTheme = LYRA; // Sunlight fading compensation uint8_t fadingFix = 0; + // Power button return from footnotes (1 = enabled, 0 = disabled) + uint8_t pwrBtnFootnoteBack = 1; // Use book's embedded CSS styles for EPUB rendering (1 = enabled, 0 = disabled) uint8_t embeddedStyle = 1; // Focus Reading - emphasizes the first part of words with bold diff --git a/src/SettingsList.h b/src/SettingsList.h index c7b223ea..acdba5bb 100644 --- a/src/SettingsList.h +++ b/src/SettingsList.h @@ -171,10 +171,12 @@ inline std::vector getSettingsList(const SdCardFontRegistry* regist {StrId::STR_LONG_PRESS_BEHAVIOR_OFF, StrId::STR_LONG_PRESS_BEHAVIOR_SKIP, StrId::STR_LONG_PRESS_BEHAVIOR_ORIENTATION}, "longPressButtonBehavior", StrId::STR_CAT_CONTROLS), - SettingInfo::Enum(StrId::STR_SHORT_PWR_BTN, &CrossPointSettings::shortPwrBtn, - {StrId::STR_IGNORE, StrId::STR_SLEEP, StrId::STR_PAGE_TURN, StrId::STR_FORCE_REFRESH}, - "shortPwrBtn", StrId::STR_CAT_CONTROLS), - + SettingInfo::Enum( + StrId::STR_SHORT_PWR_BTN, &CrossPointSettings::shortPwrBtn, + {StrId::STR_IGNORE, StrId::STR_SLEEP, StrId::STR_PAGE_TURN, StrId::STR_FORCE_REFRESH, StrId::STR_FOOTNOTES}, + "shortPwrBtn", StrId::STR_CAT_CONTROLS), + SettingInfo::Toggle(StrId::STR_PWR_BTN_FOOTNOTE_BACK, &CrossPointSettings::pwrBtnFootnoteBack, + "pwrBtnFootnoteBack", StrId::STR_CAT_CONTROLS), // --- System --- SettingInfo::Value( StrId::STR_TIME_TO_SLEEP, &CrossPointSettings::sleepTimeoutMinutes, diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index a5329290..08378ed3 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -312,6 +312,32 @@ void EpubReaderActivity::loop() { return; } + // auto [prevTriggered, nextTriggered] = ReaderUtils::detectPageTurn(mappedInput); + + // Handle short power button press for footnotes + if (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::FOOTNOTES && + mappedInput.wasReleased(MappedInputManager::Button::Power) && + !mappedInput.wasReleased(MappedInputManager::Button::Down)) { + if (footnoteDepth > 0) { + restoreSavedPosition(); + } else { + if (currentPageFootnotes.size() == 1) { + navigateToHref(currentPageFootnotes[0].href, true); + } else if (currentPageFootnotes.size() > 1) { + startActivityForResult( + std::make_unique(renderer, mappedInput, currentPageFootnotes), + [this](const ActivityResult& result) { + if (!result.isCancelled) { + const auto& footnoteResult = std::get(result.data); + navigateToHref(footnoteResult.href, true); + } + requestUpdate(); + }); + } + } + return; + } + const auto [prevTriggered, nextTriggered, fromTilt] = ReaderUtils::detectPageTurn(mappedInput); if (!prevTriggered && !nextTriggered) { return; diff --git a/src/activities/reader/EpubReaderFootnotesActivity.cpp b/src/activities/reader/EpubReaderFootnotesActivity.cpp index a50163ae..390dd3c5 100644 --- a/src/activities/reader/EpubReaderFootnotesActivity.cpp +++ b/src/activities/reader/EpubReaderFootnotesActivity.cpp @@ -26,7 +26,8 @@ void EpubReaderFootnotesActivity::loop() { return; } - if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { + if (mappedInput.wasReleased(MappedInputManager::Button::Confirm) || + mappedInput.wasReleased(MappedInputManager::Button::Power)) { if (selectedIndex >= 0 && selectedIndex < static_cast(footnotes.size())) { setResult(FootnoteResult{footnotes[selectedIndex].href}); finish(); diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 5e8b5773..8c0a7ef6 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -46,6 +46,10 @@ void SettingsActivity::rebuildSettingsLists() { } else if (setting.category == StrId::STR_CAT_READER) { readerSettings.push_back(setting); } else if (setting.category == StrId::STR_CAT_CONTROLS) { + if (setting.valuePtr == &CrossPointSettings::pwrBtnFootnoteBack && + SETTINGS.shortPwrBtn != CrossPointSettings::SHORT_PWRBTN::FOOTNOTES) { + continue; + } controlsSettings.push_back(setting); } else if (setting.category == StrId::STR_CAT_SYSTEM) { systemSettings.push_back(setting); @@ -271,6 +275,8 @@ void SettingsActivity::toggleCurrentSetting() { syncQuickResumeTimeoutForSleepScreen(sleepScreenChanged, quickResumeTimeoutChanged); SETTINGS.saveToFile(); + rebuildSettingsLists(); + selectedSettingIndex = std::min(selectedSettingIndex, settingsCount); } void SettingsActivity::syncQuickResumeTimeoutForSleepScreen(bool sleepScreenChanged, bool quickResumeTimeoutChanged) { diff --git a/src/network/html/SettingsPage.html b/src/network/html/SettingsPage.html index 4291a21b..8b3bee41 100644 --- a/src/network/html/SettingsPage.html +++ b/src/network/html/SettingsPage.html @@ -479,8 +479,23 @@ return changed; } + function updateSettingsVisibility() { + const shortPwrBtnVal = getControlValue('shortPwrBtn'); + const pwrBtnFootnoteBackRow = document.getElementById('row-setting-pwrBtnFootnoteBack'); + if (pwrBtnFootnoteBackRow) { + if (shortPwrBtnVal === 4) { + pwrBtnFootnoteBackRow.style.display = ''; + } else { + pwrBtnFootnoteBackRow.style.display = 'none'; + } + } + } + function handleSettingChanged(key) { syncQuickResumeTimeoutForSleepScreen(key === 'sleepScreen', key === 'quickResumeSleepScreen'); + if (key === 'shortPwrBtn') { + updateSettingsVisibility(); + } markChanged(); } @@ -511,7 +526,7 @@ for (const category in groups) { html += '

' + escapeHtml(category) + '

'; groups[category].forEach(function(s) { - html += '
' + + html += '
' + '' + escapeHtml(s.name) + '' + '' + renderControl(s) + '' + '
'; @@ -520,6 +535,7 @@ } container.innerHTML = html; + updateSettingsVisibility(); document.getElementById('save-container').style.display = ''; document.getElementById('saveBtn').disabled = true; preserveQuickResumeTimeoutOn = getControlValue('quickResumeSleepScreen') === 1;