mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-01 07:21:17 +00:00
Add an inline star rating control to the player toolbar, next to the Love button. It is shown only when EnableStarRating is enabled and is hidden for radio streams, and reflects/updates the current track's rating live. Adds an `alwaysVisible` prop to RatingField so the empty stars are shown for unrated tracks (the list views only reveal them on row hover). Signed-off-by: realrossmanngroup <youtube@rossmanngroup.com>
91 lines
2.2 KiB
JavaScript
91 lines
2.2 KiB
JavaScript
import React, { useCallback } from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import Rating from '@material-ui/lab/Rating'
|
|
import { makeStyles } from '@material-ui/core/styles'
|
|
import { isDateSet } from '../utils/validations'
|
|
import StarBorderIcon from '@material-ui/icons/StarBorder'
|
|
import clsx from 'clsx'
|
|
import { useRating } from './useRating'
|
|
import { useRecordContext } from 'react-admin'
|
|
|
|
const useStyles = makeStyles({
|
|
rating: {
|
|
color: (props) => props.color,
|
|
visibility: (props) => (props.visible === false ? 'hidden' : 'inherit'),
|
|
},
|
|
show: {
|
|
visibility: 'visible !important',
|
|
},
|
|
hide: {
|
|
visibility: 'hidden',
|
|
},
|
|
})
|
|
|
|
export const RatingField = ({
|
|
resource,
|
|
visible,
|
|
className,
|
|
size,
|
|
color,
|
|
alwaysVisible,
|
|
...rest
|
|
}) => {
|
|
const record = useRecordContext(rest) || {}
|
|
const [rate, rating] = useRating(resource, record)
|
|
const classes = useStyles({ color, visible })
|
|
|
|
const stopPropagation = (e) => {
|
|
e.stopPropagation()
|
|
}
|
|
|
|
const handleRating = useCallback(
|
|
(e, val) => {
|
|
const targetId = record.mediaFileId || record.id
|
|
rate(val ?? 0, targetId)
|
|
},
|
|
[rate, record.mediaFileId, record.id],
|
|
)
|
|
|
|
return (
|
|
<span
|
|
onClick={(e) => stopPropagation(e)}
|
|
title={
|
|
isDateSet(record.ratedAt)
|
|
? new Date(record.ratedAt).toLocaleString()
|
|
: undefined
|
|
}
|
|
>
|
|
<Rating
|
|
name={record.mediaFileId || record.id}
|
|
className={clsx(
|
|
className,
|
|
classes.rating,
|
|
rating > 0 || alwaysVisible ? classes.show : classes.hide,
|
|
)}
|
|
value={rating}
|
|
size={size}
|
|
disabled={record?.missing}
|
|
emptyIcon={<StarBorderIcon fontSize="inherit" />}
|
|
onChange={(e, newValue) => handleRating(e, newValue)}
|
|
/>
|
|
</span>
|
|
)
|
|
}
|
|
RatingField.propTypes = {
|
|
resource: PropTypes.string.isRequired,
|
|
record: PropTypes.object,
|
|
visible: PropTypes.bool,
|
|
size: PropTypes.string,
|
|
// When true, the empty stars are always shown (not just on hover / when
|
|
// already rated). Used by the player toolbar so the current track can be
|
|
// rated directly.
|
|
alwaysVisible: PropTypes.bool,
|
|
}
|
|
|
|
RatingField.defaultProps = {
|
|
visible: true,
|
|
size: 'small',
|
|
color: 'inherit',
|
|
alwaysVisible: false,
|
|
}
|