feat: remember scroll + search position on Back (web + android)
Going into an album/artist and back now restores the scroll position and keeps the typed query, instead of resetting to the top. - Web: navigation.js snapshots each history entry's #main-content scroll and any open local (header) search, restoring them on Back/Forward; a genuine new navigation still starts at the top. - Android: the Alben/Künstler lists (LibraryViewModel) and the global/local search-results lists (ExploreViewModel/SearchViewModel) hoist their LazyListState/LazyGridState, so scroll survives a drill-in/back for the tab's lifetime. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
3ceba8a365
commit
845f125d76
7 files changed
+64
-5
No files matched your search
+35
-1
@@ -8,6 +8,7 @@ import { loadHomeData, loadAlbumRow, loadArtists, loadAlbums, loadGenreDetail }
|
||||
import { loadArtistDetail, loadArtistAllSongs, loadAlbumDetail, loadDeezerAlbumDetail, loadPartialAlbumDetail } from './detail.js';
|
||||
import { loadPlaylists, loadPlaylistDetail, loadStarred, loadRandom } from './playlists.js';
|
||||
import { loadNewReleases, loadRecommendations } from './discover.js';
|
||||
import { onHeaderSearch } from './search.js';
|
||||
import { invalidateApiCache } from '../api.js';
|
||||
|
||||
// ─── NAVIGATION HISTORY ───
|
||||
@@ -59,13 +60,39 @@ export function refreshCurrentView() {
|
||||
}
|
||||
|
||||
export function navigate(page, data=null) {
|
||||
// Scroll + search memory: remember where each history entry was scrolled AND any open local
|
||||
// (header) search, so Back/Forward returns you to the same spot with the same query. The global
|
||||
// search page keeps its query/results on its own (its DOM persists). A genuine new navigation
|
||||
// still starts at the top with a clean header search. On a genuine nav we snapshot the OUTGOING
|
||||
// view here (cursor still points at it); on Back/Forward the snapshot is taken in _navOnPopState.
|
||||
const _main = document.getElementById('main-content');
|
||||
const _hsInput = document.getElementById('header-search-input');
|
||||
S._scrollByIdx = S._scrollByIdx || {};
|
||||
S._hsByIdx = S._hsByIdx || {};
|
||||
if(!S._navJumping) {
|
||||
if(_main) S._scrollByIdx[S._navCursor] = _main.scrollTop;
|
||||
S._hsByIdx[S._navCursor] = _hsInput?.value?.trim() ? _hsInput.value : '';
|
||||
}
|
||||
closeHeaderSearch();
|
||||
|
||||
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
||||
document.querySelectorAll('.nav-item,.bnav-item').forEach(n => n.classList.remove('active','active-blue'));
|
||||
const cls = ['discover','new-releases','recommendations'].includes(page) ? 'active-blue' : 'active';
|
||||
document.querySelectorAll(`[data-page="${page}"]`).forEach(el => el.classList.add(cls));
|
||||
const pageEl = document.getElementById(`page-${page}`);
|
||||
if(pageEl) { pageEl.classList.add('active'); document.getElementById('main-content').scrollTop = 0; }
|
||||
if(pageEl) {
|
||||
pageEl.classList.add('active');
|
||||
if(S._navJumping) {
|
||||
// Back/Forward → restore this entry's saved scroll (rAF so the shown page has laid out) and
|
||||
// re-open the local (header) search if one was active here.
|
||||
const y = S._scrollByIdx[S._navCursor] || 0;
|
||||
if(_main) requestAnimationFrame(() => { _main.scrollTop = y; });
|
||||
const hsq = S._hsByIdx[S._navCursor];
|
||||
if(hsq && _hsInput) { _hsInput.value = hsq; onHeaderSearch(hsq); }
|
||||
} else if(_main) {
|
||||
_main.scrollTop = 0;
|
||||
}
|
||||
}
|
||||
closeSidebar();
|
||||
if(['discover','new-releases','recommendations','random'].includes(page)) switchNavMode('discover');
|
||||
else if(['home','artists','albums','starred','playlists'].includes(page)) switchNavMode('library');
|
||||
@@ -133,6 +160,13 @@ export function _navOnPopState(state) {
|
||||
}
|
||||
const idx = (state && typeof state.nsIdx === 'number') ? state.nsIdx : 0;
|
||||
if(idx < 0 || idx >= S._navStack.length) return;
|
||||
// Snapshot the OUTGOING view's scroll + any open local search before we move the cursor.
|
||||
const _main = document.getElementById('main-content');
|
||||
const _hsInput = document.getElementById('header-search-input');
|
||||
S._scrollByIdx = S._scrollByIdx || {};
|
||||
S._hsByIdx = S._hsByIdx || {};
|
||||
if(_main) S._scrollByIdx[S._navCursor] = _main.scrollTop;
|
||||
S._hsByIdx[S._navCursor] = _hsInput?.value?.trim() ? _hsInput.value : '';
|
||||
S._navCursor = idx;
|
||||
const entry = S._navStack[idx];
|
||||
_navSave();
|
||||
|
||||
Reference in new issue
Block a user