feat(queue): preserve Play Next order toggle (#464)

* feat(queue): add preservePlayNextOrder setting + playNext store action

- New Track.playNextAdded flag (analogous to autoAdded / radioAdded).
  Stale flags behind queueIndex are harmless — only forward streak scan.
- New playerStore action playNext(tracks): tags incoming tracks and
  delegates to enqueueAt for unified undo + server sync.
- New authStore boolean preservePlayNextOrder (default false). When on,
  playNext appends behind the existing Play-Next streak (Spotify-style)
  instead of inserting directly after the current track.

* refactor(context-menu): centralise Play Next; add Settings toggle + i18n

- Replace 3 inline splice/enqueueAt call sites in ContextMenu with the
  new playNext action. Side-benefit: the single-song path now goes
  through enqueueAt and gets undo + queue sync (previously missing).
- Settings → Audio → Playback: new toggle below Gapless.
- 8 locales: preservePlayNextOrder + preservePlayNextOrderDesc.

* docs(contributors): credit + changelog entry for #464
This commit is contained in:
Frank Stellmacher
2026-05-05 22:33:15 +02:00
committed by GitHub
parent e1f2cb4c37
commit 0fab2849e5
13 changed files with 76 additions and 27 deletions
+2
View File
@@ -891,6 +891,8 @@ export const deTranslation = {
notWithCrossfade: 'Nicht verfügbar wenn Crossfade aktiv ist',
gapless: 'Nahtlose Wiedergabe',
gaplessDesc: 'Nächsten Track vorpuffern um Lücken zwischen Songs zu vermeiden',
preservePlayNextOrder: '„Als Nächstes"-Reihenfolge bewahren',
preservePlayNextOrderDesc: 'Neu hinzugefügte „Als Nächstes"-Titel reihen sich hinten an statt sich vorn einzuschieben.',
trackPreviewsTitle: 'Track-Vorschau',
trackPreviewsToggle: 'Track-Vorschau aktivieren',
trackPreviewsDesc: 'Inline Play- und Vorschau-Buttons in den Tracklisten anzeigen für eine kurze Hörprobe mitten im Song.',
+2
View File
@@ -897,6 +897,8 @@ export const enTranslation = {
notWithCrossfade: 'Not available while Crossfade is active',
gapless: 'Gapless Playback',
gaplessDesc: 'Pre-buffer next track to eliminate gaps between songs',
preservePlayNextOrder: 'Preserve "Play Next" order',
preservePlayNextOrderDesc: 'Newly added Play Next items queue up behind earlier ones instead of jumping in front.',
trackPreviewsTitle: 'Track Previews',
trackPreviewsToggle: 'Enable track previews',
trackPreviewsDesc: 'Show inline Play and Preview buttons in tracklists for a quick mid-song sample.',
+2
View File
@@ -884,6 +884,8 @@ export const esTranslation = {
notWithCrossfade: 'No disponible mientras Crossfade está activo',
gapless: 'Reproducción Gapless',
gaplessDesc: 'Precarga siguiente pista para eliminar silencios entre canciones',
preservePlayNextOrder: 'Mantener el orden de "Reproducir Siguiente"',
preservePlayNextOrderDesc: 'Los elementos añadidos a "Reproducir Siguiente" se encolan detrás de los anteriores en vez de saltar al principio.',
trackPreviewsTitle: 'Previsualizaciones de pistas',
trackPreviewsToggle: 'Activar previsualizaciones',
trackPreviewsDesc: 'Mostrar botones de Reproducir y Previsualización en las listas de pistas para una muestra rápida a mitad de canción.',
+2
View File
@@ -879,6 +879,8 @@ export const frTranslation = {
notWithCrossfade: 'Non disponible quand le fondu enchaîné est actif',
gapless: 'Lecture sans blanc',
gaplessDesc: 'Préparer la piste suivante pour éliminer les silences entre les morceaux',
preservePlayNextOrder: "Préserver l'ordre « Lire ensuite »",
preservePlayNextOrderDesc: 'Les nouveaux éléments « Lire ensuite » s\'ajoutent à la fin de la file existante au lieu de la doubler.',
trackPreviewsTitle: 'Aperçus de pistes',
trackPreviewsToggle: 'Activer les aperçus de pistes',
trackPreviewsDesc: 'Affiche les boutons Lecture et Aperçu dans les listes pour un court extrait au milieu du morceau.',
+2
View File
@@ -878,6 +878,8 @@ export const nbTranslation = {
notWithCrossfade: 'Ikke tilgjengelig mens Crossfade er aktiv',
gapless: 'Gapless avspilling',
gaplessDesc: 'Forhåndsbuffer neste spor for å eliminere mellomrom mellom sanger',
preservePlayNextOrder: 'Behold "Spill neste"-rekkefølge',
preservePlayNextOrderDesc: 'Nye "Spill neste"-elementer havner bak de eksisterende i stedet for å snike seg foran.',
trackPreviewsTitle: 'Sporforhåndsvisning',
trackPreviewsToggle: 'Aktiver sporforhåndsvisning',
trackPreviewsDesc: 'Vis innebygde Spill- og Forhåndsvisning-knapper i sporlister for en kort smakebit fra midten av sangen.',
+2
View File
@@ -878,6 +878,8 @@ export const nlTranslation = {
notWithCrossfade: 'Niet beschikbaar als overgang actief is',
gapless: 'Naadloos afspelen',
gaplessDesc: 'Volgend nummer vooraf bufferen om stiltes tussen nummers te elimineren',
preservePlayNextOrder: '"Volgende afspelen"-volgorde behouden',
preservePlayNextOrderDesc: 'Nieuwe "Volgende afspelen"-items komen achter bestaande te staan in plaats van ervoor.',
trackPreviewsTitle: 'Track-voorvertoning',
trackPreviewsToggle: 'Track-voorvertoning inschakelen',
trackPreviewsDesc: 'Inline Play- en Voorvertoning-knoppen in trackslijsten tonen voor een korte sample midden in het nummer.',
+2
View File
@@ -930,6 +930,8 @@ export const ruTranslation = {
notWithCrossfade: 'Недоступно при включённом кроссфейде',
gapless: 'Без пауз между треками',
gaplessDesc: 'Заранее подгружать следующий трек, чтобы не было тишины',
preservePlayNextOrder: 'Сохранять порядок «Играть следующим»',
preservePlayNextOrderDesc: 'Новые элементы «Играть следующим» становятся в конец очереди, а не лезут вперёд.',
trackPreviewsTitle: 'Превью треков',
trackPreviewsToggle: 'Включить превью треков',
trackPreviewsDesc: 'Показывать встроенные кнопки воспроизведения и превью в списках треков для быстрого прослушивания фрагмента.',
+2
View File
@@ -873,6 +873,8 @@ export const zhTranslation = {
notWithCrossfade: '交叉淡入淡出开启时不可用',
gapless: '无缝播放',
gaplessDesc: '预缓冲下一首曲目以消除歌曲间的间隙',
preservePlayNextOrder: '保留"下一首播放"顺序',
preservePlayNextOrderDesc: '新添加的"下一首播放"项目排在现有项目之后,而不是插到前面。',
trackPreviewsTitle: '曲目预览',
trackPreviewsToggle: '启用曲目预览',
trackPreviewsDesc: '在曲目列表中显示内联播放与预览按钮,可快速试听歌曲中段。',