feat(player): Wiedergabeposition merken und beim Laden fortsetzen

- MeloAudioHandler bekommt MeloDb per Konstruktor injiziert
- Positions-Timer (alle 5s) schreibt db.recordPlayback(songId, positionMs)
  während aktiv abgespielt wird (songId aus mediaItem.extras['songId'])
- loadPlaylist liest db.lastPosition() für den Start-Song und seekt vor
  dem play() an die gespeicherte Position, statt immer von vorne zu starten
- shouldResumeAt() als reine, testbare Funktion extrahiert: kein Resume bei
  Position 0 oder innerhalb der letzten 3s einer bekannten Track-Dauer
- dispose() zum gefahrlosen Abbrechen des Positions-Timers in Tests ohne
  vollen App-Lifecycle (super.stop() lässt sich in Widget-Tests wegen der
  aktiven playbackState-Pipe nicht gefahrlos aufrufen)
- library_screen_test.dart: MeloAudioHandler-Konstruktion angepasst (db
  jetzt Pflichtparameter) + handler.dispose() im Teardown

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Hermes (Server)
2026-08-18 18:17:26 +02:00
co-authored by Claude Haiku 4.5
parent 09dd4a4367
commit edc93224b0
4 changed files with 79 additions and 5 deletions
+26
View File
@@ -0,0 +1,26 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:melo/player/audio_handler.dart';
void main() {
group('shouldResumeAt', () {
test('kein Resume bei Position 0', () {
expect(shouldResumeAt(0, const Duration(minutes: 3)), false);
});
test('kein Resume innerhalb der letzten 3 Sekunden einer bekannten Dauer', () {
final duration = const Duration(minutes: 3);
final lastPositionMs = duration.inMilliseconds - 2000; // 2s vor Ende
expect(shouldResumeAt(lastPositionMs, duration), false);
});
test('Resume bei Position deutlich vor dem Ende', () {
final duration = const Duration(minutes: 3);
final lastPositionMs = duration.inMilliseconds - 60000; // 1min vor Ende
expect(shouldResumeAt(lastPositionMs, duration), true);
});
test('Resume bei unbekannter Dauer (null) und Position > 0', () {
expect(shouldResumeAt(45000, null), true);
});
});
}