Add list view + per-grouping persistence for the audiobooks library#585
Add list view + per-grouping persistence for the audiobooks library#585kevinheneveld wants to merge 2 commits into
Conversation
|
Small note regarding the issue linked to this: Is there a particular reason why you created it on the fork instead of here ? It might be better to open them here instead if you expect feedback on those (or perhaps there is a way to see forked repository issues from here ?) |
|
Good point. My workflow tracks issues on the fork as a working backlog, but you're right that anything expecting upstream feedback belongs here. I'll re-open this one on Listenarrs/Listenarr and relink it. |
|
Re-filed the linked issue here: #595 (was kevinheneveld#1). Will update the PR body to point at the new one. |
284cea4 to
e965c30
Compare
e965c30 to
c365ece
Compare
c365ece to
cd9b0d4
Compare
The audiobooks toolbar exposes a list/grid toggle, but the grouped view template only rendered a grid — toggling to list mode while grouped by author or series was silently ignored. The list template only existed inside the `groupBy === 'books'` branch. This adds a parallel list rendering for grouped collections: - Row per collection (cover thumb, name, book count) - Clicking a row navigates to the collection page (matches grid behavior) - Keyboard accessible (Enter / Space activate the row) CSS reuses the existing `.audiobooks-list` / `.audiobook-list-item` patterns; the row layout has its own three-column grid template (cover / name / count) since collection rows don't carry status badges or per-item actions. Tests added for both authors and series groupings in list mode. (cherry picked from commit 284cea4)
The view mode toggle's persistence was previously gated by scrollContainer being mounted, which only happens for groupBy === 'books'. So switching to list mode while grouped by author or series, then navigating away and back, would silently revert to grid. Switches to three localStorage keys (one per grouping: books, authors, series), reads the relevant key unconditionally on mount, and re-reads when groupBy changes — so each grouping can independently remember list vs grid. A one-time migration seeds all three keys from the legacy listenarr.viewMode value when first encountered, so existing users keep their preference. Persistence watch moved to top level so it's no longer gated by the scrollContainer guard.
cd9b0d4 to
7d4da6c
Compare
therobbiedavis
left a comment
There was a problem hiding this comment.
Thanks for taking care of this; it was actually on my list of todo's eventually. I left a couple of inline comments around the new grouped-list image path: the fallback argument is currently not a real image URL, and the author list rows do not participate in the existing author-cover lookup flow used by grid cards.
| groupBy === 'authors' | ||
| ? getAuthorImageUrl(collection) | ||
| : collection.coverUrls && collection.coverUrls[0], | ||
| `${groupBy}-list:${collection.name}`, |
There was a problem hiding this comment.
getProtectedImageSrc() treats its second argument as the actual fallback image URL, not as an image/cache key. With the current value, coverless author/series rows get a src like authors-list:Author A or series-list:Series 1 until the image error handler replaces it. Could this pass getPlaceholderUrl() instead?
| " | ||
| :alt="collection.name" | ||
| loading="lazy" | ||
| decoding="async" |
There was a problem hiding this comment.
This new author list path bypasses the existing author-cover lookup behavior. Grid author cards call into ensureAuthorCover() through handleAuthorImageError() and the observeAuthorCards() marker selector at AudiobooksView.vue:1519, but these list rows only use the generic handleImageError and do not render a data-author-name target. For authors without authorAsins, list mode will stay on the placeholder instead of fetching the lookup cover.
I’d avoid fixing this only by swapping @error to handleAuthorImageError: once my previous comment changes the fallback to a valid placeholder, no error fires for missing covers, so lookup still won’t happen. A safer fix would make list author rows participate in the same lazy observer path, and add a test where an author has no authorAsins but apiService.getAuthorLookup() returns a cover.
Summary
Two related changes to the audiobooks library's grouped views, combined into one PR (was previously split across #585 and #590; #590 is being closed in favor of this).
1. List view for grouped authors and series. The audiobooks toolbar exposes a list/grid view toggle, but the grouped views (
?group=authors,?group=series) only had a grid template. Toggling list mode while grouped was silently a no-op. This PR adds a parallel list rendering for grouped collections: one row per collection (cover thumb, collection name, book count). Clicking a row navigates to the collection page, matching the grid-card behavior.2. Per-grouping persistence of the view mode. Previously the load-from-storage was nested inside an
if (scrollContainer.value)block that only runs for the Books grouping — so switching to list mode while grouped by Author or Series, then navigating away, would silently revert to grid. This switches to three per-grouping keys (listenarr.viewMode.books,.authors,.series) and reads the relevant one unconditionally on mount + whenevergroupBychanges. A one-time migration seeds all three keys from the legacylistenarr.viewModevalue so existing users keep their preference.Implementation notes
fe/src/views/library/AudiobooksView.vue. The existing grid is wrapped inv-else; newv-if=\"viewMode === 'list'\"branch above it..audiobooks-list/.audiobook-list-itempatterns; collection rows have their own three-column grid template (cover / name / count) since they don't carry status badges or per-item actions.Test plan
Closes #595
Supersedes #590