Library: persist Enhanced / Standard view toggle in localStorage

User feedback: the Enhanced view toggle on the artist detail page reset
to Standard on every artist click, so admins who prefer Enhanced had to
re-flip the toggle every single time. Persist the choice in
localStorage and reapply on every artist navigation + page reload.

- `toggleEnhancedView()` writes `soulsync-library-view-mode` to
  localStorage on every change.
- `navigateToArtistDetail()` reads the saved value after the standard
  reset block runs; if `enhanced` AND `isEnhancedAdmin()` it calls
  `toggleEnhancedView(true)` after `loadArtistDetailData` kicks off.
  The brief Standard render is hidden as soon as the toggle flips.
- Gated on `isEnhancedAdmin()` so non-admin profiles (which never see
  the toggle) can't end up with a stale Enhanced preference being
  applied silently.
- Wrapped in try/catch since localStorage is unavailable in some
  private-browsing modes.

No backend change; no DB migration needed.
This commit is contained in:
Broque Thomas 2026-05-27 07:08:21 -07:00
parent 39f582a690
commit b67d13164a
2 changed files with 23 additions and 0 deletions

View file

@ -3415,6 +3415,7 @@ function closeHelperSearch() {
const WHATS_NEW = {
'2.6.3': [
{ unreleased: true },
{ title: 'Library: Enhanced / Standard view toggle now sticks per browser', desc: 'the artist detail page used to revert to Standard view every time you clicked into a new artist — flipping to Enhanced was a per-click thing with no memory. now the choice is persisted in localStorage and reapplied automatically on every artist open. survives page reloads too. non-admins (who can\'t toggle Enhanced anyway) are unaffected; admins who never touched the Enhanced view stay on Standard since the saved value defaults to it.' },
{ title: 'Fix popup: manual matches survive Playlist Pipeline runs', desc: 'manually mapping a mirrored-playlist track via the Fix popup (search or MBID) saved correctly and the download went through, but the next Playlist Pipeline run kept reverting the match — the track flipped back to "Provider Changed" and you had to map it again. three things were ganging up on it: the manual-fix save always stamped `provider: \'spotify\'` even when the match came from MusicBrainz / iTunes / Deezer, so prepare-discovery saw a provider mismatch on the next run; the discovery worker also re-queued any matched_data that lacked `track_number` / `album.id` / `release_date` for re-discovery, and Fix-popup saves never carry those fields by design (search results don\'t include track_number, MBID lookups don\'t include album.id) — so manual fixes always looked "incomplete" and got overwritten; and the prepare-discovery provider check didn\'t honour the `manual_match` flag at all. all three patched — manual matches now stamp the actual source, the worker short-circuits on `manual_match` before the incomplete-data branch, and prepare-discovery treats manual fixes as cached regardless of provider drift.' },
{ title: 'Fix popup: artist + track fields no longer surface unrelated covers', desc: 'separate artist / track inputs in the Fix popup used to dump both into a bare MusicBrainz keyword query — and MB\'s scorer heavily favours title matches, so searching "Coffee Break" + "Zeds Dead" surfaced random "Coffee Break" tracks by other artists ahead of the canonical Zeds Dead one. fields-mode now uses a field-scoped Lucene query that actually anchors the artist, with the old bare query kept as a fallback for diacritic mismatches like "Bjork" vs "Björk" where strict phrase match misses. results also stable-prefer entries with known track length so the canonical 3:04 sibling sits above the 0:00 duplicate.' },
{ title: 'Groundwork: unified playlist source layer', desc: 'first slice of a refactor that\'ll let ListenBrainz, Last.fm radio, and SoulSync Discovery playlists live as Sync-page tabs alongside Spotify / Tidal / Qobuz / YouTube — so they can be mirrored + scheduled like the rest. this commit adds the shared adapter layer all those sources will plug into; no UI changes yet. nothing to do on your end.' },

View file

@ -879,6 +879,15 @@ function navigateToArtistDetail(artistId, artistName, sourceOverride = null, opt
const bulkBar = document.getElementById('enhanced-bulk-bar');
if (bulkBar) bulkBar.classList.remove('visible');
// Restore persisted view preference. Non-admins can't see / toggle the
// Enhanced control so only honour the saved choice for admins; default
// is still Standard. Wrapped in try/catch because localStorage can be
// disabled in private-browsing modes.
let _preferEnhanced = false;
try {
_preferEnhanced = localStorage.getItem('soulsync-library-view-mode') === 'enhanced';
} catch (_) { /* localStorage unavailable */ }
// Navigate to artist detail page
navigateToPage('artist-detail', {
artistId,
@ -895,6 +904,13 @@ function navigateToArtistDetail(artistId, artistName, sourceOverride = null, opt
// Load artist data
loadArtistDetailData(artistId, artistName);
// Apply persisted Enhanced view after the standard data load is kicked off.
// toggleEnhancedView() triggers its own loadEnhancedViewData() in parallel;
// the brief Standard render is hidden as soon as the toggle flips.
if (_preferEnhanced && isEnhancedAdmin()) {
toggleEnhancedView(true);
}
}
function _updateArtistDetailBackButtonLabel() {
@ -2905,6 +2921,12 @@ function toggleEnhancedView(enabled) {
const bulkBar = document.getElementById('enhanced-bulk-bar');
if (bulkBar) bulkBar.classList.remove('visible');
}
// Persist the choice so the next artist click (and the next page reload)
// honours it instead of always reverting to Standard.
try {
localStorage.setItem('soulsync-library-view-mode', enabled ? 'enhanced' : 'standard');
} catch (_) { /* localStorage unavailable */ }
}
async function loadEnhancedViewData(artistId) {