From 2e74f7533ad95f35bfce6f3b895303ebe8a3b387 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sun, 15 Jan 2023 20:39:43 -0800 Subject: [PATCH] Reuse song list for artist songs --- .../album-artist-detail-content.tsx | 51 ++++++++++++-- .../components/jellyfin-song-filters.tsx | 42 +++++------ .../components/navidrome-song-filters.tsx | 43 ++++++------ .../songs/components/song-list-content.tsx | 21 +++--- .../songs/components/song-list-header.tsx | 70 +++++++++++-------- .../features/songs/routes/song-list-route.tsx | 24 ++++++- src/renderer/router/app-router.tsx | 6 +- 7 files changed, 160 insertions(+), 97 deletions(-) diff --git a/src/renderer/features/artists/components/album-artist-detail-content.tsx b/src/renderer/features/artists/components/album-artist-detail-content.tsx index 613a5606..304dd33d 100644 --- a/src/renderer/features/artists/components/album-artist-detail-content.tsx +++ b/src/renderer/features/artists/components/album-artist-detail-content.tsx @@ -73,6 +73,13 @@ export const AlbumArtistDetailContent = () => { artistName: detailQuery?.data?.name || '', })}`; + const artistSongsLink = `${generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_SONGS, { + albumArtistId, + })}?${createSearchParams({ + artistId: albumArtistId, + artistName: detailQuery?.data?.name || '', + })}`; + const recentAlbumsQuery = useAlbumList({ jfParams: server?.type === ServerType.JELLYFIN ? { artistIds: albumArtistId } : undefined, limit: itemsPerPage, @@ -85,6 +92,19 @@ export const AlbumArtistDetailContent = () => { startIndex: 0, }); + const compilationAlbumsQuery = useAlbumList({ + jfParams: + server?.type === ServerType.JELLYFIN ? { contributingArtistIds: albumArtistId } : undefined, + limit: itemsPerPage, + ndParams: + server?.type === ServerType.NAVIDROME + ? { artist_id: albumArtistId, compilation: true } + : undefined, + sortBy: AlbumListSort.RELEASE_DATE, + sortOrder: SortOrder.DESC, + startIndex: 0, + }); + const topSongsQuery = useTopSongsList( { artist: detailQuery?.data?.name || '' }, { enabled: server?.type !== ServerType.JELLYFIN && !!detailQuery?.data?.name }, @@ -136,6 +156,7 @@ export const AlbumArtistDetailContent = () => { const carousels = [ { data: recentAlbumsQuery?.data?.items, + isHidden: !recentAlbumsQuery?.data?.items?.length, itemType: LibraryItem.ALBUM, loading: recentAlbumsQuery?.isLoading || recentAlbumsQuery.isFetching, pagination: { @@ -147,7 +168,7 @@ export const AlbumArtistDetailContent = () => { fw="bold" order={3} > - Recent albums + Recent releases ), - uniqueId: 'recentAlbums', + uniqueId: 'recentReleases', + }, + { + data: compilationAlbumsQuery?.data?.items, + isHidden: !compilationAlbumsQuery?.data?.items?.length, + itemType: LibraryItem.ALBUM, + loading: compilationAlbumsQuery?.isLoading || compilationAlbumsQuery.isFetching, + pagination: { + itemsPerPage, + }, + title: ( + + Appears on + + ), + uniqueId: 'compilationAlbums', }, { data: detailQuery?.data?.similarArtists?.slice(0, itemsPerPage), @@ -232,12 +271,10 @@ export const AlbumArtistDetailContent = () => { const showBiography = detailQuery?.data?.biography !== undefined && detailQuery?.data?.biography !== null; const showTopSongs = server?.type !== ServerType.JELLYFIN && topSongsQuery?.data?.items?.length; - const showGenres = detailQuery?.data?.genres?.length !== 0; + const showGenres = detailQuery?.data?.genres ? detailQuery?.data?.genres.length !== 0 : false; const isLoading = - detailQuery?.isLoading || - recentAlbumsQuery?.isLoading || - (server?.type === ServerType.NAVIDROME && topSongsQuery?.isLoading); + detailQuery?.isLoading || (server?.type === ServerType.NAVIDROME && topSongsQuery?.isLoading); if (isLoading) return ; @@ -297,7 +334,7 @@ export const AlbumArtistDetailContent = () => { compact uppercase component={Link} - to={generatePath(AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL_SONGS, { albumArtistId })} + to={artistSongsLink} variant="subtle" > View all songs diff --git a/src/renderer/features/songs/components/jellyfin-song-filters.tsx b/src/renderer/features/songs/components/jellyfin-song-filters.tsx index aa0e96e6..1bd845d2 100644 --- a/src/renderer/features/songs/components/jellyfin-song-filters.tsx +++ b/src/renderer/features/songs/components/jellyfin-song-filters.tsx @@ -96,38 +96,34 @@ export const JellyfinSongFilters = ({ handleFilterChange }: JellyfinSongFiltersP ))} - - Year range - - - - + + + - - - Genres + - + ); }; diff --git a/src/renderer/features/songs/components/navidrome-song-filters.tsx b/src/renderer/features/songs/components/navidrome-song-filters.tsx index 89793db6..2736dbce 100644 --- a/src/renderer/features/songs/components/navidrome-song-filters.tsx +++ b/src/renderer/features/songs/components/navidrome-song-filters.tsx @@ -59,29 +59,6 @@ export const NavidromeSongFilters = ({ handleFilterChange }: NavidromeSongFilter return ( - - Year - - - - - Genre - + ); }; diff --git a/src/renderer/features/songs/components/song-list-content.tsx b/src/renderer/features/songs/components/song-list-content.tsx index 14fc1315..5e61d3b9 100644 --- a/src/renderer/features/songs/components/song-list-content.tsx +++ b/src/renderer/features/songs/components/song-list-content.tsx @@ -19,6 +19,7 @@ import { VirtualTable, } from '/@/renderer/components'; import { + SongListFilter, useCurrentServer, useSetSongTable, useSetSongTablePagination, @@ -31,15 +32,16 @@ import debounce from 'lodash/debounce'; import { useHandleTableContextMenu } from '/@/renderer/features/context-menu'; import { SONG_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items'; import { usePlayButtonBehavior } from '/@/renderer/store/settings.store'; -import { LibraryItem, QueueSong } from '/@/renderer/api/types'; +import { LibraryItem, QueueSong, SongListQuery } from '/@/renderer/api/types'; import { usePlayQueueAdd } from '/@/renderer/features/player'; interface SongListContentProps { + customFilters?: Partial; itemCount?: number; tableRef: MutableRefObject; } -export const SongListContent = ({ itemCount, tableRef }: SongListContentProps) => { +export const SongListContent = ({ customFilters, itemCount, tableRef }: SongListContentProps) => { const queryClient = useQueryClient(); const server = useCurrentServer(); const page = useSongListStore(); @@ -64,21 +66,20 @@ export const SongListContent = ({ itemCount, tableRef }: SongListContentProps) = const limit = params.endRow - params.startRow; const startIndex = params.startRow; - const queryKey = queryKeys.songs.list(server?.id || '', { + const query: SongListQuery = { limit, startIndex, ...page.filter, - }); + ...customFilters, + }; + + const queryKey = queryKeys.songs.list(server?.id || '', query); const songsRes = await queryClient.fetchQuery( queryKey, async ({ signal }) => api.controller.getSongList({ - query: { - limit, - startIndex, - ...page.filter, - }, + query, server, signal, }), @@ -93,7 +94,7 @@ export const SongListContent = ({ itemCount, tableRef }: SongListContentProps) = params.api.setDatasource(dataSource); params.api.ensureIndexVisible(page.table.scrollOffset, 'top'); }, - [page.filter, page.table.scrollOffset, queryClient, server], + [customFilters, page.filter, page.table.scrollOffset, queryClient, server], ); const onPaginationChanged = useCallback( diff --git a/src/renderer/features/songs/components/song-list-header.tsx b/src/renderer/features/songs/components/song-list-header.tsx index 5d8bf176..97da27a4 100644 --- a/src/renderer/features/songs/components/song-list-header.tsx +++ b/src/renderer/features/songs/components/song-list-header.tsx @@ -1,6 +1,7 @@ import type { 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 { openModal } from '@mantine/modals'; import debounce from 'lodash/debounce'; import { ChangeEvent, MouseEvent, MutableRefObject, useCallback } from 'react'; import { @@ -89,11 +90,18 @@ const ORDER = [ ]; interface SongListHeaderProps { + customFilters?: Partial; itemCount?: number; tableRef: MutableRefObject; + title?: string; } -export const SongListHeader = ({ itemCount, tableRef }: SongListHeaderProps) => { +export const SongListHeader = ({ + customFilters, + title, + itemCount, + tableRef, +}: SongListHeaderProps) => { const server = useCurrentServer(); const page = useSongListStore(); const setPage = useSetSongStore(); @@ -123,21 +131,20 @@ export const SongListHeader = ({ itemCount, tableRef }: SongListHeaderProps) => const pageFilters = filters || page.filter; - const queryKey = queryKeys.songs.list(server?.id || '', { + const query: SongListQuery = { limit, startIndex, ...pageFilters, - }); + ...customFilters, + }; + + const queryKey = queryKeys.songs.list(server?.id || '', query); const songsRes = await queryClient.fetchQuery( queryKey, async ({ signal }) => api.controller.getSongList({ - query: { - limit, - startIndex, - ...pageFilters, - }, + query, server, signal, }), @@ -154,7 +161,7 @@ export const SongListHeader = ({ itemCount, tableRef }: SongListHeaderProps) => tableRef.current?.api.ensureIndexVisible(0, 'top'); setPagination({ currentPage: 0 }); }, - [page.filter, server, setPagination, tableRef], + [customFilters, page.filter, server, setPagination, tableRef], ); const handleSetSortBy = useCallback( @@ -273,6 +280,21 @@ export const SongListHeader = ({ itemCount, tableRef }: SongListHeaderProps) => }); }; + const handleOpenFiltersModal = () => { + openModal({ + children: ( + <> + {server?.type === ServerType.NAVIDROME ? ( + + ) : ( + + )} + + ), + title: 'Song Filters', + }); + }; + return ( - Tracks + {title || 'Tracks'} )} - - - - - - {server?.type === ServerType.NAVIDROME ? ( - - ) : ( - - )} - - +