Use and populate metadata
This commit is contained in:
@@ -301,6 +301,7 @@ bool JsonSettingsIO::saveRecentBooks(const RecentBooksStore& store, const char*
|
||||
obj["path"] = book.path;
|
||||
obj["title"] = book.title;
|
||||
obj["author"] = book.author;
|
||||
obj["series"] = book.series;
|
||||
obj["coverBmpPath"] = book.coverBmpPath;
|
||||
}
|
||||
|
||||
@@ -325,6 +326,7 @@ bool JsonSettingsIO::loadRecentBooks(RecentBooksStore& store, const char* json)
|
||||
book.path = obj["path"] | std::string("");
|
||||
book.title = obj["title"] | std::string("");
|
||||
book.author = obj["author"] | std::string("");
|
||||
book.series = obj["series"] | std::string("");
|
||||
book.coverBmpPath = obj["coverBmpPath"] | std::string("");
|
||||
store.recentBooks.push_back(book);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ constexpr int MAX_RECENT_BOOKS = 10;
|
||||
RecentBooksStore RecentBooksStore::instance;
|
||||
|
||||
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
|
||||
auto it =
|
||||
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
|
||||
recentBooks.insert(recentBooks.begin(), {path, title, author, coverBmpPath});
|
||||
recentBooks.insert(recentBooks.begin(), {path, title, author, series, coverBmpPath});
|
||||
|
||||
// Trim to max size
|
||||
if (recentBooks.size() > MAX_RECENT_BOOKS) {
|
||||
@@ -73,17 +73,18 @@ RecentBook RecentBooksStore::getDataFromBook(std::string path) const {
|
||||
if (FsHelpers::hasEpubExtension(lastBookFileName)) {
|
||||
Epub epub(path, "/.crosspoint");
|
||||
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)) {
|
||||
// Handle XTC file
|
||||
Xtc xtc(path, "/.crosspoint");
|
||||
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)) {
|
||||
return RecentBook{path, lastBookFileName, "", ""};
|
||||
return RecentBook{path, lastBookFileName, "", "", ""};
|
||||
}
|
||||
return RecentBook{path, "", "", ""};
|
||||
return RecentBook{path, "", "", "", ""};
|
||||
}
|
||||
|
||||
bool RecentBooksStore::loadFromFile() {
|
||||
|
||||
@@ -6,6 +6,7 @@ struct RecentBook {
|
||||
std::string path;
|
||||
std::string title;
|
||||
std::string author;
|
||||
std::string series;
|
||||
std::string coverBmpPath;
|
||||
|
||||
bool operator==(const RecentBook& other) const { return path == other.path; }
|
||||
@@ -31,7 +32,7 @@ class RecentBooksStore {
|
||||
static RecentBooksStore& getInstance() { return instance; }
|
||||
|
||||
// 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);
|
||||
|
||||
void updateBook(const std::string& path, const std::string& title, const std::string& author,
|
||||
|
||||
@@ -103,7 +103,9 @@ void EpubReaderActivity::onEnter() {
|
||||
// Save current epub as last opened epub and add to recent books
|
||||
APP_STATE.openEpubPath = epub->getPath();
|
||||
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
|
||||
requestUpdate();
|
||||
|
||||
@@ -54,7 +54,7 @@ void TxtReaderActivity::onEnter() {
|
||||
auto fileName = filePath.substr(filePath.rfind('/') + 1);
|
||||
APP_STATE.openEpubPath = filePath;
|
||||
APP_STATE.saveToFile();
|
||||
RECENT_BOOKS.addBook(filePath, fileName, "", "");
|
||||
RECENT_BOOKS.addBook(filePath, fileName, "", "", "");
|
||||
|
||||
// Trigger first update
|
||||
requestUpdate();
|
||||
|
||||
@@ -40,7 +40,7 @@ void XtcReaderActivity::onEnter() {
|
||||
// Save current XTC as last opened book and add to recent books
|
||||
APP_STATE.openEpubPath = xtc->getPath();
|
||||
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
|
||||
requestUpdate();
|
||||
|
||||
@@ -482,6 +482,7 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
if (hasContinueReading) {
|
||||
const std::string& lastBookTitle = recentBooks[0].title;
|
||||
const std::string& lastBookAuthor = recentBooks[0].author;
|
||||
const std::string& lastBookSeries = recentBooks[0].series;
|
||||
|
||||
// Invert text colors based on selection state:
|
||||
// - 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()) {
|
||||
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
|
||||
int titleYStart = bookY + (bookHeight - totalTextHeight) / 2;
|
||||
@@ -501,8 +505,11 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
const auto truncatedAuthor = lastBookAuthor.empty()
|
||||
? std::string{}
|
||||
: 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) {
|
||||
constexpr int boxPadding = 8;
|
||||
// Calculate the max text width for the box
|
||||
@@ -519,6 +526,12 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
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 boxHeight = totalTextHeight + boxPadding * 2;
|
||||
@@ -539,6 +552,11 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
if (!truncatedAuthor.empty()) {
|
||||
titleYStart += renderer.getLineHeight(UI_10_FONT_ID) / 2;
|
||||
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
|
||||
|
||||
@@ -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 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 titleBlockHeight = titleLineHeight * static_cast<int>(titleLines.size());
|
||||
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;
|
||||
const int textX = tileX + hPaddingInSelection + coverWidth + LyraMetrics::values.verticalSpacing;
|
||||
for (const auto& line : titleLines) {
|
||||
@@ -500,6 +502,10 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
if (!book.author.empty()) {
|
||||
titleY += renderer.getLineHeight(UI_10_FONT_ID) / 2;
|
||||
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 {
|
||||
drawEmptyRecents(renderer, rect);
|
||||
|
||||
Reference in New Issue
Block a user