v2.49.5 — Play-Next verschiebt statt zu duplizieren + Shuffle-Priorität

## Fix (Code-Review Finding 3, MED)
- spieleAlsNaechstes: Song bereits in der Queue wird an Position nach dem
  aktuellen VERSCHOBEN (inkl. _aktuellerIndex-Anpassung), keine Kopie mehr
- Shuffle: keine Neu-Mischung nach Play-Next — Song wird via
  _pinneInShuffleReihenfolge an die nächste Position gepinnt (Index-
  Korrektur für Verschiebungen, _shufflePos-Nachführung am Reihenende)
- 3 Tests ergänzt: Verschieben statt Duplizieren, Song von vor dem
  aktuellen, Shuffle-Pin (kein Duplikat + naechsterIndex == gepinnter Song)
This commit is contained in:
Dustin
2026-08-04 16:47:29 +02:00
parent bd692d4682
commit 8e9d9efc64
2 changed files with 123 additions and 5 deletions
+92 -5
View File
@@ -277,17 +277,104 @@ class PlayerService extends ChangeNotifier {
/// Index des aktuell spielenden Songs in der Warteschlange.
int get aktuellerIndex => _aktuellerIndex;
/// Fügt [song] direkt nach dem aktuellen Song ein.
/// Setzt [song] als nächstes auf die Wiedergabe — direkt nach dem aktuellen
/// Song. Ist der Song bereits in der Warteschlange, wird er dorthin VERSCHOBEN
/// statt dupliziert. Im Shuffle wird die Reihenfolge nicht neu gemischt:
/// der Song wird an die nächste Position gepinnt (Play-Next hat Priorität).
void spieleAlsNaechstes(Song song) {
if (_aktuellerIndex < 0 || _warteschlange.isEmpty) {
if (_warteschlange.isEmpty) {
_warteschlange.add(song);
} else {
_warteschlange.insert(_aktuellerIndex + 1, song);
if (_zufallsmodus) _baueShuffleReihenfolge();
notifyListeners();
return;
}
if (_aktuellerIndex < 0) {
// Kein aktiver Song → ans Ende hängen
final vorhanden = _warteschlange.indexWhere((s) => s.id == song.id);
if (vorhanden < 0) _warteschlange.add(song);
if (_zufallsmodus) _baueShuffleReihenfolge();
notifyListeners();
return;
}
final ziel = _aktuellerIndex + 1;
final vorhandenerIndex = _warteschlange.indexWhere((s) => s.id == song.id);
var gepinnt = -1;
var alterIndex = -1;
var einfuegePosition = -1;
var queueGeaendert = false;
if (vorhandenerIndex >= 0 && vorhandenerIndex != _aktuellerIndex) {
// Bereits in der Queue → verschieben statt duplizieren
if (vorhandenerIndex != ziel) {
alterIndex = vorhandenerIndex;
final item = _warteschlange.removeAt(vorhandenerIndex);
einfuegePosition = vorhandenerIndex < ziel ? ziel - 1 : ziel;
_warteschlange.insert(einfuegePosition, item);
if (vorhandenerIndex < _aktuellerIndex) _aktuellerIndex -= 1;
gepinnt = einfuegePosition;
queueGeaendert = true;
} else {
gepinnt = vorhandenerIndex; // steht schon direkt nach dem aktuellen
}
} else if (vorhandenerIndex < 0) {
einfuegePosition = ziel;
_warteschlange.insert(ziel, song);
gepinnt = ziel;
queueGeaendert = true;
}
// vorhandenerIndex == _aktuellerIndex → Song läuft gerade, nichts zu tun
if (_zufallsmodus && gepinnt >= 0) {
_pinneInShuffleReihenfolge(
gepinnt: gepinnt,
alterIndex: alterIndex,
einfuegePosition: einfuegePosition,
queueGeaendert: queueGeaendert,
);
}
if (_zufallsmodus) _baueShuffleReihenfolge();
notifyListeners();
}
/// Korrigiert [_shuffleReihenfolge] nach einer Queue-Änderung und pinnt
/// [gepinnt] (neuer Queue-Index des Songs) als nächstes.
void _pinneInShuffleReihenfolge({
required int gepinnt,
required int alterIndex,
required int einfuegePosition,
required bool queueGeaendert,
}) {
if (queueGeaendert) {
// 1) Entfernung spiegeln (alter Index war evtl. noch in der Reihenfolge)
final entferntPos = alterIndex >= 0
? _shuffleReihenfolge.indexOf(alterIndex)
: -1;
if (entferntPos >= 0) {
_shuffleReihenfolge.removeAt(entferntPos);
if (entferntPos < _shufflePos) _shufflePos -= 1;
for (var k = 0; k < _shuffleReihenfolge.length; k++) {
if (_shuffleReihenfolge[k] > alterIndex) {
_shuffleReihenfolge[k] -= 1;
}
}
}
// 2) Einfügung spiegeln (Indizes ab der Einfügeposition rücken nach rechts)
for (var k = 0; k < _shuffleReihenfolge.length; k++) {
if (_shuffleReihenfolge[k] >= einfuegePosition) {
_shuffleReihenfolge[k] += 1;
}
}
}
// 3) Song an die Position direkt nach dem aktuellen pinnten
_shuffleReihenfolge.remove(gepinnt);
final pinPos = _shufflePos + 1 > _shuffleReihenfolge.length
? _shuffleReihenfolge.length
: _shufflePos + 1;
_shuffleReihenfolge.insert(pinPos, gepinnt);
// _shufflePos so setzen, dass der gepinnte Song als nächstes gespielt wird
_shufflePos = pinPos - 1;
}
/// Hängt [song] ans Ende der Warteschlange an.
void amEndeHinzufuegen(Song song) {
_warteschlange.add(song);