From d0edd925e487f411f9c0d81652063b2621bb6c20 Mon Sep 17 00:00:00 2001 From: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com> Date: Mon, 13 Jul 2026 21:29:46 +0200 Subject: [PATCH] feat(player-bar): configurable stop button, album line and reorderable actions (#1287) * feat(player-bar): configurable stop button, album line and reorderable actions Extends the existing player-bar layout store instead of adding a second one. - 'stop' becomes a layout item, so the stop button can be hidden. It lives in a 'transport' zone: visibility only, no reordering -- the play button is a centred special case and shuffling controls around it would fight the adaptive small-window layout. Hiding it leaves no dead end, since the primary button already acts as stop while previewing. - Track info gains an optional album line under the artist, off by default and suppressed for radio and previews, which have no album. - The right-hand action buttons are drag-reorderable via the shared useListReorderDnd primitive. Moves resolve by stable id against the full list, so the zone filter that decides which rows render cannot desync the reorder. - The section is no longer gated behind Advanced. Rehydrate keeps older stored layouts working: items added later ('stop') are appended with their default instead of silently disappearing. * i18n(settings): player bar constructor strings in all 14 locales * docs(changelog): add entry and credit for PR #1287 --- CHANGELOG.md | 7 ++ src/config/settingsCredits.ts | 1 + .../components/playerBar/PlayerTrackInfo.tsx | 13 +++ .../playerBar/PlayerTransportControls.tsx | 38 ++++--- .../store/playerBarLayoutStore.test.ts | 90 +++++++++++++-- .../playback/store/playerBarLayoutStore.ts | 47 +++++++- .../components/PersonalisationTab.tsx | 1 - .../components/PlayerBarLayoutCustomizer.tsx | 103 +++++++++++++++--- src/locales/bg/settings.ts | 6 + src/locales/de/settings.ts | 6 + src/locales/en/settings.ts | 6 + src/locales/es/settings.ts | 6 + src/locales/fr/settings.ts | 6 + src/locales/hu/settings.ts | 6 + src/locales/it/settings.ts | 6 + src/locales/ja/settings.ts | 6 + src/locales/nb/settings.ts | 6 + src/locales/nl/settings.ts | 6 + src/locales/pl/settings.ts | 6 + src/locales/ro/settings.ts | 6 + src/locales/ru/settings.ts | 6 + src/locales/zh/settings.ts | 6 + src/styles/layout/player-bar.css | 9 ++ 23 files changed, 352 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34024b84..9a6e3128 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -142,6 +142,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * While a Navidrome public share queue is active, **Save Playlist** is hidden in the queue toolbar (share tracks cannot be saved to the server). **Load Playlist** stays available. * The queue **Share** button copies the original Navidrome `/share/{id}` page URL instead of a Psysonic magic-string queue payload. +### Player bar — build your own + +**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#1287](https://github.com/Psychotoxical/psysonic/pull/1287)** + +* **Settings → Personalisation → Player bar** now also hides the **stop button** and shows the **album name** under the artist (off by default; clicking it opens the album). The right-hand buttons — star rating, favorite, love, playback speed, equalizer, mini player — can be **dragged into any order** you like. +* The section is no longer behind **Advanced**. + ## Fixed ### Per-track covers when playing from a playlist diff --git a/src/config/settingsCredits.ts b/src/config/settingsCredits.ts index 1e4b7cf6..1bb41076 100644 --- a/src/config/settingsCredits.ts +++ b/src/config/settingsCredits.ts @@ -202,6 +202,7 @@ const CONTRIBUTOR_ENTRIES = [ 'Windows MSI bundle on dev/RC versions — numeric WiX mapping; album easter-egg import chunk (PR #1278)', 'Track lists — optional album cover thumbnails via standard cover pipeline; queue rows use playback scope (PR #1280)', 'Internet Radio — Web Audio EQ on HTML5 streams; presets apply without reconnect (PR #1284)', + 'Player bar — hideable stop button, optional album line, drag-reorderable action buttons (request: mikmik on Psysonic Discord, PR #1287)', ], }, { diff --git a/src/features/playback/components/playerBar/PlayerTrackInfo.tsx b/src/features/playback/components/playerBar/PlayerTrackInfo.tsx index 947671dd..ab31be43 100644 --- a/src/features/playback/components/playerBar/PlayerTrackInfo.tsx +++ b/src/features/playback/components/playerBar/PlayerTrackInfo.tsx @@ -73,6 +73,11 @@ export function PlayerTrackInfo({ const layoutItems = usePlayerBarLayoutStore(s => s.items); const isLayoutVisible = (id: PlayerBarLayoutItemId) => layoutItems.find(i => i.id === id)?.visible !== false; + const trackInfoMode = usePlayerBarLayoutStore(s => s.trackInfoMode); + // Radio has no album, and a preview shows the previewed track's own meta. + const albumLine = trackInfoMode === 'titleAlbum' && !isRadio && !showPreviewMeta + ? currentTrack?.album + : undefined; const offlineBrowseActive = useOfflineBrowseContext().active; const playerPolicy = offlineActionPolicy('playerBar', offlineBrowseActive); @@ -177,6 +182,14 @@ export function PlayerTrackInfo({ onClick={() => !isRadio && !showPreviewMeta && currentTrack?.artistId && navigate(`/artist/${currentTrack.artistId}`)} /> )} + {albumLine && ( + currentTrack?.albumId && navigate(`/album/${currentTrack.albumId}`)} + /> + )} {currentTrack && !isRadio && !showPreviewMeta && isLayoutVisible('starRating') && playerPolicy.canRate && ( ['playPauseBind']; @@ -36,24 +37,31 @@ export function PlayerTransportControls({ const autodjPhase = useAutodjTransitionUi(s => s.phase); const showAutodjTransition = isPlaying && !isPreviewing && scheduleRemaining == null && autodjPhase === 'mixing'; + // Hiding Stop leaves no dead end: while previewing, the primary button already + // renders as a stop control and ends the preview. + const showStop = usePlayerBarLayoutStore( + s => s.items.find(i => i.id === 'stop')?.visible !== false, + ); return (
- + {showStop && ( + + )}