Option to toggle fields in songs, albums & artists (#923)

* Add toggleColumns

- Add logic for toggling columns
- Add MenuComponent + useSelectedFields hook

* Refactoring

* eslint-fixes

* Typo

* skip menu in albumGridView

* add omittedFields

* Add toggling for playlists and albumSong

* Refactoring

* defaultProps - fix

* Add toggling for PlaylistSongs

* remove accidental console log

* Refactoring for future compatibility

* Hide ToggleMenu in albumGridView

* Add TopBarComponent in ToggleFieldsMenu

* Add defaultOff for useSelectedFields

* Fix edge case

* eslint fix

* Refactoring

* Add propType for forwardRef

* Fix issues

* add translation for grid and table

* add translation for grid and table

* Ignore menuBtn for spotify-ish and Ligera themes

* hide bpm by default in playlistSongs

* Add memoization

* Default album view must be Grid

Co-authored-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Aldrin Jenson
2021-05-24 20:39:06 +05:30
committed by GitHub
parent 6a17717e30
commit cf8ee251ee
22 changed files with 681 additions and 215 deletions
+54 -42
View File
@@ -19,15 +19,22 @@ import { M3U_MIME_TYPE, REST_URL } from '../consts'
import subsonic from '../subsonic'
import PropTypes from 'prop-types'
import { formatBytes } from '../utils'
import { useMediaQuery } from '@material-ui/core'
import { useMediaQuery, makeStyles } from '@material-ui/core'
import config from '../config'
import ToggleFieldsMenu from '../common/ToggleFieldsMenu'
const useStyles = makeStyles({
toolbar: { display: 'flex', justifyContent: 'space-between', width: '100%' },
})
const PlaylistActions = ({ className, ids, data, record, ...rest }) => {
const dispatch = useDispatch()
const translate = useTranslate()
const classes = useStyles()
const dataProvider = useDataProvider()
const notify = useNotify()
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm'))
const getAllSongsAndDispatch = React.useCallback(
(action) => {
@@ -94,47 +101,52 @@ const PlaylistActions = ({ className, ids, data, record, ...rest }) => {
return (
<TopToolbar className={className} {...sanitizeListRestProps(rest)}>
<Button
onClick={handlePlay}
label={translate('resources.album.actions.playAll')}
>
<PlayArrowIcon />
</Button>
<Button
onClick={handleShuffle}
label={translate('resources.album.actions.shuffle')}
>
<ShuffleIcon />
</Button>
<Button
onClick={handlePlayNext}
label={translate('resources.album.actions.playNext')}
>
<RiPlayList2Fill />
</Button>
<Button
onClick={handlePlayLater}
label={translate('resources.album.actions.addToQueue')}
>
<RiPlayListAddFill />
</Button>
{config.enableDownloads && (
<Button
onClick={handleDownload}
label={
translate('resources.album.actions.download') +
(isDesktop ? ` (${formatBytes(record.size)})` : '')
}
>
<CloudDownloadOutlinedIcon />
</Button>
)}
<Button
onClick={handleExport}
label={translate('resources.playlist.actions.export')}
>
<QueueMusicIcon />
</Button>
<div className={classes.toolbar}>
<div>
<Button
onClick={handlePlay}
label={translate('resources.album.actions.playAll')}
>
<PlayArrowIcon />
</Button>
<Button
onClick={handleShuffle}
label={translate('resources.album.actions.shuffle')}
>
<ShuffleIcon />
</Button>
<Button
onClick={handlePlayNext}
label={translate('resources.album.actions.playNext')}
>
<RiPlayList2Fill />
</Button>
<Button
onClick={handlePlayLater}
label={translate('resources.album.actions.addToQueue')}
>
<RiPlayListAddFill />
</Button>
{config.enableDownloads && (
<Button
onClick={handleDownload}
label={
translate('resources.album.actions.download') +
(isDesktop ? ` (${formatBytes(record.size)})` : '')
}
>
<CloudDownloadOutlinedIcon />
</Button>
)}
<Button
onClick={handleExport}
label={translate('resources.playlist.actions.export')}
>
<QueueMusicIcon />
</Button>
</div>
<div>{isNotSmall && <ToggleFieldsMenu resource="playlistTrack" />}</div>
</div>
</TopToolbar>
)
}
+34 -14
View File
@@ -1,4 +1,4 @@
import React from 'react'
import React, { useMemo } from 'react'
import {
Datagrid,
DateField,
@@ -11,8 +11,10 @@ import {
useNotify,
} from 'react-admin'
import Switch from '@material-ui/core/Switch'
import { DurationField, List, Writable, isWritable } from '../common'
import { useMediaQuery } from '@material-ui/core'
import { DurationField, List, Writable, isWritable } from '../common'
import useSelectedFields from '../common/useSelectedFields'
import PlaylistListActions from './PlaylistListActions'
const PlaylistFilter = (props) => (
<Filter {...props} variant={'outlined'}>
@@ -60,24 +62,42 @@ const PlaylistList = ({ permissions, ...props }) => {
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
const toggleableFields = useMemo(() => {
return {
owner: <TextField source="owner" />,
songCount: isDesktop && <NumberField source="songCount" />,
duration: isDesktop && <DurationField source="duration" />,
updatedAt: isDesktop && (
<DateField source="updatedAt" sortByOrder={'DESC'} />
),
public: !isXsmall && (
<TogglePublicInput
source="public"
permissions={permissions}
sortByOrder={'DESC'}
/>
),
}
}, [isDesktop, isXsmall, permissions])
const columns = useSelectedFields({
resource: 'playlist',
columns: toggleableFields,
})
return (
<List {...props} exporter={false} filters={<PlaylistFilter />}>
<List
{...props}
exporter={false}
filters={<PlaylistFilter />}
actions={<PlaylistListActions />}
>
<Datagrid
rowClick="show"
isRowSelectable={(r) => isWritable(r && r.owner)}
>
<TextField source="name" />
<TextField source="owner" />
{isDesktop && <NumberField source="songCount" />}
{isDesktop && <DurationField source="duration" />}
{isDesktop && <DateField source="updatedAt" sortByOrder={'DESC'} />}
{!isXsmall && (
<TogglePublicInput
source="public"
permissions={permissions}
sortByOrder={'DESC'}
/>
)}
{columns}
<Writable>
<EditButton />
</Writable>
+25
View File
@@ -0,0 +1,25 @@
import React from 'react'
import {
sanitizeListRestProps,
TopToolbar,
CreateButton,
useTranslate,
} from 'react-admin'
import { useMediaQuery } from '@material-ui/core'
import ToggleFieldsMenu from '../common/ToggleFieldsMenu'
const PlaylistListActions = ({ className, ...rest }) => {
const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm'))
const translate = useTranslate()
return (
<TopToolbar className={className} {...sanitizeListRestProps(rest)}>
<CreateButton basePath="/playlist">
{translate('ra.action.create')}
</CreateButton>
{isNotSmall && <ToggleFieldsMenu resource="playlist" />}
</TopToolbar>
)
}
export default PlaylistListActions
+3 -1
View File
@@ -13,7 +13,9 @@ import PlaylistActions from './PlaylistActions'
import { Title, isReadOnly } from '../common'
const useStyles = makeStyles(
(theme) => ({
playlistActions: {},
playlistActions: {
width: '100%',
},
}),
{
name: 'NDPlaylistShow',
+23 -8
View File
@@ -1,4 +1,4 @@
import React, { useCallback } from 'react'
import React, { useCallback, useMemo } from 'react'
import {
BulkActionsToolbar,
ListToolbar,
@@ -28,6 +28,7 @@ import { AlbumLinkField } from '../song/AlbumLinkField'
import { playTracks } from '../actions'
import PlaylistSongBulkActions from './PlaylistSongBulkActions'
import { QualityInfo } from '../common/QualityInfo'
import useSelectedFields from '../common/useSelectedFields'
const useStyles = makeStyles(
(theme) => ({
@@ -127,6 +128,26 @@ const PlaylistSongs = ({ playlistId, readOnly, actions, ...props }) => {
[playlistId, reorder, ids]
)
const toggleableFields = useMemo(() => {
return {
trackNumber: isDesktop && <TextField source="id" label={'#'} />,
title: <SongTitleField source="title" showTrackNumbers={false} />,
album: isDesktop && <AlbumLinkField source="album" />,
artist: isDesktop && <TextField source="artist" />,
duration: (
<DurationField source="duration" className={classes.draggable} />
),
quality: isDesktop && <QualityInfo source="quality" sortable={false} />,
bpm: isDesktop && <NumberField source="bpm" />,
}
}, [isDesktop, classes.draggable])
const columns = useSelectedFields({
resource: 'playlistTrack',
columns: toggleableFields,
defaultOff: ['bpm'],
})
return (
<>
<ListToolbar
@@ -161,13 +182,7 @@ const PlaylistSongs = ({ playlistId, readOnly, actions, ...props }) => {
contextAlwaysVisible={!isDesktop}
classes={{ row: classes.row }}
>
{isDesktop && <TextField source="id" label={'#'} />}
<SongTitleField source="title" showTrackNumbers={false} />
{isDesktop && <AlbumLinkField source="album" />}
{isDesktop && <TextField source="artist" />}
<DurationField source="duration" className={classes.draggable} />
{isDesktop && <QualityInfo source="quality" sortable={false} />}
{isDesktop && <NumberField source="bpm" />}
{columns}
<SongContextMenu
onAddToPlaylist={onAddToPlaylist}
showLove={false}