This commit is contained in:
ts 2024-04-27 20:04:19 +02:00 committed by GitHub
commit 11617be2e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 120 additions and 13 deletions

View File

@ -1,6 +1,7 @@
export const SET_NOTIFICATIONS_STATE = 'SET_NOTIFICATIONS_STATE'
export const SET_TOGGLEABLE_FIELDS = 'SET_TOGGLEABLE_FIELDS'
export const SET_OMITTED_FIELDS = 'SET_OMITTED_FIELDS'
export const SET_PLAYER_RATING_CONTROL = 'SET_PLAYER_RATING_CONTROL'
export const setNotificationsState = (enabled) => ({
type: SET_NOTIFICATIONS_STATE,
@ -16,3 +17,8 @@ export const setOmittedFields = (obj) => ({
type: SET_OMITTED_FIELDS,
data: obj,
})
export const setPlayerRatingControl = (obj) => ({
type: SET_PLAYER_RATING_CONTROL,
data: obj,
})

View File

@ -1,12 +1,36 @@
import React, { useCallback } from 'react'
import { useGetOne } from 'react-admin'
import { GlobalHotKeys } from 'react-hotkeys'
import { LoveButton, useToggleLove } from '../common'
import { LoveButton, RatingField, useToggleLove } from '../common'
import { keyMap } from '../hotkeys'
import { useSelector } from 'react-redux'
const Placeholder = () => <LoveButton disabled={true} resource={'song'} />
const Placeholder = () => {
const playerRatingControl = useSelector(
(state) => state.settings.playerRatingControl,
)
switch (playerRatingControl) {
case 'love':
return <LoveButton disabled={true} resource={'song'} />
case 'rating':
return (
<RatingField
disabled={true}
source={'rating'}
resource={'song'}
size={'small'}
/>
)
default:
return null
}
}
const Toolbar = ({ id }) => {
const playerRatingControl = useSelector(
(state) => state.settings.playerRatingControl,
)
const { data, loading } = useGetOne('song', id)
const [toggleLove, toggling] = useToggleLove('song', data)
@ -14,16 +38,31 @@ const Toolbar = ({ id }) => {
TOGGLE_LOVE: useCallback(() => toggleLove(), [toggleLove]),
}
return (
<>
<GlobalHotKeys keyMap={keyMap} handlers={handlers} allowChanges />
<LoveButton
record={data}
resource={'song'}
disabled={loading || toggling}
/>
</>
)
switch (playerRatingControl) {
case 'love':
return (
<>
<GlobalHotKeys keyMap={keyMap} handlers={handlers} allowChanges />
<LoveButton
record={data}
resource={'song'}
disabled={loading || toggling}
/>
</>
)
case 'rating':
return (
<RatingField
record={data}
source={'rating'}
resource={'song'}
size={'small'}
disabled={loading || toggling}
/>
)
default:
return null
}
}
const PlayerToolbar = ({ id, isRadio }) =>

View File

@ -26,6 +26,7 @@ export const RatingField = ({
className,
size,
color,
disabled,
...rest
}) => {
const record = useRecordContext(rest) || {}
@ -43,6 +44,11 @@ export const RatingField = ({
[rate],
)
// If the rating is not yet loaded or unset, it will be `undefined`.
// material-ui uses an `null` to indicate an unset value.
// Passing `undefined` will switch the component into "uncontrolled" mode.
const ratingValue = rating ?? null
return (
<span onClick={(e) => stopPropagation(e)}>
<Rating
@ -52,10 +58,11 @@ export const RatingField = ({
classes.rating,
rating > 0 ? classes.show : classes.hide,
)}
value={rating}
value={ratingValue}
size={size}
emptyIcon={<StarBorderIcon fontSize="inherit" />}
onChange={(e, newValue) => handleRating(e, newValue)}
disabled={disabled}
/>
</span>
)
@ -64,6 +71,7 @@ RatingField.propTypes = {
resource: PropTypes.string.isRequired,
record: PropTypes.object,
visible: PropTypes.bool,
disabled: PropTypes.bool,
size: PropTypes.string,
}
@ -71,4 +79,5 @@ RatingField.defaultProps = {
visible: true,
size: 'small',
color: 'inherit',
disabled: false,
}

View File

@ -400,6 +400,12 @@
"none": "Disabled",
"album": "Use Album Gain",
"track": "Use Track Gain"
},
"playerRatingControl": "Player rating control",
"playerRatingControls": {
"none": "None",
"love": "Love",
"rating": "Rating"
}
}
},

View File

@ -9,6 +9,7 @@ import { LastfmScrobbleToggle } from './LastfmScrobbleToggle'
import { ListenBrainzScrobbleToggle } from './ListenBrainzScrobbleToggle'
import config from '../config'
import { ReplayGainToggle } from './ReplayGainToggle'
import { SelectPlayerRatingControl } from './SelectPlayerRatingControl'
const useStyles = makeStyles({
root: { marginTop: '1em' },
@ -26,6 +27,7 @@ const Personal = () => {
<SelectLanguage />
<SelectDefaultView />
{config.enableReplayGain && <ReplayGainToggle />}
<SelectPlayerRatingControl />
<NotificationsToggle />
{config.lastFMEnabled && <LastfmScrobbleToggle />}
{config.listenBrainzEnabled && <ListenBrainzScrobbleToggle />}

View File

@ -0,0 +1,37 @@
import { SelectInput, useTranslate } from 'react-admin'
import { setPlayerRatingControl } from '../actions/settings'
import { useDispatch, useSelector } from 'react-redux'
export const SelectPlayerRatingControl = (props) => {
const translate = useTranslate()
const dispatch = useDispatch()
const current = useSelector((state) => state.settings.playerRatingControl)
const choices = [
{
id: 'none',
name: translate(`menu.personal.options.playerRatingControls.none`),
},
{
id: 'love',
name: translate(`menu.personal.options.playerRatingControls.love`),
},
{
id: 'rating',
name: translate(`menu.personal.options.playerRatingControls.rating`),
},
]
return (
<SelectInput
{...props}
source="playerRatingControl"
label={translate('menu.personal.options.playerRatingControl')}
defaultValue={current}
choices={choices}
translateChoice={false}
onChange={(event) => {
dispatch(setPlayerRatingControl(event.target.value))
}}
/>
)
}

View File

@ -2,12 +2,14 @@ import {
SET_NOTIFICATIONS_STATE,
SET_OMITTED_FIELDS,
SET_TOGGLEABLE_FIELDS,
SET_PLAYER_RATING_CONTROL,
} from '../actions'
const initialState = {
notifications: false,
toggleableFields: {},
omittedFields: {},
playerRatingControl: localStorage.getItem('playerRating') ?? 'love',
}
export const settingsReducer = (previousState = initialState, payload) => {
@ -34,6 +36,12 @@ export const settingsReducer = (previousState = initialState, payload) => {
...data,
},
}
case SET_PLAYER_RATING_CONTROL:
localStorage.setItem('playerRating', data)
return {
...previousState,
playerRatingControl: data,
}
default:
return previousState
}