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:
+1
-1
@@ -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');
|
||||
|
||||
@@ -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,16 +1018,32 @@ 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 {
|
||||
if (_speedTapLaeuft) return;
|
||||
_speedTapLaeuft = true;
|
||||
try {
|
||||
final aktuell = _player.geschwindigkeit;
|
||||
final idx = _geschwindigkeiten.indexOf(aktuell);
|
||||
final neu = idx >= 0
|
||||
? _geschwindigkeiten[(idx + 1) % _geschwindigkeiten.length]
|
||||
: 1.0;
|
||||
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();
|
||||
@@ -1033,6 +1052,9 @@ class _NowPlayingScreenState extends State<NowPlayingScreen>
|
||||
debugPrint('Geschwindigkeit persistieren fehlgeschlagen: $e');
|
||||
}
|
||||
await _player.setGeschwindigkeit(neu);
|
||||
} finally {
|
||||
_speedTapLaeuft = false;
|
||||
}
|
||||
}
|
||||
|
||||
String _formatZeit(Duration d) {
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user