diff --git a/src/renderer/features/albums/components/album-list-content.tsx b/src/renderer/features/albums/components/album-list-content.tsx
index 33d0a893..c82d1891 100644
--- a/src/renderer/features/albums/components/album-list-content.tsx
+++ b/src/renderer/features/albums/components/album-list-content.tsx
@@ -2,8 +2,8 @@ import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/li
import { lazy, MutableRefObject, Suspense } from 'react';
import { Spinner } from '/@/renderer/components';
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
-import { useAlbumListContext } from '/@/renderer/features/albums/context/album-list-context';
-import { useAlbumListStore } from '/@/renderer/store';
+import { useListContext } from '/@/renderer/context/list-context';
+import { useListStoreByKey } from '/@/renderer/store';
import { ListDisplayType } from '/@/renderer/types';
const AlbumListGridView = lazy(() =>
@@ -25,8 +25,8 @@ interface AlbumListContentProps {
}
export const AlbumListContent = ({ itemCount, gridRef, tableRef }: AlbumListContentProps) => {
- const { id, pageKey } = useAlbumListContext();
- const { display } = useAlbumListStore({ id, key: pageKey });
+ const { pageKey } = useListContext();
+ const { display } = useListStoreByKey({ key: pageKey });
return (
}>
diff --git a/src/renderer/features/albums/components/album-list-grid-view.tsx b/src/renderer/features/albums/components/album-list-grid-view.tsx
index 6a574569..414369d7 100644
--- a/src/renderer/features/albums/components/album-list-grid-view.tsx
+++ b/src/renderer/features/albums/components/album-list-grid-view.tsx
@@ -1,35 +1,35 @@
+import { QueryKey, useQueryClient } from '@tanstack/react-query';
import { useCallback, useMemo } from 'react';
-import { useQueryClient } from '@tanstack/react-query';
import AutoSizer from 'react-virtualized-auto-sizer';
import { ListOnScrollProps } from 'react-window';
import { controller } from '/@/renderer/api/controller';
-import { queryKeys } from '/@/renderer/api/query-keys';
-import { Album, AlbumListQuery, AlbumListSort, LibraryItem } from '/@/renderer/api/types';
+import { queryKeys, splitPaginatedQuery } from '/@/renderer/api/query-keys';
+import {
+ Album,
+ AlbumListQuery,
+ AlbumListResponse,
+ AlbumListSort,
+ LibraryItem,
+} from '/@/renderer/api/types';
import { ALBUM_CARD_ROWS } from '/@/renderer/components';
import {
VirtualGridAutoSizerContainer,
VirtualInfiniteGrid,
} from '/@/renderer/components/virtual-grid';
-import { useAlbumListContext } from '/@/renderer/features/albums/context/album-list-context';
+import { useListContext } from '/@/renderer/context/list-context';
import { usePlayQueueAdd } from '/@/renderer/features/player';
-import { AppRoute } from '/@/renderer/router/routes';
-import {
- useAlbumListFilter,
- useAlbumListStore,
- useCurrentServer,
- useListStoreActions,
-} from '/@/renderer/store';
-import { CardRow, ListDisplayType } from '/@/renderer/types';
import { useCreateFavorite, useDeleteFavorite } from '/@/renderer/features/shared';
+import { AppRoute } from '/@/renderer/router/routes';
+import { useCurrentServer, useListStoreActions, useListStoreByKey } from '/@/renderer/store';
+import { CardRow, ListDisplayType } from '/@/renderer/types';
export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
const queryClient = useQueryClient();
const server = useCurrentServer();
const handlePlayQueueAdd = usePlayQueueAdd();
- const { id, pageKey } = useAlbumListContext();
- const { grid, display } = useAlbumListStore({ id, key: pageKey });
+ const { pageKey, customFilters } = useListContext();
+ const { grid, display, filter } = useListStoreByKey({ key: pageKey });
const { setGrid } = useListStoreActions();
- const filter = useAlbumListFilter({ id, key: pageKey });
const createFavoriteMutation = useCreateFavorite({});
const deleteFavoriteMutation = useDeleteFavorite({});
@@ -129,27 +129,56 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
[pageKey, setGrid],
);
+ const fetchInitialData = useCallback(() => {
+ const query: Omit = {
+ ...filter,
+ ...customFilters,
+ };
+
+ const queriesFromCache: [QueryKey, AlbumListResponse][] = queryClient.getQueriesData({
+ exact: false,
+ fetchStatus: 'idle',
+ queryKey: queryKeys.albums.list(server?.id || '', query),
+ stale: false,
+ });
+
+ const itemData = [];
+
+ for (const [, data] of queriesFromCache) {
+ const { items, startIndex } = data || {};
+
+ if (items && startIndex !== undefined) {
+ let itemIndex = 0;
+ for (
+ let rowIndex = startIndex;
+ rowIndex < startIndex + items.length;
+ rowIndex += 1
+ ) {
+ itemData[rowIndex] = items[itemIndex];
+ itemIndex += 1;
+ }
+ }
+ }
+
+ return itemData;
+ }, [customFilters, filter, queryClient, server?.id]);
+
const fetch = useCallback(
async ({ skip, take }: { skip: number; take: number }) => {
if (!server) {
return [];
}
- const query: AlbumListQuery = {
+ const listQuery: AlbumListQuery = {
limit: take,
startIndex: skip,
...filter,
- _custom: {
- jellyfin: {
- ...filter._custom?.jellyfin,
- },
- navidrome: {
- ...filter._custom?.navidrome,
- },
- },
+ ...customFilters,
};
- const queryKey = queryKeys.albums.list(server?.id || '', query);
+ const { query, pagination } = splitPaginatedQuery(listQuery);
+
+ const queryKey = queryKeys.albums.list(server?.id || '', query, pagination);
const albums = await queryClient.fetchQuery(queryKey, async ({ signal }) =>
controller.getAlbumList({
@@ -157,13 +186,13 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
server,
signal,
},
- query,
+ query: listQuery,
}),
);
return albums;
},
- [filter, queryClient, server],
+ [customFilters, filter, queryClient, server],
);
return (
@@ -176,6 +205,7 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
cardRows={cardRows}
display={display || ListDisplayType.CARD}
fetchFn={fetch}
+ fetchInitialData={fetchInitialData}
handleFavorite={handleFavorite}
handlePlayQueueAdd={handlePlayQueueAdd}
height={height}
diff --git a/src/renderer/features/albums/components/album-list-header-filters.tsx b/src/renderer/features/albums/components/album-list-header-filters.tsx
index be4f61be..651e62a9 100644
--- a/src/renderer/features/albums/components/album-list-header-filters.tsx
+++ b/src/renderer/features/albums/components/album-list-header-filters.tsx
@@ -1,38 +1,36 @@
-import { MutableRefObject, useCallback, MouseEvent, ChangeEvent, useMemo } from 'react';
-import { IDatasource } from '@ag-grid-community/core';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { Divider, Flex, Group, Stack } from '@mantine/core';
import { openModal } from '@mantine/modals';
import { useQueryClient } from '@tanstack/react-query';
+import { ChangeEvent, MouseEvent, MutableRefObject, useCallback, useMemo } from 'react';
import {
+ RiAddBoxFill,
+ RiAddCircleFill,
+ RiFilterFill,
RiFolder2Line,
RiMoreFill,
- RiAddBoxFill,
RiPlayFill,
- RiAddCircleFill,
RiRefreshLine,
RiSettings3Fill,
- RiFilterFill,
} from 'react-icons/ri';
-import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
-import { AlbumListQuery, AlbumListSort, LibraryItem, SortOrder } from '/@/renderer/api/types';
+import { AlbumListSort, LibraryItem, SortOrder } from '/@/renderer/api/types';
import { Button, DropdownMenu, MultiSelect, Slider, Switch, Text } from '/@/renderer/components';
-import { useContainerQuery } from '/@/renderer/hooks';
-import {
- AlbumListFilter,
- useAlbumListStore,
- useCurrentServer,
- useListStoreActions,
-} from '/@/renderer/store';
-import { ServerType, Play, ListDisplayType, TableColumn } from '/@/renderer/types';
-import { OrderToggleButton, useMusicFolders } from '/@/renderer/features/shared';
-import { usePlayQueueAdd } from '/@/renderer/features/player';
-import { JellyfinAlbumFilters } from '/@/renderer/features/albums/components/jellyfin-album-filters';
-import { NavidromeAlbumFilters } from '/@/renderer/features/albums/components/navidrome-album-filters';
-import { useAlbumListContext } from '/@/renderer/features/albums/context/album-list-context';
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
import { ALBUM_TABLE_COLUMNS } from '/@/renderer/components/virtual-table';
+import { useListContext } from '/@/renderer/context/list-context';
+import { JellyfinAlbumFilters } from '/@/renderer/features/albums/components/jellyfin-album-filters';
+import { NavidromeAlbumFilters } from '/@/renderer/features/albums/components/navidrome-album-filters';
+import { OrderToggleButton, useMusicFolders } from '/@/renderer/features/shared';
+import { useContainerQuery } from '/@/renderer/hooks';
+import { useListFilterRefresh } from '/@/renderer/hooks/use-list-filter-refresh';
+import {
+ AlbumListFilter,
+ useCurrentServer,
+ useListStoreActions,
+ useListStoreByKey,
+} from '/@/renderer/store';
+import { ListDisplayType, Play, ServerType, TableColumn } from '/@/renderer/types';
const FILTERS = {
jellyfin: [
@@ -77,26 +75,23 @@ const FILTERS = {
};
interface AlbumListHeaderFiltersProps {
- customFilters?: Partial;
gridRef: MutableRefObject;
- itemCount?: number;
tableRef: MutableRefObject;
}
-export const AlbumListHeaderFilters = ({
- customFilters,
- gridRef,
- tableRef,
- itemCount,
-}: AlbumListHeaderFiltersProps) => {
+export const AlbumListHeaderFilters = ({ gridRef, tableRef }: AlbumListHeaderFiltersProps) => {
const queryClient = useQueryClient();
- const { id, pageKey } = useAlbumListContext();
+ const { pageKey, customFilters, handlePlay } = useListContext();
const server = useCurrentServer();
- const { setFilter, setTablePagination, setTable, setGrid, setDisplayType } =
- useListStoreActions();
- const { display, filter, table, grid } = useAlbumListStore({ id, key: pageKey });
+ const { setFilter, setTable, setGrid, setDisplayType } = useListStoreActions();
+ const { display, filter, table, grid } = useListStoreByKey({ key: pageKey });
const cq = useContainerQuery();
+ const { handleRefreshTable, handleRefreshGrid } = useListFilterRefresh({
+ itemType: LibraryItem.ALBUM,
+ server,
+ });
+
const musicFoldersQuery = useMusicFolders({ query: null, serverId: server?.id });
const sortByLabel =
@@ -107,123 +102,21 @@ export const AlbumListHeaderFilters = ({
const isGrid = display === ListDisplayType.CARD || display === ListDisplayType.POSTER;
- const fetch = useCallback(
- async (skip: number, take: number, filters: AlbumListFilter) => {
- const query: AlbumListQuery = {
- limit: take,
- startIndex: skip,
- ...filters,
- _custom: {
- jellyfin: {
- ...filters._custom?.jellyfin,
- ...customFilters?._custom?.jellyfin,
- },
- navidrome: {
- ...filters._custom?.navidrome,
- ...customFilters?._custom?.navidrome,
- },
- },
- ...customFilters,
- };
-
- const queryKey = queryKeys.albums.list(server?.id || '', query);
-
- const albums = await queryClient.fetchQuery(
- queryKey,
- async ({ signal }) =>
- api.controller.getAlbumList({
- apiClientProps: {
- server,
- signal,
- },
- query,
- }),
- { cacheTime: 1000 * 60 * 1 },
- );
-
- return albums;
- },
- [customFilters, queryClient, server],
- );
-
- const handleFilterChange = useCallback(
- async (filters: AlbumListFilter) => {
+ const onFilterChange = useCallback(
+ (filter: AlbumListFilter) => {
if (isGrid) {
- gridRef.current?.scrollTo(0);
- gridRef.current?.resetLoadMoreItemsCache();
-
- // Refetching within the virtualized grid may be inconsistent due to it refetching
- // using an outdated set of filters. To avoid this, we fetch using the updated filters
- // and then set the grid's data here.
- const data = await fetch(0, 200, filters);
-
- if (!data?.items) return;
- gridRef.current?.setItemData(data.items);
- } else {
- const dataSource: IDatasource = {
- getRows: async (params) => {
- const limit = params.endRow - params.startRow;
- const startIndex = params.startRow;
-
- const query: AlbumListQuery = {
- limit,
- startIndex,
- ...filters,
- ...customFilters,
- _custom: {
- jellyfin: {
- ...filters._custom?.jellyfin,
- ...customFilters?._custom?.jellyfin,
- },
- navidrome: {
- ...filters._custom?.navidrome,
- ...customFilters?._custom?.navidrome,
- },
- },
- };
-
- const queryKey = queryKeys.albums.list(server?.id || '', query);
-
- const albumsRes = await queryClient.fetchQuery(
- queryKey,
- async ({ signal }) =>
- api.controller.getAlbumList({
- apiClientProps: {
- server,
- signal,
- },
- query,
- }),
- { cacheTime: 1000 * 60 * 1 },
- );
-
- return params.successCallback(
- albumsRes?.items || [],
- albumsRes?.totalRecordCount || 0,
- );
- },
- rowCount: undefined,
- };
- tableRef.current?.api.setDatasource(dataSource);
- tableRef.current?.api.purgeInfiniteCache();
- tableRef.current?.api.ensureIndexVisible(0, 'top');
-
- if (display === ListDisplayType.TABLE_PAGINATED) {
- setTablePagination({ data: { currentPage: 0 }, key: 'album' });
- }
+ handleRefreshGrid(gridRef, {
+ ...filter,
+ ...customFilters,
+ });
}
+
+ handleRefreshTable(tableRef, {
+ ...filter,
+ ...customFilters,
+ });
},
- [
- isGrid,
- gridRef,
- fetch,
- tableRef,
- display,
- customFilters,
- server,
- queryClient,
- setTablePagination,
- ],
+ [customFilters, gridRef, handleRefreshGrid, handleRefreshTable, isGrid, tableRef],
);
const handleOpenFiltersModal = () => {
@@ -232,19 +125,19 @@ export const AlbumListHeaderFilters = ({
<>
{server?.type === ServerType.NAVIDROME ? (
) : (
)}
>
@@ -255,8 +148,8 @@ export const AlbumListHeaderFilters = ({
const handleRefresh = useCallback(() => {
queryClient.invalidateQueries(queryKeys.albums.list(server?.id || ''));
- handleFilterChange(filter);
- }, [filter, handleFilterChange, queryClient, server?.id]);
+ onFilterChange(filter);
+ }, [filter, onFilterChange, queryClient, server?.id]);
const handleSetSortBy = useCallback(
(e: MouseEvent) => {
@@ -267,17 +160,18 @@ export const AlbumListHeaderFilters = ({
)?.defaultOrder;
const updatedFilters = setFilter({
+ customFilters,
data: {
sortBy: e.currentTarget.value as AlbumListSort,
sortOrder: sortOrder || SortOrder.ASC,
},
itemType: LibraryItem.ALBUM,
- key: 'album',
+ key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
},
- [handleFilterChange, server?.type, setFilter],
+ [customFilters, onFilterChange, pageKey, server?.type, setFilter],
);
const handleSetMusicFolder = useCallback(
@@ -287,86 +181,50 @@ export const AlbumListHeaderFilters = ({
let updatedFilters = null;
if (e.currentTarget.value === String(filter.musicFolderId)) {
updatedFilters = setFilter({
+ customFilters,
data: { musicFolderId: undefined },
itemType: LibraryItem.ALBUM,
- key: 'album',
+ key: pageKey,
}) as AlbumListFilter;
} else {
updatedFilters = setFilter({
+ customFilters,
data: { musicFolderId: e.currentTarget.value },
itemType: LibraryItem.ALBUM,
- key: 'album',
+ key: pageKey,
}) as AlbumListFilter;
}
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
},
- [handleFilterChange, filter.musicFolderId, setFilter],
+ [filter.musicFolderId, onFilterChange, setFilter, customFilters, pageKey],
);
const handleToggleSortOrder = useCallback(() => {
const newSortOrder = filter.sortOrder === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
const updatedFilters = setFilter({
+ customFilters,
data: { sortOrder: newSortOrder },
itemType: LibraryItem.ALBUM,
- key: 'album',
+ key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
- }, [filter.sortOrder, handleFilterChange, setFilter]);
-
- const handlePlayQueueAdd = usePlayQueueAdd();
-
- const handlePlay = async (playType: Play) => {
- if (!itemCount || itemCount === 0 || !server) return;
-
- const query = {
- startIndex: 0,
- ...filter,
- ...customFilters,
- _custom: {
- jellyfin: {
- ...filter._custom?.jellyfin,
- ...customFilters?._custom?.jellyfin,
- },
- navidrome: {
- ...filter._custom?.navidrome,
- ...customFilters?._custom?.navidrome,
- },
- },
- };
- const queryKey = queryKeys.albums.list(server?.id || '', query);
-
- const albumListRes = await queryClient.fetchQuery({
- queryFn: ({ signal }) =>
- api.controller.getAlbumList({ apiClientProps: { server, signal }, query }),
- queryKey,
- });
-
- const albumIds = albumListRes?.items?.map((a) => a.id) || [];
-
- handlePlayQueueAdd?.({
- byItemType: {
- id: albumIds,
- type: LibraryItem.ALBUM,
- },
- playType,
- });
- };
+ onFilterChange(updatedFilters);
+ }, [customFilters, filter.sortOrder, onFilterChange, pageKey, setFilter]);
const handleItemSize = (e: number) => {
if (isGrid) {
- setGrid({ data: { itemsPerRow: e }, key: 'album' });
+ setGrid({ data: { itemsPerRow: e }, key: pageKey });
} else {
- setTable({ data: { rowHeight: e }, key: 'album' });
+ setTable({ data: { rowHeight: e }, key: pageKey });
}
};
const handleSetViewType = useCallback(
(e: MouseEvent) => {
if (!e.currentTarget?.value) return;
- setDisplayType({ data: e.currentTarget.value as ListDisplayType, key: 'album' });
+ setDisplayType({ data: e.currentTarget.value as ListDisplayType, key: pageKey });
},
- [setDisplayType],
+ [pageKey, setDisplayType],
);
const handleTableColumns = (values: TableColumn[]) => {
@@ -375,7 +233,7 @@ export const AlbumListHeaderFilters = ({
if (values.length === 0) {
return setTable({
data: { columns: [] },
- key: 'album',
+ key: pageKey,
});
}
@@ -383,20 +241,20 @@ export const AlbumListHeaderFilters = ({
if (values.length > existingColumns.length) {
const newColumn = { column: values[values.length - 1], width: 100 };
- setTable({ data: { columns: [...existingColumns, newColumn] }, key: 'album' });
+ setTable({ data: { columns: [...existingColumns, newColumn] }, key: pageKey });
} else {
// If removing a column
const removed = existingColumns.filter((column) => !values.includes(column.column));
const newColumns = existingColumns.filter((column) => !removed.includes(column));
- setTable({ data: { columns: newColumns }, key: 'album' });
+ setTable({ data: { columns: newColumns }, key: pageKey });
}
return tableRef.current?.api.sizeColumnsToFit();
};
const handleAutoFitColumns = (e: ChangeEvent) => {
- setTable({ data: { autoFit: e.currentTarget.checked }, key: 'album' });
+ setTable({ data: { autoFit: e.currentTarget.checked }, key: pageKey });
if (e.currentTarget.checked) {
tableRef.current?.api.sizeColumnsToFit();
@@ -511,19 +369,19 @@ export const AlbumListHeaderFilters = ({
}
- onClick={() => handlePlay(Play.NOW)}
+ onClick={() => handlePlay?.({ playType: Play.NOW })}
>
Play
}
- onClick={() => handlePlay(Play.LAST)}
+ onClick={() => handlePlay?.({ playType: Play.LAST })}
>
Add to queue
}
- onClick={() => handlePlay(Play.NEXT)}
+ onClick={() => handlePlay?.({ playType: Play.NEXT })}
>
Add to queue next
diff --git a/src/renderer/features/albums/components/album-list-header.tsx b/src/renderer/features/albums/components/album-list-header.tsx
index 4119b74e..0555bccf 100644
--- a/src/renderer/features/albums/components/album-list-header.tsx
+++ b/src/renderer/features/albums/components/album-list-header.tsx
@@ -1,214 +1,60 @@
-import type { ChangeEvent, MutableRefObject } from 'react';
-import { useCallback } from 'react';
-import { IDatasource } from '@ag-grid-community/core';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { Flex, Group, Stack } from '@mantine/core';
-import { useQueryClient } from '@tanstack/react-query';
import debounce from 'lodash/debounce';
-import { api } from '/@/renderer/api';
-import { controller } from '/@/renderer/api/controller';
-import { queryKeys } from '/@/renderer/api/query-keys';
-import { AlbumListQuery, LibraryItem } from '/@/renderer/api/types';
+import type { ChangeEvent, MutableRefObject } from 'react';
+import { useListFilterRefresh } from '../../../hooks/use-list-filter-refresh';
+import { LibraryItem } from '/@/renderer/api/types';
import { PageHeader, SearchInput } from '/@/renderer/components';
+import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
+import { useListContext } from '/@/renderer/context/list-context';
+import { AlbumListHeaderFilters } from '/@/renderer/features/albums/components/album-list-header-filters';
import { FilterBar, LibraryHeaderBar } from '/@/renderer/features/shared';
import { useContainerQuery } from '/@/renderer/hooks';
import {
AlbumListFilter,
- useAlbumListFilter,
- useAlbumListStore,
useCurrentServer,
useListStoreActions,
+ useListStoreByKey,
+ usePlayButtonBehavior,
} from '/@/renderer/store';
-import { ListDisplayType, Play } from '/@/renderer/types';
-import { AlbumListHeaderFilters } from '/@/renderer/features/albums/components/album-list-header-filters';
-import { usePlayQueueAdd } from '/@/renderer/features/player';
-import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
-import { useAlbumListContext } from '/@/renderer/features/albums/context/album-list-context';
-import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
+import { ListDisplayType } from '/@/renderer/types';
interface AlbumListHeaderProps {
- customFilters?: Partial;
gridRef: MutableRefObject;
itemCount?: number;
tableRef: MutableRefObject;
title?: string;
}
-export const AlbumListHeader = ({
- itemCount,
- gridRef,
- tableRef,
- title,
- customFilters,
-}: AlbumListHeaderProps) => {
- const queryClient = useQueryClient();
+export const AlbumListHeader = ({ itemCount, gridRef, tableRef, title }: AlbumListHeaderProps) => {
const server = useCurrentServer();
const { setFilter, setTablePagination } = useListStoreActions();
const cq = useContainerQuery();
- const { id, pageKey } = useAlbumListContext();
- const { display } = useAlbumListStore({ id, key: pageKey });
- const filter = useAlbumListFilter({ id, key: pageKey });
+ const { pageKey, handlePlay } = useListContext();
+ const { display, filter } = useListStoreByKey({ key: pageKey });
+ const playButtonBehavior = usePlayButtonBehavior();
- const fetch = useCallback(
- async (skip: number, take: number, filters: AlbumListFilter) => {
- const query: AlbumListQuery = {
- limit: take,
- startIndex: skip,
- ...filters,
- ...customFilters,
- _custom: {
- jellyfin: {
- ...filters._custom?.jellyfin,
- ...customFilters?._custom?.jellyfin,
- },
- navidrome: {
- ...filters._custom?.navidrome,
- ...customFilters?._custom?.navidrome,
- },
- },
- };
-
- const queryKey = queryKeys.albums.list(server?.id || '', query);
-
- const albums = await queryClient.fetchQuery(
- queryKey,
- async ({ signal }) =>
- controller.getAlbumList({
- apiClientProps: {
- server,
- signal,
- },
- query,
- }),
- { cacheTime: 1000 * 60 * 1 },
- );
-
- return albums;
- },
- [customFilters, queryClient, server],
- );
-
- const handleFilterChange = useCallback(
- async (filters: AlbumListFilter) => {
- if (display === ListDisplayType.TABLE || display === ListDisplayType.TABLE_PAGINATED) {
- const dataSource: IDatasource = {
- getRows: async (params) => {
- const limit = params.endRow - params.startRow;
- const startIndex = params.startRow;
-
- const query: AlbumListQuery = {
- limit,
- startIndex,
- ...filters,
- ...customFilters,
- _custom: {
- jellyfin: {
- ...filters._custom?.jellyfin,
- ...customFilters?._custom?.jellyfin,
- },
- navidrome: {
- ...filters._custom?.navidrome,
- ...customFilters?._custom?.navidrome,
- },
- },
- };
-
- const queryKey = queryKeys.albums.list(server?.id || '', query);
-
- const albumsRes = await queryClient.fetchQuery(
- queryKey,
- async ({ signal }) =>
- api.controller.getAlbumList({
- apiClientProps: {
- server,
- signal,
- },
- query,
- }),
- { cacheTime: 1000 * 60 * 1 },
- );
-
- params.successCallback(
- albumsRes?.items || [],
- albumsRes?.totalRecordCount || 0,
- );
- },
- rowCount: undefined,
- };
- tableRef.current?.api.setDatasource(dataSource);
- tableRef.current?.api.purgeInfiniteCache();
- tableRef.current?.api.ensureIndexVisible(0, 'top');
-
- if (display === ListDisplayType.TABLE_PAGINATED) {
- setTablePagination({ data: { currentPage: 0 }, key: 'album' });
- }
- } else {
- gridRef.current?.scrollTo(0);
- gridRef.current?.resetLoadMoreItemsCache();
-
- // Refetching within the virtualized grid may be inconsistent due to it refetching
- // using an outdated set of filters. To avoid this, we fetch using the updated filters
- // and then set the grid's data here.
- const data = await fetch(0, 200, filters);
-
- if (!data?.items) return;
- gridRef.current?.setItemData(data.items);
- }
- },
- [display, tableRef, customFilters, server, queryClient, setTablePagination, gridRef, fetch],
- );
+ const { handleRefreshGrid, handleRefreshTable } = useListFilterRefresh({
+ itemType: LibraryItem.ALBUM,
+ server,
+ });
const handleSearch = debounce((e: ChangeEvent) => {
- const previousSearchTerm = filter.searchTerm;
const searchTerm = e.target.value === '' ? undefined : e.target.value;
const updatedFilters = setFilter({
data: { searchTerm },
itemType: LibraryItem.ALBUM,
- key: 'album',
+ key: pageKey,
}) as AlbumListFilter;
- if (previousSearchTerm !== searchTerm) handleFilterChange(updatedFilters);
+
+ if (display === ListDisplayType.TABLE || display === ListDisplayType.TABLE_PAGINATED) {
+ handleRefreshTable(tableRef, updatedFilters);
+ setTablePagination({ data: { currentPage: 0 }, key: pageKey });
+ } else {
+ handleRefreshGrid(gridRef, updatedFilters);
+ }
}, 500);
- const handlePlayQueueAdd = usePlayQueueAdd();
- const playButtonBehavior = usePlayButtonBehavior();
-
- const handlePlay = async (playType: Play) => {
- if (!itemCount || itemCount === 0) return;
-
- const query = {
- startIndex: 0,
- ...filter,
- ...customFilters,
- _custom: {
- jellyfin: {
- ...filter._custom?.jellyfin,
- ...customFilters?._custom?.jellyfin,
- },
- navidrome: {
- ...filter._custom?.navidrome,
- ...customFilters?._custom?.navidrome,
- },
- },
- };
- const queryKey = queryKeys.albums.list(server?.id || '', query);
-
- const albumListRes = await queryClient.fetchQuery({
- queryFn: ({ signal }) =>
- api.controller.getAlbumList({ apiClientProps: { server, signal }, query }),
- queryKey,
- });
-
- const albumIds = albumListRes?.items?.map((item) => item.id) || [];
-
- handlePlayQueueAdd?.({
- byItemType: {
- id: albumIds,
- type: LibraryItem.ALBUM,
- },
- playType,
- });
- };
-
return (
handlePlay(playButtonBehavior)}
+ onClick={() => handlePlay?.({ playType: playButtonBehavior })}
/>
{title || 'Albums'}
diff --git a/src/renderer/features/albums/components/album-list-table-view.tsx b/src/renderer/features/albums/components/album-list-table-view.tsx
index cf9d6129..ecbf3f8f 100644
--- a/src/renderer/features/albums/components/album-list-table-view.tsx
+++ b/src/renderer/features/albums/components/album-list-table-view.tsx
@@ -1,68 +1,22 @@
-import { useCallback } from 'react';
-import { api } from '/@/renderer/api';
-import { queryKeys } from '/@/renderer/api/query-keys';
-import { AlbumListQuery, AlbumListResponse, LibraryItem } from '/@/renderer/api/types';
-import { VirtualTable } from '/@/renderer/components/virtual-table';
-import { useAlbumListContext } from '/@/renderer/features/albums/context/album-list-context';
-import {
- useCurrentServer,
- useAlbumListFilter,
- useListStoreActions,
- useAlbumListStore,
-} from '/@/renderer/store';
-import { ALBUM_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
+import { useVirtualTable } from '../../../components/virtual-table/hooks/use-virtual-table';
+import { LibraryItem } from '/@/renderer/api/types';
import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid';
-import {
- useVirtualTable,
- AgGridFetchFn,
-} from '../../../components/virtual-table/hooks/use-virtual-table';
+import { VirtualTable } from '/@/renderer/components/virtual-table';
+import { useListContext } from '/@/renderer/context/list-context';
+import { ALBUM_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
+import { useCurrentServer } from '/@/renderer/store';
export const AlbumListTableView = ({ tableRef, itemCount }: any) => {
const server = useCurrentServer();
- const { id, pageKey } = useAlbumListContext();
- const filter = useAlbumListFilter({ id, key: pageKey });
- const { setTable, setTablePagination } = useListStoreActions();
- const listProperties = useAlbumListStore({ id, key: pageKey });
+ const { pageKey, customFilters } = useListContext();
- const fetchFn: AgGridFetchFn<
- AlbumListResponse,
- Omit
- > = useCallback(
- async ({ filter, limit, startIndex }, signal) => {
- const res = api.controller.getAlbumList({
- apiClientProps: {
- server,
- signal,
- },
- query: {
- ...filter,
- limit,
- sortBy: filter.sortBy,
- sortOrder: filter.sortOrder,
- startIndex,
- },
- });
-
- return res;
- },
- [server],
- );
-
- const tableProps = useVirtualTable>({
+ const tableProps = useVirtualTable({
contextMenu: ALBUM_CONTEXT_MENU_ITEMS,
- fetch: {
- filter,
- fn: fetchFn,
- itemCount,
- queryKey: queryKeys.albums.list,
- server,
- },
+ customFilters,
itemCount,
itemType: LibraryItem.ALBUM,
pageKey,
- properties: listProperties,
- setTable,
- setTablePagination,
+ server,
tableRef,
});
@@ -71,7 +25,7 @@ export const AlbumListTableView = ({ tableRef, itemCount }: any) => {
diff --git a/src/renderer/features/albums/components/jellyfin-album-filters.tsx b/src/renderer/features/albums/components/jellyfin-album-filters.tsx
index baa665c2..89330c11 100644
--- a/src/renderer/features/albums/components/jellyfin-album-filters.tsx
+++ b/src/renderer/features/albums/components/jellyfin-album-filters.tsx
@@ -1,28 +1,29 @@
-import { ChangeEvent, useMemo, useState } from 'react';
import { Divider, Group, Stack } from '@mantine/core';
-import { MultiSelect, NumberInput, SpinnerIcon, Switch, Text } from '/@/renderer/components';
-import { AlbumListFilter, useAlbumListFilter, useListStoreActions } from '/@/renderer/store';
import debounce from 'lodash/debounce';
-import { useGenreList } from '/@/renderer/features/genres';
+import { ChangeEvent, useMemo, useState } from 'react';
+import { useListFilterByKey } from '../../../store/list.store';
import { AlbumArtistListSort, LibraryItem, SortOrder } from '/@/renderer/api/types';
+import { MultiSelect, NumberInput, SpinnerIcon, Switch, Text } from '/@/renderer/components';
import { useAlbumArtistList } from '/@/renderer/features/artists/queries/album-artist-list-query';
+import { useGenreList } from '/@/renderer/features/genres';
+import { AlbumListFilter, useListStoreActions } from '/@/renderer/store';
interface JellyfinAlbumFiltersProps {
+ customFilters?: Partial;
disableArtistFilter?: boolean;
- handleFilterChange: (filters: AlbumListFilter) => void;
- id?: string;
+ onFilterChange: (filters: AlbumListFilter) => void;
pageKey: string;
serverId?: string;
}
export const JellyfinAlbumFilters = ({
+ customFilters,
disableArtistFilter,
- handleFilterChange,
+ onFilterChange,
pageKey,
- id,
serverId,
}: JellyfinAlbumFiltersProps) => {
- const filter = useAlbumListFilter({ id, key: pageKey });
+ const filter = useListFilterByKey({ key: pageKey });
const { setFilter } = useListStoreActions();
// TODO - eventually replace with /items/filters endpoint to fetch genres and tags specific to the selected library
@@ -45,6 +46,7 @@ export const JellyfinAlbumFilters = ({
label: 'Is favorited',
onChange: (e: ChangeEvent) => {
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
...filter._custom,
@@ -57,7 +59,7 @@ export const JellyfinAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
},
value: filter._custom?.jellyfin?.IsFavorite,
},
@@ -66,6 +68,7 @@ export const JellyfinAlbumFilters = ({
const handleMinYearFilter = debounce((e: number | string) => {
if (typeof e === 'number' && (e < 1700 || e > 2300)) return;
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
...filter._custom,
@@ -78,12 +81,13 @@ export const JellyfinAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
}, 500);
const handleMaxYearFilter = debounce((e: number | string) => {
if (typeof e === 'number' && (e < 1700 || e > 2300)) return;
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
...filter._custom,
@@ -96,12 +100,13 @@ export const JellyfinAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
}, 500);
const handleGenresFilter = debounce((e: string[] | undefined) => {
const genreFilterString = e?.length ? e.join(',') : undefined;
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
...filter._custom,
@@ -114,7 +119,7 @@ export const JellyfinAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
}, 250);
const [albumArtistSearchTerm, setAlbumArtistSearchTerm] = useState('');
@@ -144,6 +149,7 @@ export const JellyfinAlbumFilters = ({
const handleAlbumArtistFilter = (e: string[] | null) => {
const albumArtistFilterString = e?.length ? e.join(',') : undefined;
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
...filter._custom,
@@ -156,7 +162,7 @@ export const JellyfinAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
};
return (
diff --git a/src/renderer/features/albums/components/navidrome-album-filters.tsx b/src/renderer/features/albums/components/navidrome-album-filters.tsx
index 43cddd0e..9cdacaa1 100644
--- a/src/renderer/features/albums/components/navidrome-album-filters.tsx
+++ b/src/renderer/features/albums/components/navidrome-album-filters.tsx
@@ -1,28 +1,28 @@
import { ChangeEvent, useMemo, useState } from 'react';
import { Divider, Group, Stack } from '@mantine/core';
import { NumberInput, Switch, Text, Select, SpinnerIcon } from '/@/renderer/components';
-import { AlbumListFilter, useAlbumListFilter, useListStoreActions } from '/@/renderer/store';
+import { AlbumListFilter, useListStoreActions, useListStoreByKey } from '/@/renderer/store';
import debounce from 'lodash/debounce';
import { useGenreList } from '/@/renderer/features/genres';
import { useAlbumArtistList } from '/@/renderer/features/artists/queries/album-artist-list-query';
import { AlbumArtistListSort, LibraryItem, SortOrder } from '/@/renderer/api/types';
interface NavidromeAlbumFiltersProps {
+ customFilters?: Partial;
disableArtistFilter?: boolean;
- handleFilterChange: (filters: AlbumListFilter) => void;
- id?: string;
+ onFilterChange: (filters: AlbumListFilter) => void;
pageKey: string;
serverId?: string;
}
export const NavidromeAlbumFilters = ({
- handleFilterChange,
+ customFilters,
+ onFilterChange,
disableArtistFilter,
pageKey,
- id,
serverId,
}: NavidromeAlbumFiltersProps) => {
- const filter = useAlbumListFilter({ id, key: pageKey });
+ const { filter } = useListStoreByKey({ key: pageKey });
const { setFilter } = useListStoreActions();
const genreListQuery = useGenreList({ query: null, serverId });
@@ -37,6 +37,7 @@ export const NavidromeAlbumFilters = ({
const handleGenresFilter = debounce((e: string | null) => {
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
...filter._custom,
@@ -47,9 +48,9 @@ export const NavidromeAlbumFilters = ({
},
},
itemType: LibraryItem.ALBUM,
- key: 'album',
+ key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
}, 250);
const toggleFilters = [
@@ -57,6 +58,7 @@ export const NavidromeAlbumFilters = ({
label: 'Is rated',
onChange: (e: ChangeEvent) => {
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
...filter._custom,
@@ -69,7 +71,7 @@ export const NavidromeAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
},
value: filter._custom?.navidrome?.has_rating,
},
@@ -77,6 +79,7 @@ export const NavidromeAlbumFilters = ({
label: 'Is favorited',
onChange: (e: ChangeEvent) => {
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
...filter._custom,
@@ -89,7 +92,7 @@ export const NavidromeAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
},
value: filter._custom?.navidrome?.starred,
},
@@ -97,6 +100,7 @@ export const NavidromeAlbumFilters = ({
label: 'Is compilation',
onChange: (e: ChangeEvent) => {
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
...filter._custom,
@@ -109,7 +113,7 @@ export const NavidromeAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
},
value: filter._custom?.navidrome?.compilation,
},
@@ -117,6 +121,7 @@ export const NavidromeAlbumFilters = ({
label: 'Is recently played',
onChange: (e: ChangeEvent) => {
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
...filter._custom,
@@ -129,7 +134,7 @@ export const NavidromeAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
},
value: filter._custom?.navidrome?.recently_played,
},
@@ -137,6 +142,7 @@ export const NavidromeAlbumFilters = ({
const handleYearFilter = debounce((e: number | string) => {
const updatedFilters = setFilter({
+ customFilters,
data: {
_custom: {
navidrome: {
@@ -149,7 +155,7 @@ export const NavidromeAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
}, 500);
const [albumArtistSearchTerm, setAlbumArtistSearchTerm] = useState('');
@@ -191,7 +197,7 @@ export const NavidromeAlbumFilters = ({
itemType: LibraryItem.ALBUM,
key: pageKey,
}) as AlbumListFilter;
- handleFilterChange(updatedFilters);
+ onFilterChange(updatedFilters);
};
return (
diff --git a/src/renderer/features/albums/routes/album-list-route.tsx b/src/renderer/features/albums/routes/album-list-route.tsx
index 5d819e4a..d80ade24 100644
--- a/src/renderer/features/albums/routes/album-list-route.tsx
+++ b/src/renderer/features/albums/routes/album-list-route.tsx
@@ -1,28 +1,39 @@
-import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
-import { AnimatedPage } from '/@/renderer/features/shared';
-import { AlbumListHeader } from '/@/renderer/features/albums/components/album-list-header';
-import { AlbumListContent } from '/@/renderer/features/albums/components/album-list-content';
-import { useRef } from 'react';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
-import { useAlbumList } from '/@/renderer/features/albums/queries/album-list-query';
-import { generatePageKey, useAlbumListFilter, useCurrentServer } from '/@/renderer/store';
+import { useCallback, useMemo, useRef } from 'react';
import { useParams, useSearchParams } from 'react-router-dom';
-import { AlbumListContext } from '/@/renderer/features/albums/context/album-list-context';
+import { api } from '/@/renderer/api';
+import { queryKeys } from '/@/renderer/api/query-keys';
+import { LibraryItem } from '/@/renderer/api/types';
+import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
+import { ListContext } from '/@/renderer/context/list-context';
+import { AlbumListContent } from '/@/renderer/features/albums/components/album-list-content';
+import { AlbumListHeader } from '/@/renderer/features/albums/components/album-list-header';
+import { useAlbumList } from '/@/renderer/features/albums/queries/album-list-query';
+import { usePlayQueueAdd } from '/@/renderer/features/player';
+import { AnimatedPage } from '/@/renderer/features/shared';
+import { queryClient } from '/@/renderer/lib/react-query';
+import { useCurrentServer, useListFilterByKey } from '/@/renderer/store';
+import { Play } from '/@/renderer/types';
const AlbumListRoute = () => {
const gridRef = useRef(null);
const tableRef = useRef(null);
const server = useCurrentServer();
-
const [searchParams] = useSearchParams();
const { albumArtistId } = useParams();
+ const pageKey = albumArtistId ? `albumArtistAlbum` : 'album';
+ const handlePlayQueueAdd = usePlayQueueAdd();
- const pageKey = generatePageKey(
- 'album',
- albumArtistId ? `${albumArtistId}_${server?.id}` : undefined,
- );
+ const customFilters = useMemo(() => {
+ return {
+ ...(albumArtistId && { artistIds: [albumArtistId] }),
+ };
+ }, [albumArtistId]);
- const albumListFilter = useAlbumListFilter({ id: albumArtistId || undefined, key: pageKey });
+ const albumListFilter = useListFilterByKey({
+ filter: customFilters,
+ key: pageKey,
+ });
const itemCountCheck = useAlbumList({
options: {
@@ -42,9 +53,43 @@ const AlbumListRoute = () => {
? undefined
: itemCountCheck.data?.totalRecordCount;
+ const handlePlay = useCallback(
+ async (args: { initialSongId?: string; playType: Play }) => {
+ if (!itemCount || itemCount === 0) return;
+ const { playType } = args;
+ const query = {
+ startIndex: 0,
+ ...albumListFilter,
+ ...customFilters,
+ };
+ const queryKey = queryKeys.albums.list(server?.id || '', query);
+
+ const albumListRes = await queryClient.fetchQuery({
+ queryFn: ({ signal }) => {
+ return api.controller.getAlbumList({
+ apiClientProps: { server, signal },
+ query,
+ });
+ },
+ queryKey,
+ });
+
+ const albumIds = albumListRes?.items?.map((a) => a.id) || [];
+
+ handlePlayQueueAdd?.({
+ byItemType: {
+ id: albumIds,
+ type: LibraryItem.ALBUM,
+ },
+ playType,
+ });
+ },
+ [albumListFilter, customFilters, handlePlayQueueAdd, itemCount, server],
+ );
+
return (
-
+
{
itemCount={itemCount}
tableRef={tableRef}
/>
-
+
);
};
diff --git a/src/renderer/store/list.store.ts b/src/renderer/store/list.store.ts
index 3e8f5a11..e883ca5e 100644
--- a/src/renderer/store/list.store.ts
+++ b/src/renderer/store/list.store.ts
@@ -55,6 +55,7 @@ export interface ListState {
item: {
album: ListItemProps;
albumArtist: ListItemProps;
+ albumArtistAlbum: ListItemProps;
albumArtistSong: ListItemProps;
albumDetail: ListItemProps;
playlist: ListItemProps;
@@ -380,6 +381,47 @@ export const useListStore = create()(
scrollOffset: 0,
},
},
+ albumArtistAlbum: {
+ display: ListDisplayType.POSTER,
+ filter: {
+ sortBy: AlbumListSort.RECENTLY_ADDED,
+ sortOrder: SortOrder.DESC,
+ },
+ grid: { itemsPerRow: 5, scrollOffset: 0 },
+ table: {
+ autoFit: true,
+ columns: [
+ {
+ column: TableColumn.ROW_INDEX,
+ width: 50,
+ },
+ {
+ column: TableColumn.TITLE_COMBINED,
+ width: 500,
+ },
+ {
+ column: TableColumn.DURATION,
+ width: 100,
+ },
+ {
+ column: TableColumn.ALBUM_ARTIST,
+ width: 300,
+ },
+ {
+ column: TableColumn.YEAR,
+ width: 100,
+ },
+ ],
+ pagination: {
+ currentPage: 1,
+ itemsPerPage: 100,
+ totalItems: 1,
+ totalPages: 1,
+ },
+ rowHeight: 60,
+ scrollOffset: 0,
+ },
+ },
albumArtistSong: {
display: ListDisplayType.TABLE,
filter: {
@@ -553,69 +595,6 @@ export const useListFilterByKey = (args: { filter?: Partial; k
);
};
-export const useAlbumListStore = (args?: { id?: string; key?: string }) =>
- useListStore((state) => {
- const detail = args?.key ? state.detail[args.key] : undefined;
-
- return {
- ...state.item.album,
- filter: {
- ...state.item.album.filter,
- ...detail?.filter,
- },
- grid: {
- ...state.item.album.grid,
- ...detail?.grid,
- },
- table: {
- ...state.item.album.table,
- ...detail?.table,
- },
- };
- }, shallow);
-
-export const useSongListStore = (args?: { id?: string; key?: string }) =>
- useListStore((state) => {
- const detail = args?.key ? state.detail[args.key] : undefined;
-
- return {
- ...state.item.song,
- filter: {
- ...state.item.song.filter,
- ...detail?.filter,
- },
- grid: {
- ...state.item.song.grid,
- ...detail?.grid,
- },
- table: {
- ...state.item.song.table,
- ...detail?.table,
- },
- };
- }, shallow);
-
-export const usePlaylistListStore = (args?: { key?: string }) =>
- useListStore((state) => {
- const detail = args?.key ? state.detail[args.key] : undefined;
-
- return {
- ...state.item.playlist,
- filter: {
- ...state.item.playlist.filter,
- ...detail?.filter,
- },
- grid: {
- ...state.item.playlist.grid,
- ...detail?.grid,
- },
- table: {
- ...state.item.playlist.table,
- ...detail?.table,
- },
- };
- }, shallow);
-
export const useAlbumListFilter = (args: { id?: string; key?: string }) =>
useListStore((state) => {
return state._actions.getFilter({