Files
Melo/lib/shared/server_favorite_button.dart
T
Hermes (Server)andClaude Opus 5 0d76d8cc58 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
2026-08-23 21:53:31 +02:00

73 lines
2.3 KiB
Dart

import 'package:flutter/material.dart';
import '../services/navidrome_service.dart';
import 'theme.dart';
/// Herz für einen Titel, der nur am Server liegt.
///
/// Solche Titel haben keine Zeile in der Bibliothek und damit keine UUID —
/// das gewöhnliche [FavoriteButton] muss sie deshalb ablehnen. Der Server
/// führt aber eine eigene Favoritenliste (`star`/`unstar`), und die ist
/// genau der richtige Ort dafür: von dort holt sie auch der
/// Favoriten-Abgleich in den Einstellungen.
///
/// Der Zustand wird bewusst nur lokal gehalten und nicht vom Server
/// nachgeladen: für ein einzelnes Herz wäre eine eigene Abfrage bei jedem
/// Titelwechsel zu teuer, und die Antwort träfe ohnehin erst nach dem
/// nächsten Tippen ein.
class ServerFavoriteButton extends StatefulWidget {
const ServerFavoriteButton({
super.key,
required this.navidromeId,
required this.navidrome,
});
final String navidromeId;
final NavidromeService navidrome;
@override
State<ServerFavoriteButton> createState() => _ServerFavoriteButtonState();
}
class _ServerFavoriteButtonState extends State<ServerFavoriteButton> {
bool? _favorit;
bool _laeuft = false;
Future<void> _umschalten() async {
if (_laeuft) return;
final neu = !(_favorit ?? false);
setState(() => _laeuft = true);
final messenger = ScaffoldMessenger.of(context);
final ok = neu
? await widget.navidrome.setFavorite(widget.navidromeId)
: await widget.navidrome.removeFavorite(widget.navidromeId);
if (!mounted) return;
setState(() {
_laeuft = false;
// Nur bei Erfolg umschalten — sonst zeigte das Herz einen Zustand, den
// der Server nicht kennt.
if (ok) _favorit = neu;
});
if (!ok) {
messenger.showSnackBar(
const SnackBar(content: Text('Der Server hat es nicht übernommen')),
);
}
}
@override
Widget build(BuildContext context) {
final favorit = _favorit ?? false;
return IconButton(
tooltip: favorit
? 'Favorit am Server entfernen'
: 'Am Server zu Favoriten hinzufügen',
icon: Icon(
favorit ? Icons.favorite : Icons.favorite_border,
color: favorit ? MeloTheme.red : MeloTheme.text2,
),
onPressed: _laeuft ? null : _umschalten,
);
}
}