diff --git a/ui/src/actions/settings.js b/ui/src/actions/settings.js
index bb8942a6b..e62ecde8f 100644
--- a/ui/src/actions/settings.js
+++ b/ui/src/actions/settings.js
@@ -1,6 +1,18 @@
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 setNotificationsState = (enabled) => ({
type: SET_NOTIFICATIONS_STATE,
data: enabled,
})
+
+export const setToggleableFields = (obj) => ({
+ type: SET_TOGGLEABLE_FIELDS,
+ data: obj,
+})
+
+export const setOmittedFields = (obj) => ({
+ type: SET_OMITTED_FIELDS,
+ data: obj,
+})
diff --git a/ui/src/album/AlbumActions.js b/ui/src/album/AlbumActions.js
index 6f2b0576d..95ad15363 100644
--- a/ui/src/album/AlbumActions.js
+++ b/ui/src/album/AlbumActions.js
@@ -14,8 +14,13 @@ import { RiPlayListAddFill, RiPlayList2Fill } from 'react-icons/ri'
import { playNext, addTracks, playTracks, shuffleTracks } from '../actions'
import subsonic from '../subsonic'
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 AlbumActions = ({
className,
@@ -27,7 +32,9 @@ const AlbumActions = ({
}) => {
const dispatch = useDispatch()
const translate = useTranslate()
+ const classes = useStyles()
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
+ const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm'))
const handlePlay = React.useCallback(() => {
dispatch(playTracks(data, ids))
@@ -51,41 +58,46 @@ const AlbumActions = ({
return (
-
-
-
-
- {config.enableDownloads && (
-
- )}
+
+
+
+
+
+
+ {config.enableDownloads && (
+
+ )}
+
+
{isNotSmall && }
+
)
}
diff --git a/ui/src/album/AlbumList.js b/ui/src/album/AlbumList.js
index 91008e550..0707358c7 100644
--- a/ui/src/album/AlbumList.js
+++ b/ui/src/album/AlbumList.js
@@ -6,9 +6,9 @@ import {
Filter,
NullableBooleanInput,
NumberInput,
+ Pagination,
ReferenceInput,
SearchInput,
- Pagination,
useTranslate,
} from 'react-admin'
import FavoriteIcon from '@material-ui/icons/Favorite'
@@ -20,6 +20,7 @@ import AlbumGridView from './AlbumGridView'
import { AddToPlaylistDialog } from '../dialogs'
import albumLists, { defaultAlbumList } from './albumLists'
import config from '../config'
+import useSelectedFields from '../common/useSelectedFields'
const AlbumFilter = (props) => {
const translate = useTranslate()
@@ -70,6 +71,21 @@ const AlbumList = (props) => {
.replace(/^\/album/, '')
.replace(/^\//, '')
+ // Workaround to force album columns to appear the first time.
+ // See https://github.com/navidrome/navidrome/pull/923#issuecomment-833004842
+ // TODO: Find a better solution
+ useSelectedFields({
+ resource: 'album',
+ columns: {
+ artist: 'artist',
+ songCount: 'songCount',
+ playCount: 'playCount',
+ year: 'year',
+ duration: 'duration',
+ rating: 'rating',
+ },
+ })
+
// If it does not have filter/sort params (usually coming from Menu),
// reload with correct filter/sort params
if (!location.search) {
diff --git a/ui/src/album/AlbumListActions.js b/ui/src/album/AlbumListActions.js
index 09135bb65..97ce05de8 100644
--- a/ui/src/album/AlbumListActions.js
+++ b/ui/src/album/AlbumListActions.js
@@ -1,10 +1,71 @@
import React, { cloneElement } from 'react'
-import { Button, sanitizeListRestProps, TopToolbar } from 'react-admin'
-import { ButtonGroup } from '@material-ui/core'
+import {
+ Button,
+ sanitizeListRestProps,
+ TopToolbar,
+ useTranslate,
+} from 'react-admin'
+import {
+ ButtonGroup,
+ useMediaQuery,
+ Typography,
+ makeStyles,
+} from '@material-ui/core'
import ViewHeadlineIcon from '@material-ui/icons/ViewHeadline'
import ViewModuleIcon from '@material-ui/icons/ViewModule'
import { useDispatch, useSelector } from 'react-redux'
import { albumViewGrid, albumViewList } from '../actions'
+import ToggleFieldsMenu from '../common/ToggleFieldsMenu'
+
+const useStyles = makeStyles({
+ title: { margin: '1rem' },
+ buttonGroup: { width: '100%', justifyContent: 'center' },
+ leftButton: { paddingRight: '0.5rem' },
+ rightButton: { paddingLeft: '0.5rem' },
+})
+
+const AlbumViewToggler = React.forwardRef(
+ ({ showTitle = true, disableElevation, fullWidth }, ref) => {
+ const dispatch = useDispatch()
+ const albumView = useSelector((state) => state.albumView)
+ const classes = useStyles()
+ const translate = useTranslate()
+ return (
+
+ {showTitle && (
+
+ {translate('ra.toggleFieldsMenu.layout')}
+
+ )}
+
+
+
+
+
+ )
+ }
+)
const AlbumListActions = ({
currentSort,
@@ -24,9 +85,7 @@ const AlbumListActions = ({
fullWidth,
...rest
}) => {
- const dispatch = useDispatch()
- const albumView = useSelector((state) => state.albumView)
-
+ const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm'))
return (
{filters &&
@@ -37,26 +96,11 @@ const AlbumListActions = ({
filterValues,
context: 'button',
})}
-
-
-
-
+ {isNotSmall ? (
+
+ ) : (
+
+ )}
)
}
diff --git a/ui/src/album/AlbumListView.js b/ui/src/album/AlbumListView.js
index 99ef1e5b4..487970388 100644
--- a/ui/src/album/AlbumListView.js
+++ b/ui/src/album/AlbumListView.js
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useMemo } from 'react'
import Paper from '@material-ui/core/Paper'
import Table from '@material-ui/core/Table'
import TableBody from '@material-ui/core/TableBody'
@@ -28,6 +28,7 @@ import {
RatingField,
} from '../common'
import config from '../config'
+import useSelectedFields from '../common/useSelectedFields'
const useStyles = makeStyles({
columnIcon: {
@@ -109,6 +110,36 @@ const AlbumListView = ({
const classes = useStyles()
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
+
+ const toggleableFields = useMemo(() => {
+ return {
+ artist: ,
+ songCount: isDesktop && (
+
+ ),
+ playCount: isDesktop && (
+
+ ),
+ year: (
+
+ ),
+ duration: isDesktop && ,
+ rating: config.enableStarRating && (
+
+ ),
+ }
+ }, [classes.ratingField, isDesktop])
+
+ const columns = useSelectedFields({
+ resource: 'album',
+ columns: toggleableFields,
+ })
+
return isXsmall ? (
r.name}
@@ -147,19 +178,7 @@ const AlbumListView = ({
{...rest}
>
-
- {isDesktop && }
- {isDesktop && }
-
- {isDesktop && }
- {config.enableStarRating && (
-
- )}
+ {columns}
({
- albumActions: {},
+ albumActions: {
+ width: '100%',
+ },
}),
{
name: 'NDAlbumShow',
diff --git a/ui/src/album/AlbumSongs.js b/ui/src/album/AlbumSongs.js
index 9c5210478..307992d9d 100644
--- a/ui/src/album/AlbumSongs.js
+++ b/ui/src/album/AlbumSongs.js
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useMemo } from 'react'
import {
BulkActionsToolbar,
ListToolbar,
@@ -24,6 +24,7 @@ import {
} from '../common'
import { AddToPlaylistDialog } from '../dialogs'
import { QualityInfo } from '../common/QualityInfo'
+import useSelectedFields from '../common/useSelectedFields'
import config from '../config'
const useStyles = makeStyles(
@@ -87,6 +88,46 @@ const AlbumSongs = (props) => {
const classes = useStyles({ isDesktop })
const dispatch = useDispatch()
const version = useVersion()
+
+ const toggleableFields = useMemo(() => {
+ return {
+ trackNumber: isDesktop && (
+
+ ),
+ title: (
+
+ ),
+ artist: isDesktop && ,
+ duration: ,
+ quality: isDesktop && ,
+ bpm: isDesktop && ,
+ rating: isDesktop && config.enableStarRating && (
+
+ ),
+ }
+ }, [isDesktop, classes.ratingField])
+
+ const columns = useSelectedFields({
+ resource: 'albumSong',
+ columns: toggleableFields,
+ omittedColumns: ['title'],
+ defaultOff: ['bpm'],
+ })
+
return (
<>
{
contextAlwaysVisible={!isDesktop}
classes={{ row: classes.row }}
>
- {isDesktop && (
-
- )}
-
- {isDesktop && }
-
- {isDesktop && }
- {isDesktop && }
- {isDesktop && config.enableStarRating && (
-
- )}
+ {columns}
{
const handleArtistLink = useGetHandleArtistClick(width)
const history = useHistory()
const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs'))
+
+ const toggleableFields = useMemo(() => {
+ return {
+ albumCount: ,
+ songCount: ,
+ playCount: ,
+ rating: config.enableStarRating && (
+
+ ),
+ }
+ }, [classes.ratingField])
+
+ const columns = useSelectedFields({
+ resource: 'artist',
+ columns: toggleableFields,
+ })
+
return isXsmall ? (
history.push(handleArtistLink(id))}
@@ -72,17 +96,7 @@ const ArtistListView = ({ hasShow, hasEdit, hasList, width, ...rest }) => {
) : (
-
-
-
- {config.enableStarRating && (
-
- )}
+ {columns}
{
exporter={false}
bulkActionButtons={false}
filters={}
+ actions={}
>
diff --git a/ui/src/artist/ArtistListActions.js b/ui/src/artist/ArtistListActions.js
new file mode 100644
index 000000000..a1aa4c089
--- /dev/null
+++ b/ui/src/artist/ArtistListActions.js
@@ -0,0 +1,16 @@
+import React from 'react'
+import { sanitizeListRestProps, TopToolbar } from 'react-admin'
+import { useMediaQuery } from '@material-ui/core'
+import ToggleFieldsMenu from '../common/ToggleFieldsMenu'
+
+const ArtistListActions = ({ className, ...rest }) => {
+ const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm'))
+
+ return (
+
+ {isNotSmall && }
+
+ )
+}
+
+export default ArtistListActions
diff --git a/ui/src/common/ToggleFieldsMenu.js b/ui/src/common/ToggleFieldsMenu.js
new file mode 100644
index 000000000..cdae143e9
--- /dev/null
+++ b/ui/src/common/ToggleFieldsMenu.js
@@ -0,0 +1,109 @@
+import React, { useState } from 'react'
+import PropTypes from 'prop-types'
+import IconButton from '@material-ui/core/IconButton'
+import Menu from '@material-ui/core/Menu'
+import MenuItem from '@material-ui/core/MenuItem'
+import { makeStyles, Typography } from '@material-ui/core'
+import MoreVertIcon from '@material-ui/icons/MoreVert'
+import Checkbox from '@material-ui/core/Checkbox'
+import { useDispatch, useSelector } from 'react-redux'
+import { useTranslate } from 'react-admin'
+import { setToggleableFields } from '../actions'
+
+const useStyles = makeStyles({
+ menuIcon: {
+ position: 'relative',
+ top: '-0.5em',
+ },
+ menu: {
+ width: '24ch',
+ },
+ columns: {
+ maxHeight: '21rem',
+ overflow: 'auto',
+ },
+ title: {
+ margin: '1rem',
+ },
+})
+
+const ToggleFieldsMenu = ({ resource, topbarComponent: TopBarComponent }) => {
+ const [anchorEl, setAnchorEl] = useState(null)
+ const dispatch = useDispatch()
+ const translate = useTranslate()
+ const toggleableColumns = useSelector(
+ (state) => state.settings.toggleableFields[resource]
+ )
+ const omittedColumns =
+ useSelector((state) => state.settings.omittedFields[resource]) || []
+
+ const classes = useStyles()
+ const open = Boolean(anchorEl)
+
+ const handleOpen = (event) => {
+ setAnchorEl(event.currentTarget)
+ }
+ const handleClose = () => {
+ setAnchorEl(null)
+ }
+
+ const handleClick = (selectedColumn) => {
+ dispatch(
+ setToggleableFields({
+ [resource]: {
+ ...toggleableColumns,
+ [selectedColumn]: !toggleableColumns[selectedColumn],
+ },
+ })
+ )
+ }
+
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default ToggleFieldsMenu
+
+ToggleFieldsMenu.propTypes = {
+ resource: PropTypes.string.isRequired,
+ topbarComponent: PropTypes.elementType,
+}
diff --git a/ui/src/common/useSelectedFields.js b/ui/src/common/useSelectedFields.js
new file mode 100644
index 000000000..6e3d40c74
--- /dev/null
+++ b/ui/src/common/useSelectedFields.js
@@ -0,0 +1,79 @@
+import React, { useState, useEffect } from 'react'
+import PropTypes from 'prop-types'
+import { useDispatch, useSelector } from 'react-redux'
+import { setOmittedFields, setToggleableFields } from '../actions'
+
+const useSelectedFields = ({
+ resource,
+ columns,
+ omittedColumns = [],
+ defaultOff = [],
+}) => {
+ const dispatch = useDispatch()
+ const resourceFields = useSelector(
+ (state) => state.settings.toggleableFields
+ )?.[resource]
+ const omittedFields = useSelector((state) => state.settings.omittedFields)?.[
+ resource
+ ]
+
+ const [filteredComponents, setFilteredComponents] = useState([])
+
+ useEffect(() => {
+ if (
+ !resourceFields ||
+ Object.keys(resourceFields).length !== Object.keys(columns).length
+ ) {
+ const obj = {}
+ for (const key of Object.keys(columns)) {
+ obj[key] = !defaultOff.includes(key)
+ }
+ dispatch(setToggleableFields({ [resource]: obj }))
+ }
+ if (!omittedFields) {
+ dispatch(setOmittedFields({ [resource]: omittedColumns }))
+ }
+ }, [
+ columns,
+ defaultOff,
+ dispatch,
+ omittedColumns,
+ omittedFields,
+ resource,
+ resourceFields,
+ ])
+
+ useEffect(() => {
+ if (resourceFields) {
+ const filtered = []
+ const omitted = omittedColumns
+ for (const [key, val] of Object.entries(columns)) {
+ if (!val) omitted.push(key)
+ else if (resourceFields[key]) filtered.push(val)
+ }
+ if (filteredComponents.length !== filtered.length)
+ setFilteredComponents(filtered)
+ if (omittedFields.length !== omitted.length)
+ dispatch(setOmittedFields({ [resource]: omitted }))
+ }
+ }, [
+ resourceFields,
+ columns,
+ dispatch,
+ omittedColumns,
+ omittedFields,
+ resource,
+ filteredComponents.length,
+ ])
+
+ return React.Children.toArray(filteredComponents)
+}
+
+export default useSelectedFields
+
+useSelectedFields.propTypes = {
+ resource: PropTypes.string,
+ columns: PropTypes.object,
+ omittedColumns: PropTypes.arrayOf(PropTypes.string),
+ defaultOff: PropTypes.arrayOf(PropTypes.string),
+}
diff --git a/ui/src/i18n/en.json b/ui/src/i18n/en.json
index 2ec45ce3e..aef6d4284 100644
--- a/ui/src/i18n/en.json
+++ b/ui/src/i18n/en.json
@@ -278,6 +278,12 @@
"i18n_error": "Cannot load the translations for the specified language",
"canceled": "Action cancelled",
"logged_out": "Your session has ended, please reconnect."
+ },
+ "toggleFieldsMenu": {
+ "columnsToDisplay": "Columns To Display",
+ "layout": "Layout",
+ "grid": "Grid",
+ "table": "Table"
}
},
"message": {
diff --git a/ui/src/playlist/PlaylistActions.js b/ui/src/playlist/PlaylistActions.js
index 24cfd0b25..3987e4180 100644
--- a/ui/src/playlist/PlaylistActions.js
+++ b/ui/src/playlist/PlaylistActions.js
@@ -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 (
-
-
-
-
- {config.enableDownloads && (
-
- )}
-
+
+
+
+
+
+
+ {config.enableDownloads && (
+
+ )}
+
+
+
{isNotSmall && }
+
)
}
diff --git a/ui/src/playlist/PlaylistList.js b/ui/src/playlist/PlaylistList.js
index 434c8cd20..320f16c5e 100644
--- a/ui/src/playlist/PlaylistList.js
+++ b/ui/src/playlist/PlaylistList.js
@@ -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) => (
@@ -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: ,
+ songCount: isDesktop && ,
+ duration: isDesktop && ,
+ updatedAt: isDesktop && (
+
+ ),
+ public: !isXsmall && (
+
+ ),
+ }
+ }, [isDesktop, isXsmall, permissions])
+
+ const columns = useSelectedFields({
+ resource: 'playlist',
+ columns: toggleableFields,
+ })
+
return (
-
}>
+
}
+ actions={}
+ >
isWritable(r && r.owner)}
>
-
- {isDesktop && }
- {isDesktop && }
- {isDesktop && }
- {!isXsmall && (
-
- )}
+ {columns}
diff --git a/ui/src/playlist/PlaylistListActions.js b/ui/src/playlist/PlaylistListActions.js
new file mode 100644
index 000000000..3717dfac7
--- /dev/null
+++ b/ui/src/playlist/PlaylistListActions.js
@@ -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 (
+
+
+ {translate('ra.action.create')}
+
+ {isNotSmall && }
+
+ )
+}
+
+export default PlaylistListActions
diff --git a/ui/src/playlist/PlaylistShow.js b/ui/src/playlist/PlaylistShow.js
index 7cb705ef7..8fb1e216e 100644
--- a/ui/src/playlist/PlaylistShow.js
+++ b/ui/src/playlist/PlaylistShow.js
@@ -13,7 +13,9 @@ import PlaylistActions from './PlaylistActions'
import { Title, isReadOnly } from '../common'
const useStyles = makeStyles(
(theme) => ({
- playlistActions: {},
+ playlistActions: {
+ width: '100%',
+ },
}),
{
name: 'NDPlaylistShow',
diff --git a/ui/src/playlist/PlaylistSongs.js b/ui/src/playlist/PlaylistSongs.js
index fbf6c901a..8a4556864 100644
--- a/ui/src/playlist/PlaylistSongs.js
+++ b/ui/src/playlist/PlaylistSongs.js
@@ -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 && ,
+ title: ,
+ album: isDesktop && ,
+ artist: isDesktop && ,
+ duration: (
+
+ ),
+ quality: isDesktop && ,
+ bpm: isDesktop && ,
+ }
+ }, [isDesktop, classes.draggable])
+
+ const columns = useSelectedFields({
+ resource: 'playlistTrack',
+ columns: toggleableFields,
+ defaultOff: ['bpm'],
+ })
+
return (
<>
{
contextAlwaysVisible={!isDesktop}
classes={{ row: classes.row }}
>
- {isDesktop && }
-
- {isDesktop && }
- {isDesktop && }
-
- {isDesktop && }
- {isDesktop && }
+ {columns}
{
@@ -12,6 +18,22 @@ export const settingsReducer = (previousState = initialState, payload) => {
...previousState,
notifications: data,
}
+ case SET_TOGGLEABLE_FIELDS:
+ return {
+ ...previousState,
+ toggleableFields: {
+ ...previousState.toggleableFields,
+ ...data,
+ },
+ }
+ case SET_OMITTED_FIELDS:
+ return {
+ ...previousState,
+ omittedFields: {
+ ...previousState.omittedFields,
+ ...data,
+ },
+ }
default:
return previousState
}
diff --git a/ui/src/song/SongList.js b/ui/src/song/SongList.js
index 9aabf325d..37017bcb5 100644
--- a/ui/src/song/SongList.js
+++ b/ui/src/song/SongList.js
@@ -28,6 +28,7 @@ import { AddToPlaylistDialog } from '../dialogs'
import { makeStyles } from '@material-ui/core/styles'
import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder'
import config from '../config'
+import useSelectedFields from '../common/useSelectedFields'
import { QualityInfo } from '../common/QualityInfo'
const useStyles = makeStyles({
@@ -77,6 +78,49 @@ const SongList = (props) => {
dispatch(setTrack(record))
}
+ const toggleableFields = React.useMemo(() => {
+ return {
+ album: isDesktop && (
+
+ ),
+ artist: ,
+ trackNumber: isDesktop && ,
+ playCount: isDesktop && (
+
+ ),
+ year: isDesktop && (
+ r.year || ''}
+ sortByOrder={'DESC'}
+ />
+ ),
+ quality: isDesktop && ,
+ duration: ,
+ rating: config.enableStarRating && (
+
+ ),
+ bpm: isDesktop && ,
+ }
+ }, [isDesktop, classes.ratingField])
+
+ const columns = useSelectedFields({
+ resource: 'song',
+ columns: toggleableFields,
+ defaultOff: ['bpm'],
+ })
+
return (
<>
{
classes={{ row: classes.row }}
>
- {isDesktop && (
-
- )}
-
- {isDesktop && }
- {isDesktop && (
-
- )}
- {isDesktop && (
- r.year || ''}
- sortByOrder={'DESC'}
- />
- )}
- {isDesktop && }
-
- {isDesktop && }
- {config.enableStarRating && (
-
- )}
+ {columns}
{
+ const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm'))
return (
{filters &&
@@ -31,6 +34,7 @@ export const SongListActions = ({
context: 'button',
})}
+ {isNotSmall && }
)
}
diff --git a/ui/src/themes/ligera.js b/ui/src/themes/ligera.js
index 1b6790279..8ba96418f 100644
--- a/ui/src/themes/ligera.js
+++ b/ui/src/themes/ligera.js
@@ -16,7 +16,7 @@ const musicListActions = {
backgroundColor: 'inherit !important',
},
},
- 'button:first-child': {
+ 'button:first-child:not(:only-child)': {
'@media screen and (max-width: 720px)': {
transform: 'scale(1.5)',
margin: '1rem',
@@ -40,6 +40,9 @@ const musicListActions = {
boxShadow: '0px 0px 4px 0px #5656567d',
},
},
+ 'button:only-child': {
+ margin: '1.5rem',
+ },
'button:first-child>span:first-child': {
padding: 0,
color: bLight['300'],
diff --git a/ui/src/themes/spotify.js b/ui/src/themes/spotify.js
index 8f49f6394..c7ad01345 100644
--- a/ui/src/themes/spotify.js
+++ b/ui/src/themes/spotify.js
@@ -19,7 +19,7 @@ const musicListActions = {
backgroundColor: 'inherit !important',
},
},
- 'button:first-child': {
+ 'button:first-child:not(:only-child)': {
'@media screen and (max-width: 720px)': {
transform: 'scale(1.5)',
margin: '1rem',
@@ -42,6 +42,9 @@ const musicListActions = {
border: 0,
},
},
+ 'button:only-child': {
+ margin: '1.5rem',
+ },
'button:first-child>span:first-child': {
padding: 0,
},