Add reading lists feature with pinning and management

Adds full support for book lists managed by the Companion App:
- New /list API endpoints (GET/POST) for uploading, retrieving, and deleting lists
- BookListStore for binary serialization of lists to /.lists/ directory
- ListViewActivity for viewing list contents with book thumbnails
- Reading Lists tab in My Library with pin/unpin and delete actions
- Pinnable list shortcut on home screen (split button layout)
- Automatic cleanup of pinned status when lists are deleted
This commit is contained in:
cottongin
2026-01-26 02:08:59 -05:00
parent cda8a5ec6d
commit 2c24ee3f81
14 changed files with 1296 additions and 33 deletions

View File

@@ -181,6 +181,77 @@ Source: `src/network/CrossPointWebServer.cpp` and `CrossPointWebServer.h`
- Falls back to copy+delete if rename fails
- Uses `deleteFolderRecursive()` for folder cleanup
### GET /list
**Handler:** `handleListGet()`
**Query params:**
- `name` (optional): Specific list name to retrieve
**Response:** JSON array of lists (if no name) or single list details (if name specified)
**Content-Type:** application/json
**Response (all lists - no name param):**
```json
[
{"name": "MyReadingList", "path": "/.lists/MyReadingList.bin", "bookCount": 5},
{"name": "Favorites", "path": "/.lists/Favorites.bin", "bookCount": 12}
]
```
**Response (specific list - with name param):**
```json
{
"name": "MyReadingList",
"path": "/.lists/MyReadingList.bin",
"books": [
{"order": 1, "title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "path": "/Books/gatsby.epub"},
{"order": 2, "title": "1984", "author": "George Orwell", "path": "/Books/1984.epub"}
]
}
```
**Errors:**
- 404: List not found (when `name` specified but doesn't exist)
**Notes:**
- Lists are stored in `/.lists/` directory as `.bin` files
- Uses `BookListStore::listAllLists()` and `BookListStore::loadList()`
### POST /list
**Handler:** `handleListPost()`
**Query params:**
- `action` (required): "upload" or "delete"
- `name` (required): List name (without .bin extension)
**Request body (for upload):** CSV text with one book per line
**Content-Type:** text/plain (for upload body)
**Input format (POST body for upload action):**
```
1,The Great Gatsby,F. Scott Fitzgerald,/Books/gatsby.epub
2,1984,George Orwell,/Books/1984.epub
3,Pride and Prejudice,Jane Austen,/Books/pride.epub
```
Format: `order,title,author,path` (one per line)
**Response (upload success):**
```json
{"success": true, "path": "/.lists/MyReadingList.bin"}
```
**Response (delete success):**
```json
{"success": true}
```
**Errors:**
- 400: Missing action or name parameter, empty name, failed to parse list data
- 404: List not found (for delete action)
- 500: Failed to save/delete list
**Notes:**
- Lists are stored as binary files in `/.lists/` directory
- Uses `BookListStore::parseFromText()`, `BookListStore::saveList()`, `BookListStore::deleteList()`
- Order field determines display order (books are sorted by order when loaded)
- Overwrites existing list with same name on upload
## WebSocket Protocol (port 81)
**Handler:** `onWebSocketEvent()` via `wsEventCallback()` trampoline
@@ -258,5 +329,6 @@ Source: `src/network/CrossPointWebServer.cpp` and `CrossPointWebServer.h`
- `<ArduinoJson.h>` - JSON serialization
- `<SDCardManager.h>` - SD card operations (SdMan singleton)
- `<Epub.h>` - Epub cache management
- `BookListStore.h` - Book list management (lists feature)
- `BookManager.h` - Book deletion, archiving, recent books
- `StringUtils.h` - File extension checking