mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 05:20:13 +02:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 27dce55ca2 | |||
| 830f453642 | |||
| 8f48824955 | |||
| fbc23d545c | |||
| 15eb4a70aa | |||
| 3a13301e23 | |||
| eb5ad541d9 | |||
| 68df672953 |
@@ -37,10 +37,6 @@ jobs:
|
|||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
type=semver,pattern={{major}}
|
type=semver,pattern={{major}}
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Setup Docker buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
|
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
|
||||||
with:
|
with:
|
||||||
@@ -48,7 +44,3 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
platforms: |
|
|
||||||
linux/amd64
|
|
||||||
linux/arm/v7
|
|
||||||
linux/arm64/v8
|
|
||||||
|
|||||||
@@ -29,10 +29,6 @@ jobs:
|
|||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=latest,enable={{is_default_branch}}
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Setup Docker buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
|
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
|
||||||
with:
|
with:
|
||||||
@@ -40,7 +36,3 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
platforms: |
|
|
||||||
linux/amd64
|
|
||||||
linux/arm/v7
|
|
||||||
linux/arm64/v8
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "feishin",
|
"name": "feishin",
|
||||||
"version": "0.5.0",
|
"version": "0.4.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "feishin",
|
"name": "feishin",
|
||||||
"version": "0.5.0",
|
"version": "0.4.1",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+1
-34
@@ -2,7 +2,7 @@
|
|||||||
"name": "feishin",
|
"name": "feishin",
|
||||||
"productName": "Feishin",
|
"productName": "Feishin",
|
||||||
"description": "Feishin music server",
|
"description": "Feishin music server",
|
||||||
"version": "0.5.0",
|
"version": "0.4.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "concurrently \"npm run build:main\" \"npm run build:renderer\" \"npm run build:remote\"",
|
"build": "concurrently \"npm run build:main\" \"npm run build:renderer\" \"npm run build:remote\"",
|
||||||
"build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts",
|
"build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts",
|
||||||
@@ -93,39 +93,6 @@
|
|||||||
],
|
],
|
||||||
"icon": "assets/icons/icon.ico"
|
"icon": "assets/icons/icon.ico"
|
||||||
},
|
},
|
||||||
"deb": {
|
|
||||||
"depends": [
|
|
||||||
"libgssapi_krb5.so.2",
|
|
||||||
"libavahi-common.so.3",
|
|
||||||
"libavahi-client.so.3",
|
|
||||||
"libkrb5.so.3",
|
|
||||||
"libkrb5support.so.0",
|
|
||||||
"libkeyutils.so.1",
|
|
||||||
"libcups.so.2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"rpm": {
|
|
||||||
"depends": [
|
|
||||||
"libgssapi_krb5.so.2",
|
|
||||||
"libavahi-common.so.3",
|
|
||||||
"libavahi-client.so.3",
|
|
||||||
"libkrb5.so.3",
|
|
||||||
"libkrb5support.so.0",
|
|
||||||
"libkeyutils.so.1",
|
|
||||||
"libcups.so.2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"freebsd": {
|
|
||||||
"depends": [
|
|
||||||
"libgssapi_krb5.so.2",
|
|
||||||
"libavahi-common.so.3",
|
|
||||||
"libavahi-client.so.3",
|
|
||||||
"libkrb5.so.3",
|
|
||||||
"libkrb5support.so.0",
|
|
||||||
"libkeyutils.so.1",
|
|
||||||
"libcups.so.2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"linux": {
|
"linux": {
|
||||||
"target": [
|
"target": [
|
||||||
"AppImage",
|
"AppImage",
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "feishin",
|
"name": "feishin",
|
||||||
"version": "0.5.0",
|
"version": "0.4.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "feishin",
|
"name": "feishin",
|
||||||
"version": "0.5.0",
|
"version": "0.4.1",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "feishin",
|
"name": "feishin",
|
||||||
"version": "0.5.0",
|
"version": "0.4.1",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./dist/main/main.js",
|
"main": "./dist/main/main.js",
|
||||||
"author": {
|
"author": {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { Group, Image, Text, Title } from '@mantine/core';
|
import { Group, Image, Rating, Text, Title } from '@mantine/core';
|
||||||
import { useInfo, useSend, useShowImage } from '/@/remote/store';
|
import { useInfo, useSend, useShowImage } from '/@/remote/store';
|
||||||
import { RemoteButton } from '/@/remote/components/buttons/remote-button';
|
import { RemoteButton } from '/@/remote/components/buttons/remote-button';
|
||||||
import formatDuration from 'format-duration';
|
import formatDuration from 'format-duration';
|
||||||
@@ -18,7 +18,6 @@ import {
|
|||||||
import { PlayerRepeat, PlayerStatus } from '/@/renderer/types';
|
import { PlayerRepeat, PlayerStatus } from '/@/renderer/types';
|
||||||
import { WrapperSlider } from '/@/remote/components/wrapped-slider';
|
import { WrapperSlider } from '/@/remote/components/wrapped-slider';
|
||||||
import { Tooltip } from '/@/renderer/components/tooltip';
|
import { Tooltip } from '/@/renderer/components/tooltip';
|
||||||
import { Rating } from '/@/renderer/components';
|
|
||||||
|
|
||||||
export const RemoteContainer = () => {
|
export const RemoteContainer = () => {
|
||||||
const { repeat, shuffle, song, status, volume } = useInfo();
|
const { repeat, shuffle, song, status, volume } = useInfo();
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||||
import { useCallback } from 'react';
|
import { MouseEvent } from 'react';
|
||||||
import { Rating as MantineRating, RatingProps } from '@mantine/core';
|
import { Rating as MantineRating, RatingProps as MantineRatingProps } from '@mantine/core';
|
||||||
import debounce from 'lodash/debounce';
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import { Tooltip } from '/@/renderer/components/tooltip';
|
||||||
|
|
||||||
|
interface RatingProps extends Omit<MantineRatingProps, 'onClick'> {
|
||||||
|
onClick: (e: MouseEvent<HTMLDivElement>, value: number | undefined) => void;
|
||||||
|
}
|
||||||
|
|
||||||
const StyledRating = styled(MantineRating)`
|
const StyledRating = styled(MantineRating)`
|
||||||
& .mantine-Rating-symbolBody {
|
& .mantine-Rating-symbolBody {
|
||||||
@@ -12,32 +16,18 @@ const StyledRating = styled(MantineRating)`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Rating = ({ onChange, ...props }: RatingProps) => {
|
export const Rating = ({ onClick, ...props }: RatingProps) => {
|
||||||
const valueChange = useCallback(
|
// const debouncedOnClick = debounce(onClick, 100);
|
||||||
(rating: number) => {
|
|
||||||
if (onChange) {
|
|
||||||
if (rating === props.value) {
|
|
||||||
onChange(0);
|
|
||||||
} else {
|
|
||||||
onChange(rating);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[onChange, props.value],
|
|
||||||
);
|
|
||||||
|
|
||||||
const debouncedOnChange = debounce(valueChange, 100);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledRating
|
<Tooltip
|
||||||
{...props}
|
label="Double click to clear"
|
||||||
onChange={(e) => {
|
openDelay={1000}
|
||||||
debouncedOnChange(e);
|
>
|
||||||
}}
|
<StyledRating
|
||||||
onClick={(e) => {
|
{...props}
|
||||||
e.preventDefault();
|
onDoubleClick={(e) => onClick(e, props.value)}
|
||||||
e.stopPropagation();
|
/>
|
||||||
}}
|
</Tooltip>
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/* eslint-disable import/no-cycle */
|
/* eslint-disable import/no-cycle */
|
||||||
|
import { MouseEvent } from 'react';
|
||||||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||||
import { Rating } from '/@/renderer/components/rating';
|
import { Rating } from '/@/renderer/components/rating';
|
||||||
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
import { CellContainer } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||||
@@ -8,6 +9,8 @@ export const RatingCell = ({ value, node }: ICellRendererParams) => {
|
|||||||
const updateRatingMutation = useSetRating({});
|
const updateRatingMutation = useSetRating({});
|
||||||
|
|
||||||
const handleUpdateRating = (rating: number) => {
|
const handleUpdateRating = (rating: number) => {
|
||||||
|
if (!value) return;
|
||||||
|
|
||||||
updateRatingMutation.mutate(
|
updateRatingMutation.mutate(
|
||||||
{
|
{
|
||||||
query: {
|
query: {
|
||||||
@@ -24,12 +27,32 @@ export const RatingCell = ({ value, node }: ICellRendererParams) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClearRating = (e: MouseEvent<HTMLDivElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
updateRatingMutation.mutate(
|
||||||
|
{
|
||||||
|
query: {
|
||||||
|
item: [value],
|
||||||
|
rating: 0,
|
||||||
|
},
|
||||||
|
serverId: value?.serverId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
node.setData({ ...node.data, userRating: 0 });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CellContainer $position="center">
|
<CellContainer $position="center">
|
||||||
<Rating
|
<Rating
|
||||||
size="xs"
|
size="xs"
|
||||||
value={value?.userRating}
|
value={value?.userRating}
|
||||||
onChange={handleUpdateRating}
|
onChange={handleUpdateRating}
|
||||||
|
onClick={handleClearRating}
|
||||||
/>
|
/>
|
||||||
</CellContainer>
|
</CellContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -55,6 +55,18 @@ export const AlbumDetailHeader = forwardRef(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClearRating = () => {
|
||||||
|
if (!detailQuery?.data || !detailQuery?.data.userRating) return;
|
||||||
|
|
||||||
|
updateRatingMutation.mutate({
|
||||||
|
query: {
|
||||||
|
item: [detailQuery.data],
|
||||||
|
rating: 0,
|
||||||
|
},
|
||||||
|
serverId: detailQuery.data.serverId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const showRating = detailQuery?.data?.serverType === ServerType.NAVIDROME;
|
const showRating = detailQuery?.data?.serverType === ServerType.NAVIDROME;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -84,6 +96,7 @@ export const AlbumDetailHeader = forwardRef(
|
|||||||
}
|
}
|
||||||
value={detailQuery?.data?.userRating || 0}
|
value={detailQuery?.data?.userRating || 0}
|
||||||
onChange={handleUpdateRating}
|
onChange={handleUpdateRating}
|
||||||
|
onClick={handleClearRating}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { forwardRef, Fragment, Ref } from 'react';
|
import { forwardRef, Fragment, Ref, MouseEvent } from 'react';
|
||||||
import { Group, Rating, Stack } from '@mantine/core';
|
import { Group, Rating, Stack } from '@mantine/core';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
import { LibraryItem, ServerType } from '/@/renderer/api/types';
|
import { LibraryItem, ServerType } from '/@/renderer/api/types';
|
||||||
@@ -55,6 +55,21 @@ export const AlbumArtistDetailHeader = forwardRef(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClearRating = (_e: MouseEvent<HTMLDivElement>, rating?: number) => {
|
||||||
|
if (!detailQuery?.data || !detailQuery?.data.userRating) return;
|
||||||
|
|
||||||
|
const isSameRatingAsPrevious = rating === detailQuery.data.userRating;
|
||||||
|
if (!isSameRatingAsPrevious) return;
|
||||||
|
|
||||||
|
updateRatingMutation.mutate({
|
||||||
|
query: {
|
||||||
|
item: [detailQuery.data],
|
||||||
|
rating: 0,
|
||||||
|
},
|
||||||
|
serverId: detailQuery.data.serverId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const showRating = detailQuery?.data?.serverType === ServerType.NAVIDROME;
|
const showRating = detailQuery?.data?.serverType === ServerType.NAVIDROME;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -84,6 +99,7 @@ export const AlbumArtistDetailHeader = forwardRef(
|
|||||||
}
|
}
|
||||||
value={detailQuery?.data?.userRating || 0}
|
value={detailQuery?.data?.userRating || 0}
|
||||||
onChange={handleUpdateRating}
|
onChange={handleUpdateRating}
|
||||||
|
onClick={handleClearRating}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -714,6 +714,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||||||
<Rating
|
<Rating
|
||||||
readOnly
|
readOnly
|
||||||
value={0}
|
value={0}
|
||||||
|
onClick={() => {}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
onClick: () => handleUpdateRating(0),
|
onClick: () => handleUpdateRating(0),
|
||||||
@@ -724,6 +725,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||||||
<Rating
|
<Rating
|
||||||
readOnly
|
readOnly
|
||||||
value={1}
|
value={1}
|
||||||
|
onClick={() => {}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
onClick: () => handleUpdateRating(1),
|
onClick: () => handleUpdateRating(1),
|
||||||
@@ -734,6 +736,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||||||
<Rating
|
<Rating
|
||||||
readOnly
|
readOnly
|
||||||
value={2}
|
value={2}
|
||||||
|
onClick={() => {}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
onClick: () => handleUpdateRating(2),
|
onClick: () => handleUpdateRating(2),
|
||||||
@@ -744,6 +747,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||||||
<Rating
|
<Rating
|
||||||
readOnly
|
readOnly
|
||||||
value={3}
|
value={3}
|
||||||
|
onClick={() => {}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
onClick: () => handleUpdateRating(3),
|
onClick: () => handleUpdateRating(3),
|
||||||
@@ -754,6 +758,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||||||
<Rating
|
<Rating
|
||||||
readOnly
|
readOnly
|
||||||
value={4}
|
value={4}
|
||||||
|
onClick={() => {}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
onClick: () => handleUpdateRating(4),
|
onClick: () => handleUpdateRating(4),
|
||||||
@@ -764,6 +769,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||||||
<Rating
|
<Rating
|
||||||
readOnly
|
readOnly
|
||||||
value={5}
|
value={5}
|
||||||
|
onClick={() => {}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
onClick: () => handleUpdateRating(5),
|
onClick: () => handleUpdateRating(5),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect } from 'react';
|
import { MouseEvent, useEffect } from 'react';
|
||||||
import { Flex, Group } from '@mantine/core';
|
import { Flex, Group } from '@mantine/core';
|
||||||
import { useHotkeys, useMediaQuery } from '@mantine/hooks';
|
import { useHotkeys, useMediaQuery } from '@mantine/hooks';
|
||||||
import isElectron from 'is-electron';
|
import isElectron from 'is-electron';
|
||||||
@@ -84,6 +84,18 @@ export const RightControls = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClearRating = (_e: MouseEvent<HTMLDivElement> | null, rating?: number) => {
|
||||||
|
if (!currentSong || !rating) return;
|
||||||
|
|
||||||
|
updateRatingMutation.mutate({
|
||||||
|
query: {
|
||||||
|
item: [currentSong],
|
||||||
|
rating: 0,
|
||||||
|
},
|
||||||
|
serverId: currentSong?.serverId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleRemoveFromFavorites = (song: QueueSong | undefined) => {
|
const handleRemoveFromFavorites = (song: QueueSong | undefined) => {
|
||||||
if (!song?.id) return;
|
if (!song?.id) return;
|
||||||
|
|
||||||
@@ -142,7 +154,7 @@ export const RightControls = () => {
|
|||||||
bindings.favoritePreviousToggle.isGlobal ? '' : bindings.favoritePreviousToggle.hotkey,
|
bindings.favoritePreviousToggle.isGlobal ? '' : bindings.favoritePreviousToggle.hotkey,
|
||||||
() => handleToggleFavorite(previousSong),
|
() => handleToggleFavorite(previousSong),
|
||||||
],
|
],
|
||||||
[bindings.rate0.isGlobal ? '' : bindings.rate0.hotkey, () => handleUpdateRating(0)],
|
[bindings.rate0.isGlobal ? '' : bindings.rate0.hotkey, () => handleClearRating(null, 0)],
|
||||||
[bindings.rate1.isGlobal ? '' : bindings.rate1.hotkey, () => handleUpdateRating(1)],
|
[bindings.rate1.isGlobal ? '' : bindings.rate1.hotkey, () => handleUpdateRating(1)],
|
||||||
[bindings.rate2.isGlobal ? '' : bindings.rate2.hotkey, () => handleUpdateRating(2)],
|
[bindings.rate2.isGlobal ? '' : bindings.rate2.hotkey, () => handleUpdateRating(2)],
|
||||||
[bindings.rate3.isGlobal ? '' : bindings.rate3.hotkey, () => handleUpdateRating(3)],
|
[bindings.rate3.isGlobal ? '' : bindings.rate3.hotkey, () => handleUpdateRating(3)],
|
||||||
@@ -202,6 +214,7 @@ export const RightControls = () => {
|
|||||||
size="sm"
|
size="sm"
|
||||||
value={currentSong?.userRating || 0}
|
value={currentSong?.userRating || 0}
|
||||||
onChange={handleUpdateRating}
|
onChange={handleUpdateRating}
|
||||||
|
onClick={handleClearRating}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
Reference in New Issue
Block a user