fix: NP flicker, fully-random shuffle, playlist count backpatch
NP overlay flicker (stronger fix): - Remove contain:layout style paint (causes layer issues on some Android WebView) - Add ::before pseudo-element with solid background so no frame can be transparent - Add -webkit-transform prefixes for both open and closed states Shuffle fully random: - playQueue no longer pins startIdx when shuffle is on - All songs shuffled into a completely random order, S.qIdx=0 always - toggleShuffle mid-queue still pins current song first (Spotify toggle behavior) Playlist count wrong in overview: - Navidrome's getPlaylists returns stale/wrong songCount in its index - Add data-pl-id to each playlist card in loadPlaylists - After loadPlaylistDetail gets the accurate entry count, backpatch the matching overview card's subtitle so the grid shows the real song count Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
3c9a8e892a
commit
1d5f4a620d
3 files changed
+16
-9
No files matched your search
+3
-5
@@ -359,13 +359,11 @@ export function playQueue(songs, startIdx) {
|
|||||||
_radioFilling = false; // cancel any in-flight radio fill for the old queue
|
_radioFilling = false; // cancel any in-flight radio fill for the old queue
|
||||||
S._origQueue = null;
|
S._origQueue = null;
|
||||||
_histClear();
|
_histClear();
|
||||||
// Spotify-style shuffle: build a fixed shuffled order once, pin the tapped song first.
|
// Shuffle: fully random order, no pinning — startIdx is ignored.
|
||||||
// Applies to both web and Android — queue is traversed sequentially in this fixed order.
|
// Both web and Android traverse this fixed shuffled order sequentially.
|
||||||
if (S.shuffle && songs.length > 1) {
|
if (S.shuffle && songs.length > 1) {
|
||||||
const start = songs[startIdx];
|
|
||||||
const rest = songs.filter((_, i) => i !== startIdx).sort(() => Math.random() - 0.5);
|
|
||||||
S._origQueue = songs.map(s => ({...s}));
|
S._origQueue = songs.map(s => ({...s}));
|
||||||
S.queue = [start, ...rest].map(s => ({...s}));
|
S.queue = [...songs].sort(() => Math.random() - 0.5).map(s => ({...s}));
|
||||||
S.qIdx = 0;
|
S.qIdx = 0;
|
||||||
} else {
|
} else {
|
||||||
S.queue = songs.map(s => ({...s}));
|
S.queue = songs.map(s => ({...s}));
|
||||||
|
|||||||
@@ -687,6 +687,7 @@ export async function loadPlaylists() {
|
|||||||
lists.forEach(pl => {
|
lists.forEach(pl => {
|
||||||
const cv = coverUrl(pl.coverArt, 512);
|
const cv = coverUrl(pl.coverArt, 512);
|
||||||
const c = makeCard(pl.name, pl.songCount+' Titel', cv, '🎶');
|
const c = makeCard(pl.name, pl.songCount+' Titel', cv, '🎶');
|
||||||
|
c.dataset.plId = pl.id;
|
||||||
c.querySelector('.card-art').onclick = (e) => { e.stopPropagation(); quickPlayPlaylist(pl); };
|
c.querySelector('.card-art').onclick = (e) => { e.stopPropagation(); quickPlayPlaylist(pl); };
|
||||||
c.querySelector('.card-info').onclick = () => navigate('playlist-detail', pl);
|
c.querySelector('.card-info').onclick = () => navigate('playlist-detail', pl);
|
||||||
g.appendChild(c);
|
g.appendChild(c);
|
||||||
@@ -728,6 +729,10 @@ export async function loadPlaylistDetail(pl) {
|
|||||||
const songs = full.entry || [];
|
const songs = full.entry || [];
|
||||||
const totalMin = Math.round(songs.reduce((s,t) => s+(t.duration||0), 0) / 60);
|
const totalMin = Math.round(songs.reduce((s,t) => s+(t.duration||0), 0) / 60);
|
||||||
document.getElementById('playlist-detail-stats').textContent = `${songs.length} Titel · ${totalMin} Min.`;
|
document.getElementById('playlist-detail-stats').textContent = `${songs.length} Titel · ${totalMin} Min.`;
|
||||||
|
// Navidrome's getPlaylists can return a stale songCount — backpatch the overview card
|
||||||
|
// with the real count we just got from getPlaylist so the grid always shows truth.
|
||||||
|
const overviewCard = document.querySelector(`#playlists-grid [data-pl-id="${pl.id}"]`);
|
||||||
|
if (overviewCard) overviewCard.querySelector('.card-sub').textContent = songs.length + ' Titel';
|
||||||
const descEl = document.getElementById('playlist-detail-desc');
|
const descEl = document.getElementById('playlist-detail-desc');
|
||||||
if(descEl) { descEl.textContent = full.comment||''; descEl.style.display = full.comment ? '' : 'none'; }
|
if(descEl) { descEl.textContent = full.comment||''; descEl.style.display = full.comment ? '' : 'none'; }
|
||||||
document.getElementById('btn-play-playlist').onclick = () => playQueue(songs, 0);
|
document.getElementById('btn-play-playlist').onclick = () => playQueue(songs, 0);
|
||||||
|
|||||||
+8
-4
@@ -573,16 +573,20 @@ button:focus{outline:none}
|
|||||||
position:fixed;inset:0;z-index:300;
|
position:fixed;inset:0;z-index:300;
|
||||||
display:flex;flex-direction:column;
|
display:flex;flex-direction:column;
|
||||||
background:var(--bg);
|
background:var(--bg);
|
||||||
/* translate3d keeps the element on a stable GPU layer without will-change's
|
|
||||||
layer-creation/destruction cycle that causes WebView to flash the content below */
|
|
||||||
transform:translate3d(0,100%,0);
|
transform:translate3d(0,100%,0);
|
||||||
|
-webkit-transform:translate3d(0,100%,0);
|
||||||
transition:transform .35s cubic-bezier(.4,0,.2,1);
|
transition:transform .35s cubic-bezier(.4,0,.2,1);
|
||||||
overflow:hidden;
|
overflow:hidden;
|
||||||
backface-visibility:hidden;-webkit-backface-visibility:hidden;
|
backface-visibility:hidden;-webkit-backface-visibility:hidden;
|
||||||
contain:layout style paint;
|
|
||||||
isolation:isolate;
|
isolation:isolate;
|
||||||
}
|
}
|
||||||
.np-overlay.open{transform:translate3d(0,0,0)}
|
/* Solid opaque floor so no frame can ever be transparent to content below */
|
||||||
|
.np-overlay::before{
|
||||||
|
content:'';position:absolute;inset:0;
|
||||||
|
background:var(--bg);z-index:-1;
|
||||||
|
transform:translateZ(0);
|
||||||
|
}
|
||||||
|
.np-overlay.open{transform:translate3d(0,0,0);-webkit-transform:translate3d(0,0,0)}
|
||||||
|
|
||||||
/* Blurred album art as background — two layers for crossfade */
|
/* Blurred album art as background — two layers for crossfade */
|
||||||
.np-bg{
|
.np-bg{
|
||||||
|
|||||||
Reference in new issue
Block a user