feat(android): Songs loeschen und Playlist aus dem Import, plus Web-Scrollfix

Android holt zwei Sachen nach, die es im Web laengst gibt:

- Song von der Festplatte loeschen, im Kontextmenue unten abgesetzt und rot, mit
  derselben Sicherheitsabfrage wie im Web. Laeuft ueber /api/delete-song und
  erscheint nur mit konfiguriertem Backend — Navidrome allein loescht nichts.
- Playlist direkt aus dem Import anlegen: Haekchen plus Namensfeld ab zwei
  Titeln, danach Scan anstossen, Titel suchen, Playlist aus den gefundenen.
  Nicht gefundene werden gezaehlt statt die Erstellung scheitern zu lassen.

Dazu der Web-Fix zur Album-Position: die gespeicherte Scrollposition wurde in
genau einem requestAnimationFrame gesetzt. Solange Cover und Eintraege noch
nachluden, war scrollHeight kleiner als das Ziel und der Browser kappte den Wert
stillschweigend — man landete wieder oben. Jetzt wird er ueber bis zu ~0,5 s
erneut gesetzt, bis er sitzt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-09-04 23:40:57 +02:00
1 parent a05c15df93
commit aae358c4c7
12 files changed
+1031 -12

No files matched your search

+16 -1
View File
@@ -59,6 +59,21 @@ export function refreshCurrentView() {
}
}
// Gespeicherte Scrollposition wiederherstellen. Ein einzelner requestAnimationFrame reicht dafuer
// nicht: solange Cover und Listeneintraege noch nachladen, ist scrollHeight kleiner als das Ziel und
// der Browser kappt den gesetzten Wert stillschweigend — man landete dann doch wieder oben. Deshalb
// wird der Wert ueber bis zu ~0,5 s erneut gesetzt, bis er sitzt.
function _restoreScroll(el, y) {
if(!el) return;
if(!y) { el.scrollTop = 0; return; }
let versuche = 0;
const setzen = () => {
el.scrollTop = y;
if(Math.abs(el.scrollTop - y) > 2 && versuche++ < 30) requestAnimationFrame(setzen);
};
requestAnimationFrame(setzen);
}
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
@@ -86,7 +101,7 @@ export function navigate(page, data=null) {
// 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; });
if(_main) _restoreScroll(_main, y);
const hsq = S._hsByIdx[S._navCursor];
if(hsq && _hsInput) { _hsInput.value = hsq; onHeaderSearch(hsq); }
} else if(_main) {