Browse Source
- - Add genre sort to getAllAlbums api - Add genres to sortType picker - Add router query param for sortType on album list - Remove deprecated LibraryView pagemaster
jeffvli
3 years ago
8 changed files with 303 additions and 166 deletions
@ -0,0 +1,93 @@ |
|||||
|
import React, { useState } from 'react'; |
||||
|
import settings from 'electron-settings'; |
||||
|
import { useQuery } from 'react-query'; |
||||
|
import { useHistory } from 'react-router'; |
||||
|
import useSearchQuery from '../../hooks/useSearchQuery'; |
||||
|
import GenericPage from '../layout/GenericPage'; |
||||
|
import GenericPageHeader from '../layout/GenericPageHeader'; |
||||
|
import ListViewType from '../viewtypes/ListViewType'; |
||||
|
import PageLoader from '../loader/PageLoader'; |
||||
|
import { useAppDispatch } from '../../redux/hooks'; |
||||
|
import { |
||||
|
clearSelected, |
||||
|
setRangeSelected, |
||||
|
toggleRangeSelected, |
||||
|
toggleSelected, |
||||
|
} from '../../redux/multiSelectSlice'; |
||||
|
import { getGenres } from '../../api/api'; |
||||
|
|
||||
|
const GenreList = () => { |
||||
|
const dispatch = useAppDispatch(); |
||||
|
const history = useHistory(); |
||||
|
const { isLoading, isError, data: genres, error }: any = useQuery(['genreList'], () => |
||||
|
getGenres() |
||||
|
); |
||||
|
const [searchQuery, setSearchQuery] = useState(''); |
||||
|
const filteredData = useSearchQuery(searchQuery, genres, ['value']); |
||||
|
|
||||
|
let timeout: any = null; |
||||
|
const handleRowClick = (e: any, rowData: any) => { |
||||
|
if (timeout === null) { |
||||
|
timeout = window.setTimeout(() => { |
||||
|
timeout = null; |
||||
|
|
||||
|
if (e.ctrlKey) { |
||||
|
dispatch(toggleSelected(rowData)); |
||||
|
} else if (e.shiftKey) { |
||||
|
dispatch(setRangeSelected(rowData)); |
||||
|
dispatch(toggleRangeSelected(searchQuery !== '' ? filteredData : genres)); |
||||
|
} |
||||
|
}, 100); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const handleRowDoubleClick = (rowData: any) => { |
||||
|
window.clearTimeout(timeout); |
||||
|
timeout = null; |
||||
|
|
||||
|
dispatch(clearSelected()); |
||||
|
history.push(`/library/album?sortType=${rowData.value}`); |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<GenericPage |
||||
|
hideDivider |
||||
|
header={ |
||||
|
<GenericPageHeader |
||||
|
title="Genres" |
||||
|
searchQuery={searchQuery} |
||||
|
handleSearch={(e: any) => setSearchQuery(e)} |
||||
|
clearSearchQuery={() => setSearchQuery('')} |
||||
|
viewTypeSetting="genre" |
||||
|
showSearchBar |
||||
|
/> |
||||
|
} |
||||
|
> |
||||
|
{isLoading && <PageLoader />} |
||||
|
{isError && <div>Error: {error}</div>} |
||||
|
{!isLoading && !isError && ( |
||||
|
<ListViewType |
||||
|
data={searchQuery !== '' ? filteredData : genres} |
||||
|
tableColumns={settings.getSync('genreListColumns')} |
||||
|
rowHeight={Number(settings.getSync('genreListRowHeight'))} |
||||
|
fontSize={settings.getSync('genreListFontSize')} |
||||
|
handleRowClick={handleRowClick} |
||||
|
handleRowDoubleClick={handleRowDoubleClick} |
||||
|
listType="genre" |
||||
|
virtualized |
||||
|
disabledContextMenuOptions={[ |
||||
|
'addToQueue', |
||||
|
'moveSelectedTo', |
||||
|
'removeFromCurrent', |
||||
|
'addToPlaylist', |
||||
|
'deletePlaylist', |
||||
|
'addToFavorites', |
||||
|
'removeFromFavorites', |
||||
|
]} |
||||
|
/> |
||||
|
)} |
||||
|
</GenericPage> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default GenreList; |
@ -1,133 +0,0 @@ |
|||||
import React, { useState } from 'react'; |
|
||||
import { Nav, SelectPicker } from 'rsuite'; |
|
||||
import { useQuery } from 'react-query'; |
|
||||
import VisibilitySensor from 'react-visibility-sensor'; |
|
||||
import settings from 'electron-settings'; |
|
||||
import _ from 'lodash'; |
|
||||
import useSearchQuery from '../../hooks/useSearchQuery'; |
|
||||
import { getAlbumsDirect, getArtists } from '../../api/api'; |
|
||||
import GenericPage from '../layout/GenericPage'; |
|
||||
import GenericPageHeader from '../layout/GenericPageHeader'; |
|
||||
import ArtistList from './ArtistList'; |
|
||||
import PageLoader from '../loader/PageLoader'; |
|
||||
|
|
||||
const ALBUM_SORT_TYPES = [ |
|
||||
{ label: 'A-Z (Name)', value: 'alphabeticalByName' }, |
|
||||
{ |
|
||||
label: 'A-Z (Artist)', |
|
||||
value: 'alphabeticalByArtist', |
|
||||
}, |
|
||||
{ label: 'Most Played', value: 'frequent' }, |
|
||||
{ label: 'Newly Added', value: 'newest' }, |
|
||||
{ label: 'Recently Played', value: 'recent' }, |
|
||||
]; |
|
||||
|
|
||||
const LibraryView = () => { |
|
||||
const [currentPage, setCurrentPage] = useState('albums'); |
|
||||
const [sortBy, setSortBy] = useState(null); |
|
||||
const [data, setData] = useState<any[]>([]); |
|
||||
const [offset, setOffset] = useState(0); |
|
||||
const [viewType, setViewType] = useState(settings.getSync('albumViewType')); |
|
||||
const { isLoading: isLoadingArtists, data: artists }: any = useQuery('artists', getArtists, { |
|
||||
enabled: currentPage === 'artists', |
|
||||
}); |
|
||||
const [searchQuery, setSearchQuery] = useState(''); |
|
||||
const filteredData = useSearchQuery( |
|
||||
searchQuery, |
|
||||
currentPage === 'artists' ? artists : currentPage === 'albums' ? data : data, |
|
||||
['name', 'artist'] |
|
||||
); |
|
||||
|
|
||||
const onChange = (isVisible: boolean) => { |
|
||||
if (isVisible) { |
|
||||
setOffset(offset + 50); |
|
||||
|
|
||||
setTimeout(async () => { |
|
||||
const res = await getAlbumsDirect({ |
|
||||
type: sortBy || 'random', |
|
||||
size: 50, |
|
||||
offset, |
|
||||
}); |
|
||||
|
|
||||
const combinedData = data.concat(res); |
|
||||
|
|
||||
// Ensure that no duplicates are added in the case of random fetching
|
|
||||
const uniqueCombinedData = _.uniqBy(combinedData, (e: any) => e.id); |
|
||||
|
|
||||
return setData(uniqueCombinedData); |
|
||||
}, 0); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
const handleNavClick = (e: React.SetStateAction<string>) => { |
|
||||
setData([]); |
|
||||
setOffset(0); |
|
||||
setCurrentPage(e); |
|
||||
}; |
|
||||
|
|
||||
return ( |
|
||||
<GenericPage |
|
||||
header={ |
|
||||
<GenericPageHeader |
|
||||
title="Library" |
|
||||
subtitle={ |
|
||||
<Nav activeKey={currentPage} onSelect={handleNavClick}> |
|
||||
<Nav.Item eventKey="albums">Albums</Nav.Item> |
|
||||
<Nav.Item eventKey="artists">Artists</Nav.Item> |
|
||||
<Nav.Item eventKey="genres">Genres</Nav.Item> |
|
||||
</Nav> |
|
||||
} |
|
||||
subsidetitle={ |
|
||||
currentPage === 'albums' ? ( |
|
||||
<SelectPicker |
|
||||
data={ALBUM_SORT_TYPES} |
|
||||
searchable={false} |
|
||||
placeholder="Sort Type" |
|
||||
menuAutoWidth |
|
||||
onChange={(value) => { |
|
||||
setData([]); |
|
||||
setOffset(0); |
|
||||
setSortBy(value); |
|
||||
}} |
|
||||
/> |
|
||||
) : undefined |
|
||||
} |
|
||||
searchQuery={searchQuery} |
|
||||
handleSearch={(e: any) => setSearchQuery(e)} |
|
||||
clearSearchQuery={() => setSearchQuery('')} |
|
||||
showViewTypeButtons={currentPage === 'albums'} |
|
||||
viewTypeSetting="album" |
|
||||
showSearchBar |
|
||||
handleListClick={() => setViewType('list')} |
|
||||
handleGridClick={() => setViewType('grid')} |
|
||||
/> |
|
||||
} |
|
||||
> |
|
||||
{isLoadingArtists && <PageLoader />} |
|
||||
|
|
||||
{artists && ( |
|
||||
<> |
|
||||
{currentPage === 'artists' && ( |
|
||||
<ArtistList viewType={viewType} data={searchQuery === '' ? artists : filteredData} /> |
|
||||
)} |
|
||||
</> |
|
||||
)} |
|
||||
|
|
||||
{data.length !== 1 && searchQuery === '' && currentPage === 'albums' && ( |
|
||||
<VisibilitySensor onChange={onChange}> |
|
||||
<div |
|
||||
style={{ |
|
||||
textAlign: 'center', |
|
||||
marginTop: '25px', |
|
||||
marginBottom: '25px', |
|
||||
}} |
|
||||
> |
|
||||
<PageLoader size="md" /> |
|
||||
</div> |
|
||||
</VisibilitySensor> |
|
||||
)} |
|
||||
</GenericPage> |
|
||||
); |
|
||||
}; |
|
||||
|
|
||||
export default LibraryView; |
|
Loading…
Reference in new issue