Files
crosspoint-reader-mod/chat-summaries/2026-02-12_20-00-summary.md

41 lines
3.4 KiB
Markdown
Raw Normal View History

# Bookmark Feature Implementation
## Task
Implement bookmark functionality for the e-reader, replacing existing "Coming soon" stubs with full add/remove bookmark, visual page indicator, and bookmark navigation features.
## Changes Made
### New Files Created
- **`src/util/BookmarkStore.h`** / **`src/util/BookmarkStore.cpp`** - Bookmark persistence utility. Stores bookmarks as binary data (`bookmarks.bin`) per-book in the epub cache directory on SD card. Each bookmark is a (spineIndex, pageNumber) pair (4 bytes). Provides static methods: `load`, `save`, `addBookmark`, `removeBookmark`, `hasBookmark`.
- **`src/activities/reader/EpubReaderBookmarkSelectionActivity.h`** / **`.cpp`** - New activity for the "Go to Bookmark" list UI, modeled on the existing chapter selection activity. Shows bookmark entries as "Chapter Title - Page N" with ButtonNavigator for scrolling. Selecting a bookmark navigates to that spine/page.
### Edited Files
- **`src/activities/reader/EpubReaderMenuActivity.h`** - Added `REMOVE_BOOKMARK` to `MenuAction` enum. Changed `buildMenuItems()` to accept `isBookmarked` parameter; dynamically shows "Remove Bookmark" or "Add Bookmark" as the first menu item.
- **`src/activities/reader/EpubReaderActivity.cpp`** - Main integration point:
- Added includes for `BookmarkStore.h` and `EpubReaderBookmarkSelectionActivity.h`
- Menu creation now computes `isBookmarked` state and passes it through
- `ADD_BOOKMARK` handler: calls `BookmarkStore::addBookmark()`, shows "Bookmark added" popup
- `REMOVE_BOOKMARK` handler (new): calls `BookmarkStore::removeBookmark()`, shows "Bookmark removed" popup
- `GO_TO_BOOKMARK` handler: loads bookmarks, opens `EpubReaderBookmarkSelectionActivity` if any exist, falls back to Table of Contents if no bookmarks but TOC exists, otherwise returns to reader
- `renderContents()`: draws a small bookmark ribbon (fillPolygon, 5-point shape) in the top-right corner when the current page is bookmarked
## Follow-up Changes (same session)
### Force half refresh on menu exit
- `onReaderMenuBack()`: sets `pagesUntilFullRefresh = 1` so the next render uses `HALF_REFRESH` to clear menu/popup ghosting artifacts from the e-ink display.
- `ADD_BOOKMARK` / `REMOVE_BOOKMARK` handlers: also set `pagesUntilFullRefresh = 1` after their popups.
### Bookmark snippet (first sentence)
- `Bookmark` struct now includes a `snippet` string field storing the first sentence from the bookmarked page.
- `BookmarkStore` binary format upgraded to v2: version marker byte (0xFF) + count + entries with variable-length snippet. Backward-compatible: reads v1 files (no snippets) gracefully.
- `addBookmark()` now accepts an optional `snippet` parameter (max 120 chars).
- `EpubReaderActivity::onReaderMenuConfirm(ADD_BOOKMARK)`: extracts the first sentence from the page by iterating PageLine elements and their TextBlock words, stopping at sentence-ending punctuation (.!?:).
- `EpubReaderBookmarkSelectionActivity::getBookmarkLabel()`: displays bookmark as "Chapter Title - First sentence here - Page N".
## Follow-up Items
- Test on device to verify bookmark ribbon sizing/positioning looks good across orientations
- Consider caching bookmark state in memory to avoid SD reads on every page render (currently `hasBookmark` reads from SD each time in `renderContents`)
- The bookmark selection list could potentially support deleting bookmarks directly from the list in a future iteration