feat(library): play all and shuffle all on every track list
Four pages that list tracks — Tracks, genre, artist, and both playlist views — had no way to start the whole list, or had a broken one. One shared helper (utils/play-all.ts) now owns what "shuffle this collection" means: SetQueue's shuffleStart only picks a random first track when shuffle mode is already on, it does not turn it on, so the mode is toggled before the queue is set. Each host passes an honest queue Source (#14): anything that builds a queue names what it built it from, so "Playing from" stops lying. Two behaviour changes ride along, both flagged: smart-playlist-details' Shuffle was a live no-op (shuffleStart without enabling mode played track 1 in order) and is fixed; playlist-details' Play all drops its shuffleStart:true, so with shuffle mode already on it now starts at the first row instead of a random one — the album page's existing semantics. Verified: make ui-test (1147, incl. a case that fails when the smart-playlist fix is reverted), npx tsc --noEmit, make e2e (255, incl. new play-all and header-fit specs), make lint, make test, make bindings-check, make css-check; artist header read from screenshots at 424/320/900 (the pair wraps below the name on a phone). Closes #31
This commit is contained in:
@@ -26,7 +26,10 @@ import type { ContextMenuHost, MenuTarget } from '@utils/context-menu-controller
|
||||
import { PlayerController } from '@store/controllers/player-controller';
|
||||
import { SearchController } from '@store/controllers/search-controller';
|
||||
import '@components/page-header/page-header';
|
||||
import type { SortOption } from '@components/page-header/page-header';
|
||||
import type {
|
||||
SortOption,
|
||||
PageAction,
|
||||
} from '@components/page-header/page-header';
|
||||
import { TrackListController } from '@store/controllers/tracklist-controller';
|
||||
import { FavoritesController } from '@store/controllers/favorites-controller';
|
||||
import { queueStore } from '@store/queue-store';
|
||||
@@ -87,7 +90,9 @@ import {
|
||||
ICON_PLAYLIST,
|
||||
ICON_PLAY_NEXT,
|
||||
ICON_QUEUE,
|
||||
ICON_SHUFFLE,
|
||||
} from '@utils/icon-language';
|
||||
import { playAll } from '@utils/play-all';
|
||||
|
||||
const COLUMN_STORAGE_KEY = 'track-list-column-widths';
|
||||
const SORT_FIELD_KEY = 'track-list-sort-field';
|
||||
@@ -2393,6 +2398,27 @@ export class TrackList
|
||||
.map((c) => ({ id: c.id, label: c.label })),
|
||||
];
|
||||
|
||||
const hasTracks = this.cachedSortedTracks.length > 0;
|
||||
|
||||
const actions: PageAction[] = [
|
||||
{
|
||||
id: 'play-all',
|
||||
label: 'Play all',
|
||||
icon: ICON_PLAY,
|
||||
priority: 1,
|
||||
disabled: !hasTracks,
|
||||
onSelect: this.handlePlayAll,
|
||||
},
|
||||
{
|
||||
id: 'shuffle-all',
|
||||
label: 'Shuffle all',
|
||||
icon: ICON_SHUFFLE,
|
||||
priority: 0,
|
||||
disabled: !hasTracks,
|
||||
onSelect: this.handleShuffleAll,
|
||||
},
|
||||
];
|
||||
|
||||
return html`
|
||||
<page-header
|
||||
heading=${this.externalTracks === undefined ? 'Tracks' : ''}
|
||||
@@ -2404,11 +2430,29 @@ export class TrackList
|
||||
sort-field=${this.sortField ?? ''}
|
||||
sort-direction=${this.sortDirection}
|
||||
search-term=${this.searchCtrl.term}
|
||||
.actions=${actions}
|
||||
@sort-change=${this.onPageHeaderSort}
|
||||
></page-header>
|
||||
`;
|
||||
}
|
||||
|
||||
/** The queue is the list as displayed, in the order the user sees. */
|
||||
private handlePlayAll = (): void => {
|
||||
playAll(
|
||||
this.cachedSortedTracks.map((t) => t.FilePath),
|
||||
this.effectiveQueueSource,
|
||||
false,
|
||||
);
|
||||
};
|
||||
|
||||
private handleShuffleAll = (): void => {
|
||||
playAll(
|
||||
this.cachedSortedTracks.map((t) => t.FilePath),
|
||||
this.effectiveQueueSource,
|
||||
true,
|
||||
);
|
||||
};
|
||||
|
||||
private onPageHeaderSort = (
|
||||
e: CustomEvent<{ field: string; direction: 'asc' | 'desc' }>,
|
||||
) => {
|
||||
|
||||
Reference in New Issue
Block a user