Restore the playing playlist when returning to Now Playing
This commit is contained in:
@@ -7126,6 +7126,7 @@ const SectionRail = (() => {
|
||||
const el = elOf(sec);
|
||||
if (!el) return;
|
||||
flashLabel(btn);
|
||||
if (sec.id === 'player' || sec.id === 'meta') restoreNowPlayingList();
|
||||
if (st.active === sec.id && sec.fold) {
|
||||
// Already here: this is the second tap — fold or unfold the card.
|
||||
setFolded(sec.id, !isFolded(sec.id));
|
||||
@@ -8048,6 +8049,27 @@ function playQueue(index = 0) {
|
||||
playFromList(data.queue.slice(), index, 'queue');
|
||||
}
|
||||
|
||||
// Browsing replaces the shared list pane independently of the playing queue.
|
||||
// Rebuild it whenever the player is revealed, including when home-over was
|
||||
// already false: merely removing that class leaves Search's hidden pane stale.
|
||||
function restoreNowPlayingList({ remember = true } = {}) {
|
||||
if (!current?.meta) return;
|
||||
if (remember && !history.state?.ytpNowPlaying) {
|
||||
history.replaceState({ ...history.state, ytpBrowseView: view, ytpHomeOver: els.playerPane.classList.contains('home-over') }, '', location.href);
|
||||
history.pushState({ ...history.state, ytpNowPlaying: true, ytpSettingsSection: null }, '', location.href);
|
||||
}
|
||||
setHomeOverPlayer(false);
|
||||
els.playerPane.classList.remove('empty');
|
||||
els.placeholder.classList.add('hidden');
|
||||
const playlistId = queueSource.startsWith('playlist:') ? queueSource.slice(9) : null;
|
||||
view = playlistId && data.playlists.some(p => p.id === playlistId)
|
||||
? { type: 'playlist', id: playlistId }
|
||||
: { type: 'nowPlaying' };
|
||||
_lastViewKey = [view.type, view.id, view.smartType].join('|');
|
||||
render();
|
||||
renderUpNext();
|
||||
}
|
||||
|
||||
function renderUpNext() {
|
||||
updateServiceUpNext();
|
||||
Remote.changed();
|
||||
@@ -8664,6 +8686,7 @@ function updateHomeGridScrollState() {
|
||||
}
|
||||
|
||||
function currentList() {
|
||||
if (view.type === 'nowPlaying') return queue;
|
||||
if (view.type === 'search') return searchResults;
|
||||
if (view.type === 'history') return data.history;
|
||||
if (view.type === 'queue') return data.queue;
|
||||
@@ -8758,7 +8781,7 @@ function renderList() {
|
||||
if (view.type === 'library') { renderLibrary(); return; }
|
||||
|
||||
// Filter bar — show for filterable views
|
||||
const filterableViews = ['history', 'playlist', 'queue', 'channel', 'smart'];
|
||||
const filterableViews = ['history', 'playlist', 'queue', 'channel', 'smart', 'nowPlaying'];
|
||||
const showFilter = filterableViews.includes(view.type);
|
||||
$('listFilterBar').classList.toggle('hidden', !showFilter);
|
||||
$('batchBar').classList.toggle('hidden', !selectMode);
|
||||
@@ -8782,7 +8805,9 @@ function renderList() {
|
||||
Recommendations.inList();
|
||||
}
|
||||
|
||||
if (view.type === 'search') {
|
||||
if (view.type === 'nowPlaying') {
|
||||
els.listTitle.textContent = 'Now playing';
|
||||
} else if (view.type === 'search') {
|
||||
els.listTitle.textContent = 'Search results';
|
||||
} else if (view.type === 'history') {
|
||||
els.listTitle.textContent = 'History';
|
||||
@@ -10096,7 +10121,7 @@ function renderCard(v, index, list) {
|
||||
card.addEventListener('click', (e) => {
|
||||
if (e.target.closest('.card-menu') || e.target.closest('.card-del') || e.target.closest('.card-note-btn') || e.target.closest('.card-channel.link')) return;
|
||||
if (selectMode) { toggleSelectCard(v.id); return; }
|
||||
playFromList(list, index, view.type === 'playlist' ? 'playlist:' + view.id : view.type);
|
||||
playFromList(list, index, view.type === 'playlist' ? 'playlist:' + view.id : view.type === 'nowPlaying' ? queueSource : view.type);
|
||||
});
|
||||
card.querySelector('.card-menu').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
@@ -10175,8 +10200,28 @@ function markPlayingCard() {
|
||||
});
|
||||
}
|
||||
|
||||
// Only entries created by returning to the player participate here; leave
|
||||
// unrelated history (including Settings section navigation) to its owner.
|
||||
window.addEventListener('popstate', event => {
|
||||
const state = event.state;
|
||||
if (state?.ytpSettingsSection) return;
|
||||
if (state?.ytpNowPlaying) {
|
||||
restoreNowPlayingList({ remember: false });
|
||||
if (isStackedPlayerLayout()) document.querySelector('.body')?.scrollTo({ top: 0 });
|
||||
}
|
||||
else if (state?.ytpBrowseView) {
|
||||
view = state.ytpBrowseView;
|
||||
setHomeOverPlayer(!!state.ytpHomeOver);
|
||||
render();
|
||||
}
|
||||
});
|
||||
|
||||
let _lastViewKey = null;
|
||||
function render() {
|
||||
const key = [view.type, view.id, view.smartType].join('|');
|
||||
if (history.state?.ytpNowPlaying && _lastViewKey !== null && key !== _lastViewKey) {
|
||||
history.pushState({ ...history.state, ytpNowPlaying: false, ytpBrowseView: view, ytpHomeOver: els.playerPane.classList.contains('home-over'), ytpSettingsSection: null }, '', location.href);
|
||||
}
|
||||
listFilter = '';
|
||||
const fi = $('listFilterInput');
|
||||
if (fi) fi.value = '';
|
||||
@@ -10845,6 +10890,7 @@ function applyPortraitPwaClass() {
|
||||
// In portrait mode, .body is the single scroll container (player pane on top,
|
||||
// list pane below). Scrolling it to 0 brings the player fully into view.
|
||||
function scrollPlayerIntoViewPortrait() {
|
||||
restoreNowPlayingList();
|
||||
if (!isStackedPlayerLayout()) return;
|
||||
const body = document.querySelector('.body');
|
||||
if (body) {
|
||||
@@ -11484,14 +11530,16 @@ document.querySelectorAll('.chip').forEach((c) => {
|
||||
$('updateIconBtn').addEventListener('click', updateFromIcon);
|
||||
$('chBadge').addEventListener('click', (e) => { e.stopPropagation(); Notes.openChapterPicker(); });
|
||||
$('miniBar').addEventListener('click', () => {
|
||||
setHomeOverPlayer(false);
|
||||
hideMiniBar();
|
||||
// Scroll the player into view if needed. In portrait PWA, scroll only the
|
||||
// .body pane (the designated scroll container) — scrollIntoView() also
|
||||
// scrolls overflow:hidden ancestors up to <html> on iOS, leaving the
|
||||
// document offset and fixed-element hit testing broken.
|
||||
if (isStackedPlayerLayout()) scrollPlayerIntoViewPortrait();
|
||||
else els.playerPane.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
else {
|
||||
restoreNowPlayingList();
|
||||
els.playerPane.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
});
|
||||
// Opens the set-list view for whatever is already playing. No playlist arg,
|
||||
// so enterServiceMode leaves the live queue and position untouched.
|
||||
@@ -11500,7 +11548,7 @@ document.querySelectorAll('.chip').forEach((c) => {
|
||||
enterServiceMode();
|
||||
});
|
||||
// On the home screen the mini bar is the way back, so ✕ returns to the player.
|
||||
$('miniCloseBtn').addEventListener('click', (e) => { e.stopPropagation(); setHomeOverPlayer(false); hideMiniBar(); });
|
||||
$('miniCloseBtn').addEventListener('click', (e) => { e.stopPropagation(); restoreNowPlayingList(); hideMiniBar(); });
|
||||
|
||||
// Drag-to-reorder: prevent default on cards container
|
||||
els.cards.addEventListener('dragover', (e) => {
|
||||
|
||||
Reference in New Issue
Block a user