#include "RecentBooksActivity.h" #include #include #include #include #include "../util/ConfirmationActivity.h" #include "BookManageMenuActivity.h" #include "MappedInputManager.h" #include "RecentBooksStore.h" #include "activities/ActivityResult.h" #include "components/UITheme.h" #include "fontIds.h" #include "util/BookManager.h" namespace { constexpr unsigned long GO_HOME_MS = 1000; } // namespace void RecentBooksActivity::loadRecentBooks() { recentBooks.clear(); const auto& books = RECENT_BOOKS.getBooks(); recentBooks.reserve(books.size()); for (const auto& book : books) { // Skip if file no longer exists if (!Storage.exists(book.path.c_str())) { continue; } recentBooks.push_back(book); } } void RecentBooksActivity::onEnter() { Activity::onEnter(); // Load data loadRecentBooks(); selectorIndex = 0; requestUpdate(); } void RecentBooksActivity::onExit() { Activity::onExit(); recentBooks.clear(); } void RecentBooksActivity::executeManageAction(BookManageMenuActivity::Action action, const std::string& capturedPath) { 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)); } loadRecentBooks(); selectorIndex = 0; requestUpdate(); } void RecentBooksActivity::openManageMenu(const std::string& bookPath) { const bool isArchived = BookManager::isArchived(bookPath); const std::string capturedPath = bookPath; startActivityForResult( std::make_unique(renderer, mappedInput, capturedPath, isArchived, false), [this, capturedPath](const ActivityResult& result) { if (result.isCancelled) { requestUpdate(); return; } const auto& menuResult = std::get(result.data); auto action = static_cast(menuResult.action); if (action == BookManageMenuActivity::Action::DELETE || action == BookManageMenuActivity::Action::ARCHIVE) { const char* promptKey = (action == BookManageMenuActivity::Action::DELETE) ? tr(STR_DELETE_BOOK) : tr(STR_ARCHIVE_BOOK); std::string heading = std::string(promptKey) + "?"; std::string fileName = capturedPath; const auto slash = capturedPath.rfind('/'); if (slash != std::string::npos) fileName = capturedPath.substr(slash + 1); startActivityForResult(std::make_unique(renderer, mappedInput, heading, fileName), [this, action, capturedPath](const ActivityResult& confirmResult) { if (!confirmResult.isCancelled) { executeManageAction(action, capturedPath); } else { requestUpdate(); } }); } else { executeManageAction(action, capturedPath); } }); } void RecentBooksActivity::loop() { const int pageItems = UITheme::getInstance().getNumberOfItemsPerPage(renderer, true, false, true, true); if (mappedInput.isPressed(MappedInputManager::Button::Confirm) && mappedInput.getHeldTime() >= LONG_PRESS_MS) { if (!recentBooks.empty() && selectorIndex < static_cast(recentBooks.size())) { ignoreNextConfirmRelease = true; openManageMenu(recentBooks[selectorIndex].path); return; } } if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { if (ignoreNextConfirmRelease) { ignoreNextConfirmRelease = false; } else if (!recentBooks.empty() && selectorIndex < static_cast(recentBooks.size())) { LOG_DBG("RBA", "Selected recent book: %s", recentBooks[selectorIndex].path.c_str()); onSelectBook(recentBooks[selectorIndex].path); return; } } if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { onGoHome(); } int listSize = static_cast(recentBooks.size()); buttonNavigator.onNextRelease([this, listSize] { selectorIndex = ButtonNavigator::nextIndex(static_cast(selectorIndex), listSize); requestUpdate(); }); buttonNavigator.onPreviousRelease([this, listSize] { selectorIndex = ButtonNavigator::previousIndex(static_cast(selectorIndex), listSize); requestUpdate(); }); buttonNavigator.onNextContinuous([this, listSize, pageItems] { selectorIndex = ButtonNavigator::nextPageIndex(static_cast(selectorIndex), listSize, pageItems); requestUpdate(); }); buttonNavigator.onPreviousContinuous([this, listSize, pageItems] { selectorIndex = ButtonNavigator::previousPageIndex(static_cast(selectorIndex), listSize, pageItems); requestUpdate(); }); } void RecentBooksActivity::render(RenderLock&&) { renderer.clearScreen(); const auto pageWidth = renderer.getScreenWidth(); const auto pageHeight = renderer.getScreenHeight(); const auto& metrics = UITheme::getInstance().getMetrics(); GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_MENU_RECENT_BOOKS)); const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing; const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing; // Recent tab if (recentBooks.empty()) { renderer.drawText(UI_10_FONT_ID, metrics.contentSidePadding, contentTop + 20, tr(STR_NO_RECENT_BOOKS)); } else { GUI.drawList( renderer, Rect{0, contentTop, pageWidth, contentHeight}, recentBooks.size(), selectorIndex, [this](int index) { return recentBooks[index].title; }, [this](int index) { const auto& book = recentBooks[index]; if (!book.series.empty() && !book.author.empty()) { return book.author + " \xE2\x80\xA2 " + book.series; } if (!book.series.empty()) return book.series; return book.author; }, [this](int index) { return UITheme::getFileIcon(recentBooks[index].path); }); } // Help text const auto labels = mappedInput.mapLabels(tr(STR_HOME), tr(STR_OPEN), tr(STR_DIR_UP), tr(STR_DIR_DOWN)); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); renderer.displayBuffer(); }