From ae2e123a1427725538902d91be1362b2371bc12f Mon Sep 17 00:00:00 2001 From: ImAsra <34755744+ImAsra@users.noreply.github.com> Date: Thu, 28 May 2026 22:59:49 +0200 Subject: [PATCH] feat: add long press to shuffle with a wave animation (#888) * feat: add long press to shuffle with a wave animation to singnify how long to press * refactor: long-press shuffle cleanup Follow-up on the long-press shuffle PR: shared hook/overlay, playback parity, pointer events, broader surface coverage, locales, and tests. * docs: credit ImAsra for long-press album shuffle (PR #888) Add CHANGELOG entry and Settings credits for the hold-to-shuffle play interaction shipped in Psychotoxical/psysonic#888. * fix: restore playAlbumShuffled and long-press hook wiring The follow-up merge dropped playAlbumShuffled and reverted the shared long-press hook in album play buttons, breaking tsc and vitest on PR #888. --------- Co-authored-by: cucadmuh <49571317+cucadmuh@users.noreply.github.com> --- CHANGELOG.md | 9 + src/components/AlbumCard.tsx | 29 +-- src/components/BecauseYouLikeRail.tsx | 23 ++- src/components/Hero.tsx | 40 +++-- src/components/LongPressWaveOverlay.tsx | 20 +++ src/config/settingsCredits.ts | 7 + src/hooks/useLongPressAction.test.ts | 108 ++++++++++++ src/hooks/useLongPressAction.ts | 91 ++++++++++ src/locales/de/hero.ts | 1 + src/locales/en/hero.ts | 1 + src/locales/es/hero.ts | 1 + src/locales/fr/hero.ts | 1 + src/locales/nb/hero.ts | 1 + src/locales/nl/hero.ts | 1 + src/locales/ro/hero.ts | 1 + src/locales/ru/hero.ts | 1 + src/locales/zh/hero.ts | 1 + src/pages/MostPlayed.tsx | 38 ++-- src/styles/components/album-row-container.css | 73 ++++++++ src/utils/playback/playAlbum.test.ts | 165 ++++++++++++++++++ src/utils/playback/playAlbum.ts | 17 +- 21 files changed, 585 insertions(+), 44 deletions(-) create mode 100644 src/components/LongPressWaveOverlay.tsx create mode 100644 src/hooks/useLongPressAction.test.ts create mode 100644 src/hooks/useLongPressAction.ts create mode 100644 src/utils/playback/playAlbum.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 3059d0a2..9e0871e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -142,6 +142,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 +### Album play — hold to shuffle + +**By [@ImAsra](https://github.com/ImAsra), PR [#888](https://github.com/Psychotoxical/psysonic/pull/888)** + +* Hold an album **Play** button (~1 s) for a filling wave animation, then the album starts in shuffled order; a short click still plays in track order. +* Album cards, hero, Because-you-like rail, and Most Played; tooltip in all locales. + + + ## Changed ### Linux — session GDK, WebKitGTK mitigations, and Wayland text diff --git a/src/components/AlbumCard.tsx b/src/components/AlbumCard.tsx index 5ddc2a97..1141b35f 100644 --- a/src/components/AlbumCard.tsx +++ b/src/components/AlbumCard.tsx @@ -16,7 +16,9 @@ import { COVER_DENSE_GRID_MIN_CELL_CSS_PX } from '../cover/layoutSizes'; import { resolveCoverDisplayTier } from '../cover/tiers'; import { acquireUrl } from '../utils/imageCache/urlPool'; import { OpenArtistRefInline } from './OpenArtistRefInline'; -import { playAlbum } from '../utils/playback/playAlbum'; +import { playAlbum, playAlbumShuffled } from '../utils/playback/playAlbum'; +import { useLongPressAction } from '../hooks/useLongPressAction'; +import { LongPressWaveOverlay } from './LongPressWaveOverlay'; import { useDragDrop } from '../contexts/DragDropContext'; import { isAlbumRecentlyAdded } from '../utils/albumRecency'; import { deriveAlbumArtistRefs } from '../utils/album/deriveAlbumHeaderArtistRefs'; @@ -59,6 +61,10 @@ function AlbumCard({ libraryResolve = false, }: AlbumCardProps) { const { t } = useTranslation(); + const { isHolding, pressBind } = useLongPressAction({ + onShortPress: () => playAlbum(album.id), + onLongPress: () => playAlbumShuffled(album.id), + }); const navigate = useNavigate(); const openContextMenu = usePlayerStore(s => s.openContextMenu); const enqueue = usePlayerStore(s => s.enqueue); @@ -157,15 +163,18 @@ function AlbumCard({ )} {!selectionMode && (
- + + + ); +} + export default function MostPlayed() { const { t } = useTranslation(); @@ -230,15 +256,7 @@ export default function MostPlayed() {
- +