Files
crosspoint-reader-mod/src/activities/reader/EndOfBookMenuActivity.cpp
cottongin 0e2440aea8 fix: resolve end-of-book deadlock, long-press guards, archive UX, and home screen refresh
- Fix device freeze at end-of-book by deferring EndOfBookMenuActivity
  creation from render() to loop() (avoids RenderLock deadlock) in
  EpubReaderActivity and XtcReaderActivity
- Add initialSkipRelease to BookManageMenuActivity to prevent stale
  Confirm release from triggering actions when opened via long-press
- Add initialSkipRelease to MyLibraryActivity for long-press Browse
  Files -> archive navigation
- Thread skip-release through HomeActivity callback and main.cpp
- Fix HomeActivity stale cover buffer after archive/delete by fully
  resetting render state (freeCoverBuffer, firstRenderDone, etc.)
- Swap short/long-press actions in .archive context: short-press opens
  manage menu, long-press unarchives and opens the book
- Add deferred open pattern (pendingOpenPath) to wait for Confirm
  release before navigating to reader after unarchive
- Add BookManager::cleanupEmptyArchiveDirs() to remove empty parent
  directories after unarchive/delete inside .archive
- Add optional unarchivedPath output parameter to BookManager::unarchiveBook
- Restyle EndOfBookMenuActivity to standard list layout with proper
  header, margins, and button hints matching other screens
- Change EndOfBookMenuActivity back button hint to "« Back"
- Add Table of Contents option to EndOfBookMenuActivity

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-21 07:37:36 -05:00

75 lines
2.5 KiB
C++

#include "EndOfBookMenuActivity.h"
#include <GfxRenderer.h>
#include <I18n.h>
#include "MappedInputManager.h"
#include "components/UITheme.h"
#include "fontIds.h"
void EndOfBookMenuActivity::buildMenuItems() {
menuItems.clear();
menuItems.push_back({Action::ARCHIVE, StrId::STR_ARCHIVE_BOOK});
menuItems.push_back({Action::DELETE, StrId::STR_DELETE_BOOK});
menuItems.push_back({Action::TABLE_OF_CONTENTS, StrId::STR_TABLE_OF_CONTENTS});
menuItems.push_back({Action::BACK_TO_BEGINNING, StrId::STR_BACK_TO_BEGINNING});
menuItems.push_back({Action::CLOSE_BOOK, StrId::STR_CLOSE_BOOK});
menuItems.push_back({Action::CLOSE_MENU, StrId::STR_CLOSE_MENU});
}
void EndOfBookMenuActivity::onEnter() {
Activity::onEnter();
selectedIndex = 0;
requestUpdate();
}
void EndOfBookMenuActivity::onExit() { Activity::onExit(); }
void EndOfBookMenuActivity::loop() {
buttonNavigator.onNext([this] {
selectedIndex = ButtonNavigator::nextIndex(selectedIndex, static_cast<int>(menuItems.size()));
requestUpdate();
});
buttonNavigator.onPrevious([this] {
selectedIndex = ButtonNavigator::previousIndex(selectedIndex, static_cast<int>(menuItems.size()));
requestUpdate();
});
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
if (selectedIndex < static_cast<int>(menuItems.size())) {
auto cb = onAction;
cb(menuItems[selectedIndex].action);
return;
}
}
if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
auto cb = onAction;
cb(Action::CLOSE_MENU);
return;
}
}
void EndOfBookMenuActivity::render(Activity::RenderLock&&) {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
auto metrics = UITheme::getInstance().getMetrics();
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_END_OF_BOOK));
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing;
GUI.drawList(
renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast<int>(menuItems.size()), selectedIndex,
[this](int index) { return std::string(I18N.get(menuItems[index].labelId)); });
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();
}