Some fixes

This commit is contained in:
jpirnay
2026-05-20 20:56:03 +02:00
parent d729201321
commit c5b8c55c04
13 changed files with 52 additions and 20 deletions
+8 -2
View File
@@ -53,7 +53,10 @@ void ReadingSessionTracker::markFinished() {
if (!active) return;
const int64_t walltime = HalClock::isSynced() ? static_cast<int64_t>(HalClock::now()) : 0;
READING_STATS.markFinished(docId, title, author, static_cast<time_t>(walltime));
READING_STATS.saveToFile();
if (!READING_STATS.saveToFile()) {
LOG_ERR("RST", "saveToFile failed (markFinished) doc=%s title=%s author=%s wall=%lld", docId.c_str(), title.c_str(),
author.c_str(), (long long)walltime);
}
LOG_DBG("RST", "Marked finished doc=%s wall=%lld", docId.c_str(), (long long)walltime);
}
@@ -77,7 +80,10 @@ void ReadingSessionTracker::end() {
if (seconds > 0 && !docId.empty()) {
READING_STATS.recordSession(docId, title, author, seconds, pagesTurnedThisSession, lastKnownProgress,
static_cast<time_t>(walltime));
READING_STATS.saveToFile();
if (!READING_STATS.saveToFile()) {
LOG_ERR("RST", "saveToFile failed (session end) doc=%s title=%s author=%s secs=%u pages=%u wall=%lld",
docId.c_str(), title.c_str(), author.c_str(), seconds, pagesTurnedThisSession, (long long)walltime);
}
}
active = false;
+2 -6
View File
@@ -118,7 +118,6 @@ uint16_t ReadingStatsStore::computeCurrentStreak(uint16_t today) const {
// yesterday. After that the chain is broken.
uint16_t anchor = today;
if (getSecondsForDay(anchor) == 0) {
if (anchor == 0) return 0;
anchor -= 1;
if (getSecondsForDay(anchor) == 0) return 0;
}
@@ -170,11 +169,8 @@ void ReadingStatsStore::markFinished(const std::string& docId, const std::string
}
size_t ReadingStatsStore::getFinishedBookCount() const {
size_t n = 0;
for (const auto& b : books) {
if (b.finishedCount > 0) ++n;
}
return n;
return static_cast<size_t>(
std::count_if(books.begin(), books.end(), [](const BookReadingStats& b) { return b.finishedCount > 0; }));
}
const BookReadingStats* ReadingStatsStore::findBook(const std::string& docId) const {
@@ -905,23 +905,27 @@ void TxtReaderActivity::onButtonAction(const CrossPointSettings::BUTTON_ACTION a
case BA::BTN_PAGE_FORWARD:
if (currentPage < totalPages - 1) {
currentPage++;
globalReadingSessionTracker().onPageTurn();
requestUpdate();
}
break;
case BA::BTN_PAGE_BACK:
if (currentPage > 0) {
currentPage--;
globalReadingSessionTracker().onPageTurn();
requestUpdate();
}
break;
case BA::BTN_PAGE_FORWARD_10:
currentPage += 10;
clampPage();
globalReadingSessionTracker().onPageTurn();
requestUpdate();
break;
case BA::BTN_PAGE_BACK_10:
currentPage -= 10;
clampPage();
globalReadingSessionTracker().onPageTurn();
requestUpdate();
break;
case BA::BTN_STAR_PAGE:
@@ -523,21 +523,25 @@ void XtcReaderActivity::onButtonAction(const CrossPointSettings::BUTTON_ACTION a
case BA::BTN_PAGE_FORWARD:
if (currentPage + 1 < pageCount) {
currentPage++;
globalReadingSessionTracker().onPageTurn();
requestUpdate();
}
break;
case BA::BTN_PAGE_BACK:
if (currentPage > 0) {
currentPage--;
globalReadingSessionTracker().onPageTurn();
requestUpdate();
}
break;
case BA::BTN_PAGE_FORWARD_10:
currentPage = (currentPage + 10 < pageCount) ? currentPage + 10 : pageCount - 1;
globalReadingSessionTracker().onPageTurn();
requestUpdate();
break;
case BA::BTN_PAGE_BACK_10:
currentPage = (currentPage >= 10) ? currentPage - 10 : 0;
globalReadingSessionTracker().onPageTurn();
requestUpdate();
break;
case BA::BTN_NEXT_SECTION:
@@ -547,6 +551,7 @@ void XtcReaderActivity::onButtonAction(const CrossPointSettings::BUTTON_ACTION a
[this](const auto& ch) { return ch.startPage > currentPage; });
if (it != chapters.end()) {
currentPage = it->startPage;
globalReadingSessionTracker().onPageTurn();
requestUpdate();
}
}
@@ -559,6 +564,7 @@ void XtcReaderActivity::onButtonAction(const CrossPointSettings::BUTTON_ACTION a
if (prevChapter != chapters.rend()) {
currentPage = prevChapter->startPage;
globalReadingSessionTracker().onPageTurn();
requestUpdate();
}
}
@@ -3,10 +3,12 @@
#include <Arduino.h> // millis()
#include <GfxRenderer.h>
#include <I18n.h>
#include <Utf8.h>
#include <algorithm>
#include <array>
#include <cstdio>
#include <iterator>
#include <utility>
#include <vector>
@@ -178,7 +180,8 @@ void ReadingStatsActivity::render(RenderLock&&) {
if (!store.getBooks().empty()) {
std::vector<const BookReadingStats*> sorted;
sorted.reserve(store.getBooks().size());
for (const auto& b : store.getBooks()) sorted.push_back(&b);
std::transform(store.getBooks().begin(), store.getBooks().end(), std::back_inserter(sorted),
[](const BookReadingStats& b) { return &b; });
std::sort(sorted.begin(), sorted.end(),
[](const BookReadingStats* a, const BookReadingStats* b) { return a->totalSeconds > b->totalSeconds; });
@@ -199,7 +202,7 @@ void ReadingStatsActivity::render(RenderLock&&) {
if (maxLabelWidth > 0 && renderer.getTextWidth(UI_10_FONT_ID, label.c_str()) > maxLabelWidth) {
while (!label.empty() &&
renderer.getTextWidth(UI_10_FONT_ID, label.c_str()) + ellipsisWidth > maxLabelWidth) {
label.pop_back();
utf8RemoveLastChar(label);
}
label += "";
}
@@ -3,6 +3,7 @@
#include <GfxRenderer.h>
#include <HalClock.h>
#include <I18n.h>
#include <Utf8.h>
#include <algorithm>
#include <array>
@@ -107,9 +108,19 @@ void ReadingStatsBookDetailActivity::render(RenderLock&&) {
// Header — title (truncated) and author. Title fallback to docId so we
// still produce a usable screen if the book's metadata was never recorded.
std::string headerTitle = (book && !book->title.empty()) ? book->title : docId;
if (headerTitle.size() > 28) {
headerTitle.resize(28);
headerTitle += "";
{
constexpr size_t kMaxChars = 28;
const auto* p = reinterpret_cast<const unsigned char*>(headerTitle.c_str());
const auto* start = p;
size_t chars = 0;
while (*p != 0 && chars < kMaxChars) {
utf8NextCodepoint(&p);
++chars;
}
if (*p != 0) {
headerTitle.resize(static_cast<size_t>(p - start));
headerTitle += "";
}
}
GUI.drawHeader(renderer,
Rect{contentRect.x, contentRect.y + metrics.topPadding, contentRect.width, metrics.headerHeight},
@@ -5,6 +5,7 @@
#include <algorithm>
#include <cstdio>
#include <iterator>
#include "MappedInputManager.h"
#include "ReadingStatsBookDetailActivity.h"
@@ -35,9 +36,9 @@ std::string formatDuration(uint32_t totalSeconds) {
void ReadingStatsBookListActivity::rebuildSortedBooks() {
sortedBooks.clear();
for (const auto& b : READING_STATS.getBooks()) {
sortedBooks.push_back(&b);
}
sortedBooks.reserve(READING_STATS.getBooks().size());
std::transform(READING_STATS.getBooks().begin(), READING_STATS.getBooks().end(), std::back_inserter(sortedBooks),
[](const BookReadingStats& b) { return &b; });
std::sort(sortedBooks.begin(), sortedBooks.end(),
[](const BookReadingStats* a, const BookReadingStats* b) { return a->totalSeconds > b->totalSeconds; });
}
+1 -1
View File
@@ -7,7 +7,7 @@
#include "fontIds.h"
CardLayout::CardLayout(GfxRenderer& renderer, Rect contentRect, int startY, CardLayoutConfig cfg)
CardLayout::CardLayout(GfxRenderer& renderer, Rect contentRect, int startY, const CardLayoutConfig& cfg)
: renderer_(renderer), contentRect_(contentRect), cfg_(cfg), y_(startY) {
cardLeft_ = contentRect.x + cfg_.outerMarginX;
cardWidth_ = contentRect.width - cfg_.outerMarginX * 2;
+1 -1
View File
@@ -85,7 +85,7 @@ class CardLayout {
void centeredMessage(const char* msg);
};
CardLayout(GfxRenderer& renderer, Rect contentRect, int startY, CardLayoutConfig cfg = {});
CardLayout(GfxRenderer& renderer, Rect contentRect, int startY, const CardLayoutConfig& cfg = {});
// Render a single card. `bodyFn` receives a `Body&` and may call its
// helpers in any order; the card auto-sizes to whatever the body draws.
+1
View File
@@ -108,6 +108,7 @@
.nav-links {
margin: 20px 0;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
+1
View File
@@ -113,6 +113,7 @@
.nav-links {
margin: 20px 0;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
+1
View File
@@ -59,6 +59,7 @@
.nav-links {
margin: 20px 0;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.nav-links a {
+4 -2
View File
@@ -310,8 +310,10 @@
// seconds.
function formatEta(seconds) {
if (!seconds || seconds <= 0) return "—";
const h = Math.floor(seconds / 3600);
const m = Math.round((seconds % 3600) / 60);
let h = Math.floor(seconds / 3600);
let m = Math.round((seconds % 3600) / 60);
// Rounding can push m to 60 (e.g. 3570s → 0h 60m); carry into hours.
if (m === 60) { h += 1; m = 0; }
if (h > 0) return `${h}h ${String(m).padStart(2, "0")}m`;
if (m > 0) return `${m}m`;
return "<1m";