From 57c389c0b69917659beeff5f153bb2aec206c7b3 Mon Sep 17 00:00:00 2001 From: Justin Mitchell Date: Fri, 19 Jun 2026 14:41:21 -0400 Subject: [PATCH] Add touch-down visual feedback to settings menus Handle touch-down events separately from tap events in settings activities to provide immediate visual feedback when menu items are touched, before the tap is completed. This improves UI responsiveness by updating the selected index on touch-down. --- .gitmodules | 2 +- freeink-sdk | 2 +- platformio.ini | 1 + src/MappedInputManager.cpp | 14 +++- src/MappedInputManager.h | 2 + .../browser/OpdsBookBrowserActivity.cpp | 38 +++++++-- .../browser/OpdsBookBrowserActivity.h | 1 + src/activities/home/CrashActivity.cpp | 4 +- .../reader/EpubReaderFootnotesActivity.cpp | 23 ++++++ .../EpubReaderPercentSelectionActivity.cpp | 43 +++++++++++ .../EpubReaderPercentSelectionActivity.h | 1 + src/activities/reader/QrDisplayActivity.cpp | 7 ++ .../XtcReaderChapterSelectionActivity.cpp | 20 ++++- .../settings/ClearCacheActivity.cpp | 25 +++++- src/activities/settings/ClockSyncActivity.cpp | 7 ++ .../settings/FontDownloadActivity.cpp | 77 +++++++++++-------- .../settings/FontDownloadActivity.h | 1 + .../settings/KOReaderAuthActivity.cpp | 4 +- .../settings/KOReaderSettingsActivity.cpp | 14 ++++ .../settings/OpdsSettingsActivity.cpp | 17 +++- src/activities/settings/OtaUpdateActivity.cpp | 24 +++++- .../settings/SdFirmwareUpdateActivity.cpp | 4 +- src/activities/util/BmpViewerActivity.cpp | 32 +++++++- .../util/IntervalSelectionActivity.cpp | 39 ++++++++++ .../util/IntervalSelectionActivity.h | 1 + 25 files changed, 351 insertions(+), 52 deletions(-) diff --git a/.gitmodules b/.gitmodules index 7c0ed75c..ceeb9c15 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "freeink-sdk"] path = freeink-sdk url = https://github.com/Free-Ink/freeink-sdk.git - branch = main + branch = sticky diff --git a/freeink-sdk b/freeink-sdk index e016d51e..5ea178c6 160000 --- a/freeink-sdk +++ b/freeink-sdk @@ -1 +1 @@ -Subproject commit e016d51e51ccb858dbbc8e25fca9894b4ed0913b +Subproject commit 5ea178c69b5df5fd5338514486c13d19b8e28ed4 diff --git a/platformio.ini b/platformio.ini index 34339a5e..ff8accda 100644 --- a/platformio.ini +++ b/platformio.ini @@ -68,6 +68,7 @@ lib_deps = PowerManager=symlink://freeink-sdk/libs/hardware/PowerManager Rtc=symlink://freeink-sdk/libs/hardware/Rtc Imu=symlink://freeink-sdk/libs/hardware/Imu + FreeInkUI=symlink://freeink-sdk/libs/ui/FreeInkUI Icons=symlink://freeink-sdk/libs/assets/Icons bblanchon/ArduinoJson @ 7.4.2 ricmoo/QRCode @ 0.0.1 diff --git a/src/MappedInputManager.cpp b/src/MappedInputManager.cpp index 5049a8aa..b8f76abd 100644 --- a/src/MappedInputManager.cpp +++ b/src/MappedInputManager.cpp @@ -1,5 +1,6 @@ #include "MappedInputManager.h" +#include #include #include @@ -162,18 +163,23 @@ bool MappedInputManager::wasCoverTapped(int& id) const { return TouchRegistry::getInstance().hitTest(lx, ly, TouchRegistry::Cover, id); } +bool MappedInputManager::wasScreenTapped(int& x, int& y) const { + float nx = 0.0f, ny = 0.0f; + if (!gpio.wasTouchTap(nx, ny)) return false; + renderer.tapToLogical(nx, ny, x, y); + return true; +} + bool MappedInputManager::wasListScroll(int& index, int count, int pageItems) const { if (count <= 0) return false; if (pageItems < 1) pageItems = 1; if (wasBottomEdgeSwipeUp()) return false; const SwipeDir swipe = wasSwipe(); if (swipe == SwipeDir::Up) { - index = std::min(index + pageItems, count - 1); - return true; + return freeink::ui::listPageIndex(index, +1, count, pageItems); } if (swipe == SwipeDir::Down) { - index = std::max(index - pageItems, 0); - return true; + return freeink::ui::listPageIndex(index, -1, count, pageItems); } return false; } diff --git a/src/MappedInputManager.h b/src/MappedInputManager.h index d623a371..d435efe0 100644 --- a/src/MappedInputManager.h +++ b/src/MappedInputManager.h @@ -39,6 +39,8 @@ class MappedInputManager { // (id = item index). Distinct kinds so a screen with both doesn't confuse them. bool wasTabTapped(int& id) const; bool wasCoverTapped(int& id) const; + // True on a touch release anywhere on screen, with logical/oriented coords. + bool wasScreenTapped(int& x, int& y) const; // Swipe direction in the current logical (oriented) frame, or None. A swipe also // raises the tap helpers above, so check this first and consume it. SwipeDir wasSwipe() const; diff --git a/src/activities/browser/OpdsBookBrowserActivity.cpp b/src/activities/browser/OpdsBookBrowserActivity.cpp index 6ff5b719..8333a4f2 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.cpp +++ b/src/activities/browser/OpdsBookBrowserActivity.cpp @@ -1,6 +1,7 @@ #include "OpdsBookBrowserActivity.h" #include +#include #include #include #include @@ -10,6 +11,7 @@ #include "SilentRestart.h" #include "activities/network/WifiSelectionActivity.h" #include "activities/util/KeyboardEntryActivity.h" +#include "components/TouchRegistry.h" #include "components/UITheme.h" #include "fontIds.h" #include "network/HttpDownloader.h" @@ -91,11 +93,28 @@ void OpdsBookBrowserActivity::loop() { if (state == BrowserState::DOWNLOADING) return; if (state == BrowserState::BROWSING) { - if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - if (!entries.empty()) { - const auto& entry = entries[selectorIndex]; - entry.type == OpdsEntryType::BOOK ? downloadBook(entry) : navigateToEntry(entry); + if (!entries.empty()) { + if (mappedInput.wasListScroll(selectorIndex, static_cast(entries.size()), PAGE_ITEMS)) { + requestUpdate(); + return; } + + int downId = -1; + if (mappedInput.wasItemTouchedDown(downId) && + freeink::ui::listSelectIndex(selectorIndex, downId, static_cast(entries.size()))) { + requestUpdate(); + } + + int tappedId = -1; + if (mappedInput.wasItemTapped(tappedId) && tappedId >= 0 && tappedId < static_cast(entries.size())) { + selectorIndex = tappedId; + activateSelectedEntry(); + return; + } + } + + if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { + activateSelectedEntry(); } else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { navigateBack(); } else if (mappedInput.wasReleased(MappedInputManager::Button::Left)) { @@ -178,13 +197,20 @@ void OpdsBookBrowserActivity::render(RenderLock&&) { std::string displayText = (entry.type == OpdsEntryType::NAVIGATION) ? "> " + entry.title : entry.title; if (entry.type == OpdsEntryType::BOOK && !entry.author.empty()) displayText += " - " + entry.author; auto item = renderer.truncatedText(UI_10_FONT_ID, displayText.c_str(), pageWidth - 40); - renderer.drawText(UI_10_FONT_ID, 20, 60 + (i % PAGE_ITEMS) * 30, item.c_str(), - i != static_cast(selectorIndex)); + const int itemY = 60 + (i % PAGE_ITEMS) * 30; + renderer.drawText(UI_10_FONT_ID, 20, itemY, item.c_str(), i != static_cast(selectorIndex)); + TouchRegistry::getInstance().add(Rect{0, itemY - 2, pageWidth, 30}, static_cast(i), TouchRegistry::Item); } } renderer.displayBuffer(); } +void OpdsBookBrowserActivity::activateSelectedEntry() { + if (entries.empty() || selectorIndex < 0 || selectorIndex >= static_cast(entries.size())) return; + const auto& entry = entries[selectorIndex]; + entry.type == OpdsEntryType::BOOK ? downloadBook(entry) : navigateToEntry(entry); +} + void OpdsBookBrowserActivity::fetchFeed(const std::string& path) { if (server.url.empty()) { state = BrowserState::ERROR; diff --git a/src/activities/browser/OpdsBookBrowserActivity.h b/src/activities/browser/OpdsBookBrowserActivity.h index 437ba58b..bf8642b0 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.h +++ b/src/activities/browser/OpdsBookBrowserActivity.h @@ -51,5 +51,6 @@ class OpdsBookBrowserActivity final : public Activity { void downloadBook(const OpdsEntry& book); void launchSearch(); void performSearch(const std::string& query); + void activateSelectedEntry(); bool preventAutoSleep() override { return true; } }; diff --git a/src/activities/home/CrashActivity.cpp b/src/activities/home/CrashActivity.cpp index 4f5a392b..6ef4b71d 100644 --- a/src/activities/home/CrashActivity.cpp +++ b/src/activities/home/CrashActivity.cpp @@ -20,7 +20,9 @@ void CrashActivity::onEnter() { } void CrashActivity::loop() { - if (mappedInput.isPressed(MappedInputManager::Button::Back)) { + int tapX = 0; + int tapY = 0; + if (mappedInput.isPressed(MappedInputManager::Button::Back) || mappedInput.wasScreenTapped(tapX, tapY)) { finish(); } } diff --git a/src/activities/reader/EpubReaderFootnotesActivity.cpp b/src/activities/reader/EpubReaderFootnotesActivity.cpp index 390dd3c5..a6d4ea59 100644 --- a/src/activities/reader/EpubReaderFootnotesActivity.cpp +++ b/src/activities/reader/EpubReaderFootnotesActivity.cpp @@ -1,11 +1,13 @@ #include "EpubReaderFootnotesActivity.h" +#include #include #include #include #include "MappedInputManager.h" +#include "components/TouchRegistry.h" #include "components/UITheme.h" #include "fontIds.h" @@ -18,6 +20,26 @@ void EpubReaderFootnotesActivity::onEnter() { void EpubReaderFootnotesActivity::onExit() { Activity::onExit(); } void EpubReaderFootnotesActivity::loop() { + const int visibleCount = std::max(1, renderer.getScreenHeight() / 36); + if (mappedInput.wasListScroll(selectedIndex, static_cast(footnotes.size()), visibleCount)) { + requestUpdate(); + return; + } + + int downId = -1; + if (mappedInput.wasItemTouchedDown(downId) && + freeink::ui::listSelectIndex(selectedIndex, downId, static_cast(footnotes.size()))) { + requestUpdate(); + } + + int tappedId = -1; + if (mappedInput.wasItemTapped(tappedId) && tappedId >= 0 && tappedId < static_cast(footnotes.size())) { + selectedIndex = tappedId; + setResult(FootnoteResult{footnotes[selectedIndex].href}); + finish(); + return; + } + if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { ActivityResult result; result.isCancelled = true; @@ -102,6 +124,7 @@ void EpubReaderFootnotesActivity::render(RenderLock&&) { label = tr(STR_LINK); } renderer.drawText(UI_10_FONT_ID, marginLeft, y + 4, label.c_str(), !isSelected); + TouchRegistry::getInstance().add(Rect{contentX, y, contentWidth, lineHeight}, i, TouchRegistry::Item); } const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), "", ""); diff --git a/src/activities/reader/EpubReaderPercentSelectionActivity.cpp b/src/activities/reader/EpubReaderPercentSelectionActivity.cpp index 78cb2683..0adc3c8e 100644 --- a/src/activities/reader/EpubReaderPercentSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderPercentSelectionActivity.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "MappedInputManager.h" #include "components/UITheme.h" #include "fontIds.h" @@ -32,6 +34,22 @@ void EpubReaderPercentSelectionActivity::adjustPercent(const int delta) { requestUpdate(); } +bool EpubReaderPercentSelectionActivity::setPercentFromTouch(const int x, const int y) { + auto& theme = UITheme::getInstance(); + const auto metrics = theme.getMetrics(); + const Rect screen = theme.getScreenSafeArea(renderer, true, false); + const int contentTop = screen.y + metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing * 4; + constexpr int barWidth = 360; + constexpr int barHeight = 16; + const int barX = screen.x + (screen.width - barWidth) / 2; + const int barY = contentTop + metrics.verticalSpacing * 2; + if (y < barY - 28 || y > barY + barHeight + 36 || x < barX - 20 || x > barX + barWidth + 20) return false; + + const int clampedX = std::max(barX, std::min(x, barX + barWidth)); + percent = (clampedX - barX) * 100 / barWidth; + return true; +} + void EpubReaderPercentSelectionActivity::loop() { // Back cancels, confirm selects, arrows adjust the percent. if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { @@ -48,6 +66,31 @@ void EpubReaderPercentSelectionActivity::loop() { return; } + switch (mappedInput.wasSwipe()) { + case MappedInputManager::SwipeDir::Left: + adjustPercent(-kSmallStep); + return; + case MappedInputManager::SwipeDir::Right: + adjustPercent(kSmallStep); + return; + case MappedInputManager::SwipeDir::Up: + adjustPercent(kLargeStep); + return; + case MappedInputManager::SwipeDir::Down: + adjustPercent(-kLargeStep); + return; + case MappedInputManager::SwipeDir::None: + break; + } + + int tapX = 0; + int tapY = 0; + if (mappedInput.wasScreenTapped(tapX, tapY) && setPercentFromTouch(tapX, tapY)) { + setResult(PercentResult{percent}); + finish(); + return; + } + buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Left}, [this] { adjustPercent(-kSmallStep); }); buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Right}, [this] { adjustPercent(kSmallStep); }); diff --git a/src/activities/reader/EpubReaderPercentSelectionActivity.h b/src/activities/reader/EpubReaderPercentSelectionActivity.h index 8cba8664..1bbd7707 100644 --- a/src/activities/reader/EpubReaderPercentSelectionActivity.h +++ b/src/activities/reader/EpubReaderPercentSelectionActivity.h @@ -24,4 +24,5 @@ class EpubReaderPercentSelectionActivity final : public Activity { // Change the current percent by a delta and clamp within bounds. void adjustPercent(int delta); + bool setPercentFromTouch(int x, int y); }; diff --git a/src/activities/reader/QrDisplayActivity.cpp b/src/activities/reader/QrDisplayActivity.cpp index 2bcf330a..6bef36cb 100644 --- a/src/activities/reader/QrDisplayActivity.cpp +++ b/src/activities/reader/QrDisplayActivity.cpp @@ -21,6 +21,13 @@ void QrDisplayActivity::loop() { finish(); return; } + + int tapX = 0; + int tapY = 0; + if (mappedInput.wasScreenTapped(tapX, tapY)) { + finish(); + return; + } } void QrDisplayActivity::render(RenderLock&&) { diff --git a/src/activities/reader/XtcReaderChapterSelectionActivity.cpp b/src/activities/reader/XtcReaderChapterSelectionActivity.cpp index b95ac2b1..06ed7d0b 100644 --- a/src/activities/reader/XtcReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/XtcReaderChapterSelectionActivity.cpp @@ -1,11 +1,13 @@ #include "XtcReaderChapterSelectionActivity.h" +#include #include #include #include #include "MappedInputManager.h" +#include "components/TouchRegistry.h" #include "components/UITheme.h" #include "fontIds.h" @@ -62,6 +64,20 @@ void XtcReaderChapterSelectionActivity::loop() { return; } + int downId = -1; + if (mappedInput.wasItemTouchedDown(downId) && freeink::ui::listSelectIndex(selectorIndex, downId, totalItems)) { + requestUpdate(); + } + + int tappedId = -1; + if (mappedInput.wasItemTapped(tappedId) && tappedId >= 0 && tappedId < totalItems) { + selectorIndex = tappedId; + const auto& chapters = xtc->getChapters(); + setResult(PageResult{chapters[selectorIndex].startPage}); + finish(); + return; + } + if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { const auto& chapters = xtc->getChapters(); if (!chapters.empty() && selectorIndex >= 0 && selectorIndex < static_cast(chapters.size())) { @@ -133,7 +149,9 @@ void XtcReaderChapterSelectionActivity::render(RenderLock&&) { for (int i = pageStartIndex; i < static_cast(chapters.size()) && i < pageStartIndex + pageItems; i++) { const auto& chapter = chapters[i]; const char* title = chapter.name.empty() ? tr(STR_UNNAMED) : chapter.name.c_str(); - renderer.drawText(UI_10_FONT_ID, contentX + 20, 60 + contentY + (i % pageItems) * 30, title, i != selectorIndex); + const int itemY = 60 + contentY + (i % pageItems) * 30; + renderer.drawText(UI_10_FONT_ID, contentX + 20, itemY, title, i != selectorIndex); + TouchRegistry::getInstance().add(Rect{contentX, itemY - 2, contentWidth, 30}, i, TouchRegistry::Item); } // Skip button hints in landscape CW mode (they overlap content) diff --git a/src/activities/settings/ClearCacheActivity.cpp b/src/activities/settings/ClearCacheActivity.cpp index b0dcbfbb..efa63c3a 100644 --- a/src/activities/settings/ClearCacheActivity.cpp +++ b/src/activities/settings/ClearCacheActivity.cpp @@ -122,6 +122,27 @@ void ClearCacheActivity::clearCache() { void ClearCacheActivity::loop() { if (state == WARNING) { + int tapX = 0; + int tapY = 0; + if (mappedInput.wasScreenTapped(tapX, tapY)) { + const int actionTop = renderer.getScreenHeight() - UITheme::getInstance().getMetrics().buttonHintsHeight - 12; + if (tapY >= actionTop) { + if (tapX < renderer.getScreenWidth() / 2) { + LOG_DBG("CLEAR_CACHE", "User cancelled via touch"); + goBack(); + } else { + LOG_DBG("CLEAR_CACHE", "User confirmed via touch, starting cache clear"); + { + RenderLock lock(*this); + state = CLEARING; + } + requestUpdateAndWait(); + clearCache(); + } + return; + } + } + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { LOG_DBG("CLEAR_CACHE", "User confirmed, starting cache clear"); { @@ -141,7 +162,9 @@ void ClearCacheActivity::loop() { } if (state == SUCCESS || state == FAILED) { - if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + int tapX = 0; + int tapY = 0; + if (mappedInput.wasPressed(MappedInputManager::Button::Back) || mappedInput.wasScreenTapped(tapX, tapY)) { goBack(); } return; diff --git a/src/activities/settings/ClockSyncActivity.cpp b/src/activities/settings/ClockSyncActivity.cpp index 407af69a..1f75192f 100644 --- a/src/activities/settings/ClockSyncActivity.cpp +++ b/src/activities/settings/ClockSyncActivity.cpp @@ -62,6 +62,13 @@ void ClockSyncActivity::loop() { if (mappedInput.wasPressed(MappedInputManager::Button::Back) || mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { finish(); + return; + } + + int tapX = 0; + int tapY = 0; + if (mappedInput.wasScreenTapped(tapX, tapY)) { + finish(); } } diff --git a/src/activities/settings/FontDownloadActivity.cpp b/src/activities/settings/FontDownloadActivity.cpp index cc381b4b..2bf24314 100644 --- a/src/activities/settings/FontDownloadActivity.cpp +++ b/src/activities/settings/FontDownloadActivity.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -420,6 +421,38 @@ bool FontDownloadActivity::isSelectedFamilyDeletable() const { return family.installed && !family.hasUpdate; } +void FontDownloadActivity::activateSelectedItem() { + if (families_.empty()) return; + + if (isDownloadAllRow(selectedIndex_)) { + currentFileIndex_ = 0; + currentFileTotal_ = 0; + for (const auto& f : families_) { + if (!f.installed) currentFileTotal_ += f.files.size(); + } + + downloadAll(); + } else if (isUpdateAllRow(selectedIndex_)) { + currentFileIndex_ = 0; + currentFileTotal_ = 0; + for (const auto& f : families_) { + if (f.hasUpdate) currentFileTotal_ += f.files.size(); + } + updateAll(); + } else { + auto& family = families_[familyIndexFromList(selectedIndex_)]; + if (!family.installed || family.hasUpdate) { + currentFileIndex_ = 0; + currentFileTotal_ = family.files.size(); + downloadFamily(family); + } else { + promptDeleteSelectedFamily(); + return; + } + } + requestUpdateAndWait(); +} + // --- Input handling --- void FontDownloadActivity::loop() { @@ -437,6 +470,18 @@ void FontDownloadActivity::loop() { return; } + int downId = -1; + if (mappedInput.wasItemTouchedDown(downId) && freeink::ui::listSelectIndex(selectedIndex_, downId, listSize)) { + requestUpdate(); + } + + int tappedId = -1; + if (mappedInput.wasItemTapped(tappedId) && tappedId >= 0 && tappedId < listSize) { + selectedIndex_ = tappedId; + activateSelectedItem(); + return; + } + buttonNavigator_.onNextRelease([this, listSize] { selectedIndex_ = ButtonNavigator::nextIndex(selectedIndex_, listSize); requestUpdate(); @@ -458,36 +503,8 @@ void FontDownloadActivity::loop() { }); if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { - if (!families_.empty()) { - if (isDownloadAllRow(selectedIndex_)) { - currentFileIndex_ = 0; - currentFileTotal_ = 0; - for (const auto& f : families_) { - if (!f.installed) currentFileTotal_ += f.files.size(); - } - - downloadAll(); - } else if (isUpdateAllRow(selectedIndex_)) { - currentFileIndex_ = 0; - currentFileTotal_ = 0; - for (const auto& f : families_) { - if (f.hasUpdate) currentFileTotal_ += f.files.size(); - } - updateAll(); - } else { - auto& family = families_[familyIndexFromList(selectedIndex_)]; - if (!family.installed || family.hasUpdate) { - currentFileIndex_ = 0; - currentFileTotal_ = family.files.size(); - downloadFamily(family); - } else { - promptDeleteSelectedFamily(); - return; - } - } - requestUpdateAndWait(); - return; - } + activateSelectedItem(); + return; } } else if (state_ == COMPLETE) { if (mappedInput.wasPressed(MappedInputManager::Button::Back) || diff --git a/src/activities/settings/FontDownloadActivity.h b/src/activities/settings/FontDownloadActivity.h index 7686b24b..38a45e13 100644 --- a/src/activities/settings/FontDownloadActivity.h +++ b/src/activities/settings/FontDownloadActivity.h @@ -99,6 +99,7 @@ class FontDownloadActivity : public Activity { bool isDownloadAllRow(int index) const; bool isUpdateAllRow(int index) const; bool isSelectedFamilyDeletable() const; + void activateSelectedItem(); void promptDeleteSelectedFamily(); void onDeleteConfirmationResult(const ActivityResult& result); int familyIndexFromList(int listIndex) const { return listIndex - specialRowCount(); } diff --git a/src/activities/settings/KOReaderAuthActivity.cpp b/src/activities/settings/KOReaderAuthActivity.cpp index 72921c16..e70dc7d9 100644 --- a/src/activities/settings/KOReaderAuthActivity.cpp +++ b/src/activities/settings/KOReaderAuthActivity.cpp @@ -101,8 +101,10 @@ void KOReaderAuthActivity::render(RenderLock&&) { void KOReaderAuthActivity::loop() { if (state == SUCCESS || state == FAILED) { + int tapX = 0; + int tapY = 0; if (mappedInput.wasPressed(MappedInputManager::Button::Back) || - mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + mappedInput.wasPressed(MappedInputManager::Button::Confirm) || mappedInput.wasScreenTapped(tapX, tapY)) { finish(); } } diff --git a/src/activities/settings/KOReaderSettingsActivity.cpp b/src/activities/settings/KOReaderSettingsActivity.cpp index 60edddcc..9aab7d08 100644 --- a/src/activities/settings/KOReaderSettingsActivity.cpp +++ b/src/activities/settings/KOReaderSettingsActivity.cpp @@ -11,6 +11,7 @@ #include "activities/util/KeyboardEntryActivity.h" #include "components/UITheme.h" #include "fontIds.h" +#include namespace { constexpr int MENU_ITEMS = 5; @@ -33,6 +34,19 @@ void KOReaderSettingsActivity::loop() { return; } + int downId = -1; + if (mappedInput.wasItemTouchedDown(downId) && freeink::ui::listSelectIndex(selectedIndex, downId, MENU_ITEMS)) { + requestUpdate(); + } + + int tappedId = -1; + if (mappedInput.wasItemTapped(tappedId) && tappedId >= 0 && tappedId < MENU_ITEMS) { + selectedIndex = tappedId; + handleSelection(); + requestUpdate(); + return; + } + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { handleSelection(); return; diff --git a/src/activities/settings/OpdsSettingsActivity.cpp b/src/activities/settings/OpdsSettingsActivity.cpp index ec07c1f9..a3a7f914 100644 --- a/src/activities/settings/OpdsSettingsActivity.cpp +++ b/src/activities/settings/OpdsSettingsActivity.cpp @@ -11,6 +11,7 @@ #include "activities/util/KeyboardEntryActivity.h" #include "components/UITheme.h" #include "fontIds.h" +#include namespace { // Editable fields: Name, URL, Username, Password. @@ -53,12 +54,26 @@ void OpdsSettingsActivity::loop() { return; } + const int menuItems = getMenuItemCount(); + + int downId = -1; + if (mappedInput.wasItemTouchedDown(downId) && freeink::ui::listSelectIndex(selectedIndex, downId, menuItems)) { + requestUpdate(); + } + + int tappedId = -1; + if (mappedInput.wasItemTapped(tappedId) && tappedId >= 0 && tappedId < menuItems) { + selectedIndex = tappedId; + handleSelection(); + requestUpdate(); + return; + } + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { handleSelection(); return; } - const int menuItems = getMenuItemCount(); buttonNavigator.onNext([this, menuItems] { selectedIndex = (selectedIndex + 1) % menuItems; requestUpdate(); diff --git a/src/activities/settings/OtaUpdateActivity.cpp b/src/activities/settings/OtaUpdateActivity.cpp index 905e1933..3f19dc88 100644 --- a/src/activities/settings/OtaUpdateActivity.cpp +++ b/src/activities/settings/OtaUpdateActivity.cpp @@ -145,7 +145,21 @@ void OtaUpdateActivity::render(RenderLock&&) { void OtaUpdateActivity::loop() { if (state == WAITING_CONFIRMATION) { - if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + int tapX = 0; + int tapY = 0; + bool touchUpdate = false; + if (mappedInput.wasScreenTapped(tapX, tapY)) { + const int actionTop = renderer.getScreenHeight() - UITheme::getInstance().getMetrics().buttonHintsHeight - 12; + if (tapY >= actionTop) { + if (tapX < renderer.getScreenWidth() / 2) { + finish(); + return; + } + touchUpdate = true; + } + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm) || touchUpdate) { LOG_DBG("OTA", "New update available, starting download..."); { RenderLock lock(*this); @@ -192,14 +206,18 @@ void OtaUpdateActivity::loop() { } if (state == FAILED) { - if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + int tapX = 0; + int tapY = 0; + if (mappedInput.wasPressed(MappedInputManager::Button::Back) || mappedInput.wasScreenTapped(tapX, tapY)) { finish(); } return; } if (state == NO_UPDATE) { - if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + int tapX = 0; + int tapY = 0; + if (mappedInput.wasPressed(MappedInputManager::Button::Back) || mappedInput.wasScreenTapped(tapX, tapY)) { finish(); } return; diff --git a/src/activities/settings/SdFirmwareUpdateActivity.cpp b/src/activities/settings/SdFirmwareUpdateActivity.cpp index b0ca1f63..f7dc54c7 100644 --- a/src/activities/settings/SdFirmwareUpdateActivity.cpp +++ b/src/activities/settings/SdFirmwareUpdateActivity.cpp @@ -186,8 +186,10 @@ void SdFirmwareUpdateActivity::performUpdate() { void SdFirmwareUpdateActivity::loop() { if (state == State::FAILED) { + int tapX = 0; + int tapY = 0; if (mappedInput.wasPressed(MappedInputManager::Button::Back) || - mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + mappedInput.wasPressed(MappedInputManager::Button::Confirm) || mappedInput.wasScreenTapped(tapX, tapY)) { if (recoveryMode) { // Go back to picker so user can try a different .bin state = State::PICKING; diff --git a/src/activities/util/BmpViewerActivity.cpp b/src/activities/util/BmpViewerActivity.cpp index def41015..f36d3425 100644 --- a/src/activities/util/BmpViewerActivity.cpp +++ b/src/activities/util/BmpViewerActivity.cpp @@ -185,6 +185,36 @@ void BmpViewerActivity::loop() { return; } + const auto swipe = mappedInput.wasSwipe(); + if (swipe == MappedInputManager::SwipeDir::Right) { + if (siblingImages.size() > 1 && currentImageIndex > 0) { + currentImageIndex--; + std::string dirPath = FsHelpers::extractFolderPath(filePath); + if (dirPath.back() != '/') dirPath += "/"; + filePath = dirPath + siblingImages[currentImageIndex]; + onEnter(); + } + return; + } + if (swipe == MappedInputManager::SwipeDir::Left) { + if (siblingImages.size() > 1 && currentImageIndex != -1 && + currentImageIndex < static_cast(siblingImages.size()) - 1) { + currentImageIndex++; + std::string dirPath = FsHelpers::extractFolderPath(filePath); + if (dirPath.back() != '/') dirPath += "/"; + filePath = dirPath + siblingImages[currentImageIndex]; + onEnter(); + } + return; + } + + int tapX = 0; + int tapY = 0; + if (mappedInput.wasScreenTapped(tapX, tapY)) { + doSetSleepCover(); + return; + } + if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { doSetSleepCover(); return; @@ -214,4 +244,4 @@ void BmpViewerActivity::loop() { } return; } -} \ No newline at end of file +} diff --git a/src/activities/util/IntervalSelectionActivity.cpp b/src/activities/util/IntervalSelectionActivity.cpp index 8323b7cb..ea4c3f5b 100644 --- a/src/activities/util/IntervalSelectionActivity.cpp +++ b/src/activities/util/IntervalSelectionActivity.cpp @@ -25,6 +25,20 @@ void IntervalSelectionActivity::adjustValue(const int delta) { requestUpdate(); } +bool IntervalSelectionActivity::setValueFromTouch(const int x, const int y) { + const int screenWidth = renderer.getScreenWidth(); + const int barWidth = std::min(360, std::max(0, screenWidth - 40)); + constexpr int barHeight = 16; + const int barX = std::max(0, (screenWidth - barWidth) / 2); + const int barY = 140; + if (y < barY - 28 || y > barY + barHeight + 36 || x < barX - 20 || x > barX + barWidth + 20) return false; + + const int clampedX = std::max(barX, std::min(x, barX + barWidth)); + const int range = std::max(1, maxValue - minValue); + value = clampedValue(minValue + (clampedX - barX) * range / std::max(1, barWidth)); + return true; +} + void IntervalSelectionActivity::loop() { if (ignoreConfirmRelease) { if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { @@ -50,6 +64,31 @@ void IntervalSelectionActivity::loop() { return; } + switch (mappedInput.wasSwipe()) { + case MappedInputManager::SwipeDir::Left: + adjustValue(-smallStep); + return; + case MappedInputManager::SwipeDir::Right: + adjustValue(smallStep); + return; + case MappedInputManager::SwipeDir::Up: + adjustValue(largeStep); + return; + case MappedInputManager::SwipeDir::Down: + adjustValue(-largeStep); + return; + case MappedInputManager::SwipeDir::None: + break; + } + + int tapX = 0; + int tapY = 0; + if (mappedInput.wasScreenTapped(tapX, tapY) && setValueFromTouch(tapX, tapY)) { + setResult(IntervalResult{static_cast(value)}); + finish(); + return; + } + buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Left}, [this] { adjustValue(-smallStep); }); buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Right}, [this] { adjustValue(smallStep); }); buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Up}, [this] { adjustValue(largeStep); }); diff --git a/src/activities/util/IntervalSelectionActivity.h b/src/activities/util/IntervalSelectionActivity.h index d20fc0c4..ee0fc108 100644 --- a/src/activities/util/IntervalSelectionActivity.h +++ b/src/activities/util/IntervalSelectionActivity.h @@ -49,4 +49,5 @@ class IntervalSelectionActivity final : public Activity { void adjustValue(int delta); int clampedValue(int candidate) const; + bool setValueFromTouch(int x, int y); };