port: upstream PR #1342 - Book Info screen, richer metadata, safer controls
Ports upstream PR #1342 (feat: Add Book Info screen, richer metadata, and safer file-browser controls) with mod-specific adaptations: - Parse and cache series, seriesIndex, description from EPUB OPF - Bump book.bin cache version to 6 for new metadata fields - Add BookInfoActivity (new screen) accessible via Right button in FileBrowser - Add ManageBook menu via Left button in FileBrowser (replaces upstream hidden delete) - Guard all delete/archive actions with ConfirmationActivity (10 call sites) - Add inputArmed gating to ConfirmationActivity to prevent accidental confirmation - Safe deserialization: readString now returns bool with MAX_STRING_LENGTH guard - Add series field to RecentBooksStore with JSON and binary serialization - Add i18n keys: STR_BOOK_INFO, STR_AUTHOR, STR_SERIES, STR_FILE_SIZE, etc. Made-with: Cursor
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "../util/ConfirmationActivity.h"
|
||||
#include "BookManageMenuActivity.h"
|
||||
#include "CrossPointSettings.h"
|
||||
#include "CrossPointState.h"
|
||||
@@ -25,7 +26,6 @@
|
||||
#include "fontIds.h"
|
||||
#include "util/BookManager.h"
|
||||
|
||||
|
||||
int HomeActivity::getMenuItemCount() const {
|
||||
int count = 4; // File Browser, Recents, File transfer, Settings
|
||||
if (!recentBooks.empty()) {
|
||||
@@ -83,7 +83,7 @@ void HomeActivity::loadRecentCovers(int coverHeight) {
|
||||
success = epub.generateThumbBmp(coverHeight);
|
||||
if (success) {
|
||||
const std::string thumbPath = epub.getThumbBmpPath(coverHeight);
|
||||
RECENT_BOOKS.updateBook(book.path, book.title, book.author, thumbPath);
|
||||
RECENT_BOOKS.updateBook(book.path, book.title, book.author, book.series, thumbPath);
|
||||
book.coverBmpPath = thumbPath;
|
||||
} else {
|
||||
const int thumbWidth = static_cast<int>(coverHeight * 0.6);
|
||||
@@ -95,7 +95,7 @@ void HomeActivity::loadRecentCovers(int coverHeight) {
|
||||
success = xtc.generateThumbBmp(coverHeight);
|
||||
if (success) {
|
||||
const std::string thumbPath = xtc.getThumbBmpPath(coverHeight);
|
||||
RECENT_BOOKS.updateBook(book.path, book.title, book.author, thumbPath);
|
||||
RECENT_BOOKS.updateBook(book.path, book.title, book.author, book.series, thumbPath);
|
||||
book.coverBmpPath = thumbPath;
|
||||
}
|
||||
}
|
||||
@@ -301,6 +301,43 @@ void HomeActivity::onFileTransferOpen() { activityManager.goToFileTransfer(); }
|
||||
|
||||
void HomeActivity::onOpdsBrowserOpen() { activityManager.goToBrowser(); }
|
||||
|
||||
void HomeActivity::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));
|
||||
}
|
||||
requestUpdateAndWait();
|
||||
recentsLoaded = false;
|
||||
recentsLoading = false;
|
||||
coverRendered = false;
|
||||
freeCoverBuffer();
|
||||
selectorIndex = 0;
|
||||
firstRenderDone = false;
|
||||
loadRecentBooks(UITheme::getInstance().getMetrics().homeRecentBooksCount);
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void HomeActivity::openManageMenu(const std::string& bookPath) {
|
||||
const bool isArchived = BookManager::isArchived(bookPath);
|
||||
const std::string capturedPath = bookPath;
|
||||
@@ -314,39 +351,25 @@ void HomeActivity::openManageMenu(const std::string& bookPath) {
|
||||
}
|
||||
const auto& menuResult = std::get<MenuResult>(result.data);
|
||||
auto action = static_cast<BookManageMenuActivity::Action>(menuResult.action);
|
||||
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;
|
||||
|
||||
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<ConfirmationActivity>(renderer, mappedInput, heading, fileName),
|
||||
[this, action, capturedPath](const ActivityResult& confirmResult) {
|
||||
if (!confirmResult.isCancelled) {
|
||||
executeManageAction(action, capturedPath);
|
||||
} else {
|
||||
requestUpdate();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
executeManageAction(action, capturedPath);
|
||||
}
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
GUI.drawPopup(renderer, success ? tr(STR_DONE) : tr(STR_ACTION_FAILED));
|
||||
}
|
||||
requestUpdateAndWait();
|
||||
recentsLoaded = false;
|
||||
recentsLoading = false;
|
||||
coverRendered = false;
|
||||
freeCoverBuffer();
|
||||
selectorIndex = 0;
|
||||
firstRenderDone = false;
|
||||
loadRecentBooks(UITheme::getInstance().getMetrics().homeRecentBooksCount);
|
||||
requestUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user