v2.54.2 — Review-Fixes (Graph): Shuffle-Duplikat bei Einzel-Song+Repeat, Speed-Chip 1.75x, Drag-Race, Speed-Tap-Guard, Version

This commit is contained in:
Dustin
2026-08-05 21:04:18 +02:00
parent 5f7b652eb6
commit 70a79520d0
4 changed files with 52 additions and 13 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Logger startet sofort zeichnet ALLES auf
MeloLogger().init('2.54');
MeloLogger().init('2.54.1');
// ── Notifications initialisieren (Issue #9) ──
const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher');
+34 -12
View File
@@ -92,6 +92,9 @@ class _NowPlayingScreenState extends State<NowPlayingScreen>
_zeigeLyrics = false;
_lyrics = null;
_lyricsLaden = true;
// Drag-Position zurücksetzen: Sonst seekt onChangeEnd den NEUEN
// Song auf die alte Position des vorherigen Songs (Race).
_dragPosition = null;
// Cover-Zustand SYNCHRON zurücksetzen: Sonst rendern Hintergrund
// (und Front-Cover) beim Songwechsel kurz das ALTE Cover, bis die
// async Existenz-Prüfung durch ist — der Switcher-Key (song.id)
@@ -1015,24 +1018,43 @@ class _NowPlayingScreenState extends State<NowPlayingScreen>
}
/// Gängige Geschwindigkeitsstufen — Tipp im Fullscreen wechselt durch.
/// Muss mit dem Settings-Slider (0.25er-Schritte) übereinstimmen, sonst
/// springt indexOf(-1) auf 1.0 (Reset) statt zur nächsten Stufe.
static const List<double> _geschwindigkeiten = [
0.5, 0.75, 1.0, 1.25, 1.5, 2.0,
0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0,
];
bool _speedTapLaeuft = false; // In-Flight-Guard gegen Doppel-Tap-Race
Future<void> _naechsteGeschwindigkeit() async {
final aktuell = _player.geschwindigkeit;
final idx = _geschwindigkeiten.indexOf(aktuell);
final neu = idx >= 0
? _geschwindigkeiten[(idx + 1) % _geschwindigkeiten.length]
: 1.0;
// Wie in den Einstellungen persistieren, damit die Wahl erhalten bleibt
if (_speedTapLaeuft) return;
_speedTapLaeuft = true;
try {
final p = await SharedPreferences.getInstance();
await p.setDouble('playback_speed', neu);
} catch (e) {
debugPrint('Geschwindigkeit persistieren fehlgeschlagen: $e');
final aktuell = _player.geschwindigkeit;
var idx = _geschwindigkeiten.indexOf(aktuell);
if (idx < 0) {
// Wert außerhalb der Liste (z.B. 1.75 vor dem Fix): nächste
// höhere Stufe nehmen, sonst letzte
idx = _geschwindigkeiten.length - 1;
for (var i = 0; i < _geschwindigkeiten.length; i++) {
if (_geschwindigkeiten[i] > aktuell) {
idx = i;
break;
}
}
}
final neu = _geschwindigkeiten[(idx + 1) % _geschwindigkeiten.length];
// Wie in den Einstellungen persistieren, damit die Wahl erhalten bleibt
try {
final p = await SharedPreferences.getInstance();
await p.setDouble('playback_speed', neu);
} catch (e) {
debugPrint('Geschwindigkeit persistieren fehlgeschlagen: $e');
}
await _player.setGeschwindigkeit(neu);
} finally {
_speedTapLaeuft = false;
}
await _player.setGeschwindigkeit(neu);
}
String _formatZeit(Duration d) {
+3
View File
@@ -358,6 +358,9 @@ class PlayerService extends ChangeNotifier {
final start = _shufflePos >= 0 ? _shufflePos + 1 : 0;
for (var i = start; i < _shuffleReihenfolge.length; i++) {
final idx = _shuffleReihenfolge[i];
// Duplikat vermeiden: den laufenden Song überspringen, wenn er in
// der Shuffle-Reihenfolge auftaucht (Einzel-Song + Repeat-playlist)
if (idx == _aktuellerIndex) continue;
if (idx >= 0 && idx < _warteschlange.length) {
ergebnis.add(_warteschlange[idx]);
}
+14
View File
@@ -250,6 +250,20 @@ void main() {
expect(p.wiedergabeReihenfolge.map((s) => s.id).toList(), [1]);
});
test('shuffle + Repeat-playlist + Einzel-Song-Queue: KEIN Duplikat', () {
final p = PlayerService();
p.setWarteschlange([_song(1, 'A')]);
p.setZufallsmodus(true);
p.setWiederholmodus(Wiederholmodus.playlist);
// _shufflePos == -1 (Shuffle gerade eingeschaltet): der laufende Song
// wird separat gelistet — darf NICHT zusätzlich aus der
// Shuffle-Reihenfolge kommen (Regression: [A, A])
final reihenfolge = p.wiedergabeReihenfolge.map((s) => s.id).toList();
expect(reihenfolge, [1]);
expect(reihenfolge.toSet().length, reihenfolge.length,
reason: 'Keine Duplikate in der Wiedergabe-Reihenfolge');
});
test('verschieben (normal): ändert Wiedergabe-Reihenfolge und Queue', () {
final p = PlayerService();
p.setWarteschlange(