feat(web+android): Warteschlange bearbeiten — ziehen und entfernen

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-09-22 20:31:08 +02:00
1 parent 77a3bb33f0
commit d5b5c8cf84
9 files changed
+330 -7

No files matched your search

+43 -2
View File
@@ -3,8 +3,10 @@ import { esc, formatDur, toast } from '../utils.js';
import { api, streamUrl, coverUrl, downloadUrl, dispTitle, dispArtist, dispArtistParts, dispAlbum } from '../api.js';
// views.js/ui.js circular imports — safe (only used inside function bodies)
import { loadRecommendations } from '../views/views.js';
import { updateLyricsHighlight, onNpSongChange, syncNowPlaying } from './nowplaying.js';
import { updateLyricsHighlight, onNpSongChange, syncNowPlaying, renderNpQueue } from './nowplaying.js';
import { logPlay } from './scrobbleLog.js';
import { macheQueueBearbeitbar, QUEUE_WERKZEUGE } from './queueEdit.js';
import { queueNachEntfernen, queueNachVerschieben } from './queueMath.js';
// ─── NATIVE BRIDGE DETECTION ───────────────────────────────────────────────
// True when running inside the NovaSonic Android wrapper (NSBridge injected before loadUrl).
@@ -1187,14 +1189,53 @@ export function renderQueue() {
S.queue.forEach((s, i) => {
const item = document.createElement('div');
item.className = 'queue-item' + (i === S.qIdx ? ' active' : '');
item.dataset.qidx = i;
const cv = coverUrl(s.coverArt, 128);
item.innerHTML = `<div class="qi-idx">${i+1}</div><div class="qi-art">${cv ? `<img src="${cv}">` : '♪'}</div><div class="qi-info"><div class="qi-title">${esc(dispTitle(s))}</div><div class="qi-artist">${esc(dispArtist(s))}</div></div>`;
item.innerHTML = `<div class="qi-idx">${i+1}</div><div class="qi-art">${cv ? `<img src="${cv}">` : '♪'}</div><div class="qi-info"><div class="qi-title">${esc(dispTitle(s))}</div><div class="qi-artist">${esc(dispArtist(s))}</div></div>` + QUEUE_WERKZEUGE;
item.onclick = () => { S.qIdx = i; playCurrent(); };
el.appendChild(item);
});
macheQueueBearbeitbar('queue-list');
el.querySelector('.active')?.scrollIntoView({ block: 'nearest' });
}
// ─── WARTESCHLANGE BEARBEITEN ─────────────────────────────────────────────
// S.queue ist eine einfache Liste, S.qIdx zeigt auf den laufenden Titel. Beim Aendern muss der
// Zeiger mitwandern — sonst spielt nach dem Entfernen eines Titels weiter oben ploetzlich der
// falsche. Gemerkt wird deshalb die ID des laufenden Titels, nicht seine Position.
/** Entfernt den Titel an Position i. Traf es den laufenden, laeuft der naechste an. */
export function queueEntfernen(i) {
if (i < 0 || i >= S.queue.length) return;
const { qIdx, warAktuell } = queueNachEntfernen(S.queue.length, S.qIdx, i);
S.queue.splice(i, 1);
S.qIdx = qIdx;
_renderedQueueKey = '';
if (!S.queue.length) {
S.qIdx = -1;
try { S._audioEls?.forEach(a => { a.pause(); }); } catch {}
setPlayIcon(false);
renderQueue(); renderNpQueue();
toast('Warteschlange geleert');
return;
}
if (warAktuell) playCurrent();
renderQueue(); renderNpQueue();
}
/** Verschiebt den Titel von Position `von` auf Position `nach`. */
export function queueVerschieben(von, nach) {
const n = S.queue.length;
if (von === nach || von < 0 || von >= n || nach < 0 || nach >= n) return;
const { qIdx } = queueNachVerschieben(S.queue.map(x => x.id), S.qIdx, von, nach);
const [titel] = S.queue.splice(von, 1);
S.queue.splice(nach, 0, titel);
S.qIdx = qIdx;
_renderedQueueKey = '';
renderQueue(); renderNpQueue();
}
export function toggleQueue() {
S.queueOpen = !S.queueOpen;
document.getElementById('queue-panel').classList.toggle('open', S.queueOpen);