Make album detail columns customizable

This commit is contained in:
jeffvli 2023-08-08 08:28:40 -07:00
parent 13d6758500
commit 3f813b1a26
4 changed files with 86 additions and 65 deletions

View file

@ -187,15 +187,17 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
/> />
</Option.Control> </Option.Control>
</Option> </Option>
<Option> {type !== 'albumDetail' && (
<Option.Label>Follow current song</Option.Label> <Option>
<Option.Control> <Option.Label>Follow current song</Option.Label>
<Switch <Option.Control>
defaultChecked={tableConfig[type]?.followCurrentSong} <Switch
onChange={handleUpdateFollow} defaultChecked={tableConfig[type]?.followCurrentSong}
/> onChange={handleUpdateFollow}
</Option.Control> />
</Option> </Option.Control>
</Option>
)}
<Option> <Option>
<Option.Control> <Option.Control>
<Slider <Slider

View file

@ -1,17 +1,21 @@
import { ColDef, RowDoubleClickedEvent, RowHeightParams, RowNode } from '@ag-grid-community/core'; import { RowDoubleClickedEvent, RowHeightParams, RowNode } from '@ag-grid-community/core';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { Box, Group, Stack } from '@mantine/core'; import { Box, Group, Stack } from '@mantine/core';
import { useSetState } from '@mantine/hooks'; import { useSetState } from '@mantine/hooks';
import { MutableRefObject, useCallback, useMemo } from 'react'; import { MutableRefObject, useCallback, useMemo } from 'react';
import { RiHeartFill, RiHeartLine, RiMoreFill } from 'react-icons/ri'; import { RiHeartFill, RiHeartLine, RiMoreFill, RiSettings2Fill } from 'react-icons/ri';
import { generatePath, useParams } from 'react-router'; import { generatePath, useParams } from 'react-router';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import styled from 'styled-components'; import styled from 'styled-components';
import { queryKeys } from '/@/renderer/api/query-keys'; import { queryKeys } from '/@/renderer/api/query-keys';
import { AlbumListSort, LibraryItem, QueueSong, SortOrder } from '/@/renderer/api/types'; import { AlbumListSort, LibraryItem, QueueSong, SortOrder } from '/@/renderer/api/types';
import { Button } from '/@/renderer/components'; import { Button, Popover } from '/@/renderer/components';
import { MemoizedSwiperGridCarousel } from '/@/renderer/components/grid-carousel'; import { MemoizedSwiperGridCarousel } from '/@/renderer/components/grid-carousel';
import { getColumnDefs, VirtualTable } from '/@/renderer/components/virtual-table'; import {
getColumnDefs,
TableConfigDropdown,
VirtualTable,
} from '/@/renderer/components/virtual-table';
import { FullWidthDiscCell } from '/@/renderer/components/virtual-table/cells/full-width-disc-cell'; import { FullWidthDiscCell } from '/@/renderer/components/virtual-table/cells/full-width-disc-cell';
import { useCurrentSongRowStyles } from '/@/renderer/components/virtual-table/hooks/use-current-song-row-styles'; import { useCurrentSongRowStyles } from '/@/renderer/components/virtual-table/hooks/use-current-song-row-styles';
import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query'; import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query';
@ -30,8 +34,8 @@ import { LibraryBackgroundOverlay } from '/@/renderer/features/shared/components
import { useContainerQuery } from '/@/renderer/hooks'; import { useContainerQuery } from '/@/renderer/hooks';
import { AppRoute } from '/@/renderer/router/routes'; import { AppRoute } from '/@/renderer/router/routes';
import { useCurrentServer } from '/@/renderer/store'; import { useCurrentServer } from '/@/renderer/store';
import { PersistedTableColumn, usePlayButtonBehavior } from '/@/renderer/store/settings.store'; import { usePlayButtonBehavior, useTableSettings } from '/@/renderer/store/settings.store';
import { Play, ServerType, TableColumn } from '/@/renderer/types'; import { Play } from '/@/renderer/types';
const isFullWidthRow = (node: RowNode) => { const isFullWidthRow = (node: RowNode) => {
return node.id?.startsWith('disc-'); return node.id?.startsWith('disc-');
@ -60,52 +64,11 @@ export const AlbumDetailContent = ({ tableRef, background }: AlbumDetailContentP
const detailQuery = useAlbumDetail({ query: { id: albumId }, serverId: server?.id }); const detailQuery = useAlbumDetail({ query: { id: albumId }, serverId: server?.id });
const cq = useContainerQuery(); const cq = useContainerQuery();
const handlePlayQueueAdd = usePlayQueueAdd(); const handlePlayQueueAdd = usePlayQueueAdd();
const tableConfig = useTableSettings('albumDetail');
// TODO: Make this customizable console.log('tableConfig :>> ', tableConfig);
const columnDefs: ColDef[] = useMemo(() => {
const userRatingColumn =
detailQuery?.data?.serverType !== ServerType.JELLYFIN
? [
{
column: TableColumn.USER_RATING,
width: 0,
},
]
: [];
const cols: PersistedTableColumn[] = [ const columnDefs = useMemo(() => getColumnDefs(tableConfig.columns), [tableConfig.columns]);
{
column: TableColumn.TRACK_NUMBER,
width: 0,
},
{
column: TableColumn.TITLE_COMBINED,
width: 0,
},
{
column: TableColumn.DURATION,
width: 0,
},
{
column: TableColumn.BIT_RATE,
width: 0,
},
{
column: TableColumn.PLAY_COUNT,
width: 0,
},
{
column: TableColumn.LAST_PLAYED,
width: 0,
},
...userRatingColumn,
{
column: TableColumn.USER_FAVORITE,
width: 0,
},
];
return getColumnDefs(cols).filter((c) => c.colId !== 'album' && c.colId !== 'artist');
}, [detailQuery?.data?.serverType]);
const getRowHeight = useCallback((params: RowHeightParams) => { const getRowHeight = useCallback((params: RowHeightParams) => {
if (isFullWidthRow(params.node)) { if (isFullWidthRow(params.node)) {
@ -307,11 +270,12 @@ export const AlbumDetailContent = ({ tableRef, background }: AlbumDetailContentP
<DetailContainer> <DetailContainer>
<Box component="section"> <Box component="section">
<Group <Group
position="apart"
py="1rem" py="1rem"
spacing="md" spacing="sm"
> >
<PlayButton onClick={() => handlePlay(playButtonBehavior)} /> <Group>
<Group spacing="xs"> <PlayButton onClick={() => handlePlay(playButtonBehavior)} />
<Button <Button
compact compact
loading={ loading={
@ -341,6 +305,21 @@ export const AlbumDetailContent = ({ tableRef, background }: AlbumDetailContentP
<RiMoreFill size={20} /> <RiMoreFill size={20} />
</Button> </Button>
</Group> </Group>
<Popover position="bottom-end">
<Popover.Target>
<Button
compact
size="md"
variant="subtle"
>
<RiSettings2Fill size={20} />
</Button>
</Popover.Target>
<Popover.Dropdown>
<TableConfigDropdown type="albumDetail" />
</Popover.Dropdown>
</Popover>
</Group> </Group>
</Box> </Box>
{showGenres && ( {showGenres && (
@ -370,13 +349,12 @@ export const AlbumDetailContent = ({ tableRef, background }: AlbumDetailContentP
<Box style={{ minHeight: '300px' }}> <Box style={{ minHeight: '300px' }}>
<VirtualTable <VirtualTable
ref={tableRef} ref={tableRef}
autoFitColumns
autoHeight autoHeight
stickyHeader stickyHeader
suppressCellFocus suppressCellFocus
suppressHorizontalScroll
suppressLoadingOverlay suppressLoadingOverlay
suppressRowDrag suppressRowDrag
autoFitColumns={tableConfig.autoFit}
columnDefs={columnDefs} columnDefs={columnDefs}
enableCellChangeFlash={false} enableCellChangeFlash={false}
fullWidthCellRenderer={FullWidthDiscCell} fullWidthCellRenderer={FullWidthDiscCell}

View file

@ -167,6 +167,7 @@ export interface SettingsState {
}; };
tab: 'general' | 'playback' | 'window' | 'hotkeys' | string; tab: 'general' | 'playback' | 'window' | 'hotkeys' | string;
tables: { tables: {
albumDetail: DataTableProps;
fullScreen: DataTableProps; fullScreen: DataTableProps;
nowPlaying: DataTableProps; nowPlaying: DataTableProps;
sideDrawerQueue: DataTableProps; sideDrawerQueue: DataTableProps;
@ -287,6 +288,40 @@ const initialState: SettingsState = {
}, },
tab: 'general', tab: 'general',
tables: { tables: {
albumDetail: {
autoFit: true,
columns: [
{
column: TableColumn.TRACK_NUMBER,
width: 50,
},
{
column: TableColumn.TITLE_COMBINED,
width: 500,
},
{
column: TableColumn.DURATION,
width: 100,
},
{
column: TableColumn.BIT_RATE,
width: 300,
},
{
column: TableColumn.PLAY_COUNT,
width: 100,
},
{
column: TableColumn.LAST_PLAYED,
width: 100,
},
{
column: TableColumn.USER_FAVORITE,
width: 100,
},
],
rowHeight: 60,
},
fullScreen: { fullScreen: {
autoFit: true, autoFit: true,
columns: [ columns: [

View file

@ -26,7 +26,13 @@ export type CardRoute = {
slugs?: RouteSlug[]; slugs?: RouteSlug[];
}; };
export type TableType = 'nowPlaying' | 'sideQueue' | 'sideDrawerQueue' | 'songs' | 'fullScreen'; export type TableType =
| 'nowPlaying'
| 'sideQueue'
| 'sideDrawerQueue'
| 'songs'
| 'fullScreen'
| 'albumDetail';
export type CardRow<T> = { export type CardRow<T> = {
arrayProperty?: string; arrayProperty?: string;