[enhancement]: Support toggling Album/Track view for gneres (#591)

* [enhancement]: Support toggling Album/Track view for gneres

The _primary_ purpose of this PR is to enable viewing tracks OR albums for genres.
This has a few requirements:
1. Ability to set default route for genres, **except** when already on song/album page
2. Ability to toggle between album and genre view
3. Fixed refresh for genre ID

Additionally, there was some refactoring:
- Since the *-list-headers had very similar functions for search, export that as a hook instead

* also use hook for album artist

* support switching albumartist tracks/albums

* remove toggle on song/album list, simplify logic
This commit is contained in:
Kendall Garner 2024-04-20 06:14:31 +00:00 committed by GitHub
parent 595eba152a
commit ba531505af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 336 additions and 158 deletions

View file

@ -0,0 +1,68 @@
import { ChangeEvent, MutableRefObject, useCallback } from 'react';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import {
UseHandleListFilterChangeProps,
useListFilterRefresh,
} from '/@/renderer/hooks/use-list-filter-refresh';
import { useListContext } from '/@/renderer/context/list-context';
import { ListDisplayType } from '/@/renderer/types';
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
import { useListStoreActions, useListStoreByKey } from '/@/renderer/store';
export type UseDisplayRefreshProps = {
gridRef: MutableRefObject<VirtualInfiniteGridRef | null>;
tableRef: MutableRefObject<AgGridReactType | null>;
} & UseHandleListFilterChangeProps;
export const useDisplayRefresh = ({
isClientSideSort,
gridRef,
itemType,
server,
tableRef,
}: UseDisplayRefreshProps) => {
const { customFilters, pageKey, handlePlay } = useListContext();
const { display, filter } = useListStoreByKey({ key: pageKey });
const { handleRefreshGrid, handleRefreshTable } = useListFilterRefresh({
isClientSideSort,
itemType,
server,
});
const { setFilter, setTablePagination } = useListStoreActions();
const refresh = useCallback(
(filter: unknown) => {
if (display === ListDisplayType.TABLE || display === ListDisplayType.TABLE_PAGINATED) {
handleRefreshTable(tableRef, filter);
setTablePagination({ data: { currentPage: 0 }, key: pageKey });
} else {
handleRefreshGrid(gridRef, filter);
}
},
[
display,
gridRef,
handleRefreshGrid,
handleRefreshTable,
pageKey,
setTablePagination,
tableRef,
],
);
const search = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
const searchTerm = e.target.value === '' ? undefined : e.target.value;
const updatedFilters = setFilter({
data: { searchTerm },
itemType,
key: pageKey,
});
return updatedFilters;
},
[itemType, pageKey, setFilter],
);
return { customFilters, filter, handlePlay, refresh, search };
};

View file

@ -0,0 +1,29 @@
import { useLocation } from 'react-router';
import { GenreTarget, useSettingsStore } from '/@/renderer/store';
import { AppRoute } from '/@/renderer/router/routes';
import { useMemo } from 'react';
const ALBUM_REGEX = /albums$/;
const SONG_REGEX = /songs$/;
export const useGenreRoute = () => {
const { pathname } = useLocation();
const matchAlbum = ALBUM_REGEX.test(pathname);
const matchSongs = SONG_REGEX.test(pathname);
const baseState = useSettingsStore((state) =>
state.general.genreTarget === GenreTarget.ALBUM
? AppRoute.LIBRARY_GENRES_ALBUMS
: AppRoute.LIBRARY_GENRES_SONGS,
);
return useMemo(() => {
if (matchAlbum) {
return AppRoute.LIBRARY_GENRES_ALBUMS;
}
if (matchSongs) {
return AppRoute.LIBRARY_GENRES_SONGS;
}
return baseState;
}, [baseState, matchAlbum, matchSongs]);
};

View file

@ -8,7 +8,7 @@ import { BasePaginatedResponse, LibraryItem, ServerListItem } from '/@/renderer/
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
import orderBy from 'lodash/orderBy';
interface UseHandleListFilterChangeProps {
export interface UseHandleListFilterChangeProps {
isClientSideSort?: boolean;
itemType: LibraryItem;
server: ServerListItem | null;