mirror of
https://github.com/jeffvli/feishin.git
synced 2026-07-16 23:50:17 +02:00
add additional album group metadata rows
This commit is contained in:
@@ -1231,6 +1231,8 @@
|
||||
"general": {
|
||||
"advancedSettings": "Advanced settings",
|
||||
"albumGroupConfig": "Album Group configuration",
|
||||
"albumGroupMetadata": "Metadata fields",
|
||||
"albumGroupShowFavoriteRating": "Show favorites and ratings",
|
||||
"albumImageSize": "Album image size",
|
||||
"autoFitColumns": "Auto fit columns",
|
||||
"autosize": "Autosize",
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
}
|
||||
|
||||
.info {
|
||||
display: grid;
|
||||
grid-template-rows: auto auto auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
align-content: start;
|
||||
min-width: 0;
|
||||
@@ -71,7 +71,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.artist-name {
|
||||
.metadata-row {
|
||||
font-size: var(--theme-font-size-xs);
|
||||
line-height: 1.25;
|
||||
overflow-wrap: anywhere;
|
||||
|
||||
@@ -1,26 +1,33 @@
|
||||
import clsx from 'clsx';
|
||||
import { ReactElement, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { ReactElement, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { generatePath, Link } from 'react-router';
|
||||
|
||||
import imageColumnStyles from '../item-detail-list/columns/image-column.module.css';
|
||||
import { AlbumGroupControls } from './album-group-controls';
|
||||
import styles from './album-group-header.module.css';
|
||||
import { AlbumGroupMetadata, renderAlbumGroupMetadataItem } from './album-group-metadata';
|
||||
import { TableItemSize } from './item-table-list';
|
||||
|
||||
import { ItemImage } from '/@/renderer/components/item-image/item-image';
|
||||
import { JoinedArtists } from '/@/renderer/features/albums/components/joined-artists';
|
||||
import { PlayButton } from '/@/renderer/features/shared/components/play-button';
|
||||
import {
|
||||
LONG_PRESS_PLAY_BEHAVIOR,
|
||||
PlayTooltip,
|
||||
} from '/@/renderer/features/shared/components/play-button-group';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { useAlbumGroupImageSize, usePlayButtonBehavior } from '/@/renderer/store';
|
||||
import {
|
||||
useAlbumGroupImageSize,
|
||||
useAlbumGroupItems,
|
||||
useAlbumGroupShowFavoriteRating,
|
||||
usePlayButtonBehavior,
|
||||
} from '/@/renderer/store';
|
||||
import { LibraryItem, Song } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
interface AlbumGroupHeaderProps {
|
||||
groupRowCount?: number;
|
||||
metadata: AlbumGroupMetadata;
|
||||
onPlay?: (playType: Play) => void;
|
||||
rowIndex?: number;
|
||||
setAlbumGroupContentHeight?: (rowIndex: number, height: number) => void;
|
||||
@@ -30,12 +37,16 @@ interface AlbumGroupHeaderProps {
|
||||
|
||||
export const AlbumGroupHeader = ({
|
||||
groupRowCount,
|
||||
metadata,
|
||||
onPlay,
|
||||
rowIndex,
|
||||
setAlbumGroupContentHeight,
|
||||
size = 'normal',
|
||||
song,
|
||||
}: AlbumGroupHeaderProps): ReactElement => {
|
||||
const { t } = useTranslation();
|
||||
const albumGroupItems = useAlbumGroupItems();
|
||||
const showFavoriteRating = useAlbumGroupShowFavoriteRating();
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const [resolvedInfoHeight, setResolvedInfoHeight] = useState<number | undefined>();
|
||||
const playButtonBehavior = usePlayButtonBehavior();
|
||||
@@ -50,6 +61,16 @@ export const AlbumGroupHeader = ({
|
||||
? generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, { albumId: song.albumId })
|
||||
: null;
|
||||
|
||||
const metadataRows = useMemo(() => {
|
||||
return albumGroupItems
|
||||
.filter((item) => !item.disabled)
|
||||
.map((item) => ({
|
||||
content: renderAlbumGroupMetadataItem(item.id, song, metadata, t),
|
||||
id: item.id,
|
||||
}))
|
||||
.filter((item) => item.content != null);
|
||||
}, [albumGroupItems, metadata, song, t]);
|
||||
|
||||
// The album group spans the combined row height, but when the image is
|
||||
// enlarged the group's last row is grown so the total reaches the img size.
|
||||
const infoHeight =
|
||||
@@ -145,22 +166,21 @@ export const AlbumGroupHeader = ({
|
||||
(song?.album ?? '')
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.artistName}>
|
||||
<JoinedArtists
|
||||
artistName={song?.albumArtistName ?? ''}
|
||||
artists={song?.albumArtists ?? []}
|
||||
linkProps={{ fw: 400 }}
|
||||
rootTextProps={{ fw: 400, size: 'xs' }}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.controlsRow}>
|
||||
<AlbumGroupControls
|
||||
albumId={song?.albumId}
|
||||
isGroupHovered={isHovered}
|
||||
serverId={song?._serverId}
|
||||
serverType={song?._serverType}
|
||||
/>
|
||||
</div>
|
||||
{metadataRows.map((row) => (
|
||||
<div className={styles.metadataRow} key={row.id}>
|
||||
{row.content}
|
||||
</div>
|
||||
))}
|
||||
{showFavoriteRating && (
|
||||
<div className={styles.controlsRow}>
|
||||
<AlbumGroupControls
|
||||
albumId={song?.albumId}
|
||||
isGroupHovered={isHovered}
|
||||
serverId={song?._serverId}
|
||||
serverType={song?._serverType}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
import { TFunction } from 'i18next';
|
||||
import { Fragment, ReactNode } from 'react';
|
||||
import { generatePath, Link } from 'react-router';
|
||||
|
||||
import { JoinedArtists } from '/@/renderer/features/albums/components/joined-artists';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { AlbumGroupItem } from '/@/renderer/store';
|
||||
import { formatDurationString, formatPartialIsoDateUTC, formatSizeString } from '/@/renderer/utils';
|
||||
import { normalizeReleaseTypes } from '/@/renderer/utils/normalize-release-types';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { Genre, Song } from '/@/shared/types/domain-types';
|
||||
|
||||
export type AlbumGroupMetadata = {
|
||||
duration: number;
|
||||
genres: Genre[];
|
||||
releaseDate: Song['releaseDate'];
|
||||
releaseType: null | string;
|
||||
releaseYear: Song['releaseYear'];
|
||||
size: number;
|
||||
songCount: number;
|
||||
};
|
||||
|
||||
export const computeAlbumGroupMetadata = (
|
||||
songs: Song[],
|
||||
songCount: number,
|
||||
t: TFunction,
|
||||
): AlbumGroupMetadata => {
|
||||
const genreMap = new Map<string, Genre>();
|
||||
let duration = 0;
|
||||
let size = 0;
|
||||
|
||||
for (const song of songs) {
|
||||
duration += song.duration ?? 0;
|
||||
size += song.size ?? 0;
|
||||
|
||||
for (const genre of song.genres ?? []) {
|
||||
if (!genreMap.has(genre.id)) {
|
||||
genreMap.set(genre.id, genre);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const firstSong = songs[0];
|
||||
const releaseTypes = firstSong?.tags?.releasetype;
|
||||
const releaseType = releaseTypes?.length
|
||||
? (normalizeReleaseTypes(releaseTypes, t)[0] ?? null)
|
||||
: null;
|
||||
|
||||
return {
|
||||
duration,
|
||||
genres: Array.from(genreMap.values()),
|
||||
releaseDate: firstSong?.releaseDate ?? null,
|
||||
releaseType,
|
||||
releaseYear: firstSong?.releaseYear ?? null,
|
||||
size,
|
||||
songCount,
|
||||
};
|
||||
};
|
||||
|
||||
const formatReleaseDate = (metadata: AlbumGroupMetadata): null | string => {
|
||||
if (metadata.releaseDate) {
|
||||
return formatPartialIsoDateUTC(metadata.releaseDate);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const renderAlbumGroupMetadataItem = (
|
||||
itemId: AlbumGroupItem,
|
||||
song: Song | undefined,
|
||||
metadata: AlbumGroupMetadata,
|
||||
t: TFunction,
|
||||
): null | ReactNode => {
|
||||
switch (itemId) {
|
||||
case AlbumGroupItem.ALBUM_ARTISTS:
|
||||
if (!song?.albumArtistName && !(song?.albumArtists?.length ?? 0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<JoinedArtists
|
||||
artistName={song?.albumArtistName ?? ''}
|
||||
artists={song?.albumArtists ?? []}
|
||||
linkProps={{ fw: 400 }}
|
||||
rootTextProps={{ fw: 400, size: 'xs' }}
|
||||
/>
|
||||
);
|
||||
|
||||
case AlbumGroupItem.DURATION:
|
||||
return metadata.duration > 0 ? (
|
||||
<Text size="xs">{formatDurationString(metadata.duration)}</Text>
|
||||
) : null;
|
||||
|
||||
case AlbumGroupItem.GENRES:
|
||||
if (metadata.genres.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{metadata.genres.map((genre, index) => (
|
||||
<Fragment key={genre.id}>
|
||||
<Text
|
||||
component={Link}
|
||||
fw={400}
|
||||
isLink
|
||||
size="xs"
|
||||
state={{ item: genre }}
|
||||
to={generatePath(AppRoute.LIBRARY_GENRES_DETAIL, {
|
||||
genreId: genre.id,
|
||||
})}
|
||||
>
|
||||
{genre.name}
|
||||
</Text>
|
||||
{index < metadata.genres.length - 1 && ', '}
|
||||
</Fragment>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
case AlbumGroupItem.RELEASE_DATE: {
|
||||
const releaseDate = formatReleaseDate(metadata);
|
||||
return releaseDate ? <Text size="xs">{releaseDate}</Text> : null;
|
||||
}
|
||||
|
||||
case AlbumGroupItem.RELEASE_TYPE:
|
||||
return metadata.releaseType ? <Text size="xs">{metadata.releaseType}</Text> : null;
|
||||
|
||||
case AlbumGroupItem.RELEASE_YEAR:
|
||||
return metadata.releaseYear != null && metadata.releaseYear > 0 ? (
|
||||
<Text size="xs">{metadata.releaseYear}</Text>
|
||||
) : null;
|
||||
|
||||
case AlbumGroupItem.SIZE:
|
||||
return metadata.size > 0 ? (
|
||||
<Text size="xs">{formatSizeString(metadata.size)}</Text>
|
||||
) : null;
|
||||
|
||||
case AlbumGroupItem.SONG_COUNT:
|
||||
return metadata.songCount > 0 ? (
|
||||
<Text size="xs">{t('entity.trackWithCount', { count: metadata.songCount })}</Text>
|
||||
) : null;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { AlbumGroupHeader } from '/@/renderer/components/item-list/item-table-list/album-group-header';
|
||||
import { computeAlbumGroupMetadata } from '/@/renderer/components/item-list/item-table-list/album-group-metadata';
|
||||
import {
|
||||
isLastInAlbumGroup,
|
||||
ItemTableListInnerColumn,
|
||||
@@ -10,6 +12,7 @@ import { Song } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
export const AlbumGroupColumn = (props: ItemTableListInnerColumn) => {
|
||||
const { t } = useTranslation();
|
||||
const firstDataRow = props.enableHeader ? 1 : 0;
|
||||
const item = props.getRowItem?.(props.rowIndex) as null | Song | undefined;
|
||||
|
||||
@@ -76,13 +79,17 @@ export const AlbumGroupColumn = (props: ItemTableListInnerColumn) => {
|
||||
}
|
||||
|
||||
let groupRowCount = 1;
|
||||
const groupSongs: Song[] = [item];
|
||||
const totalDataRows = props.data.length + firstDataRow;
|
||||
for (let idx = props.rowIndex + 1; idx < totalDataRows; idx++) {
|
||||
const nextItem = props.getRowItem?.(idx) as null | Song | undefined;
|
||||
if (!nextItem || nextItem.album !== item.album) break;
|
||||
groupRowCount++;
|
||||
groupSongs.push(nextItem);
|
||||
}
|
||||
|
||||
const metadata = computeAlbumGroupMetadata(groupSongs, groupRowCount, t);
|
||||
|
||||
return (
|
||||
<TableColumnContainer
|
||||
{...props}
|
||||
@@ -92,6 +99,7 @@ export const AlbumGroupColumn = (props: ItemTableListInnerColumn) => {
|
||||
>
|
||||
<AlbumGroupHeader
|
||||
groupRowCount={groupRowCount}
|
||||
metadata={metadata}
|
||||
onPlay={handlePlay}
|
||||
rowIndex={props.rowIndex}
|
||||
setAlbumGroupContentHeight={props.setAlbumGroupContentHeight}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import { Reorder } from 'motion/react';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { DraggableItem } from '/@/renderer/features/settings/components/general/draggable-item';
|
||||
import {
|
||||
AlbumGroupItem,
|
||||
SortableItem,
|
||||
useAlbumGroupItems,
|
||||
useSettingsStoreActions,
|
||||
} from '/@/renderer/store';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
|
||||
const ALBUM_GROUP_ITEM_LABELS: Array<[AlbumGroupItem, string]> = [
|
||||
[AlbumGroupItem.ALBUM_ARTISTS, 'table.column.albumArtist'],
|
||||
[AlbumGroupItem.RELEASE_DATE, 'table.column.releaseDate'],
|
||||
[AlbumGroupItem.RELEASE_YEAR, 'table.column.releaseYear'],
|
||||
[AlbumGroupItem.SONG_COUNT, 'table.column.songCount'],
|
||||
[AlbumGroupItem.DURATION, 'common.duration'],
|
||||
[AlbumGroupItem.RELEASE_TYPE, 'common.releaseType'],
|
||||
[AlbumGroupItem.GENRES, 'table.column.genre'],
|
||||
[AlbumGroupItem.SIZE, 'table.column.size'],
|
||||
];
|
||||
|
||||
const mergeItems = (
|
||||
items: SortableItem<AlbumGroupItem>[],
|
||||
itemLabels: Array<[string, string]>,
|
||||
): SortableItem<AlbumGroupItem>[] => {
|
||||
const allItemIds = itemLabels.map(([key]) => key);
|
||||
|
||||
const missingItemIds = allItemIds.filter((id) => !items.some((item) => item.id === id));
|
||||
|
||||
const merged = [
|
||||
...items,
|
||||
...(missingItemIds.map((id) => ({
|
||||
disabled: true,
|
||||
id,
|
||||
})) as SortableItem<AlbumGroupItem>[]),
|
||||
];
|
||||
|
||||
const uniqueMerged = merged.filter(
|
||||
(item, index, self) => index === self.findIndex((t) => t.id === item.id),
|
||||
);
|
||||
|
||||
return uniqueMerged.filter((item) => itemLabels.some(([key]) => key === item.id));
|
||||
};
|
||||
|
||||
export const AlbumGroupMetadataConfig = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const albumGroupItems = useAlbumGroupItems();
|
||||
const { setAlbumGroupItems } = useSettingsStoreActions();
|
||||
|
||||
const items = useMemo(
|
||||
() => mergeItems(albumGroupItems, ALBUM_GROUP_ITEM_LABELS),
|
||||
[albumGroupItems],
|
||||
);
|
||||
|
||||
const translatedItemMap = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
ALBUM_GROUP_ITEM_LABELS.map(([key, value]) => [key, t(value)]),
|
||||
) as Record<AlbumGroupItem, string>,
|
||||
[t],
|
||||
);
|
||||
|
||||
const handleChangeDisabled = useCallback(
|
||||
(id: string, enabled: boolean) => {
|
||||
setAlbumGroupItems(
|
||||
items.map((item) => {
|
||||
if (item.id === id) {
|
||||
return {
|
||||
...item,
|
||||
disabled: !enabled,
|
||||
};
|
||||
}
|
||||
|
||||
return item;
|
||||
}),
|
||||
);
|
||||
},
|
||||
[items, setAlbumGroupItems],
|
||||
);
|
||||
|
||||
const handleReorder = useCallback(
|
||||
(reorderedItems: SortableItem<AlbumGroupItem>[]) => {
|
||||
setAlbumGroupItems(reorderedItems);
|
||||
},
|
||||
[setAlbumGroupItems],
|
||||
);
|
||||
|
||||
return (
|
||||
<Stack gap="sm" pb="md" pl="md" pr="md">
|
||||
<Stack gap={0}>
|
||||
<Text fw={500} size="sm">
|
||||
{t('table.config.general.albumGroupMetadata')}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Reorder.Group
|
||||
axis="y"
|
||||
onReorder={handleReorder}
|
||||
style={{ userSelect: 'none' }}
|
||||
values={items}
|
||||
>
|
||||
{items.map((item) => (
|
||||
<DraggableItem
|
||||
handleChangeDisabled={handleChangeDisabled}
|
||||
item={item}
|
||||
key={item.id}
|
||||
value={translatedItemMap[item.id]}
|
||||
/>
|
||||
))}
|
||||
</Reorder.Group>
|
||||
</Stack>
|
||||
);
|
||||
});
|
||||
@@ -17,6 +17,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import styles from './table-config.module.css';
|
||||
|
||||
import { ItemTableListColumnConfig } from '/@/renderer/components/item-list/types';
|
||||
import { AlbumGroupMetadataConfig } from '/@/renderer/features/shared/components/album-group-metadata-config';
|
||||
import {
|
||||
ListConfigBooleanControl,
|
||||
ListConfigTable,
|
||||
@@ -74,6 +75,9 @@ export const TableConfig = ({
|
||||
|
||||
const list = useSettingsStore((state) => state.lists[listKey]) as ItemListSettings;
|
||||
const albumGroupImageSize = useSettingsStore((state) => state.general.albumGroupImageSize);
|
||||
const albumGroupShowFavoriteRating = useSettingsStore(
|
||||
(state) => state.general.albumGroupShowFavoriteRating,
|
||||
);
|
||||
const imageResTable = useSettingsStore((state) => state.general.imageRes.table);
|
||||
const { setList, setSettings } = useSettingsStoreActions();
|
||||
const [albumGroupOpen, setAlbumGroupOpen] = useState(false);
|
||||
@@ -156,11 +160,31 @@ export const TableConfig = ({
|
||||
),
|
||||
id: 'albumImageSize',
|
||||
label: (
|
||||
<Text pl="md">
|
||||
<Text fw={500} pl="md" size="sm">
|
||||
{t('table.config.general.albumImageSize')}
|
||||
</Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
component: (
|
||||
<ListConfigBooleanControl
|
||||
onChange={(value) =>
|
||||
setSettings({
|
||||
general: {
|
||||
albumGroupShowFavoriteRating: value,
|
||||
},
|
||||
})
|
||||
}
|
||||
value={albumGroupShowFavoriteRating}
|
||||
/>
|
||||
),
|
||||
id: 'albumGroupShowFavoriteRating',
|
||||
label: (
|
||||
<Text fw={500} pl="md" size="sm">
|
||||
{t('table.config.general.albumGroupShowFavoriteRating')}
|
||||
</Text>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
]
|
||||
@@ -342,6 +366,7 @@ export const TableConfig = ({
|
||||
hasAlbumGroupColumn,
|
||||
albumGroupOpen,
|
||||
albumGroupImageSize,
|
||||
albumGroupShowFavoriteRating,
|
||||
imageResTable,
|
||||
setSettings,
|
||||
]);
|
||||
@@ -349,6 +374,9 @@ export const TableConfig = ({
|
||||
return (
|
||||
<>
|
||||
<ListConfigTable options={advancedSettings} />
|
||||
{hasAlbumGroupColumn && tableKey === 'main' && albumGroupOpen && (
|
||||
<AlbumGroupMetadataConfig />
|
||||
)}
|
||||
<Divider />
|
||||
<TableColumnConfig
|
||||
data={tableColumnsData}
|
||||
|
||||
@@ -76,6 +76,17 @@ const HomeItemSchema = z.enum([
|
||||
'recentlyReleased',
|
||||
]);
|
||||
|
||||
const AlbumGroupItemSchema = z.enum([
|
||||
'albumArtists',
|
||||
'duration',
|
||||
'genres',
|
||||
'releaseDate',
|
||||
'releaseYear',
|
||||
'releaseType',
|
||||
'size',
|
||||
'songCount',
|
||||
]);
|
||||
|
||||
const PlayerItemSchema = z.enum([
|
||||
'bit_depth',
|
||||
'bit_rate',
|
||||
@@ -475,6 +486,8 @@ export const GeneralSettingsSchema = z.object({
|
||||
albumBackground: z.boolean(),
|
||||
albumBackgroundBlur: z.number(),
|
||||
albumGroupImageSize: z.number(),
|
||||
albumGroupItems: z.array(SortableItemSchema(AlbumGroupItemSchema)),
|
||||
albumGroupShowFavoriteRating: z.boolean(),
|
||||
artistBackground: z.boolean(),
|
||||
artistBackgroundBlur: z.number(),
|
||||
artistItems: z.array(SortableItemSchema(ArtistItemSchema)),
|
||||
@@ -767,6 +780,17 @@ export const SettingsStateSchema = ValidationSettingsStateSchema.merge(
|
||||
NonValidatedSettingsStateSchema,
|
||||
);
|
||||
|
||||
export enum AlbumGroupItem {
|
||||
ALBUM_ARTISTS = 'albumArtists',
|
||||
DURATION = 'duration',
|
||||
GENRES = 'genres',
|
||||
RELEASE_DATE = 'releaseDate',
|
||||
RELEASE_TYPE = 'releaseType',
|
||||
RELEASE_YEAR = 'releaseYear',
|
||||
SIZE = 'size',
|
||||
SONG_COUNT = 'songCount',
|
||||
}
|
||||
|
||||
export enum ArtistItem {
|
||||
BIOGRAPHY = 'biography',
|
||||
FAVORITE_SONGS = 'favoriteSongs',
|
||||
@@ -944,6 +968,7 @@ export interface SettingsSlice extends z.infer<typeof SettingsStateSchema> {
|
||||
removeCollection: (id: string) => void;
|
||||
reset: () => void;
|
||||
resetSampleRate: () => void;
|
||||
setAlbumGroupItems: (items: SortableItem<AlbumGroupItem>[]) => void;
|
||||
setArtistItems: (item: SortableItem<ArtistItem>[]) => void;
|
||||
setArtistReleaseTypeItems: (item: SortableItem<ArtistReleaseTypeItem>[]) => void;
|
||||
setGenreBehavior: (target: GenreTarget) => void;
|
||||
@@ -1120,6 +1145,17 @@ const artistReleaseTypeItems = Object.values(ArtistReleaseTypeItem).map((item) =
|
||||
id: item,
|
||||
}));
|
||||
|
||||
const albumGroupItems: SortableItem<AlbumGroupItem>[] = [
|
||||
{ disabled: false, id: AlbumGroupItem.ALBUM_ARTISTS },
|
||||
{ disabled: true, id: AlbumGroupItem.RELEASE_DATE },
|
||||
{ disabled: true, id: AlbumGroupItem.RELEASE_YEAR },
|
||||
{ disabled: true, id: AlbumGroupItem.SONG_COUNT },
|
||||
{ disabled: true, id: AlbumGroupItem.DURATION },
|
||||
{ disabled: true, id: AlbumGroupItem.RELEASE_TYPE },
|
||||
{ disabled: true, id: AlbumGroupItem.GENRES },
|
||||
{ disabled: true, id: AlbumGroupItem.SIZE },
|
||||
];
|
||||
|
||||
// Determines the default/initial windowBarStyle value based on the current platform.
|
||||
const getPlatformDefaultWindowBarStyle = (): Platform => {
|
||||
if (utils?.isWindows()) {
|
||||
@@ -1173,6 +1209,8 @@ const initialState: SettingsState = {
|
||||
albumBackground: false,
|
||||
albumBackgroundBlur: 3,
|
||||
albumGroupImageSize: 0,
|
||||
albumGroupItems,
|
||||
albumGroupShowFavoriteRating: true,
|
||||
artistBackground: true,
|
||||
artistBackgroundBlur: 3,
|
||||
artistItems,
|
||||
@@ -2063,6 +2101,11 @@ export const useSettingsStore = createWithEqualityFn<SettingsSlice>()(
|
||||
state.playback.mpvProperties.audioSampleRateHz = 0;
|
||||
});
|
||||
},
|
||||
setAlbumGroupItems: (items: SortableItem<AlbumGroupItem>[]) => {
|
||||
set((state) => {
|
||||
state.general.albumGroupItems = items;
|
||||
});
|
||||
},
|
||||
setArtistItems: (items) => {
|
||||
set((state) => {
|
||||
state.general.artistItems = items;
|
||||
@@ -2681,6 +2724,9 @@ export const useImageRes = () => useSettingsStore((state) => state.general.image
|
||||
export const useAlbumGroupImageSize = () =>
|
||||
useSettingsStore((state) => state.general.albumGroupImageSize);
|
||||
|
||||
export const useAlbumGroupShowFavoriteRating = () =>
|
||||
useSettingsStore((state) => state.general.albumGroupShowFavoriteRating);
|
||||
|
||||
export const useVolumeWidth = () => useSettingsStore((state) => state.general.volumeWidth, shallow);
|
||||
|
||||
export const useFollowCurrentSong = () =>
|
||||
@@ -2800,6 +2846,9 @@ export const useHomeFeatureStyle = () =>
|
||||
|
||||
export const useHomeItems = () => useSettingsStore((state) => state.general.homeItems, shallow);
|
||||
|
||||
export const useAlbumGroupItems = () =>
|
||||
useSettingsStore((state) => state.general.albumGroupItems, shallow);
|
||||
|
||||
export const useArtistItems = () => useSettingsStore((state) => state.general.artistItems, shallow);
|
||||
|
||||
export const useArtistReleaseTypeItems = () =>
|
||||
|
||||
Reference in New Issue
Block a user