From 5792e46f0e116ea9282194377090e14799dca146 Mon Sep 17 00:00:00 2001 From: codebude Date: Fri, 23 Oct 2026 09:27:41 +0200 Subject: [PATCH 1/8] Docs: explain Read again vs status-change use cases --- docs/guide/using-librislog/progress.md | 7 +++++++ docs/releases.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/guide/using-librislog/progress.md b/docs/guide/using-librislog/progress.md index 6e8f103d..6bdc29f6 100644 --- a/docs/guide/using-librislog/progress.md +++ b/docs/guide/using-librislog/progress.md @@ -33,3 +33,10 @@ Click the delete button next to an entry to remove it from the log. A confirmati ## Reading Percentage For books with a page count, the detail view shows your current page, total pages, reading percentage, and a visual progress bar. + +## Reading Sessions & Re-reads + +Books can be read more than once. Each reading is tracked as its own session with independent dates and progress. + +- **Read again** (book detail dialog, for finished books): starts a fresh reading today, keeping all earlier sessions and progress untouched. Use this for a genuine re-read. +- **Changing status from "read" to "currently reading"** (edit drawer): the legacy correction path. It can keep the previous finish date or clear it, and may leave the book in a "currently reading" state that still carries the old finish date. Use this only to correct a book's status, not to re-read it. diff --git a/docs/releases.md b/docs/releases.md index 8e6d70f1..16944eed 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -45,7 +45,7 @@ LibrisLog v1.10.0 adds four more metadata sources to the import search (BnF, Inv **Features** - 📖 **Multiple reading sessions per book.** Each book keeps a list of reading periods (start and finish dates) so re-reads never overwrite earlier dates. A new `reading_session` table stores them; `Book.date_started` / `Book.date_finished` remain a mirror of the current session, so every existing consumer (sorting, timeline, statistics, import/export) keeps working unchanged -- 🔁 **"Read again" action.** A ghost button in the book detail dialog starts a new reading session for a finished book. Earlier sessions and their progress stay untouched, and the progress bar resets to 0 % +- 🔁 **"Read again" action.** A ghost button in the book detail dialog starts a new reading session for a finished book. Earlier sessions and their progress stay untouched, and the progress bar resets to 0 %. This is the recommended way to re-read; changing a book's status from "read" to "currently reading" via the edit drawer is the legacy correction path and can keep the previous finish date - 📜 **Reading history.** A collapsible block in the book detail dialog lists every session (#, started, finished, status, pages) with per-row edit and delete, plus "Add a past reading" for back-filling handwritten history - 🏷️ **"read ×N" badge.** Cards, list rows and the book detail dialog show a small badge once a book has been read at least twice - 📊 **Statistics distinguish unique books from total completions.** A new "Total reads" card shows the number of completed reads (with a "N re-read books" sub-line). `books_finished_per_month/year`, the `books_per_month/year` goals, and `pages_read` now count every completion; "Pages read" in the bucket still counts each book once, so no single-session user sees any change From 5da2a56c47c8f38f905f8438cf8008213a1e0cb0 Mon Sep 17 00:00:00 2001 From: codebude Date: Fri, 23 Oct 2026 09:30:20 +0200 Subject: [PATCH 2/8] UI fixes: mirror book dates on session edit, read-count tooltip, responsive conflict dialog buttons --- frontend/src/lib/components/BookCard.svelte | 7 +++---- .../src/lib/components/BookDetailDialog.svelte | 17 +++++++++++------ .../lib/components/DateConflictDialog.svelte | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/frontend/src/lib/components/BookCard.svelte b/frontend/src/lib/components/BookCard.svelte index 458fa47b..cc4c3ce3 100644 --- a/frontend/src/lib/components/BookCard.svelte +++ b/frontend/src/lib/components/BookCard.svelte @@ -104,10 +104,9 @@ {$_(STATUS_LABEL_KEYS[book.reading_status])} {#if (book.read_count ?? 0) >= 2} - ×{book.read_count} + + ×{book.read_count} + {/if} diff --git a/frontend/src/lib/components/BookDetailDialog.svelte b/frontend/src/lib/components/BookDetailDialog.svelte index 070d473a..a4f1a86b 100644 --- a/frontend/src/lib/components/BookDetailDialog.svelte +++ b/frontend/src/lib/components/BookDetailDialog.svelte @@ -178,16 +178,19 @@ date_started: addSessionStarted ? fromDateTimeInputValue(addSessionStarted, tz) : null, date_finished: addSessionFinished ? fromDateTimeInputValue(addSessionFinished, tz) : null }; + let result; if (editingSessionId !== null) { - await api.books.sessions.update(book.id, editingSessionId, payload); + result = await api.books.sessions.update(book.id, editingSessionId, payload); } else { - await api.books.sessions.create(book.id, payload); + result = await api.books.sessions.create(book.id, payload); } + book = result.book; + onSave?.(result.book); addSessionOpen = false; addSessionStarted = ''; addSessionFinished = ''; editingSessionId = null; - await loadSessions(); + await loadSessionsAndProgress(); } catch (e: unknown) { toasts.add( e instanceof Error ? e.message : $_('common.actionFailed', { values: { action: $_('book.addPastReading') } }), @@ -584,9 +587,11 @@
{#if (book.read_count ?? 0) >= 2} ×{book.read_count} + class="tooltip tooltip-bottom" + data-tip={$_('book.readCount', { values: { count: book.read_count } })} + > + ×{book.read_count} + {/if} {$_(STATUS_LABEL_KEYS[book.reading_status])}
diff --git a/frontend/src/lib/components/DateConflictDialog.svelte b/frontend/src/lib/components/DateConflictDialog.svelte index e70e088b..76826f02 100644 --- a/frontend/src/lib/components/DateConflictDialog.svelte +++ b/frontend/src/lib/components/DateConflictDialog.svelte @@ -62,7 +62,7 @@

{$_(`dateConflict.${typeKey}.message`, { values: i18nValues })}

-