Allow navigating directly to playlist song view
This commit is contained in:
parent
d64040f3f0
commit
3dcb0dc4ed
6 changed files with 58 additions and 13 deletions
|
@ -225,6 +225,13 @@ export const PLAYLIST_CARD_ROWS: { [key: string]: CardRow<Playlist> } = {
|
||||||
slugs: [{ idProperty: 'id', slugProperty: 'playlistId' }],
|
slugs: [{ idProperty: 'id', slugProperty: 'playlistId' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
nameFull: {
|
||||||
|
property: 'name',
|
||||||
|
route: {
|
||||||
|
route: AppRoute.PLAYLISTS_DETAIL_SONGS,
|
||||||
|
slugs: [{ idProperty: 'id', slugProperty: 'playlistId' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
owner: {
|
owner: {
|
||||||
property: 'owner',
|
property: 'owner',
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
import { usePlayQueueAdd } from '/@/renderer/features/player';
|
import { usePlayQueueAdd } from '/@/renderer/features/player';
|
||||||
import { useCreateFavorite, useDeleteFavorite } from '/@/renderer/features/shared';
|
import { useCreateFavorite, useDeleteFavorite } from '/@/renderer/features/shared';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useCurrentServer, usePlaylistListStore } from '/@/renderer/store';
|
import { useCurrentServer, useGeneralSettings, usePlaylistListStore } from '/@/renderer/store';
|
||||||
import { CardRow, ListDisplayType } from '/@/renderer/types';
|
import { CardRow, ListDisplayType } from '/@/renderer/types';
|
||||||
|
|
||||||
interface PlaylistListGridViewProps {
|
interface PlaylistListGridViewProps {
|
||||||
|
@ -31,6 +31,7 @@ export const PlaylistListGridView = ({ gridRef, itemCount }: PlaylistListGridVie
|
||||||
const grid = usePlaylistGridStore();
|
const grid = usePlaylistGridStore();
|
||||||
const { setGrid } = usePlaylistStoreActions();
|
const { setGrid } = usePlaylistStoreActions();
|
||||||
const page = usePlaylistListStore();
|
const page = usePlaylistListStore();
|
||||||
|
const { defaultFullPlaylist } = useGeneralSettings();
|
||||||
|
|
||||||
const createFavoriteMutation = useCreateFavorite({});
|
const createFavoriteMutation = useCreateFavorite({});
|
||||||
const deleteFavoriteMutation = useDeleteFavorite({});
|
const deleteFavoriteMutation = useDeleteFavorite({});
|
||||||
|
@ -61,7 +62,9 @@ export const PlaylistListGridView = ({ gridRef, itemCount }: PlaylistListGridVie
|
||||||
};
|
};
|
||||||
|
|
||||||
const cardRows = useMemo(() => {
|
const cardRows = useMemo(() => {
|
||||||
const rows: CardRow<Playlist>[] = [PLAYLIST_CARD_ROWS.name];
|
const rows: CardRow<Playlist>[] = defaultFullPlaylist
|
||||||
|
? [PLAYLIST_CARD_ROWS.nameFull]
|
||||||
|
: [PLAYLIST_CARD_ROWS.name];
|
||||||
|
|
||||||
switch (page.filter.sortBy) {
|
switch (page.filter.sortBy) {
|
||||||
case PlaylistListSort.DURATION:
|
case PlaylistListSort.DURATION:
|
||||||
|
@ -84,7 +87,7 @@ export const PlaylistListGridView = ({ gridRef, itemCount }: PlaylistListGridVie
|
||||||
}
|
}
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}, [page.filter.sortBy]);
|
}, [defaultFullPlaylist, page.filter.sortBy]);
|
||||||
|
|
||||||
const handleGridScroll = useCallback(
|
const handleGridScroll = useCallback(
|
||||||
(e: ListOnScrollProps) => {
|
(e: ListOnScrollProps) => {
|
||||||
|
@ -144,7 +147,9 @@ export const PlaylistListGridView = ({ gridRef, itemCount }: PlaylistListGridVie
|
||||||
loading={itemCount === undefined || itemCount === null}
|
loading={itemCount === undefined || itemCount === null}
|
||||||
minimumBatchSize={40}
|
minimumBatchSize={40}
|
||||||
route={{
|
route={{
|
||||||
route: AppRoute.PLAYLISTS_DETAIL,
|
route: defaultFullPlaylist
|
||||||
|
? AppRoute.PLAYLISTS_DETAIL_SONGS
|
||||||
|
: AppRoute.PLAYLISTS_DETAIL,
|
||||||
slugs: [{ idProperty: 'id', slugProperty: 'playlistId' }],
|
slugs: [{ idProperty: 'id', slugProperty: 'playlistId' }],
|
||||||
}}
|
}}
|
||||||
width={width}
|
width={width}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import {
|
||||||
useSetPlaylistTable,
|
useSetPlaylistTable,
|
||||||
useCurrentServer,
|
useCurrentServer,
|
||||||
usePlaylistListStore,
|
usePlaylistListStore,
|
||||||
|
useGeneralSettings,
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import { ListDisplayType } from '/@/renderer/types';
|
import { ListDisplayType } from '/@/renderer/types';
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ export const PlaylistListTableView = ({ tableRef, itemCount }: PlaylistListTable
|
||||||
const pagination = usePlaylistTablePagination();
|
const pagination = usePlaylistTablePagination();
|
||||||
const setPagination = useSetPlaylistTablePagination();
|
const setPagination = useSetPlaylistTablePagination();
|
||||||
const setTable = useSetPlaylistTable();
|
const setTable = useSetPlaylistTable();
|
||||||
|
const { defaultFullPlaylist } = useGeneralSettings();
|
||||||
|
|
||||||
const isPaginationEnabled = page.display === ListDisplayType.TABLE_PAGINATED;
|
const isPaginationEnabled = page.display === ListDisplayType.TABLE_PAGINATED;
|
||||||
|
|
||||||
|
@ -171,7 +173,11 @@ export const PlaylistListTableView = ({ tableRef, itemCount }: PlaylistListTable
|
||||||
|
|
||||||
const handleRowDoubleClick = (e: RowDoubleClickedEvent) => {
|
const handleRowDoubleClick = (e: RowDoubleClickedEvent) => {
|
||||||
if (!e.data) return;
|
if (!e.data) return;
|
||||||
navigate(generatePath(AppRoute.PLAYLISTS_DETAIL, { playlistId: e.data.id }));
|
if (defaultFullPlaylist) {
|
||||||
|
navigate(generatePath(AppRoute.PLAYLISTS_DETAIL_SONGS, { playlistId: e.data.id }));
|
||||||
|
} else {
|
||||||
|
navigate(generatePath(AppRoute.PLAYLISTS_DETAIL, { playlistId: e.data.id }));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -195,6 +195,26 @@ export const ControlSettings = () => {
|
||||||
isHidden: !isElectron(),
|
isHidden: !isElectron(),
|
||||||
title: 'Save play queue',
|
title: 'Save play queue',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
control: (
|
||||||
|
<Switch
|
||||||
|
aria-label="Go to playlist songs page by default"
|
||||||
|
defaultChecked={settings.defaultFullPlaylist}
|
||||||
|
onChange={(e) =>
|
||||||
|
setSettings({
|
||||||
|
general: {
|
||||||
|
...settings,
|
||||||
|
defaultFullPlaylist: e.currentTarget.checked,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description:
|
||||||
|
'When navigating to a playlist, go to the playlist song list page instead of the default page',
|
||||||
|
isHidden: false,
|
||||||
|
title: 'Go to playlist songs page by default',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return <SettingsSection options={controlOptions} />;
|
return <SettingsSection options={controlOptions} />;
|
||||||
|
|
|
@ -13,12 +13,21 @@ import { Play } from '/@/renderer/types';
|
||||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||||
import { FixedSizeList, ListChildComponentProps } from 'react-window';
|
import { FixedSizeList, ListChildComponentProps } from 'react-window';
|
||||||
import { useHideScrollbar } from '/@/renderer/hooks';
|
import { useHideScrollbar } from '/@/renderer/hooks';
|
||||||
|
import { useGeneralSettings } from '/@/renderer/store';
|
||||||
|
|
||||||
interface SidebarPlaylistListProps {
|
interface SidebarPlaylistListProps {
|
||||||
data: ReturnType<typeof usePlaylistList>['data'];
|
data: ReturnType<typeof usePlaylistList>['data'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlaylistRow = ({ index, data, style }: ListChildComponentProps) => {
|
const PlaylistRow = ({ index, data, style }: ListChildComponentProps) => {
|
||||||
|
const path = data?.items[index].id
|
||||||
|
? data.defaultFullPlaylist
|
||||||
|
? generatePath(AppRoute.PLAYLISTS_DETAIL_SONGS, { playlistId: data.items[index].id })
|
||||||
|
: generatePath(AppRoute.PLAYLISTS_DETAIL, {
|
||||||
|
playlistId: data?.items[index].id,
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ margin: '0.5rem 0', padding: '0 1.5rem', ...style }}>
|
<div style={{ margin: '0.5rem 0', padding: '0 1.5rem', ...style }}>
|
||||||
<Group
|
<Group
|
||||||
|
@ -47,13 +56,7 @@ const PlaylistRow = ({ index, data, style }: ListChildComponentProps) => {
|
||||||
cursor: 'default',
|
cursor: 'default',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
to={
|
to={path}
|
||||||
data?.items[index].id
|
|
||||||
? generatePath(AppRoute.PLAYLISTS_DETAIL, {
|
|
||||||
playlistId: data?.items[index].id,
|
|
||||||
})
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{data?.items[index].name}
|
{data?.items[index].name}
|
||||||
</Text>
|
</Text>
|
||||||
|
@ -110,6 +113,7 @@ const PlaylistRow = ({ index, data, style }: ListChildComponentProps) => {
|
||||||
export const SidebarPlaylistList = ({ data }: SidebarPlaylistListProps) => {
|
export const SidebarPlaylistList = ({ data }: SidebarPlaylistListProps) => {
|
||||||
const { isScrollbarHidden, hideScrollbarElementProps } = useHideScrollbar(0);
|
const { isScrollbarHidden, hideScrollbarElementProps } = useHideScrollbar(0);
|
||||||
const handlePlayQueueAdd = usePlayQueueAdd();
|
const handlePlayQueueAdd = usePlayQueueAdd();
|
||||||
|
const { defaultFullPlaylist } = useGeneralSettings();
|
||||||
|
|
||||||
const [rect, setRect] = useState({
|
const [rect, setRect] = useState({
|
||||||
height: 0,
|
height: 0,
|
||||||
|
@ -133,10 +137,11 @@ export const SidebarPlaylistList = ({ data }: SidebarPlaylistListProps) => {
|
||||||
|
|
||||||
const memoizedItemData = useMemo(() => {
|
const memoizedItemData = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
|
defaultFullPlaylist,
|
||||||
handlePlay: handlePlayPlaylist,
|
handlePlay: handlePlayPlaylist,
|
||||||
items: data?.items,
|
items: data?.items,
|
||||||
};
|
};
|
||||||
}, [data?.items, handlePlayPlaylist]);
|
}, [data?.items, defaultFullPlaylist, handlePlayPlaylist]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
|
|
|
@ -103,6 +103,7 @@ export enum BindingActions {
|
||||||
|
|
||||||
export interface SettingsState {
|
export interface SettingsState {
|
||||||
general: {
|
general: {
|
||||||
|
defaultFullPlaylist: boolean;
|
||||||
followSystemTheme: boolean;
|
followSystemTheme: boolean;
|
||||||
fontContent: string;
|
fontContent: string;
|
||||||
playButtonBehavior: Play;
|
playButtonBehavior: Play;
|
||||||
|
@ -183,6 +184,7 @@ const platformDefaultWindowBarStyle: Platform = getPlatformDefaultWindowBarStyle
|
||||||
|
|
||||||
const initialState: SettingsState = {
|
const initialState: SettingsState = {
|
||||||
general: {
|
general: {
|
||||||
|
defaultFullPlaylist: false,
|
||||||
followSystemTheme: false,
|
followSystemTheme: false,
|
||||||
fontContent: 'Poppins',
|
fontContent: 'Poppins',
|
||||||
playButtonBehavior: Play.NOW,
|
playButtonBehavior: Play.NOW,
|
||||||
|
|
Reference in a new issue