mirror of
https://github.com/navidrome/navidrome.git
synced 2026-11-05 17:58:37 +01:00
160 lines
4.3 KiB
JavaScript
160 lines
4.3 KiB
JavaScript
import React, { useCallback } from 'react'
|
|
import { useDispatch } from 'react-redux'
|
|
import { useGetOne } from 'react-admin'
|
|
import { GlobalHotKeys } from 'react-hotkeys'
|
|
import IconButton from '@material-ui/core/IconButton'
|
|
import { useMediaQuery } from '@material-ui/core'
|
|
import Tooltip from '@material-ui/core/Tooltip'
|
|
import { RiFileMusicLine } from 'react-icons/ri'
|
|
import { RiSaveLine } from 'react-icons/ri'
|
|
import { LoveButton, useToggleLove } from '../common'
|
|
import { openSaveQueueDialog } from '../actions'
|
|
import { keyMap } from '../hotkeys'
|
|
import { makeStyles } from '@material-ui/core/styles'
|
|
import { PLAYER_DESKTOP_MEDIA_QUERY } from './playerBreakpoints'
|
|
|
|
const useStyles = makeStyles((theme) => ({
|
|
toolbar: {
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
flexGrow: 1,
|
|
justifyContent: 'flex-end',
|
|
gap: '0.5rem',
|
|
listStyle: 'none',
|
|
padding: 0,
|
|
margin: 0,
|
|
},
|
|
mobileListItem: {
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
listStyle: 'none',
|
|
padding: theme.spacing(0.5),
|
|
margin: 0,
|
|
height: 24,
|
|
},
|
|
button: {
|
|
width: '2.5rem',
|
|
height: '2.5rem',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
padding: 0,
|
|
},
|
|
mobileButton: {
|
|
width: 24,
|
|
height: 24,
|
|
padding: 0,
|
|
margin: 0,
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
fontSize: '18px',
|
|
},
|
|
mobileIcon: {
|
|
fontSize: '18px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
},
|
|
}))
|
|
|
|
const PlayerToolbar = ({
|
|
id,
|
|
isRadio,
|
|
onToggleLyrics,
|
|
lyricsActive = false,
|
|
lyricsDisabled = false,
|
|
lyricsLoading = false,
|
|
lyricsLabel = 'Toggle lyrics',
|
|
lyricsLoadingLabel = 'Loading lyrics',
|
|
lyricsToggleRef,
|
|
}) => {
|
|
const dispatch = useDispatch()
|
|
const { data, loading } = useGetOne('song', id, { enabled: !!id && !isRadio })
|
|
const [toggleLove, toggling] = useToggleLove('song', data)
|
|
const isDesktop = useMediaQuery(PLAYER_DESKTOP_MEDIA_QUERY)
|
|
const classes = useStyles()
|
|
|
|
const handlers = {
|
|
TOGGLE_LOVE: useCallback(() => toggleLove(), [toggleLove]),
|
|
}
|
|
|
|
const handleSaveQueue = useCallback(
|
|
(e) => {
|
|
dispatch(openSaveQueueDialog())
|
|
e.stopPropagation()
|
|
},
|
|
[dispatch],
|
|
)
|
|
|
|
const buttonClass = isDesktop ? classes.button : classes.mobileButton
|
|
const listItemClass = isDesktop ? classes.toolbar : classes.mobileListItem
|
|
const lyricsUnavailable = lyricsDisabled || (lyricsLoading && !lyricsActive)
|
|
|
|
const saveQueueButton = (
|
|
<IconButton
|
|
size={isDesktop ? 'small' : undefined}
|
|
onClick={handleSaveQueue}
|
|
disabled={isRadio}
|
|
data-testid="save-queue-button"
|
|
className={buttonClass}
|
|
>
|
|
<RiSaveLine className={!isDesktop ? classes.mobileIcon : undefined} />
|
|
</IconButton>
|
|
)
|
|
|
|
const loveButton = (
|
|
<LoveButton
|
|
record={data}
|
|
resource={'song'}
|
|
size={isDesktop ? undefined : 'inherit'}
|
|
disabled={loading || toggling || !id || isRadio}
|
|
className={buttonClass}
|
|
/>
|
|
)
|
|
|
|
const currentLyricsLabel = lyricsLoading ? lyricsLoadingLabel : lyricsLabel
|
|
const lyricsButton = (
|
|
<Tooltip title={currentLyricsLabel}>
|
|
<span>
|
|
<IconButton
|
|
ref={lyricsToggleRef}
|
|
size={isDesktop ? 'small' : undefined}
|
|
onClick={onToggleLyrics}
|
|
disabled={!onToggleLyrics || lyricsUnavailable}
|
|
data-testid="toggle-lyrics-button"
|
|
className={buttonClass}
|
|
color={lyricsActive ? 'primary' : 'default'}
|
|
aria-label={currentLyricsLabel}
|
|
aria-busy={lyricsLoading}
|
|
aria-pressed={lyricsActive}
|
|
>
|
|
<RiFileMusicLine
|
|
className={!isDesktop ? classes.mobileIcon : undefined}
|
|
/>
|
|
</IconButton>
|
|
</span>
|
|
</Tooltip>
|
|
)
|
|
|
|
return (
|
|
<>
|
|
<GlobalHotKeys keyMap={keyMap} handlers={handlers} allowChanges />
|
|
{isDesktop ? (
|
|
<li className={`${listItemClass} item`}>
|
|
{saveQueueButton}
|
|
{loveButton}
|
|
{lyricsButton}
|
|
</li>
|
|
) : (
|
|
<>
|
|
<li className={`${listItemClass} item`}>{saveQueueButton}</li>
|
|
<li className={`${listItemClass} item`}>{loveButton}</li>
|
|
<li className={`${listItemClass} item`}>{lyricsButton}</li>
|
|
</>
|
|
)}
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default PlayerToolbar
|