Album-Ansicht, mitlaufender Songtext, Cover-Cache, Server-Favoriten

Die letzten vier Punkte aus dem Review-Bericht.

G2 — Server-Bereich: Ein Tipp auf ein Album spielte sofort alles ab;
hineinsehen ging nicht. Jetzt Album- und Kuenstler-Ansicht mit Cover,
Kuenstler, Titelzahl, Gesamtdauer, "Abspielen"/"Zufaellig" und der
Titelliste; Antippen startet an dieser Stelle. Dazu "Mehr Alben laden" —
die Liste hoerte bei 50 auf, ohne dass etwas darauf hinwies.
NICHT umgesetzt: den Server-Bereich aus dem Download-Tab loesen (das
widerspricht Commit 34d6d8e, "Auf Wunsch von Dustin") und eine
Server-Suche (die Suche bleibt ausdruecklich rein lokal).

G8 — Songtext: Traegt der Text Zeitmarken, laeuft er mit; die aktive Zeile
ist hervorgehoben, Antippen springt an die Stelle. Ohne Zeitmarken bleibt
es eine Textwand — die App schaut nach, statt zu raten.

G10 — Cover bleiben liegen. Eigener Ordner, einmal geholt. Der Schluessel
haengt an der Album-Kennung, nicht an der Adresse: die traegt bei jedem
App-Start ein neues Token, und der Ordner waere sonst gewachsen, ohne je
einen Treffer zu liefern. Keine neue Abhaengigkeit.

G3 — Das Herz ist bei Server-Titeln nicht mehr ausgegraut, sondern
favorisiert am Server (star/unstar) — dort, wo der Favoriten-Abgleich sie
auch wieder abholt. Offen bleibt der schwere Teil: Wiedergabezaehler,
Historie und Kategorien braeuchten fuer Server-Titel eine Zeile in der
Bibliothek.

Aus dem Code-Review nachgebessert (sieben Punkte): das Herz behielt beim
Titelwechsel seinen Zustand; recycelte Listenzeilen zeigten kurz das Cover
der vorherigen; der neue Songtext bekam bei Server-Titeln die
Abspiel-Adresse statt der Server-Kennung und fand deshalb nie einen Text;
ein einmal fehlgeschlagenes Cover blieb die ganze Sitzung grau; "Server
nicht erreichbar" sah aus wie "Album hat keine Titel", womit der
Wiederholen-Knopf unerreichbar war; die Kuenstler-Ansicht waere immer leer
geblieben, weil getArtist die Titel gar nicht mitliefert; und zwei
gleichzeitige Cover-Abrufe konnten ein zerschnittenes Bild hinterlassen.

Selbst gefunden: das Haekchen "schon geladen" fragte pro Zeile die Platte
ab, bei jedem Positionswechsel neu. Jetzt einmal je Bildschirm.

457 Tests gruen (vorher 433), flutter analyze ohne Befund, Release-APK
gebaut.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xAHJTJM6UUqmjUgk1PUEd
This commit is contained in:
Hermes (Server)
2026-08-23 21:53:31 +02:00
co-authored by Claude Opus 5
parent b42e045e67
commit 0d76d8cc58
16 changed files with 1194 additions and 142 deletions
+42
View File
@@ -0,0 +1,42 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:melo/services/cover_cache.dart';
/// Der Schlüssel entscheidet, ob der Cover-Ordner je einen Treffer liefert.
void main() {
Uri cover(String id, {String token = 'abc', String salt = 'xyz'}) =>
Uri.parse('https://musik.example/rest/getCoverArt.view'
'?id=$id&u=dustin&t=$token&s=$salt&v=1.16.1&c=Melo&f=json');
group('dateiName', () {
test('dasselbe Cover ergibt denselben Namen', () {
expect(CoverCache.dateiName(cover('al-7')),
CoverCache.dateiName(cover('al-7')));
});
test('Token und Salt ändern den Namen nicht', () {
// Beides wird bei jedem App-Start neu gewürfelt. Flösse es ein, wäre
// dasselbe Bild jedes Mal ein anderer Eintrag — der Ordner wüchse,
// ohne je einen Treffer zu liefern.
expect(
CoverCache.dateiName(cover('al-7', token: 'aaa', salt: 'bbb')),
CoverCache.dateiName(cover('al-7', token: 'ccc', salt: 'ddd')),
);
});
test('verschiedene Cover ergeben verschiedene Namen', () {
expect(CoverCache.dateiName(cover('al-7')),
isNot(CoverCache.dateiName(cover('al-8'))));
});
test('eine Adresse ohne id fällt auf den Pfad zurück', () {
expect(
CoverCache.dateiName(Uri.parse('https://musik.example/bild.jpg')),
isNot(CoverCache.dateiName(Uri.parse('https://musik.example/x.jpg'))),
);
});
test('endet auf .img', () {
expect(CoverCache.dateiName(cover('al-7')), endsWith('.img'));
});
});
}