feat: initial implementation of album lists
This commit is contained in:
@@ -24,6 +24,7 @@ func NewAlbumRepository(ctx context.Context, o orm.Ormer) model.AlbumRepository
|
|||||||
r.tableName = "album"
|
r.tableName = "album"
|
||||||
r.sortMappings = map[string]string{
|
r.sortMappings = map[string]string{
|
||||||
"artist": "compilation asc, album_artist asc, name asc",
|
"artist": "compilation asc, album_artist asc, name asc",
|
||||||
|
"random": "RANDOM()",
|
||||||
}
|
}
|
||||||
r.filterMappings = map[string]filterFunc{
|
r.filterMappings = map[string]filterFunc{
|
||||||
"name": fullTextFilter,
|
"name": fullTextFilter,
|
||||||
|
|||||||
@@ -1,11 +1,31 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { GridList, GridListTile, GridListTileBar } from '@material-ui/core'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
import {
|
||||||
|
GridList,
|
||||||
|
GridListTile,
|
||||||
|
GridListTileBar,
|
||||||
|
Tabs,
|
||||||
|
Tab
|
||||||
|
} from '@material-ui/core'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import withWidth from '@material-ui/core/withWidth'
|
import withWidth from '@material-ui/core/withWidth'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { linkToRecord } from 'ra-core'
|
import { linkToRecord } from 'ra-core'
|
||||||
import { Loading } from 'react-admin'
|
import { Loading } from 'react-admin'
|
||||||
import { subsonicUrl } from '../subsonic'
|
import { subsonicUrl } from '../subsonic'
|
||||||
|
import AllInclusiveIcon from '@material-ui/icons/AllInclusive'
|
||||||
|
import ShuffleIcon from '@material-ui/icons/Shuffle'
|
||||||
|
import StarIcon from '@material-ui/icons/Star'
|
||||||
|
import LibraryAddIcon from '@material-ui/icons/LibraryAdd'
|
||||||
|
import VideoLibraryIcon from '@material-ui/icons/VideoLibrary'
|
||||||
|
import {
|
||||||
|
ALBUM_LIST_ALL,
|
||||||
|
ALBUM_LIST_NEWEST,
|
||||||
|
ALBUM_LIST_RANDOM,
|
||||||
|
ALBUM_LIST_RECENT,
|
||||||
|
ALBUM_LIST_STARRED,
|
||||||
|
selectAlbumList
|
||||||
|
} from './albumState'
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
@@ -38,10 +58,39 @@ const getColsForWidth = (width) => {
|
|||||||
return 7
|
return 7
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tabOrder = [
|
||||||
|
ALBUM_LIST_ALL,
|
||||||
|
ALBUM_LIST_RANDOM,
|
||||||
|
ALBUM_LIST_NEWEST,
|
||||||
|
ALBUM_LIST_RECENT,
|
||||||
|
ALBUM_LIST_STARRED
|
||||||
|
]
|
||||||
|
|
||||||
const LoadedAlbumGrid = ({ ids, data, basePath, width }) => {
|
const LoadedAlbumGrid = ({ ids, data, basePath, width }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
const albumView = useSelector((state) => state.albumView)
|
||||||
|
const tabSelected = tabOrder.indexOf(albumView.list)
|
||||||
|
|
||||||
|
const handleChange = (event, newValue) => {
|
||||||
|
dispatch(selectAlbumList(tabOrder[newValue]))
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
|
<Tabs
|
||||||
|
value={tabSelected}
|
||||||
|
indicatorColor="primary"
|
||||||
|
textColor="primary"
|
||||||
|
aria-label="disabled tabs example"
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
<Tab label="All" icon={<AllInclusiveIcon />} />
|
||||||
|
<Tab label="Random" icon={<ShuffleIcon />} />
|
||||||
|
<Tab label="Newest" icon={<LibraryAddIcon />} />
|
||||||
|
<Tab label="Recently Played" icon={<VideoLibraryIcon />} />
|
||||||
|
<Tab label="Starred" icon={<StarIcon />} disabled={true} />
|
||||||
|
</Tabs>
|
||||||
<GridList
|
<GridList
|
||||||
cellHeight={'auto'}
|
cellHeight={'auto'}
|
||||||
cols={getColsForWidth(width)}
|
cols={getColsForWidth(width)}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { withWidth } from '@material-ui/core'
|
|||||||
import AlbumListActions from './AlbumListActions'
|
import AlbumListActions from './AlbumListActions'
|
||||||
import AlbumListView from './AlbumListView'
|
import AlbumListView from './AlbumListView'
|
||||||
import AlbumGridView from './AlbumGridView'
|
import AlbumGridView from './AlbumGridView'
|
||||||
import { ALBUM_LIST_MODE } from './albumState'
|
import { ALBUM_MODE_LIST } from './albumState'
|
||||||
|
|
||||||
const AlbumFilter = (props) => (
|
const AlbumFilter = (props) => (
|
||||||
<Filter {...props}>
|
<Filter {...props}>
|
||||||
@@ -58,17 +58,15 @@ const AlbumList = (props) => {
|
|||||||
<List
|
<List
|
||||||
{...props}
|
{...props}
|
||||||
title={<Title subTitle={'Albums'} />}
|
title={<Title subTitle={'Albums'} />}
|
||||||
sort={{ field: 'name', order: 'ASC' }}
|
sort={albumView.params.sort}
|
||||||
exporter={false}
|
exporter={false}
|
||||||
bulkActionButtons={false}
|
bulkActionButtons={false}
|
||||||
actions={<AlbumListActions />}
|
actions={<AlbumListActions />}
|
||||||
filters={<AlbumFilter />}
|
filters={<AlbumFilter />}
|
||||||
perPage={getPerPage(width)}
|
perPage={getPerPage(width)}
|
||||||
pagination={
|
pagination={<Pagination rowsPerPageOptions={getPerPageOptions(width)} />}
|
||||||
<Pagination rowsPerPageOptions={getPerPageOptions(width)} {...props} />
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{albumView.mode === ALBUM_LIST_MODE ? (
|
{albumView.mode === ALBUM_MODE_LIST ? (
|
||||||
<AlbumListView {...props} />
|
<AlbumListView {...props} />
|
||||||
) : (
|
) : (
|
||||||
<AlbumGridView {...props} />
|
<AlbumGridView {...props} />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { ButtonGroup } from '@material-ui/core'
|
|||||||
import ViewHeadlineIcon from '@material-ui/icons/ViewHeadline'
|
import ViewHeadlineIcon from '@material-ui/icons/ViewHeadline'
|
||||||
import ViewModuleIcon from '@material-ui/icons/ViewModule'
|
import ViewModuleIcon from '@material-ui/icons/ViewModule'
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import { ALBUM_GRID_MODE, ALBUM_LIST_MODE, selectViewMode } from './albumState'
|
import { ALBUM_MODE_GRID, ALBUM_MODE_LIST, selectViewMode } from './albumState'
|
||||||
|
|
||||||
const AlbumListActions = ({
|
const AlbumListActions = ({
|
||||||
currentSort,
|
currentSort,
|
||||||
@@ -44,15 +44,15 @@ const AlbumListActions = ({
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
color={albumView.mode === ALBUM_LIST_MODE ? 'primary' : 'secondary'}
|
color={albumView.mode === ALBUM_MODE_LIST ? 'primary' : 'secondary'}
|
||||||
onClick={() => dispatch(selectViewMode(ALBUM_LIST_MODE))}
|
onClick={() => dispatch(selectViewMode(ALBUM_MODE_LIST))}
|
||||||
>
|
>
|
||||||
<ViewHeadlineIcon fontSize="inherit" />
|
<ViewHeadlineIcon fontSize="inherit" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
color={albumView.mode === ALBUM_GRID_MODE ? 'primary' : 'secondary'}
|
color={albumView.mode === ALBUM_MODE_GRID ? 'primary' : 'secondary'}
|
||||||
onClick={() => dispatch(selectViewMode(ALBUM_GRID_MODE))}
|
onClick={() => dispatch(selectViewMode(ALBUM_MODE_GRID))}
|
||||||
>
|
>
|
||||||
<ViewModuleIcon fontSize="inherit" />
|
<ViewModuleIcon fontSize="inherit" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,23 +1,60 @@
|
|||||||
const ALBUM_GRID_MODE = 'ALBUM_GRID_MODE'
|
const ALBUM_MODE_GRID = 'ALBUM_GRID_MODE'
|
||||||
const ALBUM_LIST_MODE = 'ALBUM_LIST_MODE'
|
const ALBUM_MODE_LIST = 'ALBUM_LIST_MODE'
|
||||||
|
|
||||||
const selectViewMode = (mode) => ({ type: mode })
|
const selectViewMode = (mode) => ({ type: mode })
|
||||||
|
|
||||||
|
const ALBUM_LIST_ALL = 'ALBUM_LIST_ALL'
|
||||||
|
const ALBUM_LIST_RANDOM = 'ALBUM_LIST_RANDOM'
|
||||||
|
const ALBUM_LIST_NEWEST = 'ALBUM_LIST_NEWEST'
|
||||||
|
const ALBUM_LIST_RECENT = 'ALBUM_LIST_RECENT'
|
||||||
|
const ALBUM_LIST_STARRED = 'ALBUM_LIST_STARRED'
|
||||||
|
|
||||||
|
const albumListParams = {
|
||||||
|
ALBUM_LIST_ALL: { sort: { field: 'name', order: 'ASC' } },
|
||||||
|
ALBUM_LIST_RANDOM: { sort: { field: 'random' } },
|
||||||
|
ALBUM_LIST_NEWEST: { sort: { field: 'created_at', order: 'DESC' } },
|
||||||
|
ALBUM_LIST_RECENT: {
|
||||||
|
sort: { field: 'starred_at', order: 'DESC' },
|
||||||
|
filter: { starred: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectAlbumList = (mode) => ({ type: mode })
|
||||||
|
|
||||||
const albumViewReducer = (
|
const albumViewReducer = (
|
||||||
previousState = {
|
previousState = {
|
||||||
mode: localStorage.getItem('albumViewMode') || ALBUM_LIST_MODE
|
mode: localStorage.getItem('albumViewMode') || ALBUM_MODE_LIST,
|
||||||
|
list: localStorage.getItem('albumListType') || ALBUM_LIST_ALL,
|
||||||
|
params: { sort: {}, filter: {} }
|
||||||
},
|
},
|
||||||
payload
|
payload
|
||||||
) => {
|
) => {
|
||||||
const { type } = payload
|
const { type } = payload
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ALBUM_GRID_MODE:
|
case ALBUM_MODE_GRID:
|
||||||
case ALBUM_LIST_MODE:
|
case ALBUM_MODE_LIST:
|
||||||
localStorage.setItem('albumViewMode', type)
|
localStorage.setItem('albumViewMode', type)
|
||||||
return { mode: type }
|
return { ...previousState, mode: type }
|
||||||
|
case ALBUM_LIST_ALL:
|
||||||
|
case ALBUM_LIST_RANDOM:
|
||||||
|
case ALBUM_LIST_NEWEST:
|
||||||
|
case ALBUM_LIST_RECENT:
|
||||||
|
case ALBUM_LIST_STARRED:
|
||||||
|
localStorage.setItem('albumListType', type)
|
||||||
|
return { ...previousState, list: type, params: albumListParams[type] }
|
||||||
default:
|
default:
|
||||||
return previousState
|
return previousState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ALBUM_LIST_MODE, ALBUM_GRID_MODE, albumViewReducer, selectViewMode }
|
export {
|
||||||
|
ALBUM_MODE_LIST,
|
||||||
|
ALBUM_MODE_GRID,
|
||||||
|
ALBUM_LIST_ALL,
|
||||||
|
ALBUM_LIST_RANDOM,
|
||||||
|
ALBUM_LIST_NEWEST,
|
||||||
|
ALBUM_LIST_RECENT,
|
||||||
|
ALBUM_LIST_STARRED,
|
||||||
|
albumViewReducer,
|
||||||
|
selectViewMode,
|
||||||
|
selectAlbumList
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user