You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
7.8 KiB
164 lines
7.8 KiB
import React from 'react'; |
|
import { TableContainer, Table, TableHead, TableRow, TableCell, Paper, makeStyles, TableBody, Chip, Box, Button } from '@material-ui/core'; |
|
import stringifyList from '../../lib/stringifyList'; |
|
import { MainWindowStateActions } from '../MainWindow'; |
|
import { newWindowReducer, WindowType } from '../windows/Windows'; |
|
import PersonIcon from '@material-ui/icons/Person'; |
|
import AlbumIcon from '@material-ui/icons/Album'; |
|
import AudiotrackIcon from '@material-ui/icons/Audiotrack'; |
|
import LocalOfferIcon from '@material-ui/icons/LocalOffer'; |
|
|
|
export interface SongGetters { |
|
getTitle: (song: any) => string, |
|
getId: (song: any) => number, |
|
getArtistNames: (song: any) => string[], |
|
getArtistIds: (song: any) => number[], |
|
getAlbumNames: (song: any) => string[], |
|
getAlbumIds: (song: any) => number[], |
|
getTagNames: (song: any) => string[][], // Each tag is represented as a series of strings. |
|
getTagIds: (song: any) => number[][], // Each tag is represented as a series of ids. |
|
} |
|
|
|
export interface IProps { |
|
songs: any[], |
|
songGetters: SongGetters, |
|
mainDispatch: (action: any) => void, |
|
} |
|
|
|
export function SongTable(props: IProps) { |
|
const useTableStyles = makeStyles({ |
|
table: { |
|
minWidth: 650, |
|
}, |
|
}); |
|
const classes = useTableStyles(); |
|
|
|
return ( |
|
<TableContainer component={Paper}> |
|
<Table className={classes.table} aria-label="a dense table"> |
|
<TableHead> |
|
<TableRow> |
|
<TableCell align="left">Title</TableCell> |
|
<TableCell align="left">Artist</TableCell> |
|
<TableCell align="left">Album</TableCell> |
|
<TableCell align="left">Tags</TableCell> |
|
</TableRow> |
|
</TableHead> |
|
<TableBody> |
|
{props.songs.map((song: any) => { |
|
const title = props.songGetters.getTitle(song); |
|
// TODO / FIXME: display artists and albums separately! |
|
const artistNames = props.songGetters.getArtistNames(song); |
|
const artist = stringifyList(artistNames); |
|
const mainArtistId = props.songGetters.getArtistIds(song)[0]; |
|
const mainArtistName = artistNames[0]; |
|
const albumNames = props.songGetters.getAlbumNames(song); |
|
const album = stringifyList(albumNames); |
|
const mainAlbumName = albumNames[0]; |
|
const mainAlbumId = props.songGetters.getAlbumIds(song)[0]; |
|
const songId = props.songGetters.getId(song); |
|
const tagIds = props.songGetters.getTagIds(song); |
|
|
|
const onClickArtist = () => { |
|
props.mainDispatch({ |
|
type: MainWindowStateActions.AddTab, |
|
tabState: { |
|
tabLabel: <><PersonIcon />{mainArtistName}</>, |
|
artistId: mainArtistId, |
|
metadata: null, |
|
}, |
|
tabReducer: newWindowReducer[WindowType.Artist], |
|
tabType: WindowType.Artist, |
|
}) |
|
} |
|
|
|
const onClickAlbum = () => { |
|
props.mainDispatch({ |
|
type: MainWindowStateActions.AddTab, |
|
tabState: { |
|
tabLabel: <><AlbumIcon />{mainAlbumName}</>, |
|
albumId: mainAlbumId, |
|
metadata: null, |
|
}, |
|
tabReducer: newWindowReducer[WindowType.Album], |
|
tabType: WindowType.Album, |
|
}) |
|
} |
|
|
|
const onClickSong = () => { |
|
props.mainDispatch({ |
|
type: MainWindowStateActions.AddTab, |
|
tabState: { |
|
tabLabel: <><AudiotrackIcon />{title}</>, |
|
songId: songId, |
|
metadata: null, |
|
}, |
|
tabReducer: newWindowReducer[WindowType.Song], |
|
tabType: WindowType.Song, |
|
}) |
|
} |
|
|
|
const onClickTag = (id: number, name: string) => { |
|
props.mainDispatch({ |
|
type: MainWindowStateActions.AddTab, |
|
tabState: { |
|
tabLabel: <><LocalOfferIcon />{name}</>, |
|
tagId: id, |
|
metadata: null, |
|
}, |
|
tabReducer: newWindowReducer[WindowType.Tag], |
|
tabType: WindowType.Tag, |
|
}) |
|
} |
|
|
|
const tags = props.songGetters.getTagNames(song).map((tag: string[], i: number) => { |
|
const fullTag = stringifyList(tag, undefined, (idx: number, e: string) => { |
|
return (idx === 0) ? e : " / " + e; |
|
}) |
|
return <Box ml={0.5} mr={0.5}> |
|
<Chip size="small" |
|
label={fullTag} |
|
onClick={() => onClickTag(tagIds[i][tagIds[i].length-1], fullTag)} |
|
/> |
|
</Box> |
|
}); |
|
|
|
const TextCell = (props: any) => { |
|
const classes = makeStyles({ |
|
button: { |
|
textTransform: "none", |
|
fontWeight: 400, |
|
paddingLeft: '0', |
|
textAlign: 'left', |
|
} |
|
})(); |
|
return <TableCell padding="none" {...props}> |
|
<Button className={classes.button} fullWidth={true} onClick={props._onClick}> |
|
<Box |
|
width="100%" |
|
display="flex" |
|
alignItems="center" |
|
paddingLeft="16px" |
|
> |
|
{props.children} |
|
</Box> |
|
</Button> |
|
</TableCell>; |
|
} |
|
|
|
return <TableRow key={title}> |
|
<TextCell align="left" _onClick={onClickSong}>{title}</TextCell> |
|
<TextCell align="left" _onClick={onClickArtist}>{artist}</TextCell> |
|
<TextCell align="left" _onClick={onClickAlbum}>{album}</TextCell> |
|
<TableCell padding="none" align="left" width="25%"> |
|
<Box display="flex" alignItems="center"> |
|
{tags} |
|
</Box> |
|
</TableCell> |
|
</TableRow> |
|
})} |
|
</TableBody> |
|
</Table> |
|
</TableContainer> |
|
); |
|
} |