feat: add long-press Confirm for book management in file browser and recents
Long-pressing Confirm on a book file in MyLibraryActivity or RecentBooksActivity opens the BookManageMenuActivity popup with Archive/Delete/Delete Cache/Reindex options. Actions are executed via BookManager and the file list is refreshed afterward. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,9 +6,11 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "BookManageMenuActivity.h"
|
||||||
#include "MappedInputManager.h"
|
#include "MappedInputManager.h"
|
||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
#include "util/BookManager.h"
|
||||||
#include "util/StringUtils.h"
|
#include "util/StringUtils.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -133,7 +135,22 @@ void MyLibraryActivity::loop() {
|
|||||||
|
|
||||||
const int pageItems = UITheme::getInstance().getNumberOfItemsPerPage(renderer, true, false, true, false);
|
const int pageItems = UITheme::getInstance().getNumberOfItemsPerPage(renderer, true, false, true, false);
|
||||||
|
|
||||||
|
// Long-press Confirm: open manage menu for book files
|
||||||
|
if (mappedInput.isPressed(MappedInputManager::Button::Confirm) && mappedInput.getHeldTime() >= LONG_PRESS_MS &&
|
||||||
|
!ignoreNextConfirmRelease) {
|
||||||
|
if (!files.empty() && selectorIndex < files.size() && files[selectorIndex].back() != '/') {
|
||||||
|
ignoreNextConfirmRelease = true;
|
||||||
|
const std::string fullPath = (basepath.back() == '/' ? basepath : basepath + "/") + files[selectorIndex];
|
||||||
|
openManageMenu(fullPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
|
if (ignoreNextConfirmRelease) {
|
||||||
|
ignoreNextConfirmRelease = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (files.empty()) {
|
if (files.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -240,6 +257,51 @@ void MyLibraryActivity::render(Activity::RenderLock&&) {
|
|||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyLibraryActivity::openManageMenu(const std::string& bookPath) {
|
||||||
|
const bool isArchived = BookManager::isArchived(bookPath);
|
||||||
|
const std::string capturedPath = bookPath;
|
||||||
|
enterNewActivity(new BookManageMenuActivity(
|
||||||
|
renderer, mappedInput, capturedPath, isArchived,
|
||||||
|
[this, capturedPath](BookManageMenuActivity::Action action) {
|
||||||
|
exitActivity();
|
||||||
|
bool success = false;
|
||||||
|
switch (action) {
|
||||||
|
case BookManageMenuActivity::Action::ARCHIVE:
|
||||||
|
success = BookManager::archiveBook(capturedPath);
|
||||||
|
break;
|
||||||
|
case BookManageMenuActivity::Action::UNARCHIVE:
|
||||||
|
success = BookManager::unarchiveBook(capturedPath);
|
||||||
|
break;
|
||||||
|
case BookManageMenuActivity::Action::DELETE:
|
||||||
|
success = BookManager::deleteBook(capturedPath);
|
||||||
|
break;
|
||||||
|
case BookManageMenuActivity::Action::DELETE_CACHE:
|
||||||
|
success = BookManager::deleteBookCache(capturedPath);
|
||||||
|
break;
|
||||||
|
case BookManageMenuActivity::Action::REINDEX:
|
||||||
|
success = BookManager::reindexBook(capturedPath, false);
|
||||||
|
break;
|
||||||
|
case BookManageMenuActivity::Action::REINDEX_FULL:
|
||||||
|
success = BookManager::reindexBook(capturedPath, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RenderLock lock(*this);
|
||||||
|
GUI.drawPopup(renderer, success ? tr(STR_DONE) : tr(STR_ACTION_FAILED));
|
||||||
|
}
|
||||||
|
requestUpdateAndWait();
|
||||||
|
loadFiles();
|
||||||
|
if (selectorIndex >= files.size() && !files.empty()) {
|
||||||
|
selectorIndex = files.size() - 1;
|
||||||
|
}
|
||||||
|
requestUpdate();
|
||||||
|
},
|
||||||
|
[this] {
|
||||||
|
exitActivity();
|
||||||
|
requestUpdate();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
size_t MyLibraryActivity::findEntry(const std::string& name) const {
|
size_t MyLibraryActivity::findEntry(const std::string& name) const {
|
||||||
for (size_t i = 0; i < files.size(); i++)
|
for (size_t i = 0; i < files.size(); i++)
|
||||||
if (files[i] == name) return i;
|
if (files[i] == name) return i;
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ class MyLibraryActivity final : public ActivityWithSubactivity {
|
|||||||
std::string basepath = "/";
|
std::string basepath = "/";
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
|
|
||||||
|
// Long-press state
|
||||||
|
bool ignoreNextConfirmRelease = false;
|
||||||
|
static constexpr unsigned long LONG_PRESS_MS = 700;
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
const std::function<void(const std::string& path)> onSelectBook;
|
const std::function<void(const std::string& path)> onSelectBook;
|
||||||
const std::function<void()> onGoHome;
|
const std::function<void()> onGoHome;
|
||||||
@@ -25,6 +29,8 @@ class MyLibraryActivity final : public ActivityWithSubactivity {
|
|||||||
void loadFiles();
|
void loadFiles();
|
||||||
size_t findEntry(const std::string& name) const;
|
size_t findEntry(const std::string& name) const;
|
||||||
|
|
||||||
|
void openManageMenu(const std::string& bookPath);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MyLibraryActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
explicit MyLibraryActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||||
const std::function<void()>& onGoHome,
|
const std::function<void()>& onGoHome,
|
||||||
|
|||||||
@@ -6,10 +6,12 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "BookManageMenuActivity.h"
|
||||||
#include "MappedInputManager.h"
|
#include "MappedInputManager.h"
|
||||||
#include "RecentBooksStore.h"
|
#include "RecentBooksStore.h"
|
||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
#include "util/BookManager.h"
|
||||||
#include "util/StringUtils.h"
|
#include "util/StringUtils.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -53,7 +55,21 @@ void RecentBooksActivity::loop() {
|
|||||||
|
|
||||||
const int pageItems = UITheme::getInstance().getNumberOfItemsPerPage(renderer, true, false, true, true);
|
const int pageItems = UITheme::getInstance().getNumberOfItemsPerPage(renderer, true, false, true, true);
|
||||||
|
|
||||||
|
// Long-press Confirm: open manage menu
|
||||||
|
if (mappedInput.isPressed(MappedInputManager::Button::Confirm) && mappedInput.getHeldTime() >= LONG_PRESS_MS &&
|
||||||
|
!ignoreNextConfirmRelease) {
|
||||||
|
if (!recentBooks.empty() && selectorIndex < static_cast<int>(recentBooks.size())) {
|
||||||
|
ignoreNextConfirmRelease = true;
|
||||||
|
openManageMenu(recentBooks[selectorIndex].path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
|
if (ignoreNextConfirmRelease) {
|
||||||
|
ignoreNextConfirmRelease = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!recentBooks.empty() && selectorIndex < static_cast<int>(recentBooks.size())) {
|
if (!recentBooks.empty() && selectorIndex < static_cast<int>(recentBooks.size())) {
|
||||||
LOG_DBG("RBA", "Selected recent book: %s", recentBooks[selectorIndex].path.c_str());
|
LOG_DBG("RBA", "Selected recent book: %s", recentBooks[selectorIndex].path.c_str());
|
||||||
onSelectBook(recentBooks[selectorIndex].path);
|
onSelectBook(recentBooks[selectorIndex].path);
|
||||||
@@ -116,3 +132,48 @@ void RecentBooksActivity::render(Activity::RenderLock&&) {
|
|||||||
|
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecentBooksActivity::openManageMenu(const std::string& bookPath) {
|
||||||
|
const bool isArchived = BookManager::isArchived(bookPath);
|
||||||
|
const std::string capturedPath = bookPath;
|
||||||
|
enterNewActivity(new BookManageMenuActivity(
|
||||||
|
renderer, mappedInput, capturedPath, isArchived,
|
||||||
|
[this, capturedPath](BookManageMenuActivity::Action action) {
|
||||||
|
exitActivity();
|
||||||
|
bool success = false;
|
||||||
|
switch (action) {
|
||||||
|
case BookManageMenuActivity::Action::ARCHIVE:
|
||||||
|
success = BookManager::archiveBook(capturedPath);
|
||||||
|
break;
|
||||||
|
case BookManageMenuActivity::Action::UNARCHIVE:
|
||||||
|
success = BookManager::unarchiveBook(capturedPath);
|
||||||
|
break;
|
||||||
|
case BookManageMenuActivity::Action::DELETE:
|
||||||
|
success = BookManager::deleteBook(capturedPath);
|
||||||
|
break;
|
||||||
|
case BookManageMenuActivity::Action::DELETE_CACHE:
|
||||||
|
success = BookManager::deleteBookCache(capturedPath);
|
||||||
|
break;
|
||||||
|
case BookManageMenuActivity::Action::REINDEX:
|
||||||
|
success = BookManager::reindexBook(capturedPath, false);
|
||||||
|
break;
|
||||||
|
case BookManageMenuActivity::Action::REINDEX_FULL:
|
||||||
|
success = BookManager::reindexBook(capturedPath, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RenderLock lock(*this);
|
||||||
|
GUI.drawPopup(renderer, success ? tr(STR_DONE) : tr(STR_ACTION_FAILED));
|
||||||
|
}
|
||||||
|
requestUpdateAndWait();
|
||||||
|
loadRecentBooks();
|
||||||
|
if (selectorIndex >= static_cast<int>(recentBooks.size()) && !recentBooks.empty()) {
|
||||||
|
selectorIndex = recentBooks.size() - 1;
|
||||||
|
}
|
||||||
|
requestUpdate();
|
||||||
|
},
|
||||||
|
[this] {
|
||||||
|
exitActivity();
|
||||||
|
requestUpdate();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,12 +18,17 @@ class RecentBooksActivity final : public ActivityWithSubactivity {
|
|||||||
// Recent tab state
|
// Recent tab state
|
||||||
std::vector<RecentBook> recentBooks;
|
std::vector<RecentBook> recentBooks;
|
||||||
|
|
||||||
|
// Long-press state
|
||||||
|
bool ignoreNextConfirmRelease = false;
|
||||||
|
static constexpr unsigned long LONG_PRESS_MS = 700;
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
const std::function<void(const std::string& path)> onSelectBook;
|
const std::function<void(const std::string& path)> onSelectBook;
|
||||||
const std::function<void()> onGoHome;
|
const std::function<void()> onGoHome;
|
||||||
|
|
||||||
// Data loading
|
// Data loading
|
||||||
void loadRecentBooks();
|
void loadRecentBooks();
|
||||||
|
void openManageMenu(const std::string& bookPath);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit RecentBooksActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
explicit RecentBooksActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||||
|
|||||||
Reference in New Issue
Block a user