feat(player): Lyrics-Anzeige + Shuffle/Repeat Buttons

LYRICS:
- Lyrics-Button im Now-Playing Screen (📝 Icon)
- Bottom-Sheet mit Lyrics vom Server (getLyrics() API)
- Fallback: 'Keine Lyrics verfügbar'
- Lyrics-Klasse für Datenmodell

SHUFFLE/REPEAT:
- Shuffle-Button (schon implementiert!) zeigt aktiven Status rot
- Repeat-Button (Off → All → One → Off cycle)
- Beide via AudioHandler.setShuffleMode() / setRepeatMode()
- Integration in _Controls (Player-UI)

Phase 1 P1-Features jetzt funktionsfähig!
Tests: 70/70 
This commit is contained in:
Hermes (Server)
2026-08-19 18:49:34 +02:00
parent 0c39b0aa73
commit 0e5b346f68
2 changed files with 128 additions and 3 deletions
+27
View File
@@ -251,6 +251,19 @@ class NavidromeService {
return [];
}
}
Future<Lyrics> getLyrics(String songId) async {
try {
final r = await http.get(_uri('getLyrics.view', {'id': songId})).timeout(const Duration(seconds: 10));
if (r.statusCode != 200) return Lyrics.empty();
final data = jsonDecode(r.body);
final lyrics = data['subsonic-response']?['lyrics']?['value'] as String?;
return Lyrics.fromText(lyrics);
} catch (e) {
debugPrint('Navidrome getLyrics Fehler: $e');
return Lyrics.empty();
}
}
}
class SubsonicArtist {
@@ -267,3 +280,17 @@ class SubsonicArtist {
name: j['name'] as String? ?? 'Unbekannt',
);
}
class Lyrics {
final String? text;
final bool isEmpty;
const Lyrics({
this.text,
this.isEmpty = true,
});
factory Lyrics.empty() => const Lyrics(isEmpty: true);
factory Lyrics.fromText(String? text) =>
Lyrics(text: text, isEmpty: text?.isEmpty ?? true);
}