Use and populate metadata

This commit is contained in:
jpirnay
2026-03-07 18:02:21 +01:00
parent 87e5cc4fe1
commit 3ed96a7e49
8 changed files with 43 additions and 13 deletions
+2
View File
@@ -301,6 +301,7 @@ bool JsonSettingsIO::saveRecentBooks(const RecentBooksStore& store, const char*
obj["path"] = book.path; obj["path"] = book.path;
obj["title"] = book.title; obj["title"] = book.title;
obj["author"] = book.author; obj["author"] = book.author;
obj["series"] = book.series;
obj["coverBmpPath"] = book.coverBmpPath; obj["coverBmpPath"] = book.coverBmpPath;
} }
@@ -325,6 +326,7 @@ bool JsonSettingsIO::loadRecentBooks(RecentBooksStore& store, const char* json)
book.path = obj["path"] | std::string(""); book.path = obj["path"] | std::string("");
book.title = obj["title"] | std::string(""); book.title = obj["title"] | std::string("");
book.author = obj["author"] | std::string(""); book.author = obj["author"] | std::string("");
book.series = obj["series"] | std::string("");
book.coverBmpPath = obj["coverBmpPath"] | std::string(""); book.coverBmpPath = obj["coverBmpPath"] | std::string("");
store.recentBooks.push_back(book); store.recentBooks.push_back(book);
} }
+8 -7
View File
@@ -21,7 +21,7 @@ constexpr int MAX_RECENT_BOOKS = 10;
RecentBooksStore RecentBooksStore::instance; RecentBooksStore RecentBooksStore::instance;
void RecentBooksStore::addBook(const std::string& path, const std::string& title, const std::string& author, void RecentBooksStore::addBook(const std::string& path, const std::string& title, const std::string& author,
const std::string& coverBmpPath) { const std::string& series, const std::string& coverBmpPath) {
// Remove existing entry if present // Remove existing entry if present
auto it = auto it =
std::find_if(recentBooks.begin(), recentBooks.end(), [&](const RecentBook& book) { return book.path == path; }); std::find_if(recentBooks.begin(), recentBooks.end(), [&](const RecentBook& book) { return book.path == path; });
@@ -30,7 +30,7 @@ void RecentBooksStore::addBook(const std::string& path, const std::string& title
} }
// Add to front // Add to front
recentBooks.insert(recentBooks.begin(), {path, title, author, coverBmpPath}); recentBooks.insert(recentBooks.begin(), {path, title, author, series, coverBmpPath});
// Trim to max size // Trim to max size
if (recentBooks.size() > MAX_RECENT_BOOKS) { if (recentBooks.size() > MAX_RECENT_BOOKS) {
@@ -73,17 +73,18 @@ RecentBook RecentBooksStore::getDataFromBook(std::string path) const {
if (FsHelpers::hasEpubExtension(lastBookFileName)) { if (FsHelpers::hasEpubExtension(lastBookFileName)) {
Epub epub(path, "/.crosspoint"); Epub epub(path, "/.crosspoint");
epub.load(false, true); epub.load(false, true);
return RecentBook{path, epub.getTitle(), epub.getAuthor(), epub.getThumbBmpPath()}; std::string series = epub.getSeries();
if (!series.empty() && !epub.getSeriesIndex().empty()) series += " #" + epub.getSeriesIndex();
return RecentBook{path, epub.getTitle(), epub.getAuthor(), series, epub.getThumbBmpPath()};
} else if (FsHelpers::hasXtcExtension(lastBookFileName)) { } else if (FsHelpers::hasXtcExtension(lastBookFileName)) {
// Handle XTC file
Xtc xtc(path, "/.crosspoint"); Xtc xtc(path, "/.crosspoint");
if (xtc.load()) { if (xtc.load()) {
return RecentBook{path, xtc.getTitle(), xtc.getAuthor(), xtc.getThumbBmpPath()}; return RecentBook{path, xtc.getTitle(), xtc.getAuthor(), "", xtc.getThumbBmpPath()};
} }
} else if (FsHelpers::hasTxtExtension(lastBookFileName) || FsHelpers::hasMarkdownExtension(lastBookFileName)) { } else if (FsHelpers::hasTxtExtension(lastBookFileName) || FsHelpers::hasMarkdownExtension(lastBookFileName)) {
return RecentBook{path, lastBookFileName, "", ""}; return RecentBook{path, lastBookFileName, "", "", ""};
} }
return RecentBook{path, "", "", ""}; return RecentBook{path, "", "", "", ""};
} }
bool RecentBooksStore::loadFromFile() { bool RecentBooksStore::loadFromFile() {
+2 -1
View File
@@ -6,6 +6,7 @@ struct RecentBook {
std::string path; std::string path;
std::string title; std::string title;
std::string author; std::string author;
std::string series;
std::string coverBmpPath; std::string coverBmpPath;
bool operator==(const RecentBook& other) const { return path == other.path; } bool operator==(const RecentBook& other) const { return path == other.path; }
@@ -31,7 +32,7 @@ class RecentBooksStore {
static RecentBooksStore& getInstance() { return instance; } static RecentBooksStore& getInstance() { return instance; }
// Add a book to the recent list (moves to front if already exists) // Add a book to the recent list (moves to front if already exists)
void addBook(const std::string& path, const std::string& title, const std::string& author, void addBook(const std::string& path, const std::string& title, const std::string& author, const std::string& series,
const std::string& coverBmpPath); const std::string& coverBmpPath);
void updateBook(const std::string& path, const std::string& title, const std::string& author, void updateBook(const std::string& path, const std::string& title, const std::string& author,
+3 -1
View File
@@ -103,7 +103,9 @@ void EpubReaderActivity::onEnter() {
// Save current epub as last opened epub and add to recent books // Save current epub as last opened epub and add to recent books
APP_STATE.openEpubPath = epub->getPath(); APP_STATE.openEpubPath = epub->getPath();
APP_STATE.saveToFile(); APP_STATE.saveToFile();
RECENT_BOOKS.addBook(epub->getPath(), epub->getTitle(), epub->getAuthor(), epub->getThumbBmpPath()); std::string series = epub->getSeries();
if (!series.empty() && !epub->getSeriesIndex().empty()) series += " #" + epub->getSeriesIndex();
RECENT_BOOKS.addBook(epub->getPath(), epub->getTitle(), epub->getAuthor(), series, epub->getThumbBmpPath());
// Trigger first update // Trigger first update
requestUpdate(); requestUpdate();
+1 -1
View File
@@ -54,7 +54,7 @@ void TxtReaderActivity::onEnter() {
auto fileName = filePath.substr(filePath.rfind('/') + 1); auto fileName = filePath.substr(filePath.rfind('/') + 1);
APP_STATE.openEpubPath = filePath; APP_STATE.openEpubPath = filePath;
APP_STATE.saveToFile(); APP_STATE.saveToFile();
RECENT_BOOKS.addBook(filePath, fileName, "", ""); RECENT_BOOKS.addBook(filePath, fileName, "", "", "");
// Trigger first update // Trigger first update
requestUpdate(); requestUpdate();
+1 -1
View File
@@ -40,7 +40,7 @@ void XtcReaderActivity::onEnter() {
// Save current XTC as last opened book and add to recent books // Save current XTC as last opened book and add to recent books
APP_STATE.openEpubPath = xtc->getPath(); APP_STATE.openEpubPath = xtc->getPath();
APP_STATE.saveToFile(); APP_STATE.saveToFile();
RECENT_BOOKS.addBook(xtc->getPath(), xtc->getTitle(), xtc->getAuthor(), xtc->getThumbBmpPath()); RECENT_BOOKS.addBook(xtc->getPath(), xtc->getTitle(), xtc->getAuthor(), "", xtc->getThumbBmpPath());
// Trigger first update // Trigger first update
requestUpdate(); requestUpdate();
+19 -1
View File
@@ -482,6 +482,7 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
if (hasContinueReading) { if (hasContinueReading) {
const std::string& lastBookTitle = recentBooks[0].title; const std::string& lastBookTitle = recentBooks[0].title;
const std::string& lastBookAuthor = recentBooks[0].author; const std::string& lastBookAuthor = recentBooks[0].author;
const std::string& lastBookSeries = recentBooks[0].series;
// Invert text colors based on selection state: // Invert text colors based on selection state:
// - With cover: selected = white text on black box, unselected = black text on white box // - With cover: selected = white text on black box, unselected = black text on white box
@@ -494,6 +495,9 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
if (!lastBookAuthor.empty()) { if (!lastBookAuthor.empty()) {
totalTextHeight += renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2; totalTextHeight += renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2;
} }
if (!lastBookSeries.empty()) {
totalTextHeight += renderer.getLineHeight(UI_12_FONT_ID);
}
// Vertically center the title block within the card // Vertically center the title block within the card
int titleYStart = bookY + (bookHeight - totalTextHeight) / 2; int titleYStart = bookY + (bookHeight - totalTextHeight) / 2;
@@ -501,8 +505,11 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
const auto truncatedAuthor = lastBookAuthor.empty() const auto truncatedAuthor = lastBookAuthor.empty()
? std::string{} ? std::string{}
: renderer.truncatedText(UI_10_FONT_ID, lastBookAuthor.c_str(), bookWidth - 40); : renderer.truncatedText(UI_10_FONT_ID, lastBookAuthor.c_str(), bookWidth - 40);
const auto truncatedSeries = lastBookSeries.empty()
? std::string{}
: renderer.truncatedText(UI_12_FONT_ID, lastBookSeries.c_str(), bookWidth - 40);
// If cover image was rendered, draw box behind title and author // If cover image was rendered, draw box behind title, author, and series
if (coverRendered) { if (coverRendered) {
constexpr int boxPadding = 8; constexpr int boxPadding = 8;
// Calculate the max text width for the box // Calculate the max text width for the box
@@ -519,6 +526,12 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
maxTextWidth = authorWidth; maxTextWidth = authorWidth;
} }
} }
if (!truncatedSeries.empty()) {
const int seriesWidth = renderer.getTextWidth(UI_12_FONT_ID, truncatedSeries.c_str());
if (seriesWidth > maxTextWidth) {
maxTextWidth = seriesWidth;
}
}
const int boxWidth = maxTextWidth + boxPadding * 2; const int boxWidth = maxTextWidth + boxPadding * 2;
const int boxHeight = totalTextHeight + boxPadding * 2; const int boxHeight = totalTextHeight + boxPadding * 2;
@@ -539,6 +552,11 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
if (!truncatedAuthor.empty()) { if (!truncatedAuthor.empty()) {
titleYStart += renderer.getLineHeight(UI_10_FONT_ID) / 2; titleYStart += renderer.getLineHeight(UI_10_FONT_ID) / 2;
renderer.drawCenteredText(UI_10_FONT_ID, titleYStart, truncatedAuthor.c_str(), !bookSelected); renderer.drawCenteredText(UI_10_FONT_ID, titleYStart, truncatedAuthor.c_str(), !bookSelected);
titleYStart += renderer.getLineHeight(UI_10_FONT_ID);
}
if (!truncatedSeries.empty()) {
renderer.drawCenteredText(UI_12_FONT_ID, titleYStart, truncatedSeries.c_str(), !bookSelected);
} }
// "Continue Reading" label at the bottom // "Continue Reading" label at the bottom
+7 -1
View File
@@ -487,10 +487,12 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
auto titleLines = renderer.wrappedText(UI_12_FONT_ID, book.title.c_str(), textWidth, 3, EpdFontFamily::BOLD); auto titleLines = renderer.wrappedText(UI_12_FONT_ID, book.title.c_str(), textWidth, 3, EpdFontFamily::BOLD);
auto author = renderer.truncatedText(UI_10_FONT_ID, book.author.c_str(), textWidth); auto author = renderer.truncatedText(UI_10_FONT_ID, book.author.c_str(), textWidth);
auto series = renderer.truncatedText(UI_12_FONT_ID, book.series.c_str(), textWidth);
const int titleLineHeight = renderer.getLineHeight(UI_12_FONT_ID); const int titleLineHeight = renderer.getLineHeight(UI_12_FONT_ID);
const int titleBlockHeight = titleLineHeight * static_cast<int>(titleLines.size()); const int titleBlockHeight = titleLineHeight * static_cast<int>(titleLines.size());
const int authorHeight = book.author.empty() ? 0 : (renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2); const int authorHeight = book.author.empty() ? 0 : (renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2);
const int totalBlockHeight = titleBlockHeight + authorHeight; const int seriesHeight = book.series.empty() ? 0 : renderer.getLineHeight(UI_12_FONT_ID);
const int totalBlockHeight = titleBlockHeight + authorHeight + seriesHeight;
int titleY = tileY + tileHeight / 2 - totalBlockHeight / 2; int titleY = tileY + tileHeight / 2 - totalBlockHeight / 2;
const int textX = tileX + hPaddingInSelection + coverWidth + LyraMetrics::values.verticalSpacing; const int textX = tileX + hPaddingInSelection + coverWidth + LyraMetrics::values.verticalSpacing;
for (const auto& line : titleLines) { for (const auto& line : titleLines) {
@@ -500,6 +502,10 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
if (!book.author.empty()) { if (!book.author.empty()) {
titleY += renderer.getLineHeight(UI_10_FONT_ID) / 2; titleY += renderer.getLineHeight(UI_10_FONT_ID) / 2;
renderer.drawText(UI_10_FONT_ID, textX, titleY, author.c_str(), true); renderer.drawText(UI_10_FONT_ID, textX, titleY, author.c_str(), true);
titleY += renderer.getLineHeight(UI_10_FONT_ID);
}
if (!book.series.empty()) {
renderer.drawText(UI_12_FONT_ID, textX, titleY, series.c_str(), true);
} }
} else { } else {
drawEmptyRecents(renderer, rect); drawEmptyRecents(renderer, rect);