diff --git a/src/activities/home/BookManageMenuActivity.cpp b/src/activities/home/BookManageMenuActivity.cpp new file mode 100644 index 00000000..adf988bc --- /dev/null +++ b/src/activities/home/BookManageMenuActivity.cpp @@ -0,0 +1,115 @@ +#include "BookManageMenuActivity.h" + +#include +#include + +#include "MappedInputManager.h" +#include "components/UITheme.h" +#include "fontIds.h" + +void BookManageMenuActivity::buildMenuItems() { + menuItems.clear(); + if (archived) { + menuItems.push_back({Action::UNARCHIVE, StrId::STR_UNARCHIVE_BOOK}); + } else { + menuItems.push_back({Action::ARCHIVE, StrId::STR_ARCHIVE_BOOK}); + } + menuItems.push_back({Action::DELETE, StrId::STR_DELETE_BOOK}); + menuItems.push_back({Action::DELETE_CACHE, StrId::STR_DELETE_CACHE_ONLY}); + menuItems.push_back({Action::REINDEX, StrId::STR_REINDEX_BOOK}); +} + +void BookManageMenuActivity::onEnter() { + Activity::onEnter(); + selectedIndex = 0; + requestUpdate(); +} + +void BookManageMenuActivity::onExit() { Activity::onExit(); } + +void BookManageMenuActivity::loop() { + // Long-press detection: REINDEX_FULL when long-pressing on the Reindex item + if (mappedInput.isPressed(MappedInputManager::Button::Confirm) && mappedInput.getHeldTime() >= LONG_PRESS_MS) { + if (!ignoreNextConfirmRelease && selectedIndex < static_cast(menuItems.size()) && + menuItems[selectedIndex].action == Action::REINDEX) { + ignoreNextConfirmRelease = true; + auto cb = onAction; + cb(Action::REINDEX_FULL); + return; + } + } + + buttonNavigator.onNext([this] { + selectedIndex = ButtonNavigator::nextIndex(selectedIndex, static_cast(menuItems.size())); + requestUpdate(); + }); + + buttonNavigator.onPrevious([this] { + selectedIndex = ButtonNavigator::previousIndex(selectedIndex, static_cast(menuItems.size())); + requestUpdate(); + }); + + if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { + if (ignoreNextConfirmRelease) { + ignoreNextConfirmRelease = false; + return; + } + if (selectedIndex < static_cast(menuItems.size())) { + auto cb = onAction; + cb(menuItems[selectedIndex].action); + return; + } + } + + if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { + auto cb = onCancel; + cb(); + return; + } +} + +void BookManageMenuActivity::render(Activity::RenderLock&&) { + renderer.clearScreen(); + + const auto pageWidth = renderer.getScreenWidth(); + const auto pageHeight = renderer.getScreenHeight(); + + constexpr int popupMargin = 20; + constexpr int lineHeight = 30; + constexpr int titleHeight = 40; + const int optionCount = static_cast(menuItems.size()); + const int popupH = titleHeight + popupMargin + lineHeight * optionCount + popupMargin; + const int popupW = pageWidth - 60; + const int popupX = (pageWidth - popupW) / 2; + const int popupY = (pageHeight - popupH) / 2; + + // Popup border and background + renderer.fillRect(popupX - 2, popupY - 2, popupW + 4, popupH + 4, true); + renderer.fillRect(popupX, popupY, popupW, popupH, false); + + // Title + renderer.drawText(UI_12_FONT_ID, popupX + popupMargin, popupY + 8, tr(STR_MANAGE_BOOK), true, EpdFontFamily::BOLD); + + // Divider line + const int dividerY = popupY + titleHeight; + renderer.fillRect(popupX + 4, dividerY, popupW - 8, 1, true); + + // Menu items + const int startY = dividerY + popupMargin / 2; + for (int i = 0; i < optionCount; ++i) { + const int itemY = startY + i * lineHeight; + const bool isSelected = (i == selectedIndex); + + if (isSelected) { + renderer.fillRect(popupX + 2, itemY, popupW - 4, lineHeight, true); + } + + renderer.drawText(UI_10_FONT_ID, popupX + popupMargin, itemY, I18N.get(menuItems[i].labelId), !isSelected); + } + + // Button hints + const auto labels = mappedInput.mapLabels(tr(STR_CANCEL), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN)); + GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + + renderer.displayBuffer(); +} diff --git a/src/activities/home/BookManageMenuActivity.h b/src/activities/home/BookManageMenuActivity.h new file mode 100644 index 00000000..a4e6ec95 --- /dev/null +++ b/src/activities/home/BookManageMenuActivity.h @@ -0,0 +1,59 @@ +#pragma once + +#include + +#include +#include +#include + +#include "../Activity.h" +#include "util/ButtonNavigator.h" + +class BookManageMenuActivity final : public Activity { + public: + enum class Action { + ARCHIVE, + UNARCHIVE, + DELETE, + DELETE_CACHE, + REINDEX, + REINDEX_FULL, + }; + + explicit BookManageMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, + const std::string& bookPath, bool isArchived, + const std::function& onAction, + const std::function& onCancel) + : Activity("BookManageMenu", renderer, mappedInput), + bookPath(bookPath), + archived(isArchived), + onAction(onAction), + onCancel(onCancel) { + buildMenuItems(); + } + + void onEnter() override; + void onExit() override; + void loop() override; + void render(Activity::RenderLock&&) override; + + private: + struct MenuItem { + Action action; + StrId labelId; + }; + + std::string bookPath; + bool archived; + std::vector menuItems; + int selectedIndex = 0; + ButtonNavigator buttonNavigator; + + bool ignoreNextConfirmRelease = false; + static constexpr unsigned long LONG_PRESS_MS = 700; + + const std::function onAction; + const std::function onCancel; + + void buildMenuItems(); +};