v2.49.6 — Async-Exceptions abgesichert (kein Crash bei nicht-seekbaren Quellen)

## Fix (Code-Review Finding 4, MED)
- PlayerService.play/playPause/pause/seek: try/catch mit MeloLogger —
  schützt ALLE Aufrufer (Buttons, Listener, System-Controls)
- naechstes: Repeat-Titel-Zweig (seek+play) try/catch — Live-Streams ohne
  Seek-Unterstützung crashen nicht mehr
- vorheriges: kompletter Ablauf try/catch (Seek-Pfad + Songwechsel)
- NowPlayingScreen: Lyrics-Tap + Slider-Seek laufen über die abgesicherte
  seek()-Methode — keine unhandled async Exceptions aus Fire-and-Forget
This commit is contained in:
Dustin
2026-08-04 16:47:58 +02:00
parent 8e9d9efc64
commit 69b8f29f88
+58 -26
View File
@@ -160,59 +160,91 @@ class PlayerService extends ChangeNotifier {
Future<void> playPause() async {
if (_player == null) return;
if (_p.playing) {
await _p.pause();
} else if (aktuellerSong != null) {
await _p.play();
try {
if (_p.playing) {
await _p.pause();
} else if (aktuellerSong != null) {
await _p.play();
}
} catch (e) {
debugPrint('Play/Pause fehlgeschlagen: $e');
MeloLogger().fehler('player_playpause', e);
}
}
/// Explizit abspielen (kein Toggle) — für System-Controls (Bluetooth, etc.)
Future<void> play() async {
if (_player == null || aktuellerSong == null) return;
await _p.play();
try {
await _p.play();
} catch (e) {
debugPrint('Play fehlgeschlagen: $e');
MeloLogger().fehler('player_play', e);
}
}
/// Explizit pausieren (kein Toggle) — für System-Controls (Bluetooth, etc.)
Future<void> pause() async {
if (_player == null) return;
await _p.pause();
try {
await _p.pause();
} catch (e) {
debugPrint('Pause fehlgeschlagen: $e');
MeloLogger().fehler('player_pause', e);
}
}
/// Nur seeken ohne Reload der Quelle
Future<void> seek(Duration position) async {
if (_player == null) return;
await _p.seek(position);
try {
await _p.seek(position);
} catch (e) {
// Live-Streams ohne Seek-Unterstützung werfen hier — nicht crashen
debugPrint('Seek fehlgeschlagen: $e');
MeloLogger().fehler('player_seek', e);
}
}
Future<void> vorheriges() async {
if (_player == null || aktuellerSong == null) return;
final pos = _p.position;
if (pos.inSeconds > 5) {
await _p.seek(Duration.zero);
return;
}
if (_zufallsmodus && _shuffleReihenfolge.isNotEmpty) {
_shufflePos--;
if (_shufflePos < 0) _shufflePos = 0;
final idx = _shuffleReihenfolge[_shufflePos];
if (idx >= 0 && idx < _warteschlange.length) {
await spiele(_warteschlange[idx]);
try {
final pos = _p.position;
if (pos.inSeconds > 5) {
await _p.seek(Duration.zero);
return;
}
return;
}
final neuerIndex = _aktuellerIndex - 1;
if (neuerIndex >= 0) {
await spiele(_warteschlange[neuerIndex]);
if (_zufallsmodus && _shuffleReihenfolge.isNotEmpty) {
_shufflePos--;
if (_shufflePos < 0) _shufflePos = 0;
final idx = _shuffleReihenfolge[_shufflePos];
if (idx >= 0 && idx < _warteschlange.length) {
await spiele(_warteschlange[idx]);
}
return;
}
final neuerIndex = _aktuellerIndex - 1;
if (neuerIndex >= 0) {
await spiele(_warteschlange[neuerIndex]);
}
} catch (e) {
debugPrint('Vorheriger Song fehlgeschlagen: $e');
MeloLogger().fehler('player_vorheriges', e);
}
}
Future<void> naechstes() async {
if (_player == null || aktuellerSong == null) return;
if (_wiederholmodus == Wiederholmodus.titel) {
// Gleichen Song von vorn wiederholen
await _p.seek(Duration.zero);
await _p.play();
// Gleichen Song von vorn wiederholen — seek/play können bei nicht
// seekbaren Quellen (Live-Streams) werfen, daher abgesichert.
try {
await _p.seek(Duration.zero);
await _p.play();
} catch (e) {
debugPrint('Repeat-Titel fehlgeschlagen: $e');
MeloLogger().fehler('player_repeat_titel', e);
}
return;
}
final idx = naechsterIndex();