|
|
@@ -1,22 +1,25 @@
|
|
|
# BibliothecaWindow Module Overview
|
|
|
|
|
|
`BibliothecaWindow` is the top-level GTK window that stitches together the data
|
|
|
-model (`BookList`) and the UI widgets (`BookShelf`, search bar, placeholders).
|
|
|
-It owns the application chrome and orchestrates imports, filtering, and state
|
|
|
-transitions between empty / shelf / no-results views.
|
|
|
+model (`BookList`) and the UI widgets (`BookShelf`, `BookDetails`, search bar,
|
|
|
+placeholders). It owns the application chrome and orchestrates imports,
|
|
|
+filtering, and state transitions between empty / shelf / no-results / details views.
|
|
|
|
|
|
## Responsibilities
|
|
|
|
|
|
-- Build the header bar (add button, search toggle) and main layout (`Gtk::Box`).
|
|
|
+- Build the header bar (add button, back button, search toggle) and main layout.
|
|
|
- Manage the search UI (`Gtk::SearchBar` + `Gtk::SearchEntry`) and pipe queries
|
|
|
to `BookShelf::setFilter()`.
|
|
|
- Host a `Gtk::Stack` that swaps between:
|
|
|
- Empty library placeholder.
|
|
|
- Library grid (`BookShelf`).
|
|
|
- "No results" message when filtering yields nothing.
|
|
|
+ - Book details view (`BookDetails`).
|
|
|
- Handle "Add books" action: open a file dialog, import metadata/covers on a
|
|
|
- worker thread, and enqueue `BookList::upsertMany()`.
|
|
|
-- Emit simple debug logging for activated books (placeholder behaviour for now).
|
|
|
+ worker thread, detect duplicates, and enqueue `BookList::upsertMany()`.
|
|
|
+- Show toast notifications for import results and errors.
|
|
|
+- Navigate to `BookDetails` when a book is activated.
|
|
|
+- Handle keyboard navigation (Enter, Escape, Backspace).
|
|
|
|
|
|
## Layout overview
|
|
|
|
|
|
@@ -25,34 +28,49 @@ Gtk::Window (BibliothecaWindow)
|
|
|
└── Gtk::Box m_mainBox (vertical)
|
|
|
├── Gtk::SearchBar m_searchBar
|
|
|
│ └── Gtk::SearchEntry m_searchEntry
|
|
|
- └── Gtk::Stack m_stack
|
|
|
- ├── Gtk::Box m_placeholder // empty library
|
|
|
- ├── BookShelf (GridView) // main shelf view
|
|
|
- └── Gtk::Box m_noResults // "no match" placeholder
|
|
|
+ └── Gtk::Overlay m_overlay
|
|
|
+ ├── Gtk::Stack m_stack
|
|
|
+ │ ├── Gtk::Box m_placeholder // empty library
|
|
|
+ │ ├── BookShelf (GridView) // main shelf view
|
|
|
+ │ ├── Gtk::Box m_noResults // "no match" placeholder
|
|
|
+ │ └── BookDetails // book details view
|
|
|
+ └── Gtk::Revealer m_toastRevealer // toast notification overlay
|
|
|
+ └── Gtk::Box m_toastBox
|
|
|
+ ├── Gtk::Label m_toastLabel
|
|
|
+ └── Gtk::Button m_toastCloseButton
|
|
|
```
|
|
|
|
|
|
-The header bar carries the add (+) button and a search toggle button that
|
|
|
-activates the search bar.
|
|
|
+The header bar carries:
|
|
|
+- Add (+) button to import books
|
|
|
+- Back button (visible on details view)
|
|
|
+- Search toggle button that activates the search bar
|
|
|
|
|
|
## Event flow
|
|
|
|
|
|
1. **Startup**: constructor calls `buildHeaderBar()`, `buildPlaceholder()`,
|
|
|
- creates the shelf, search widgets, and stack, then calls `updateVisibleView()`
|
|
|
- to pick the correct page based on the current library.
|
|
|
+ `buildToast()`, creates the shelf and details widgets, search widgets, and
|
|
|
+ stack, then calls `updateVisibleView()` to pick the correct page.
|
|
|
2. **Search**:
|
|
|
- Clicking the search toggle (or pressing Ctrl+F) toggles the `Gtk::SearchBar`.
|
|
|
- Typing updates `m_lastQuery`, calls `BookShelf::setFilter()`, and refreshes
|
|
|
- the stack (showing “no results” if the filtered shelf is empty).
|
|
|
- - Leaving the search mode clears the entry.
|
|
|
+ the stack (showing "no results" if the filtered shelf is empty).
|
|
|
+ - Search query is preserved when navigating to details and restored on return.
|
|
|
+ - Leaving the search mode clears the entry (only on shelf/noresults views).
|
|
|
3. **Importing books**:
|
|
|
- `onAddBookClicked()` opens `Gtk::FileDialog::open_multiple()`.
|
|
|
- Each selected file is processed on a background thread: compute SHA-256,
|
|
|
call `import_book_assets()`, merge metadata, collect into a vector.
|
|
|
+ - Duplicates are detected by matching SHA-256 hash against existing books.
|
|
|
- Once done, the vector is enqueued back onto the main loop via
|
|
|
`BookList::upsertMany()`, and the UI refreshes.
|
|
|
+ - Toast notifications show import results ("Added N books", "N duplicates").
|
|
|
4. **Activation**: `BookShelf::signalBookActivated()` connects to
|
|
|
- `BibliothecaWindow::onBookActivated()`, which currently logs a placeholder
|
|
|
- message (can be extended to open a details pane or reader).
|
|
|
+ `BibliothecaWindow::onBookActivated()`, which navigates to the `BookDetails`
|
|
|
+ view for the selected book.
|
|
|
+5. **Keyboard navigation**:
|
|
|
+ - Enter/Return: Open selected book from shelf view.
|
|
|
+ - Escape: Go back from details, close search bar, or clear selection.
|
|
|
+ - Backspace: Go back from details view.
|
|
|
|
|
|
## Signals & slots
|
|
|
|
|
|
@@ -60,24 +78,35 @@ BibliothecaWindow subscribes to the relevant `BookList` signals to call
|
|
|
`updateVisibleView()` whenever the library changes. This keeps the stack in sync
|
|
|
with imports, deletions, and resets without manual intervention.
|
|
|
|
|
|
+It also subscribes to `BookDetails::signalBookRemoved()` to navigate back to the
|
|
|
+shelf when the currently displayed book is deleted.
|
|
|
+
|
|
|
+## Toast notifications
|
|
|
+
|
|
|
+The toast system uses a `Gtk::Revealer` overlay to show temporary messages:
|
|
|
+
|
|
|
+- Success messages (green styling) for successful imports.
|
|
|
+- Error messages (red styling) for failed imports.
|
|
|
+- Mixed messages when some imports succeed and others fail.
|
|
|
+- Auto-hide after 4 seconds with manual close button.
|
|
|
+
|
|
|
## Extension points
|
|
|
|
|
|
-- **Actions on activation**: replace the placeholder logging with navigation to
|
|
|
- a details page or opening the file.
|
|
|
- **Drag-and-drop import**: wire a drop controller onto `m_mainBox` that reuses
|
|
|
the existing import flow.
|
|
|
-- **Search enhancements**: add filters (e.g. tags, formats) or highlight matches
|
|
|
- inside the grid by extending `BookShelf`.
|
|
|
+- **Search enhancements**: add tag chips as quick filters in the search UI.
|
|
|
+- **Loading indicator**: add spinner during import operations.
|
|
|
|
|
|
## Expected usage
|
|
|
|
|
|
`BibliothecaWindow` is the root window instantiated in `main.cpp`. Other modules
|
|
|
-should construct it with an existing `BookList`:
|
|
|
+should construct it with an existing `DatabaseManager` and `BookList`:
|
|
|
|
|
|
```cpp
|
|
|
-auto window = Gtk::make_managed<BibliothecaWindow>(bookList);
|
|
|
+auto window = Gtk::make_managed<BibliothecaWindow>(db, bookList);
|
|
|
app->add_window(*window);
|
|
|
```
|
|
|
|
|
|
-The window takes ownership of the `BookShelf` widget and manages presentation
|
|
|
-according to the current state of the library and active search query.
|
|
|
+The window takes ownership of the `BookShelf` and `BookDetails` widgets and
|
|
|
+manages presentation according to the current state of the library and active
|
|
|
+search query.
|