mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
feat: adding setting to show/hide user ratings (#1426)
* adding show/hide user ratings setting
This commit is contained in:
committed by
GitHub
parent
f0942c7795
commit
df0d4b7032
@@ -899,6 +899,8 @@
|
|||||||
"preferLocalLyrics": "prefer local lyrics",
|
"preferLocalLyrics": "prefer local lyrics",
|
||||||
"showLyricsInSidebar_description": "a panel will be added to the attached play queue that displays the lyrics",
|
"showLyricsInSidebar_description": "a panel will be added to the attached play queue that displays the lyrics",
|
||||||
"showLyricsInSidebar": "show lyrics in player sidebar",
|
"showLyricsInSidebar": "show lyrics in player sidebar",
|
||||||
|
"showRatings_description": "controls if the star ratings feature shows up in the interface",
|
||||||
|
"showRatings": "show star ratings",
|
||||||
"showVisualizerInSidebar_description": "a panel will be added to the player sidebar that displays the visualizer",
|
"showVisualizerInSidebar_description": "a panel will be added to the player sidebar that displays the visualizer",
|
||||||
"showVisualizerInSidebar": "show visualizer in player sidebar",
|
"showVisualizerInSidebar": "show visualizer in player sidebar",
|
||||||
"combinedLyricsAndVisualizer_description": "combine lyrics and visualizer into the same panel",
|
"combinedLyricsAndVisualizer_description": "combine lyrics and visualizer into the same panel",
|
||||||
|
|||||||
@@ -383,6 +383,8 @@
|
|||||||
"savePlayQueue_description": "Salvar a fila de reprodução ao fechar a aplicação e restaurá-la ao abrir a aplicação",
|
"savePlayQueue_description": "Salvar a fila de reprodução ao fechar a aplicação e restaurá-la ao abrir a aplicação",
|
||||||
"scrobble": "Scrobblar",
|
"scrobble": "Scrobblar",
|
||||||
"scrobble_description": "Scrobblar reproduções para o seu servidor de mídia",
|
"scrobble_description": "Scrobblar reproduções para o seu servidor de mídia",
|
||||||
|
"showRatings": "exibir avaliações por estrelas",
|
||||||
|
"showRatings_description": "exibir ou ocultar as avaliações por estrelas",
|
||||||
"showSkipButton": "Exibir botões de pular",
|
"showSkipButton": "Exibir botões de pular",
|
||||||
"showSkipButton_description": "Exibir ou ocultar os botões de pular na barra do reprodutor",
|
"showSkipButton_description": "Exibir ou ocultar os botões de pular na barra do reprodutor",
|
||||||
"showSkipButtons": "Exibir botões de pular",
|
"showSkipButtons": "Exibir botões de pular",
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ interface ItemCardControlsProps {
|
|||||||
internalState?: ItemListStateActions;
|
internalState?: ItemListStateActions;
|
||||||
item: Album | AlbumArtist | Artist | Playlist | Song | undefined;
|
item: Album | AlbumArtist | Artist | Playlist | Song | undefined;
|
||||||
itemType: LibraryItem;
|
itemType: LibraryItem;
|
||||||
|
showRating: boolean;
|
||||||
type?: 'compact' | 'default' | 'poster';
|
type?: 'compact' | 'default' | 'poster';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +181,7 @@ export const ItemCardControls = ({
|
|||||||
internalState,
|
internalState,
|
||||||
item,
|
item,
|
||||||
itemType,
|
itemType,
|
||||||
|
showRating,
|
||||||
type = 'default',
|
type = 'default',
|
||||||
}: ItemCardControlsProps) => {
|
}: ItemCardControlsProps) => {
|
||||||
const playNowHandler = useMemo(
|
const playNowHandler = useMemo(
|
||||||
@@ -267,6 +269,7 @@ export const ItemCardControls = ({
|
|||||||
<FavoriteButton isFavorite={isFavorite} onClick={favoriteHandler} />
|
<FavoriteButton isFavorite={isFavorite} onClick={favoriteHandler} />
|
||||||
)}
|
)}
|
||||||
{controls?.onRating &&
|
{controls?.onRating &&
|
||||||
|
showRating &&
|
||||||
(item?._serverType === ServerType.NAVIDROME ||
|
(item?._serverType === ServerType.NAVIDROME ||
|
||||||
item?._serverType === ServerType.SUBSONIC) && (
|
item?._serverType === ServerType.SUBSONIC) && (
|
||||||
<RatingButton
|
<RatingButton
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
import { ItemControls } from '/@/renderer/components/item-list/types';
|
import { ItemControls } from '/@/renderer/components/item-list/types';
|
||||||
import { useDragDrop } from '/@/renderer/hooks/use-drag-drop';
|
import { useDragDrop } from '/@/renderer/hooks/use-drag-drop';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
|
import { useGeneralSettings } from '/@/renderer/store';
|
||||||
import { formatDateAbsolute, formatDateRelative, formatRating } from '/@/renderer/utils/format';
|
import { formatDateAbsolute, formatDateRelative, formatRating } from '/@/renderer/utils/format';
|
||||||
import { Separator } from '/@/shared/components/separator/separator';
|
import { Separator } from '/@/shared/components/separator/separator';
|
||||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||||
@@ -67,6 +68,7 @@ export const ItemCard = ({
|
|||||||
type = 'poster',
|
type = 'poster',
|
||||||
withControls,
|
withControls,
|
||||||
}: ItemCardProps) => {
|
}: ItemCardProps) => {
|
||||||
|
const { showRatings } = useGeneralSettings();
|
||||||
const imageUrl = getImageUrl(data);
|
const imageUrl = getImageUrl(data);
|
||||||
const rows = providedRows || [];
|
const rows = providedRows || [];
|
||||||
|
|
||||||
@@ -84,6 +86,7 @@ export const ItemCard = ({
|
|||||||
isRound={isRound}
|
isRound={isRound}
|
||||||
itemType={itemType}
|
itemType={itemType}
|
||||||
rows={rows}
|
rows={rows}
|
||||||
|
showRating={showRatings}
|
||||||
withControls={withControls}
|
withControls={withControls}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -100,6 +103,7 @@ export const ItemCard = ({
|
|||||||
isRound={isRound}
|
isRound={isRound}
|
||||||
itemType={itemType}
|
itemType={itemType}
|
||||||
rows={rows}
|
rows={rows}
|
||||||
|
showRating={showRatings}
|
||||||
withControls={withControls}
|
withControls={withControls}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -117,6 +121,7 @@ export const ItemCard = ({
|
|||||||
isRound={isRound}
|
isRound={isRound}
|
||||||
itemType={itemType}
|
itemType={itemType}
|
||||||
rows={rows}
|
rows={rows}
|
||||||
|
showRating={showRatings}
|
||||||
withControls={withControls}
|
withControls={withControls}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -130,6 +135,7 @@ export interface ItemCardDerivativeProps extends Omit<ItemCardProps, 'type'> {
|
|||||||
imageUrl: string | undefined;
|
imageUrl: string | undefined;
|
||||||
internalState?: ItemListStateActions;
|
internalState?: ItemListStateActions;
|
||||||
rows: DataRow[];
|
rows: DataRow[];
|
||||||
|
showRating: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CompactItemCard = ({
|
const CompactItemCard = ({
|
||||||
@@ -142,6 +148,7 @@ const CompactItemCard = ({
|
|||||||
isRound,
|
isRound,
|
||||||
itemType,
|
itemType,
|
||||||
rows,
|
rows,
|
||||||
|
showRating,
|
||||||
withControls,
|
withControls,
|
||||||
}: ItemCardDerivativeProps) => {
|
}: ItemCardDerivativeProps) => {
|
||||||
const [showControls, setShowControls] = useState(false);
|
const [showControls, setShowControls] = useState(false);
|
||||||
@@ -286,7 +293,7 @@ const CompactItemCard = ({
|
|||||||
typeof (data as { userRating: null | number }).userRating === 'number'
|
typeof (data as { userRating: null | number }).userRating === 'number'
|
||||||
? (data as { userRating: null | number }).userRating
|
? (data as { userRating: null | number }).userRating
|
||||||
: null;
|
: null;
|
||||||
const hasRating = userRating !== null && userRating > 0;
|
const hasRating = showRating && userRating !== null && userRating > 0;
|
||||||
|
|
||||||
const imageContainerClassName = clsx(styles.imageContainer, {
|
const imageContainerClassName = clsx(styles.imageContainer, {
|
||||||
[styles.isRound]: isRound,
|
[styles.isRound]: isRound,
|
||||||
@@ -312,6 +319,7 @@ const CompactItemCard = ({
|
|||||||
internalState={internalState}
|
internalState={internalState}
|
||||||
item={data}
|
item={data}
|
||||||
itemType={itemType}
|
itemType={itemType}
|
||||||
|
showRating={hasRating}
|
||||||
type="compact"
|
type="compact"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -407,6 +415,7 @@ const DefaultItemCard = ({
|
|||||||
isRound,
|
isRound,
|
||||||
itemType,
|
itemType,
|
||||||
rows,
|
rows,
|
||||||
|
showRating,
|
||||||
withControls,
|
withControls,
|
||||||
}: ItemCardDerivativeProps) => {
|
}: ItemCardDerivativeProps) => {
|
||||||
const [showControls, setShowControls] = useState(false);
|
const [showControls, setShowControls] = useState(false);
|
||||||
@@ -508,7 +517,7 @@ const DefaultItemCard = ({
|
|||||||
typeof (data as { userRating: null | number }).userRating === 'number'
|
typeof (data as { userRating: null | number }).userRating === 'number'
|
||||||
? (data as { userRating: null | number }).userRating
|
? (data as { userRating: null | number }).userRating
|
||||||
: null;
|
: null;
|
||||||
const hasRating = userRating !== null && userRating > 0;
|
const hasRating = showRating && userRating !== null && userRating > 0;
|
||||||
|
|
||||||
const imageContainerContent = (
|
const imageContainerContent = (
|
||||||
<>
|
<>
|
||||||
@@ -527,6 +536,7 @@ const DefaultItemCard = ({
|
|||||||
enableExpansion={enableExpansion}
|
enableExpansion={enableExpansion}
|
||||||
item={data}
|
item={data}
|
||||||
itemType={itemType}
|
itemType={itemType}
|
||||||
|
showRating={showRating}
|
||||||
type="default"
|
type="default"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -620,6 +630,7 @@ const PosterItemCard = ({
|
|||||||
isRound,
|
isRound,
|
||||||
itemType,
|
itemType,
|
||||||
rows,
|
rows,
|
||||||
|
showRating,
|
||||||
withControls,
|
withControls,
|
||||||
}: ItemCardDerivativeProps) => {
|
}: ItemCardDerivativeProps) => {
|
||||||
const [showControls, setShowControls] = useState(false);
|
const [showControls, setShowControls] = useState(false);
|
||||||
@@ -768,7 +779,7 @@ const PosterItemCard = ({
|
|||||||
typeof (data as { userRating: null | number }).userRating === 'number'
|
typeof (data as { userRating: null | number }).userRating === 'number'
|
||||||
? (data as { userRating: null | number }).userRating
|
? (data as { userRating: null | number }).userRating
|
||||||
: null;
|
: null;
|
||||||
const hasRating = userRating !== null && userRating > 0;
|
const hasRating = showRating && userRating !== null && userRating > 0;
|
||||||
|
|
||||||
const imageContainerContent = (
|
const imageContainerContent = (
|
||||||
<>
|
<>
|
||||||
@@ -788,6 +799,7 @@ const PosterItemCard = ({
|
|||||||
internalState={internalState}
|
internalState={internalState}
|
||||||
item={data}
|
item={data}
|
||||||
itemType={itemType}
|
itemType={itemType}
|
||||||
|
showRating={showRating}
|
||||||
type="poster"
|
type="poster"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
LibraryHeaderMenu,
|
LibraryHeaderMenu,
|
||||||
} from '/@/renderer/features/shared/components/library-header';
|
} from '/@/renderer/features/shared/components/library-header';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useCurrentServer } from '/@/renderer/store';
|
import { useCurrentServer, useGeneralSettings } from '/@/renderer/store';
|
||||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
import { Stack } from '/@/shared/components/stack/stack';
|
import { Stack } from '/@/shared/components/stack/stack';
|
||||||
@@ -24,13 +24,15 @@ import { Play } from '/@/shared/types/types';
|
|||||||
export const AlbumDetailHeader = forwardRef<HTMLDivElement>((_props, ref) => {
|
export const AlbumDetailHeader = forwardRef<HTMLDivElement>((_props, ref) => {
|
||||||
const { albumId } = useParams() as { albumId: string };
|
const { albumId } = useParams() as { albumId: string };
|
||||||
const server = useCurrentServer();
|
const server = useCurrentServer();
|
||||||
|
const { showRatings } = useGeneralSettings();
|
||||||
const detailQuery = useQuery(
|
const detailQuery = useQuery(
|
||||||
albumQueries.detail({ query: { id: albumId }, serverId: server?.id }),
|
albumQueries.detail({ query: { id: albumId }, serverId: server?.id }),
|
||||||
);
|
);
|
||||||
|
|
||||||
const showRating =
|
const showRating =
|
||||||
detailQuery?.data?._serverType === ServerType.NAVIDROME ||
|
showRatings &&
|
||||||
detailQuery?.data?._serverType === ServerType.SUBSONIC;
|
(detailQuery?.data?._serverType === ServerType.NAVIDROME ||
|
||||||
|
detailQuery?.data?._serverType === ServerType.SUBSONIC);
|
||||||
|
|
||||||
const { addToQueueByFetch, setFavorite, setRating } = usePlayer();
|
const { addToQueueByFetch, setFavorite, setRating } = usePlayer();
|
||||||
const playButtonBehavior = usePlayButtonBehavior();
|
const playButtonBehavior = usePlayButtonBehavior();
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
LibraryHeaderMenu,
|
LibraryHeaderMenu,
|
||||||
} from '/@/renderer/features/shared/components/library-header';
|
} from '/@/renderer/features/shared/components/library-header';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useCurrentServer } from '/@/renderer/store';
|
import { useCurrentServer, useGeneralSettings } from '/@/renderer/store';
|
||||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||||
import { formatDurationString } from '/@/renderer/utils';
|
import { formatDurationString } from '/@/renderer/utils';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
@@ -30,6 +30,7 @@ export const AlbumArtistDetailHeader = forwardRef((_props, ref: Ref<HTMLDivEleme
|
|||||||
};
|
};
|
||||||
const routeId = (artistId || albumArtistId) as string;
|
const routeId = (artistId || albumArtistId) as string;
|
||||||
const server = useCurrentServer();
|
const server = useCurrentServer();
|
||||||
|
const { showRatings } = useGeneralSettings();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const detailQuery = useSuspenseQuery(
|
const detailQuery = useSuspenseQuery(
|
||||||
artistsQueries.albumArtistDetail({
|
artistsQueries.albumArtistDetail({
|
||||||
@@ -124,8 +125,6 @@ export const AlbumArtistDetailHeader = forwardRef((_props, ref: Ref<HTMLDivEleme
|
|||||||
[detailQuery.data],
|
[detailQuery.data],
|
||||||
);
|
);
|
||||||
|
|
||||||
const showRating = detailQuery.data?._serverType === ServerType.NAVIDROME;
|
|
||||||
|
|
||||||
const imageUrl = useItemImageUrl({
|
const imageUrl = useItemImageUrl({
|
||||||
id: detailQuery.data?.imageId || undefined,
|
id: detailQuery.data?.imageId || undefined,
|
||||||
imageUrl: detailQuery.data?.imageUrl,
|
imageUrl: detailQuery.data?.imageUrl,
|
||||||
@@ -133,6 +132,8 @@ export const AlbumArtistDetailHeader = forwardRef((_props, ref: Ref<HTMLDivEleme
|
|||||||
type: 'itemCard',
|
type: 'itemCard',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const showRating = showRatings && detailQuery?.data?._serverType === ServerType.NAVIDROME;
|
||||||
|
|
||||||
const selectedImageUrl = useMemo(() => {
|
const selectedImageUrl = useMemo(() => {
|
||||||
return detailQuery.data?.imageUrl || imageUrl;
|
return detailQuery.data?.imageUrl || imageUrl;
|
||||||
}, [detailQuery.data?.imageUrl, imageUrl]);
|
}, [detailQuery.data?.imageUrl, imageUrl]);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useSetRating } from '/@/renderer/features/shared/mutations/set-rating-mutation';
|
import { useSetRating } from '/@/renderer/features/shared/mutations/set-rating-mutation';
|
||||||
import { useCurrentServer, useCurrentServerId } from '/@/renderer/store';
|
import { useCurrentServer, useCurrentServerId, useGeneralSettings } from '/@/renderer/store';
|
||||||
import { ContextMenu } from '/@/shared/components/context-menu/context-menu';
|
import { ContextMenu } from '/@/shared/components/context-menu/context-menu';
|
||||||
import { Rating } from '/@/shared/components/rating/rating';
|
import { Rating } from '/@/shared/components/rating/rating';
|
||||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||||
@@ -17,6 +17,7 @@ export const SetRatingAction = ({ ids, itemType }: SetRatingActionProps) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const server = useCurrentServer();
|
const server = useCurrentServer();
|
||||||
const serverId = useCurrentServerId();
|
const serverId = useCurrentServerId();
|
||||||
|
const { showRatings } = useGeneralSettings();
|
||||||
|
|
||||||
const setRatingMutation = useSetRating({});
|
const setRatingMutation = useSetRating({});
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ export const SetRatingAction = ({ ids, itemType }: SetRatingActionProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isRatingSupported) {
|
if (!showRatings || !isRatingSupported) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -554,6 +554,27 @@ export const ApplicationSettings = () => {
|
|||||||
isHidden: !settings.externalLinks,
|
isHidden: !settings.externalLinks,
|
||||||
title: t('setting.musicbrainz', { postProcess: 'sentenceCase' }),
|
title: t('setting.musicbrainz', { postProcess: 'sentenceCase' }),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
control: (
|
||||||
|
<Switch
|
||||||
|
defaultChecked={settings.showRatings}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSettings({
|
||||||
|
general: {
|
||||||
|
...settings,
|
||||||
|
showRatings: e.currentTarget.checked,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description: t('setting.showRatings', {
|
||||||
|
context: 'description',
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
}),
|
||||||
|
isHidden: false,
|
||||||
|
title: t('setting.showRatings', { postProcess: 'sentenceCase' }),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
control: (
|
control: (
|
||||||
<Switch
|
<Switch
|
||||||
|
|||||||
@@ -377,6 +377,7 @@ export const GeneralSettingsSchema = z.object({
|
|||||||
playerbarSlider: PlayerbarSliderSchema,
|
playerbarSlider: PlayerbarSliderSchema,
|
||||||
resume: z.boolean(),
|
resume: z.boolean(),
|
||||||
showLyricsInSidebar: z.boolean(),
|
showLyricsInSidebar: z.boolean(),
|
||||||
|
showRatings: z.boolean(),
|
||||||
showVisualizerInSidebar: z.boolean(),
|
showVisualizerInSidebar: z.boolean(),
|
||||||
sidebarCollapsedNavigation: z.boolean(),
|
sidebarCollapsedNavigation: z.boolean(),
|
||||||
sidebarCollapseShared: z.boolean(),
|
sidebarCollapseShared: z.boolean(),
|
||||||
@@ -885,8 +886,9 @@ const initialState: SettingsState = {
|
|||||||
type: PlayerbarSliderType.WAVEFORM,
|
type: PlayerbarSliderType.WAVEFORM,
|
||||||
},
|
},
|
||||||
resume: true,
|
resume: true,
|
||||||
showLyricsInSidebar: true,
|
showLyricsInSidebar: false,
|
||||||
showVisualizerInSidebar: true,
|
showRatings: true,
|
||||||
|
showVisualizerInSidebar: false,
|
||||||
sidebarCollapsedNavigation: true,
|
sidebarCollapsedNavigation: true,
|
||||||
sidebarCollapseShared: false,
|
sidebarCollapseShared: false,
|
||||||
sidebarItems,
|
sidebarItems,
|
||||||
|
|||||||
Reference in New Issue
Block a user