#include "EpubReaderMenuActivity.h" #include #include #include "MappedInputManager.h" #include "components/UITheme.h" #include "fontIds.h" EpubReaderMenuActivity::EpubReaderMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, const std::string& title, const int currentPage, const int totalPages, const int bookProgressPercent, const uint8_t currentOrientation, const bool hasFootnotes, const bool hasBookmarks) : Activity("EpubReaderMenu", renderer, mappedInput), menuItems(buildMenuItems(hasFootnotes, hasBookmarks)), title(title), pendingOrientation(currentOrientation), currentPage(currentPage), totalPages(totalPages), bookProgressPercent(bookProgressPercent) {} std::vector EpubReaderMenuActivity::buildMenuItems(bool hasFootnotes, bool hasBookmarks) { std::vector items; items.reserve(12); items.push_back({MenuAction::SELECT_CHAPTER, StrId::STR_SELECT_CHAPTER}); if (hasFootnotes) { items.push_back({MenuAction::FOOTNOTES, StrId::STR_FOOTNOTES}); } if (hasBookmarks) { items.push_back({MenuAction::BOOKMARKS, StrId::STR_BOOKMARKS}); } items.push_back({MenuAction::TOGGLE_BOOKMARK, StrId::STR_TOGGLE_BOOKMARK}); items.push_back({MenuAction::ROTATE_SCREEN, StrId::STR_ORIENTATION}); items.push_back({MenuAction::AUTO_PAGE_TURN, StrId::STR_AUTO_TURN_PAGES_PER_MIN}); items.push_back({MenuAction::GO_TO_PERCENT, StrId::STR_GO_TO_PERCENT}); items.push_back({MenuAction::SCREENSHOT, StrId::STR_SCREENSHOT_BUTTON}); items.push_back({MenuAction::DISPLAY_QR, StrId::STR_DISPLAY_QR}); items.push_back({MenuAction::GO_HOME, StrId::STR_GO_HOME_BUTTON}); items.push_back({MenuAction::SYNC, StrId::STR_SYNC_PROGRESS}); items.push_back({MenuAction::DELETE_CACHE, StrId::STR_DELETE_CACHE}); return items; } void EpubReaderMenuActivity::onEnter() { Activity::onEnter(); requestUpdate(); } void EpubReaderMenuActivity::onExit() { Activity::onExit(); } void EpubReaderMenuActivity::loop() { if (optionPopup.handleInput(mappedInput, [this] { requestUpdate(); })) return; // Handle navigation 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)) { const auto selectedAction = menuItems[selectedIndex].action; if (selectedAction == MenuAction::ROTATE_SCREEN) { optionPopup.show(StrId::STR_ORIENTATION, orientationLabels.data(), static_cast(orientationLabels.size()), pendingOrientation, [this](int idx) { pendingOrientation = idx; requestUpdate(); }); requestUpdate(); return; } if (selectedAction == MenuAction::AUTO_PAGE_TURN) { optionPopup.show(I18N.get(StrId::STR_AUTO_TURN_PAGES_PER_MIN), pageTurnLabels.data(), static_cast(pageTurnLabels.size()), selectedPageTurnOption, [this](int idx) { selectedPageTurnOption = idx; requestUpdate(); }); requestUpdate(); return; } setResult(MenuResult{static_cast(selectedAction), pendingOrientation, selectedPageTurnOption}); finish(); return; } else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { ActivityResult result; result.isCancelled = true; result.data = MenuResult{-1, pendingOrientation, selectedPageTurnOption}; setResult(std::move(result)); finish(); return; } } void EpubReaderMenuActivity::render(RenderLock&&) { if (optionPopup.processRender(renderer, mappedInput)) return; renderer.clearScreen(); auto metrics = UITheme::getInstance().getMetrics(); Rect screen = UITheme::getInstance().getScreenSafeArea(renderer, true, false); GUI.drawHeader(renderer, Rect{screen.x, screen.y + metrics.topPadding, screen.width, metrics.headerHeight}, title.c_str()); // Progress summary std::string progressLine; if (totalPages > 0) { progressLine = std::string(tr(STR_CHAPTER_PREFIX)) + std::to_string(currentPage) + "/" + std::to_string(totalPages) + std::string(tr(STR_PAGES_SEPARATOR)); } progressLine += std::string(tr(STR_BOOK_PREFIX)) + std::to_string(bookProgressPercent) + "%"; GUI.drawSubHeader( renderer, Rect{screen.x, screen.y + metrics.topPadding + metrics.headerHeight, screen.width, metrics.tabBarHeight}, progressLine.c_str()); const int contentTop = screen.y + metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing; const int contentHeight = screen.height - contentTop - metrics.verticalSpacing; GUI.drawList( renderer, Rect{screen.x, contentTop, screen.width, contentHeight}, menuItems.size(), selectedIndex, [this](int index) { return I18N.get(menuItems[index].labelId); }, nullptr, nullptr, [this](int index) { const auto value = menuItems[index].action; if (value == MenuAction::ROTATE_SCREEN) { // Render current orientation value on the right edge of the content area. return I18N.get(orientationLabels[pendingOrientation]); } else if (value == MenuAction::AUTO_PAGE_TURN) { // Render current page turn value on the right edge of the content area. return pageTurnLabels[selectedPageTurnOption]; } else { return ""; } }, true); // Footer / Hints const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN)); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); renderer.displayBuffer(); }