Browse Source

Update default prettier config

- Change printWidth from 80 -> 100
master
jeffvli 3 years ago
parent
commit
2243d40a66
  1. 4
      .prettierrc
  2. 15
      package.json
  3. 5
      src/App.tsx
  4. 4
      src/__tests__/App.test.tsx
  5. 35
      src/api/api.ts
  6. 28
      src/components/card/Card.tsx
  7. 27
      src/components/debug/DebugWindow.tsx
  8. 9
      src/components/layout/GenericPage.tsx
  9. 13
      src/components/layout/GenericPageHeader.tsx
  10. 5
      src/components/layout/Layout.tsx
  11. 5
      src/components/layout/NavToggle.tsx
  12. 25
      src/components/layout/Titlebar.tsx
  13. 22
      src/components/layout/styled.tsx
  14. 4
      src/components/library/AlbumList.tsx
  15. 33
      src/components/library/AlbumView.tsx
  16. 27
      src/components/library/ArtistView.tsx
  17. 19
      src/components/library/LibraryView.tsx
  18. 6
      src/components/loader/PageLoader.tsx
  19. 21
      src/components/modal/PageModal.tsx
  20. 13
      src/components/player/NowPlayingMiniView.tsx
  21. 6
      src/components/player/NowPlayingView.tsx
  22. 111
      src/components/player/Player.tsx
  23. 155
      src/components/player/PlayerBar.tsx
  24. 19
      src/components/player/styled.tsx
  25. 22
      src/components/playlist/PlaylistList.tsx
  26. 62
      src/components/playlist/PlaylistView.tsx
  27. 20
      src/components/scrollingmenu/ScrollingMenu.tsx
  28. 7
      src/components/selectionbar/SelectionBar.tsx
  29. 24
      src/components/selectionbar/SelectionButtons.tsx
  30. 4
      src/components/settings/Config.tsx
  31. 43
      src/components/settings/ConfigPanels/CacheConfig.tsx
  32. 5
      src/components/settings/ConfigPanels/DebugConfig.tsx
  33. 19
      src/components/settings/ConfigPanels/ListViewConfig.tsx
  34. 23
      src/components/settings/ConfigPanels/LookAndFeelConfig.tsx
  35. 48
      src/components/settings/ConfigPanels/PlaybackConfig.tsx
  36. 9
      src/components/settings/ConfigPanels/PlayerConfig.tsx
  37. 61
      src/components/shared/ContextMenu.tsx
  38. 17
      src/components/shared/ToolbarButtons.tsx
  39. 30
      src/components/shared/styled.ts
  40. 5
      src/components/shared/toast.ts
  41. 26
      src/components/starred/StarredView.tsx
  42. 21
      src/components/viewtypes/GridViewType.tsx
  43. 152
      src/components/viewtypes/ListViewTable.tsx
  44. 8
      src/components/viewtypes/ListViewType.tsx
  45. 6
      src/components/viewtypes/ViewTypeButtons.tsx
  46. 10
      src/components/viewtypes/styled.tsx
  47. 10
      src/hooks/useSearchQuery.ts
  48. 4
      src/index.html
  49. 53
      src/main.dev.js
  50. 39
      src/menu.ts
  51. 11
      src/redux/miscSlice.ts
  52. 16
      src/redux/multiSelectSlice.ts
  53. 144
      src/redux/playQueueSlice.ts
  54. 44
      src/shared/utils.ts
  55. 7
      yarn.lock

4
.prettierrc

@ -2,5 +2,7 @@
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": false
"singleQuote": true,
"printWidth": 100,
"arrowParens": "always"
}

15
package.json

@ -297,21 +297,6 @@
"yarn": ">=1.21.3"
},
"browserslist": [],
"prettier": {
"overrides": [
{
"files": [
".prettierrc",
".babelrc",
".eslintrc"
],
"options": {
"parser": "json"
}
}
],
"singleQuote": true
},
"renovate": {
"extends": [
"bliss"

5
src/App.tsx

@ -55,10 +55,7 @@ const App = () => {
document.getElementById('local-search-input')?.focus();
}, []);
if (
!localStorage.getItem('server') ||
!localStorage.getItem('serverBase64')
) {
if (!localStorage.getItem('server') || !localStorage.getItem('serverBase64')) {
return (
<ThemeProvider theme={theme}>
<Layout disableSidebar footer={<MockFooter />} font={font}>

4
src/__tests__/App.test.tsx

@ -9,9 +9,7 @@ import { Player } from '../redux/playerSlice';
import { General } from '../redux/miscSlice';
import App from '../App';
const middlewares:
| Middleware<Record<string, unknown>, any, Dispatch<AnyAction>>[]
| undefined = [];
const middlewares: Middleware<Record<string, unknown>, any, Dispatch<AnyAction>>[] | undefined = [];
const mockStore = configureMockStore(middlewares);
const playQueueState: PlayQueue = {

35
src/api/api.ts

@ -141,18 +141,13 @@ export const getPlaylists = async (sortBy: string) => {
return a.changed > b.changed ? -1 : a.changed < b.changed ? 1 : 0;
})
: sortBy === 'name'
? _.orderBy(
data.playlists.playlist || [],
[(entry) => entry.name.toLowerCase()],
'asc'
)
? _.orderBy(data.playlists.playlist || [], [(entry) => entry.name.toLowerCase()], 'asc')
: data.playlists?.playlist;
return (newData || []).map((playlist: any) => ({
...playlist,
name: playlist.name,
image:
playlist.songCount > 0 ? getCoverArtUrl(playlist) : 'img/placeholder.jpg',
image: playlist.songCount > 0 ? getCoverArtUrl(playlist) : 'img/placeholder.jpg',
}));
};
@ -168,10 +163,7 @@ export const getPlaylist = async (id: string) => {
index,
uniqueId: nanoid(),
})),
image:
data.playlist.songCount > 0
? getCoverArtUrl(data.playlist)
: 'img/placeholder.jpg',
image: data.playlist.songCount > 0 ? getCoverArtUrl(data.playlist) : 'img/placeholder.jpg',
};
};
@ -250,8 +242,7 @@ export const getAlbumsDirect = async (options: any, coverArtSize = 150) => {
params: options,
});
const albums = (data.albumList2.album || []).map(
(entry: any, index: any) => ({
const albums = (data.albumList2.album || []).map((entry: any, index: any) => ({
...entry,
albumId: entry.id,
image: getCoverArtUrl(entry, coverArtSize),
@ -259,8 +250,7 @@ export const getAlbumsDirect = async (options: any, coverArtSize = 150) => {
type: 'album',
index,
uniqueId: nanoid(),
})
);
}));
return albums;
};
@ -348,9 +338,7 @@ export const getArtists = async () => {
const { data } = await api.get(`/getArtists`);
const artistList: any[] = [];
const artists = (data.artists?.index || []).flatMap(
(index: any) => index.artist
);
const artists = (data.artists?.index || []).flatMap((index: any) => index.artist);
artists.map((artist: any) =>
artistList.push({
@ -523,11 +511,7 @@ export const setRating = async (id: string, rating: number) => {
return data;
};
export const getSimilarSongs = async (
id: string,
count: number,
coverArtSize = 150
) => {
export const getSimilarSongs = async (id: string, count: number, coverArtSize = 150) => {
const { data } = await api.get(`/getSimilarSongs2`, {
params: { id, count },
});
@ -559,10 +543,7 @@ export const updatePlaylistSongs = async (id: string, entry: any[]) => {
return data;
};
export const updatePlaylistSongsLg = async (
playlistId: string,
entry: any[]
) => {
export const updatePlaylistSongsLg = async (playlistId: string, entry: any[]) => {
const entryIds = _.map(entry, 'id');
// Set these in chunks so the api doesn't break

28
src/components/card/Card.tsx

@ -7,11 +7,7 @@ import { useQueryClient } from 'react-query';
import cacheImage from '../shared/cacheImage';
import { getAlbum, getPlaylist, star, unstar } from '../../api/api';
import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import {
appendPlayQueue,
fixPlayer2Index,
setPlayQueue,
} from '../../redux/playQueueSlice';
import { appendPlayQueue, fixPlayer2Index, setPlayQueue } from '../../redux/playQueueSlice';
import { isCached, getImageCachePath } from '../../shared/utils';
import {
@ -126,9 +122,7 @@ const Card = ({
{lazyLoad ? (
<LazyCardImg
src={
isCached(
`${cachePath}${rest.details.cacheType}_${rest.details.id}.jpg`
)
isCached(`${cachePath}${rest.details.cacheType}_${rest.details.id}.jpg`)
? `${cachePath}${rest.details.cacheType}_${rest.details.id}.jpg`
: rest.coverArt
}
@ -147,12 +141,7 @@ const Card = ({
}}
/>
) : (
<CardImg
src={rest.coverArt}
alt="img"
onClick={handleClick}
cardsize={size}
/>
<CardImg src={rest.coverArt} alt="img" onClick={handleClick} cardsize={size} />
)}
{hasHoverButtons && (
@ -172,9 +161,7 @@ const Card = ({
<FavoriteOverlayButton
onClick={handleFavorite}
size="xs"
icon={
<Icon icon={rest.details.starred ? 'heart' : 'heart-o'} />
}
icon={<Icon icon={rest.details.starred ? 'heart' : 'heart-o'} />}
/>
)}
{!rest.isModal && (
@ -189,12 +176,7 @@ const Card = ({
</Overlay>
<InfoPanel cardsize={size}>
<InfoSpan>
<CardTitleButton
appearance="link"
size="sm"
onClick={handleClick}
cardsize={size}
>
<CardTitleButton appearance="link" size="sm" onClick={handleClick} cardsize={size}>
{rest.title}
</CardTitleButton>
</InfoSpan>

27
src/components/debug/DebugWindow.tsx

@ -145,9 +145,7 @@ const DebugWindow = ({ ...rest }) => {
<table style={{ tableLayout: 'fixed', textAlign: 'center' }}>
<tbody>
<tr>
<th style={{ textAlign: 'left' }}>
Player [{playQueue.currentPlayer}]
</th>
<th style={{ textAlign: 'left' }}>Player [{playQueue.currentPlayer}]</th>
<th
style={{
color: 'rgb(0, 150, 0)',
@ -170,12 +168,8 @@ const DebugWindow = ({ ...rest }) => {
</tr>
<tr>
<td style={{ width: '80px', textAlign: 'left' }}>volume</td>
<td style={{ width: '65px' }}>
{Number(playQueue.player1.volume).toFixed(2)}
</td>
<td style={{ width: '65px' }}>
{Number(playQueue.player2.volume).toFixed(2)}
</td>
<td style={{ width: '65px' }}>{Number(playQueue.player1.volume).toFixed(2)}</td>
<td style={{ width: '65px' }}>{Number(playQueue.player2.volume).toFixed(2)}</td>
</tr>
</tbody>
</table>
@ -186,10 +180,7 @@ const DebugWindow = ({ ...rest }) => {
<h6>Volume fade</h6>
</FlexboxGrid.Item>
<FlexboxGrid.Item>
<Button
size="xs"
onClick={() => dispatch(setFadeData({ clear: true }))}
>
<Button size="xs" onClick={() => dispatch(setFadeData({ clear: true }))}>
Reset
</Button>
</FlexboxGrid.Item>
@ -224,18 +215,16 @@ const DebugWindow = ({ ...rest }) => {
}}
>
<li>
lastSelected: [{multiSelect.lastSelected.rowIndex}]{' '}
{multiSelect.lastSelected.title} {multiSelect.lastSelected.id}
lastSelected: [{multiSelect.lastSelected.rowIndex}] {multiSelect.lastSelected.title}{' '}
{multiSelect.lastSelected.id}
</li>
<li>
range (start): [
{multiSelect.lastRangeSelected.lastSelected.rowIndex}]{' '}
range (start): [{multiSelect.lastRangeSelected.lastSelected.rowIndex}]{' '}
{multiSelect.lastRangeSelected.lastSelected.title}{' '}
{multiSelect.lastRangeSelected.lastSelected.id}
</li>
<li>
range (end): [
{multiSelect.lastRangeSelected.lastRangeSelected.rowIndex}]{' '}
range (end): [{multiSelect.lastRangeSelected.lastRangeSelected.rowIndex}]{' '}
{multiSelect.lastRangeSelected.lastRangeSelected.title}{' '}
{multiSelect.lastRangeSelected.lastRangeSelected.id}
</li>

9
src/components/layout/GenericPage.tsx

@ -14,10 +14,7 @@ const GenericPage = ({ header, children, hideDivider, ...rest }: any) => {
useEffect(() => {
if (misc.dynamicBackground) {
const cachedImagePath = `${cachePath}album_${playQueue.current?.albumId}.jpg`;
const serverImagePath = playQueue.current?.image.replace(
/size=\d+/,
'size=500'
);
const serverImagePath = playQueue.current?.image.replace(/size=\d+/, 'size=500');
const cssBackgroundImagePath = `${cachePath}album_${playQueue.current?.albumId}.jpg`.replaceAll(
'\\',
'/'
@ -28,9 +25,7 @@ const GenericPage = ({ header, children, hideDivider, ...rest }: any) => {
preloadImage.src = serverImagePath;
}
const imagePath = isCached(cachedImagePath)
? cssBackgroundImagePath
: serverImagePath;
const imagePath = isCached(cachedImagePath) ? cssBackgroundImagePath : serverImagePath;
setBackgroundImage(imagePath);
}

13
src/components/layout/GenericPageHeader.tsx

@ -60,9 +60,7 @@ const GenericPageHeader = ({
alignSelf: 'center',
}}
>
{sidetitle && (
<span style={{ display: 'inline-block' }}>{sidetitle}</span>
)}
{sidetitle && <span style={{ display: 'inline-block' }}>{sidetitle}</span>}
{showSearchBar && (
<span style={{ display: 'inline-block' }}>
<StyledInputGroup inside>
@ -74,10 +72,7 @@ const GenericPageHeader = ({
onChange={handleSearch}
/>
{searchQuery !== '' && (
<InputGroup.Button
appearance="subtle"
onClick={clearSearchQuery}
>
<InputGroup.Button appearance="subtle" onClick={clearSearchQuery}>
<Icon icon="close" />
</InputGroup.Button>
)}
@ -105,9 +100,7 @@ const GenericPageHeader = ({
{subtitle}
</span>
<span style={{ alignSelf: 'center' }}>
{subsidetitle && (
<span style={{ display: 'inline-block' }}>{subsidetitle}</span>
)}
{subsidetitle && <span style={{ display: 'inline-block' }}>{subsidetitle}</span>}
{showViewTypeButtons && (
<span style={{ display: 'inline-block' }}>
<ViewTypeButtons

5
src/components/layout/Layout.tsx

@ -74,10 +74,7 @@ const Layout = ({ footer, children, disableSidebar, font }: any) => {
})
);
}
if (
multiSelect.selected.length > 0 &&
!multiSelect.isSelectDragging
) {
if (multiSelect.selected.length > 0 && !multiSelect.isSelectDragging) {
dispatch(clearSelected());
}
}}

5
src/components/layout/NavToggle.tsx

@ -20,10 +20,7 @@ const NavToggle = ({ expand, onChange }: any) => {
</Nav>
<Nav pullRight>
<Nav.Item
onClick={onChange}
style={{ width: 56, textAlign: 'center' }}
>
<Nav.Item onClick={onChange} style={{ width: 56, textAlign: 'center' }}>
<Icon icon={expand ? 'angle-left' : 'angle-right'} />
</Nav.Item>
</Nav>

25
src/components/layout/Titlebar.tsx

@ -1,10 +1,5 @@
import React, { useEffect, useState } from 'react';
import {
TitleHeader,
DragRegion,
WindowControl,
WindowControlButton,
} from './styled';
import { TitleHeader, DragRegion, WindowControl, WindowControlButton } from './styled';
import { useAppSelector } from '../../redux/hooks';
const Titlebar = ({ font }: any) => {
@ -21,16 +16,12 @@ const Titlebar = ({ font }: any) => {
const currentEntryList = playQueue.shuffle ? 'shuffledEntry' : 'entry';
const playStatus =
player.status !== 'PLAYING' && playQueue[currentEntryList].length > 0
? '(Paused)'
: '';
player.status !== 'PLAYING' && playQueue[currentEntryList].length > 0 ? '(Paused)' : '';
const songTitle = playQueue[currentEntryList][playQueue.currentIndex]?.title
? `(${playQueue.currentIndex + 1} / ${
playQueue[currentEntryList].length
}) ~ ${playQueue[currentEntryList][playQueue.currentIndex]?.title} ~ ${
playQueue[currentEntryList][playQueue.currentIndex]?.artist
} `
? `(${playQueue.currentIndex + 1} / ${playQueue[currentEntryList].length}) ~ ${
playQueue[currentEntryList][playQueue.currentIndex]?.title
} ~ ${playQueue[currentEntryList][playQueue.currentIndex]?.artist} `
: 'sonixd';
setTitle(`${playStatus} ${songTitle}`);
@ -59,11 +50,7 @@ const Titlebar = ({ font }: any) => {
alt=""
/>
</WindowControlButton>
<WindowControlButton
restoreButton
className="button"
id="restore-button"
>
<WindowControlButton restoreButton className="button" id="restore-button">
<img
className="icon"
srcSet="img/icons/restore-w-10.png 1x, img/icons/restore-w-12.png 1.25x, img/icons/restore-w-15.png 1.5x, img/icons/restore-w-15.png 1.75x, img/icons/restore-w-20.png 2x, img/icons/restore-w-20.png 2.25x, img/icons/restore-w-24.png 2.5x, img/icons/restore-w-30.png 3x, img/icons/restore-w-30.png 3.5x"

22
src/components/layout/styled.tsx

@ -19,12 +19,9 @@ interface ContainerProps {
children: any;
}
const StyledContainer = ({
id,
expanded,
children,
...props
}: ContainerProps) => <Container {...props}>{children}</Container>;
const StyledContainer = ({ id, expanded, children, ...props }: ContainerProps) => (
<Container {...props}>{children}</Container>
);
export const MainContainer = styled(StyledContainer)`
padding-left: ${(props) => (props.expanded ? '193px' : '56px')};
@ -44,8 +41,7 @@ export const TitleHeader = styled.header<{ font: string }>`
display: block;
position: fixed;
height: 32px;
width: ${(props) =>
props.className?.includes('maximized') ? '100%' : 'calc(100%)'};
width: ${(props) => (props.className?.includes('maximized') ? '100%' : 'calc(100%)')};
background: ${(props) => props.theme.primary.titleBar};
padding: 4px;
color: ${(props) => props.theme.primary.titleText};
@ -86,8 +82,7 @@ export const WindowControlButton = styled.div<{
align-items: center;
width: 100%;
height: 100%;
grid-column: ${(props) =>
props.minButton ? 1 : props.maxButton || props.restoreButton ? 2 : 3};
grid-column: ${(props) => (props.minButton ? 1 : props.maxButton || props.restoreButton ? 2 : 3)};
&:hover {
background: rgba(255, 255, 255, 0.1);
@ -113,9 +108,7 @@ export const PageContainer = styled(Container)<{ $backgroundSrc?: string }>`
right: 0;
display: block;
background-image: ${
props.$backgroundSrc ? `url(${props.$backgroundSrc})` : undefined
};
background-image: ${props.$backgroundSrc ? `url(${props.$backgroundSrc})` : undefined};
transition: background-image 1s ease-in-out;
width: 100%;
@ -155,8 +148,7 @@ export const FixedSidebar = styled(Sidebar)<{ font: string }>`
export const CoverArtWrapper = styled.div`
display: inline-block;
filter: ${(props) =>
`drop-shadow(0px 5px 8px ${props.theme.primary.coverArtShadow})`};
filter: ${(props) => `drop-shadow(0px 5px 8px ${props.theme.primary.coverArtShadow})`};
`;
export const PageHeaderTitle = styled.h1`

4
src/components/library/AlbumList.tsx

@ -54,9 +54,7 @@ const AlbumList = () => {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(
toggleRangeSelected(searchQuery !== '' ? filteredData : albums)
);
dispatch(toggleRangeSelected(searchQuery !== '' ? filteredData : albums));
}
}, 100);
}

33
src/components/library/AlbumView.tsx

@ -3,11 +3,7 @@ import settings from 'electron-settings';
import { ButtonToolbar, Tag } from 'rsuite';
import { useQuery, useQueryClient } from 'react-query';
import { useParams, useHistory } from 'react-router-dom';
import {
FavoriteButton,
PlayAppendButton,
PlayButton,
} from '../shared/ToolbarButtons';
import { FavoriteButton, PlayAppendButton, PlayButton } from '../shared/ToolbarButtons';
import { getAlbum, star, unstar } from '../../api/api';
import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import {
@ -44,9 +40,8 @@ const AlbumView = ({ ...rest }: any) => {
const { id } = useParams<AlbumParams>();
const albumId = rest.id ? rest.id : id;
const { isLoading, isError, data, error }: any = useQuery(
['album', albumId],
() => getAlbum(albumId)
const { isLoading, isError, data, error }: any = useQuery(['album', albumId], () =>
getAlbum(albumId)
);
const [searchQuery, setSearchQuery] = useState('');
const filteredData = useSearchQuery(searchQuery, data?.song, [
@ -66,9 +61,7 @@ const AlbumView = ({ ...rest }: any) => {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(
toggleRangeSelected(searchQuery !== '' ? filteredData : data.song)
);
dispatch(toggleRangeSelected(searchQuery !== '' ? filteredData : data.song));
}
}, 100);
}
@ -171,21 +164,9 @@ const AlbumView = ({ ...rest }: any) => {
</div>
<div style={{ marginTop: '10px' }}>
<ButtonToolbar>
<PlayButton
appearance="primary"
size="lg"
onClick={handlePlay}
/>
<PlayAppendButton
appearance="primary"
size="lg"
onClick={handlePlayAppend}
/>
<FavoriteButton
size="lg"
isFavorite={data.starred}
onClick={handleFavorite}
/>
<PlayButton appearance="primary" size="lg" onClick={handlePlay} />
<PlayAppendButton appearance="primary" size="lg" onClick={handlePlayAppend} />
<FavoriteButton size="lg" isFavorite={data.starred} onClick={handleFavorite} />
</ButtonToolbar>
</div>
</div>

27
src/components/library/ArtistView.tsx

@ -7,10 +7,7 @@ import { useParams, useHistory } from 'react-router-dom';
import { PlayAppendButton, PlayButton } from '../shared/ToolbarButtons';
import { getArtist, getArtistInfo } from '../../api/api';
import { useAppDispatch } from '../../redux/hooks';
import {
fixPlayer2Index,
setPlayQueueByRowClick,
} from '../../redux/playQueueSlice';
import { fixPlayer2Index, setPlayQueueByRowClick } from '../../redux/playQueueSlice';
import {
toggleSelected,
setRangeSelected,
@ -35,16 +32,13 @@ interface ArtistParams {
const ArtistView = ({ ...rest }: any) => {
const dispatch = useAppDispatch();
const history = useHistory();
const [viewType, setViewType] = useState(
settings.getSync('albumViewType') || 'list'
);
const [viewType, setViewType] = useState(settings.getSync('albumViewType') || 'list');
const { id } = useParams<ArtistParams>();
const artistId = rest.id ? rest.id : id;
const { isLoading, isError, data, error }: any = useQuery(
['artist', artistId],
() => getArtist(artistId)
const { isLoading, isError, data, error }: any = useQuery(['artist', artistId], () =>
getArtist(artistId)
);
const {
isLoading: isLoadingAI,
@ -54,10 +48,7 @@ const ArtistView = ({ ...rest }: any) => {
}: any = useQuery(['artistInfo', artistId], () => getArtistInfo(artistId, 8));
const [searchQuery, setSearchQuery] = useState('');
const filteredData = useSearchQuery(searchQuery, data?.album, [
'name',
'artist',
]);
const filteredData = useSearchQuery(searchQuery, data?.album, ['name', 'artist']);
let timeout: any = null;
const handleRowClick = (e: any, rowData: any) => {
@ -69,9 +60,7 @@ const ArtistView = ({ ...rest }: any) => {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(
toggleRangeSelected(searchQuery !== '' ? filteredData : data.album)
);
dispatch(toggleRangeSelected(searchQuery !== '' ? filteredData : data.album));
}
}, 100);
}
@ -147,9 +136,7 @@ const ArtistView = ({ ...rest }: any) => {
<TagLink
onClick={() => {
if (!rest.isModal) {
history.push(
`/library/artist/${artist.id}`
);
history.push(`/library/artist/${artist.id}`);
} else {
dispatch(
addModalPage({

19
src/components/library/LibraryView.tsx

@ -28,21 +28,13 @@ const LibraryView = () => {
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,
{
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,
currentPage === 'artists' ? artists : currentPage === 'albums' ? data : data,
['name', 'artist']
);
@ -116,10 +108,7 @@ const LibraryView = () => {
{artists && (
<>
{currentPage === 'artists' && (
<ArtistList
viewType={viewType}
data={searchQuery === '' ? artists : filteredData}
/>
<ArtistList viewType={viewType} data={searchQuery === '' ? artists : filteredData} />
)}
</>
)}

6
src/components/loader/PageLoader.tsx

@ -10,12 +10,10 @@ const LoaderContainer = styled.div`
div {
span {
&:after {
border-color: ${(props) =>
`${props.theme.primary.main} transparent transparent`};
border-color: ${(props) => `${props.theme.primary.main} transparent transparent`};
}
&:before {
border: ${(props) =>
`3px solid ${props.theme.primary.spinnerBackground}`};
border: ${(props) => `3px solid ${props.theme.primary.spinnerBackground}`};
}
}
}

21
src/components/modal/PageModal.tsx

@ -42,25 +42,14 @@ const PageModal = () => {
</StyledButton>
</Modal.Header>
<Modal.Body style={{ height: '800px' }}>
{misc.modalPages[misc.modal.currentPageIndex]?.pageType ===
'artist' && (
<ArtistView
id={misc.modalPages[misc.modal.currentPageIndex].id}
isModal
/>
{misc.modalPages[misc.modal.currentPageIndex]?.pageType === 'artist' && (
<ArtistView id={misc.modalPages[misc.modal.currentPageIndex].id} isModal />
)}
{misc.modalPages[misc.modal.currentPageIndex]?.pageType === 'album' && (
<AlbumView
id={misc.modalPages[misc.modal.currentPageIndex].id}
isModal
/>
<AlbumView id={misc.modalPages[misc.modal.currentPageIndex].id} isModal />
)}
{misc.modalPages[misc.modal.currentPageIndex]?.pageType ===
'playlist' && (
<PlaylistView
id={misc.modalPages[misc.modal.currentPageIndex].id}
isModal
/>
{misc.modalPages[misc.modal.currentPageIndex]?.pageType === 'playlist' && (
<PlaylistView id={misc.modalPages[misc.modal.currentPageIndex].id} isModal />
)}
</Modal.Body>
</StyledModal>

13
src/components/player/NowPlayingMiniView.tsx

@ -50,12 +50,7 @@ const NowPlayingMiniView = () => {
);
}, 100);
}
}, [
playQueue.currentIndex,
tableRef,
playQueue.displayQueue,
playQueue.scrollWithCurrentSong,
]);
}, [playQueue.currentIndex, tableRef, playQueue.displayQueue, playQueue.scrollWithCurrentSong]);
let timeout: any = null;
const handleRowClick = (e: any, rowData: any) => {
@ -143,11 +138,7 @@ const NowPlayingMiniView = () => {
padding="0px"
header={
<>
<FlexboxGrid
justify="space-between"
align="middle"
style={{ height: '50px' }}
>
<FlexboxGrid justify="space-between" align="middle" style={{ height: '50px' }}>
<FlexboxGrid.Item>
<ButtonToolbar>
<StyledIconButton

6
src/components/player/NowPlayingView.tsx

@ -37,11 +37,7 @@ const NowPlayingView = () => {
const multiSelect = useAppSelector((state) => state.multiSelect);
const [searchQuery, setSearchQuery] = useState('');
const filteredData = useSearchQuery(searchQuery, playQueue.entry, [
'title',
'artist',
'album',
]);
const filteredData = useSearchQuery(searchQuery, playQueue.entry, ['title', 'artist', 'album']);
useEffect(() => {
if (playQueue.scrollWithCurrentSong) {

111
src/components/player/Player.tsx

@ -49,8 +49,7 @@ const gaplessListenHandler = (
// Add a bit of leeway for the second track to start since the
// seek value doesn't always reach the duration
const durationPadding =
pollingInterval <= 10 ? 0.12 : pollingInterval <= 20 ? 0.13 : 0.15;
const durationPadding = pollingInterval <= 10 ? 0.12 : pollingInterval <= 20 ? 0.13 : 0.15;
if (seek + durationPadding >= duration) {
nextPlayerRef.current.audioEl.current.play();
}
@ -68,15 +67,13 @@ const listenHandler = (
volumeFade: boolean,
debug: boolean
) => {
const currentSeek =
currentPlayerRef.current?.audioEl.current?.currentTime || 0;
const currentSeek = currentPlayerRef.current?.audioEl.current?.currentTime || 0;
const duration = currentPlayerRef.current?.audioEl.current?.duration;
const fadeAtTime = duration - fadeDuration;
// Fade only if repeat is 'all' or if not on the last track
if (
playQueue[`player${player}`].index + 1 <
playQueue[currentEntryList].length ||
playQueue[`player${player}`].index + 1 < playQueue[currentEntryList].length ||
playQueue.repeat === 'all'
) {
// Detect to start fading when seek is greater than the fade time
@ -100,18 +97,15 @@ const listenHandler = (
Math.sqrt(0.5 * (2 - percentageOfFadeLeft)) * playQueue.volume;
break;
case 'linear':
currentPlayerVolumeCalculation =
(timeLeft / fadeDuration) * playQueue.volume;
currentPlayerVolumeCalculation = (timeLeft / fadeDuration) * playQueue.volume;
nextPlayerVolumeCalculation =
((fadeDuration - timeLeft) / fadeDuration) * playQueue.volume;
break;
case 'dipped':
// https://math.stackexchange.com/a/4622
percentageOfFadeLeft = timeLeft / fadeDuration;
currentPlayerVolumeCalculation =
percentageOfFadeLeft ** 2 * playQueue.volume;
nextPlayerVolumeCalculation =
(percentageOfFadeLeft - 1) ** 2 * playQueue.volume;
currentPlayerVolumeCalculation = percentageOfFadeLeft ** 2 * playQueue.volume;
nextPlayerVolumeCalculation = (percentageOfFadeLeft - 1) ** 2 * playQueue.volume;
break;
case fadeType.match(/constantPower.*/)?.input:
// https://math.stackexchange.com/a/26159
@ -126,29 +120,22 @@ const listenHandler = (
percentageOfFadeLeft = timeLeft / fadeDuration;
currentPlayerVolumeCalculation =
Math.cos(
(Math.PI / 4) *
((2 * percentageOfFadeLeft - 1) ** (2 * n + 1) - 1)
) * playQueue.volume;
Math.cos((Math.PI / 4) * ((2 * percentageOfFadeLeft - 1) ** (2 * n + 1) - 1)) *
playQueue.volume;
nextPlayerVolumeCalculation =
Math.cos(
(Math.PI / 4) *
((2 * percentageOfFadeLeft - 1) ** (2 * n + 1) + 1)
) * playQueue.volume;
Math.cos((Math.PI / 4) * ((2 * percentageOfFadeLeft - 1) ** (2 * n + 1) + 1)) *
playQueue.volume;
break;
default:
currentPlayerVolumeCalculation =
(timeLeft / fadeDuration) * playQueue.volume;
currentPlayerVolumeCalculation = (timeLeft / fadeDuration) * playQueue.volume;
nextPlayerVolumeCalculation =
((fadeDuration - timeLeft) / fadeDuration) * playQueue.volume;
break;
}
const currentPlayerVolume =
currentPlayerVolumeCalculation >= 0
? currentPlayerVolumeCalculation
: 0;
currentPlayerVolumeCalculation >= 0 ? currentPlayerVolumeCalculation : 0;
const nextPlayerVolume =
nextPlayerVolumeCalculation <= playQueue.volume
@ -223,9 +210,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
const [fadeDuration, setFadeDuration] = useState(playQueue.fadeDuration);
const [fadeType, setFadeType] = useState(playQueue.fadeType);
const [volumeFade, setVolumeFade] = useState(playQueue.volumeFade);
const [pollingInterval, setPollingInterval] = useState(
playQueue.pollingInterval
);
const [pollingInterval, setPollingInterval] = useState(playQueue.pollingInterval);
const getSrc1 = useCallback(() => {
const cachedSongPath = `${cachePath}/${
@ -369,16 +354,10 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
if (cacheSongs) {
cacheSong(
`${playQueue[currentEntryList][playQueue.player1.index].id}.mp3`,
playQueue[currentEntryList][playQueue.player1.index].streamUrl.replace(
/stream/,
'download'
)
playQueue[currentEntryList][playQueue.player1.index].streamUrl.replace(/stream/, 'download')
);
}
if (
playQueue.repeat === 'none' &&
playQueue.player1.index > playQueue.player2.index
) {
if (playQueue.repeat === 'none' && playQueue.player1.index > playQueue.player2.index) {
dispatch(fixPlayer2Index());
setTimeout(() => {
player1Ref.current.audioEl.current.pause();
@ -387,15 +366,10 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
} else {
if (!playQueue.autoIncremented) {
dispatch(incrementCurrentIndex('none'));
dispatch(
setCurrentIndex(playQueue[currentEntryList][playQueue.player2.index])
);
dispatch(setCurrentIndex(playQueue[currentEntryList][playQueue.player2.index]));
dispatch(setAutoIncremented(true));
}
if (
playQueue[currentEntryList].length > 1 ||
playQueue.repeat === 'all'
) {
if (playQueue[currentEntryList].length > 1 || playQueue.repeat === 'all') {
dispatch(setCurrentPlayer(2));
dispatch(incrementPlayerIndex(1));
if (fadeDuration !== 0) {
@ -414,16 +388,10 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
if (cacheSongs) {
cacheSong(
`${playQueue[currentEntryList][playQueue.player2.index].id}.mp3`,
playQueue[currentEntryList][playQueue.player2.index].streamUrl.replace(
/stream/,
'download'
)
playQueue[currentEntryList][playQueue.player2.index].streamUrl.replace(/stream/, 'download')
);
}
if (
playQueue.repeat === 'none' &&
playQueue.player2.index > playQueue.player1.index
) {
if (playQueue.repeat === 'none' && playQueue.player2.index > playQueue.player1.index) {
dispatch(fixPlayer2Index());
setTimeout(() => {
player1Ref.current.audioEl.current.pause();
@ -432,15 +400,10 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
} else {
if (!playQueue.autoIncremented) {
dispatch(incrementCurrentIndex('none'));
dispatch(
setCurrentIndex(playQueue[currentEntryList][playQueue.player1.index])
);
dispatch(setCurrentIndex(playQueue[currentEntryList][playQueue.player1.index]));
dispatch(setAutoIncremented(true));
}
if (
playQueue[currentEntryList].length > 1 ||
playQueue.repeat === 'all'
) {
if (playQueue[currentEntryList].length > 1 || playQueue.repeat === 'all') {
dispatch(setCurrentPlayer(1));
dispatch(incrementPlayerIndex(2));
if (fadeDuration !== 0) {
@ -454,25 +417,11 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
};
const handleGaplessPlayer1 = () => {
gaplessListenHandler(
player1Ref,
player2Ref,
playQueue,
1,
dispatch,
pollingInterval
);
gaplessListenHandler(player1Ref, player2Ref, playQueue, 1, dispatch, pollingInterval);
};
const handleGaplessPlayer2 = () => {
gaplessListenHandler(
player2Ref,
player1Ref,
playQueue,
2,
dispatch,
pollingInterval
);
gaplessListenHandler(player2Ref, player1Ref, playQueue, 2, dispatch, pollingInterval);
};
return (
@ -486,9 +435,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
src={playQueue.player1.src}
listenInterval={pollingInterval}
preload="auto"
onListen={
fadeDuration === 0 ? handleGaplessPlayer1 : handleListenPlayer1
}
onListen={fadeDuration === 0 ? handleGaplessPlayer1 : handleListenPlayer1}
onEnded={handleOnEndedPlayer1}
volume={playQueue.player1.volume}
autoPlay={
@ -500,8 +447,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
if (playQueue[currentEntryList].length > 0) {
console.log('player error', e);
player1Ref.current.audioEl.current.src =
'./components/player/dummy.mp3';
player1Ref.current.audioEl.current.src = './components/player/dummy.mp3';
player1Ref.current.audioEl.current.src = getSrc1();
}
}}
@ -512,9 +458,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
src={playQueue.player2.src}
listenInterval={pollingInterval}
preload="auto"
onListen={
fadeDuration === 0 ? handleGaplessPlayer2 : handleListenPlayer2
}
onListen={fadeDuration === 0 ? handleGaplessPlayer2 : handleListenPlayer2}
onEnded={handleOnEndedPlayer2}
volume={playQueue.player2.volume}
autoPlay={
@ -526,8 +470,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
if (playQueue[currentEntryList].length > 0) {
console.log('player error', e);
player2Ref.current.audioEl.current.src =
'./components/player/dummy.mp3';
player2Ref.current.audioEl.current.src = './components/player/dummy.mp3';
player2Ref.current.audioEl.current.src = getSrc2();
}
}}

155
src/components/player/PlayerBar.tsx

@ -50,9 +50,7 @@ const PlayerBar = () => {
const [isDraggingVolume, setIsDraggingVolume] = useState(false);
const [manualSeek, setManualSeek] = useState(0);
const [currentEntryList, setCurrentEntryList] = useState('entry');
const [localVolume, setLocalVolume] = useState(
Number(settings.getSync('volume'))
);
const [localVolume, setLocalVolume] = useState(Number(settings.getSync('volume')));
const playersRef = useRef<any>();
const history = useHistory();
@ -91,13 +89,7 @@ const PlayerBar = () => {
}, 200);
return () => clearTimeout(debounce);
}, [
dispatch,
isDraggingVolume,
localVolume,
playQueue.currentPlayer,
playQueue.fadeDuration,
]);
}, [dispatch, isDraggingVolume, localVolume, playQueue.currentPlayer, playQueue.fadeDuration]);
useEffect(() => {
// Set the seek back to 0 when the player is incremented/decremented, otherwise the
@ -164,9 +156,7 @@ const PlayerBar = () => {
const handleVolumeKey = (e: any) => {
if (e.keyCode === keyCodes.UP) {
const vol = Number(
(playQueue.volume + 0.05 > 1 ? 1 : playQueue.volume + 0.05).toFixed(2)
);
const vol = Number((playQueue.volume + 0.05 > 1 ? 1 : playQueue.volume + 0.05).toFixed(2));
dispatch(setVolume(vol));
dispatch(
setPlayerVolume({
@ -175,9 +165,7 @@ const PlayerBar = () => {
})
);
} else if (e.keyCode === keyCodes.DOWN) {
const vol = Number(
(playQueue.volume - 0.05 < 0 ? 0 : playQueue.volume - 0.05).toFixed(2)
);
const vol = Number((playQueue.volume - 0.05 < 0 ? 0 : playQueue.volume - 0.05).toFixed(2));
dispatch(setVolume(vol));
dispatch(
setPlayerVolume({
@ -190,9 +178,7 @@ const PlayerBar = () => {
const handleClickForward = () => {
if (playQueue[currentEntryList].length > 0) {
const seekForwardInterval = Number(
settings.getSync('seekForwardInterval')
);
const seekForwardInterval = Number(settings.getSync('seekForwardInterval'));
setIsDragging(true);
if (playQueue.isFading) {
@ -211,30 +197,20 @@ const PlayerBar = () => {
if (playQueue.currentPlayer === 1) {
const calculatedTime =
playersRef.current.player1.audioEl.current.currentTime +
seekForwardInterval;
const songDuration =
playersRef.current.player1.audioEl.current.duration;
setManualSeek(
calculatedTime > songDuration ? songDuration - 1 : calculatedTime
);
playersRef.current.player1.audioEl.current.currentTime + seekForwardInterval;
const songDuration = playersRef.current.player1.audioEl.current.duration;
setManualSeek(calculatedTime > songDuration ? songDuration - 1 : calculatedTime);
} else {
const calculatedTime =
playersRef.current.player2.audioEl.current.currentTime +
seekForwardInterval;
const songDuration =
playersRef.current.player2.audioEl.current.duration;
setManualSeek(
calculatedTime > songDuration ? songDuration - 1 : calculatedTime
);
playersRef.current.player2.audioEl.current.currentTime + seekForwardInterval;
const songDuration = playersRef.current.player2.audioEl.current.duration;
setManualSeek(calculatedTime > songDuration ? songDuration - 1 : calculatedTime);
}
}
};
const handleClickBackward = () => {
const seekBackwardInterval = Number(
settings.getSync('seekBackwardInterval')
);
const seekBackwardInterval = Number(settings.getSync('seekBackwardInterval'));
if (playQueue[currentEntryList].length > 0) {
setIsDragging(true);
@ -254,13 +230,11 @@ const PlayerBar = () => {
if (playQueue.currentPlayer === 1) {
const calculatedTime =
playersRef.current.player1.audioEl.current.currentTime -
seekBackwardInterval;
playersRef.current.player1.audioEl.current.currentTime - seekBackwardInterval;
setManualSeek(calculatedTime < 0 ? 0 : calculatedTime);
} else {
const calculatedTime =
playersRef.current.player2.audioEl.current.currentTime -
seekBackwardInterval;
playersRef.current.player2.audioEl.current.currentTime - seekBackwardInterval;
setManualSeek(calculatedTime < 0 ? 0 : calculatedTime);
}
}
@ -290,12 +264,7 @@ const PlayerBar = () => {
const handleRepeat = () => {
const currentRepeat = settings.getSync('repeat');
const newRepeat =
currentRepeat === 'none'
? 'all'
: currentRepeat === 'all'
? 'one'
: 'none';
const newRepeat = currentRepeat === 'none' ? 'all' : currentRepeat === 'all' ? 'one' : 'none';
dispatch(toggleRepeat());
settings.setSync('repeat', newRepeat);
};
@ -311,10 +280,7 @@ const PlayerBar = () => {
const handleFavorite = async () => {
if (!playQueue[currentEntryList][playQueue.currentIndex].starred) {
await star(
playQueue[currentEntryList][playQueue.currentIndex].id,
'music'
);
await star(playQueue[currentEntryList][playQueue.currentIndex].id, 'music');
dispatch(
setStar({
id: playQueue[currentEntryList][playQueue.currentIndex].id,
@ -322,10 +288,7 @@ const PlayerBar = () => {
})
);
} else {
await unstar(
playQueue[currentEntryList][playQueue.currentIndex].id,
'song'
);
await unstar(playQueue[currentEntryList][playQueue.currentIndex].id, 'song');
dispatch(
setStar({
id: playQueue[currentEntryList][playQueue.currentIndex].id,
@ -347,15 +310,10 @@ const PlayerBar = () => {
return (
<Player ref={playersRef} currentEntryList={currentEntryList}>
{playQueue.showDebugWindow && (
<DebugWindow currentEntryList={currentEntryList} />
)}
{playQueue.showDebugWindow && <DebugWindow currentEntryList={currentEntryList} />}
<PlayerContainer>
<FlexboxGrid align="middle" style={{ height: '100%' }}>
<FlexboxGrid.Item
colspan={6}
style={{ textAlign: 'left', paddingLeft: '10px' }}
>
<FlexboxGrid.Item colspan={6} style={{ textAlign: 'left', paddingLeft: '10px' }}>
<PlayerColumn left height="80px">
<Grid>
<Row
@ -370,8 +328,8 @@ const PlayerBar = () => {
<LazyLoadImage
tabIndex={0}
src={
playQueue[currentEntryList][playQueue.currentIndex]
?.image || placeholderImg
playQueue[currentEntryList][playQueue.currentIndex]?.image ||
placeholderImg
}
alt="trackImg"
effect="opacity"
@ -400,30 +358,24 @@ const PlayerBar = () => {
enterable
placement="topStart"
text={
playQueue[currentEntryList][playQueue.currentIndex]
?.title || 'Unknown title'
playQueue[currentEntryList][playQueue.currentIndex]?.title ||
'Unknown title'
}
>
<LinkButton
tabIndex={0}
onClick={() => {
if (
playQueue[currentEntryList][
playQueue.currentIndex
]?.albumId
) {
if (playQueue[currentEntryList][playQueue.currentIndex]?.albumId) {
history.push(
`/library/album/${
playQueue[currentEntryList][
playQueue.currentIndex
]?.albumId
playQueue[currentEntryList][playQueue.currentIndex]?.albumId
}`
);
}
}}
>
{playQueue[currentEntryList][playQueue.currentIndex]
?.title || 'Unknown title'}
{playQueue[currentEntryList][playQueue.currentIndex]?.title ||
'Unknown title'}
</LinkButton>
</CustomTooltip>
</Row>
@ -439,8 +391,8 @@ const PlayerBar = () => {
enterable
placement="topStart"
text={
playQueue[currentEntryList][playQueue.currentIndex]
?.artist || 'Unknown artist'
playQueue[currentEntryList][playQueue.currentIndex]?.artist ||
'Unknown artist'
}
>
<span
@ -454,23 +406,17 @@ const PlayerBar = () => {
tabIndex={0}
subtitle="true"
onClick={() => {
if (
playQueue[currentEntryList][
playQueue.currentIndex
]?.artistId
) {
if (playQueue[currentEntryList][playQueue.currentIndex]?.artistId) {
history.push(
`/library/artist/${
playQueue[currentEntryList][
playQueue.currentIndex
]?.artistId
playQueue[currentEntryList][playQueue.currentIndex]?.artistId
}`
);
}
}}
>
{playQueue[currentEntryList][playQueue.currentIndex]
?.artist || 'Unknown artist'}
{playQueue[currentEntryList][playQueue.currentIndex]?.artist ||
'Unknown artist'}
</LinkButton>
</span>
</CustomTooltip>
@ -480,10 +426,7 @@ const PlayerBar = () => {
</Grid>
</PlayerColumn>
</FlexboxGrid.Item>
<FlexboxGrid.Item
colspan={12}
style={{ textAlign: 'center', verticalAlign: 'middle' }}
>
<FlexboxGrid.Item colspan={12} style={{ textAlign: 'center', verticalAlign: 'middle' }}>
<PlayerColumn center height="45px">
{/* Seek Backward Button */}
<CustomTooltip text="Seek backward" delay={1000}>
@ -579,9 +522,7 @@ const PlayerBar = () => {
userSelect: 'none',
}}
>
<DurationSpan>
{format((isDragging ? manualSeek : seek) * 1000)}
</DurationSpan>
<DurationSpan>{format((isDragging ? manualSeek : seek) * 1000)}</DurationSpan>
</FlexboxGrid.Item>
<FlexboxGrid.Item colspan={16}>
{/* Seek Slider */}
@ -591,10 +532,7 @@ const PlayerBar = () => {
value={isDragging ? manualSeek : seek}
$isDragging={isDragging}
tooltip={false}
max={
playQueue[currentEntryList][playQueue.currentIndex]
?.duration || 0
}
max={playQueue[currentEntryList][playQueue.currentIndex]?.duration || 0}
onChange={handleSeekSlider}
style={{ width: '100%' }}
/>
@ -609,18 +547,14 @@ const PlayerBar = () => {
>
<DurationSpan>
{format(
playQueue[currentEntryList][playQueue.currentIndex]
?.duration * 1000 || 0
playQueue[currentEntryList][playQueue.currentIndex]?.duration * 1000 || 0
)}
</DurationSpan>
</FlexboxGrid.Item>
</FlexboxGrid>
</PlayerColumn>
</FlexboxGrid.Item>
<FlexboxGrid.Item
colspan={6}
style={{ textAlign: 'right', paddingRight: '10px' }}
>
<FlexboxGrid.Item colspan={6} style={{ textAlign: 'right', paddingRight: '10px' }}>
<PlayerColumn right height="80px">
<Grid>
<Row
@ -637,16 +571,14 @@ const PlayerBar = () => {
<PlayerControlIcon
tabIndex={0}
icon={
playQueue[currentEntryList][playQueue.currentIndex]
?.starred
playQueue[currentEntryList][playQueue.currentIndex]?.starred
? 'heart'
: 'heart-o'
}
size="lg"
fixedWidth
active={
playQueue[currentEntryList][playQueue.currentIndex]
?.starred
playQueue[currentEntryList][playQueue.currentIndex]?.starred
? 'true'
: 'false'
}
@ -676,14 +608,11 @@ const PlayerBar = () => {
}
}}
active={
playQueue.repeat === 'all' ||
playQueue.repeat === 'one'
playQueue.repeat === 'all' || playQueue.repeat === 'one'
? 'true'
: 'false'
}
flip={
playQueue.repeat === 'one' ? 'horizontal' : undefined
}
flip={playQueue.repeat === 'one' ? 'horizontal' : undefined}
/>
</CustomTooltip>
{/* Shuffle Button */}

19
src/components/player/styled.tsx

@ -17,21 +17,13 @@ export const PlayerColumn = styled.div<{
display: flex;
align-items: center;
justify-content: ${(props) =>
props.left
? 'flex-start'
: props.center
? 'center'
: props.right
? 'flex-end'
: 'center'};
props.left ? 'flex-start' : props.center ? 'center' : props.right ? 'flex-end' : 'center'};
`;
export const PlayerControlIcon = styled(Icon)`
font-size: medium;
color: ${(props) =>
props.active === 'true'
? props.theme.primary.main
: props.theme.primary.playerBarButtons};
props.active === 'true' ? props.theme.primary.main : props.theme.primary.playerBarButtons};
padding-left: 10px;
padding-right: 10px;
&:hover {
@ -82,9 +74,7 @@ export const CustomSlider = styled(Slider)<{ isDragging?: boolean }>`
}
.rs-slider-progress-bar {
background-color: ${(props) =>
props.$isDragging
? props.theme.primary.main
: props.theme.primary.sliderBackground};
props.$isDragging ? props.theme.primary.main : props.theme.primary.sliderBackground};
}
.rs-slider-handle::before {
@ -118,8 +108,7 @@ export const MiniViewContainer = styled.div<{ display: string }>`
opacity: ${(props) => (props.display === 'true' ? 0.9 : 0)};
border-radius: 10px;
color: ${(props) => `${props.theme.primary.text} !important`};
animation-name: ${(props) =>
props.display === 'true' ? 'fadeInOpacity' : 'fadeOutOpacity'};
animation-name: ${(props) => (props.display === 'true' ? 'fadeInOpacity' : 'fadeOutOpacity')};
animation-iteration-count: 1;
animation-timing-function: ease-in-out;
animation-duration: 0.5s;

22
src/components/playlist/PlaylistList.tsx

@ -21,18 +21,12 @@ const PlaylistList = () => {
const playlistTriggerRef = useRef<any>();
const [sortBy] = useState('name');
const [newPlaylistName, setNewPlaylistName] = useState('');
const [viewType, setViewType] = useState(
settings.getSync('playlistViewType') || 'list'
);
const { isLoading, isError, data: playlists, error }: any = useQuery(
['playlists', sortBy],
() => getPlaylists(sortBy)
const [viewType, setViewType] = useState(settings.getSync('playlistViewType') || 'list');
const { isLoading, isError, data: playlists, error }: any = useQuery(['playlists', sortBy], () =>
getPlaylists(sortBy)
);
const [searchQuery, setSearchQuery] = useState('');
const filteredData = useSearchQuery(searchQuery, playlists, [
'name',
'comment',
]);
const filteredData = useSearchQuery(searchQuery, playlists, ['name', 'comment']);
const handleCreatePlaylist = async (name: string) => {
try {
@ -131,12 +125,8 @@ const PlaylistList = () => {
? playlists
: playlists.filter((playlist: any) => {
return (
playlist.name
.toLowerCase()
.includes(searchQuery.toLowerCase()) ||
playlist.comment
?.toLowerCase()
.includes(searchQuery.toLowerCase())
playlist.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
playlist.comment?.toLowerCase().includes(searchQuery.toLowerCase())
);
})
}

62
src/components/playlist/PlaylistView.tsx

@ -49,15 +49,8 @@ import PageLoader from '../loader/PageLoader';
import GenericPageHeader from '../layout/GenericPageHeader';
import { setStatus } from '../../redux/playerSlice';
import { notifyToast } from '../shared/toast';
import {
addProcessingPlaylist,
removeProcessingPlaylist,
} from '../../redux/miscSlice';
import {
StyledButton,
StyledCheckbox,
StyledInputGroup,
} from '../shared/styled';
import { addProcessingPlaylist, removeProcessingPlaylist } from '../../redux/miscSlice';
import { StyledButton, StyledCheckbox, StyledInputGroup } from '../shared/styled';
interface PlaylistParams {
id: string;
@ -73,7 +66,9 @@ const PlaylistView = ({ ...rest }) => {
const { isLoading, isError, data, error }: any = useQuery(
['playlist', playlistId],
() => getPlaylist(playlistId),
{ refetchOnWindowFocus: false }
{
refetchOnWindowFocus: false,
}
);
const [editName, setEditName] = useState('');
const [editDescription, setEditDescription] = useState('');
@ -87,17 +82,10 @@ const PlaylistView = ({ ...rest }) => {
const [searchQuery, setSearchQuery] = useState('');
const [recoveryPath, setRecoveryPath] = useState('');
const [needsRecovery, setNeedsRecovery] = useState(false);
const filteredData = useSearchQuery(searchQuery, localPlaylistData, [
'title',
'artist',
'album',
]);
const filteredData = useSearchQuery(searchQuery, localPlaylistData, ['title', 'artist', 'album']);
useEffect(() => {
const recoveryFilePath = path.join(
getRecoveryPath(),
`playlist_${data?.id}.json`
);
const recoveryFilePath = path.join(getRecoveryPath(), `playlist_${data?.id}.json`);
setRecoveryPath(recoveryFilePath);
setNeedsRecovery(fs.existsSync(recoveryFilePath));
@ -129,11 +117,7 @@ const PlaylistView = ({ ...rest }) => {
dispatch(toggleSelected(rowData));
} else if (e.shiftKey) {
dispatch(setRangeSelected(rowData));
dispatch(
toggleRangeSelected(
searchQuery !== '' ? filteredData : localPlaylistData
)
);
dispatch(toggleRangeSelected(searchQuery !== '' ? filteredData : localPlaylistData));
}
}, 100);
}
@ -230,12 +214,7 @@ const PlaylistView = ({ ...rest }) => {
const handleEdit = async () => {
setIsSubmittingEdit(true);
const res = await updatePlaylist(
data.id,
editName,
editDescription,
editPublic
);
const res = await updatePlaylist(data.id, editName, editDescription, editPublic);
if (isFailedResponse(res)) {
notifyToast('error', errorMessages(res)[0]);
@ -266,11 +245,7 @@ const PlaylistView = ({ ...rest }) => {
const handleDragEnd = () => {
if (multiSelect.isDragging) {
setLocalPlaylistData(
moveToIndex(
localPlaylistData,
multiSelect.selected,
multiSelect.currentMouseOverId
)
moveToIndex(localPlaylistData, multiSelect.selected, multiSelect.currentMouseOverId)
);
dispatch(setIsDragging(false));
}
@ -318,9 +293,7 @@ const PlaylistView = ({ ...rest }) => {
<SaveButton
size="lg"
text={needsRecovery ? 'Recover playlist' : undefined}
color={
needsRecovery ? 'red' : isModified ? 'green' : undefined
}
color={needsRecovery ? 'red' : isModified ? 'green' : undefined}
disabled={
(!needsRecovery && !isModified) ||
misc.isProcessingPlaylist.includes(data?.id)
@ -330,13 +303,9 @@ const PlaylistView = ({ ...rest }) => {
/>
<UndoButton
size="lg"
color={
needsRecovery ? 'red' : isModified ? 'green' : undefined
}
color={needsRecovery ? 'red' : isModified ? 'green' : undefined}
disabled={
needsRecovery ||
!isModified ||
misc.isProcessingPlaylist.includes(data?.id)
needsRecovery || !isModified || misc.isProcessingPlaylist.includes(data?.id)
}
onClick={() => setLocalPlaylistData(data?.song)}
/>
@ -385,10 +354,7 @@ const PlaylistView = ({ ...rest }) => {
</Popover>
}
>
<EditButton
size="lg"
disabled={misc.isProcessingPlaylist.includes(data?.id)}
/>
<EditButton size="lg" disabled={misc.isProcessingPlaylist.includes(data?.id)} />
</Whisper>
<Whisper

20
src/components/scrollingmenu/ScrollingMenu.tsx

@ -18,11 +18,7 @@ const LeftArrow = () => {
const { isFirstItemVisible, scrollPrev } = useContext(VisibilityContext);
return (
<Button
appearance="link"
disabled={isFirstItemVisible}
onClick={() => scrollPrev()}
>
<Button appearance="link" disabled={isFirstItemVisible} onClick={() => scrollPrev()}>
<StyledIcon icon="arrow-left" />
</Button>
);
@ -32,23 +28,13 @@ const RightArrow = () => {
const { isLastItemVisible, scrollNext } = useContext(VisibilityContext);
return (
<Button
appearance="link"
disabled={isLastItemVisible}
onClick={() => scrollNext()}
>
<Button appearance="link" disabled={isLastItemVisible} onClick={() => scrollNext()}>
<StyledIcon icon="arrow-right" />
</Button>
);
};
const ScrollingMenu = ({
cardTitle,
cardSubtitle,
data,
title,
cardSize,
}: any) => {
const ScrollingMenu = ({ cardTitle, cardSubtitle, data, title, cardSize }: any) => {
return (
<ScrollMenuContainer>
<Title>{title}</Title>

7
src/components/selectionbar/SelectionBar.tsx

@ -27,12 +27,7 @@ const StyledTag = styled(Tag)`
background: transparent;
`;
const SelectionBar = ({
children,
handleUpClick,
handleDownClick,
handleManualClick,
}: any) => {
const SelectionBar = ({ children, handleUpClick, handleDownClick, handleManualClick }: any) => {
const multiSelect = useAppSelector((state) => state.multiSelect);
return (

24
src/components/selectionbar/SelectionButtons.tsx

@ -24,33 +24,15 @@ const CustomIconButton = ({ tooltipText, icon, handleClick, ...rest }: any) => {
};
export const MoveUpButton = ({ handleClick }: any) => {
return (
<CustomIconButton
handleClick={handleClick}
tooltipText="Move up"
icon="arrow-up2"
/>
);
return <CustomIconButton handleClick={handleClick} tooltipText="Move up" icon="arrow-up2" />;
};
export const MoveDownButton = ({ handleClick }: any) => {
return (
<CustomIconButton
handleClick={handleClick}
tooltipText="Move down"
icon="arrow-down2"
/>
);
return <CustomIconButton handleClick={handleClick} tooltipText="Move down" icon="arrow-down2" />;
};
export const MoveManualButton = ({ handleClick }: any) => {
return (
<CustomIconButton
handleClick={handleClick}
tooltipText="Move to index"
icon="arrows-v"
/>
);
return <CustomIconButton handleClick={handleClick} tooltipText="Move to index" icon="arrows-v" />;
};
export const DeselectAllButton = ({ handleClick }: any) => {

4
src/components/settings/Config.tsx

@ -72,9 +72,7 @@ const Config = () => {
trigger="click"
speaker={
<Popover title="Confirm">
<div>
Are you sure you want to reset your settings to default?
</div>
<div>Are you sure you want to reset your settings to default?</div>
<div>
<Button
id="reset-submit-button"

43
src/components/settings/ConfigPanels/CacheConfig.tsx

@ -15,25 +15,15 @@ const CacheConfig = () => {
const [isEditingCachePath, setIsEditingCachePath] = useState(false);
const [newCachePath, setNewCachePath] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const [cacheSongs, setCacheSongs] = useState(
Boolean(settings.getSync('cacheSongs'))
);
const [cacheImages, setCacheImages] = useState(
Boolean(settings.getSync('cacheImages'))
);
const [cacheSongs, setCacheSongs] = useState(Boolean(settings.getSync('cacheSongs')));
const [cacheImages, setCacheImages] = useState(Boolean(settings.getSync('cacheImages')));
useEffect(() => {
// Retrieve cache sizes on render
try {
setImgCacheSize(
Number(
(fsUtils.fsizeSync(getImageCachePath()) / 1000 / 1000).toFixed(0)
)
);
setImgCacheSize(Number((fsUtils.fsizeSync(getImageCachePath()) / 1000 / 1000).toFixed(0)));
setSongCacheSize(
Number((fsUtils.fsizeSync(getSongCachePath()) / 1000 / 1000).toFixed(0))
);
setSongCacheSize(Number((fsUtils.fsizeSync(getSongCachePath()) / 1000 / 1000).toFixed(0)));
} catch (err) {
setImgCacheSize(0);
setSongCacheSize(0);
@ -51,18 +41,15 @@ const CacheConfig = () => {
</>
)}
<p>
Songs are cached only when playback for the track fully completes and
ends. Skipping to the next or previous track after only partially
completing the track will not begin the caching process.
Songs are cached only when playback for the track fully completes and ends. Skipping to the
next or previous track after only partially completing the track will not begin the caching
process.
</p>
<br />
{isEditingCachePath && (
<>
<InputGroup>
<StyledInput
value={newCachePath}
onChange={(e: string) => setNewCachePath(e)}
/>
<StyledInput value={newCachePath} onChange={(e: string) => setNewCachePath(e)} />
<InputGroup.Button
onClick={() => {
const check = fs.existsSync(newCachePath);
@ -74,9 +61,7 @@ const CacheConfig = () => {
return setIsEditingCachePath(false);
}
return setErrorMessage(
`Path: ${newCachePath} not found. Enter a valid path.`
);
return setErrorMessage(`Path: ${newCachePath} not found. Enter a valid path.`);
}}
>
<Icon icon="check" />
@ -91,8 +76,7 @@ const CacheConfig = () => {
</InputGroup.Button>
</InputGroup>
<p style={{ fontSize: 'smaller' }}>
*You will need to manually move any existing cached files to their
new location.
*You will need to manually move any existing cached files to their new location.
</p>
</>
)}
@ -118,8 +102,7 @@ const CacheConfig = () => {
>
Songs{' '}
<Tag>
{songCacheSize} MB{' '}
{imgCacheSize === 9999999 && '- Folder not found'}
{songCacheSize} MB {imgCacheSize === 9999999 && '- Folder not found'}
</Tag>
</StyledCheckbox>
<StyledCheckbox
@ -135,9 +118,7 @@ const CacheConfig = () => {
</Tag>
</StyledCheckbox>
<br />
<Button onClick={() => setIsEditingCachePath(true)}>
Edit cache location
</Button>
<Button onClick={() => setIsEditingCachePath(true)}>Edit cache location</Button>
</div>
</ConfigPanel>
);

5
src/components/settings/ConfigPanels/DebugConfig.tsx

@ -15,10 +15,7 @@ const DebugConfig = () => {
<StyledCheckbox
defaultChecked={showDebugWindow}
onChange={() => {
settings.setSync(
'showDebugWindow',
!settings.getSync('showDebugWindow')
);
settings.setSync('showDebugWindow', !settings.getSync('showDebugWindow'));
dispatch(
setPlaybackSetting({
setting: 'showDebugWindow',

19
src/components/settings/ConfigPanels/ListViewConfig.tsx

@ -3,12 +3,7 @@ import settings from 'electron-settings';
import { TagPicker, ControlLabel } from 'rsuite';
import { StyledInputNumber } from '../../shared/styled';
const ListViewConfig = ({
defaultColumns,
columnPicker,
columnList,
settingsConfig,
}: any) => {
const ListViewConfig = ({ defaultColumns, columnPicker, columnList, settingsConfig }: any) => {
return (
<div style={{ width: '100%' }}>
<br />
@ -21,9 +16,7 @@ const ListViewConfig = ({
if (e) {
e.map((selected: string) => {
const selectedColumn = columnList.find(
(column: any) => column.label === selected
);
const selectedColumn = columnList.find((column: any) => column.label === selected);
if (selectedColumn) {
return columns.push(selectedColumn.value);
}
@ -40,9 +33,7 @@ const ListViewConfig = ({
<div style={{ marginTop: '20px' }}>
<ControlLabel>Row height</ControlLabel>
<StyledInputNumber
defaultValue={
String(settings.getSync(settingsConfig.rowHeight)) || '0'
}
defaultValue={String(settings.getSync(settingsConfig.rowHeight)) || '0'}
step={1}
min={15}
max={100}
@ -55,9 +46,7 @@ const ListViewConfig = ({
<div style={{ marginTop: '20px' }}>
<ControlLabel>Font size</ControlLabel>
<StyledInputNumber
defaultValue={
String(settings.getSync(settingsConfig.fontSize)) || '0'
}
defaultValue={String(settings.getSync(settingsConfig.fontSize)) || '0'}
step={0.5}
min={1}
max={100}

23
src/components/settings/ConfigPanels/LookAndFeelConfig.tsx

@ -12,11 +12,7 @@ import {
import ListViewConfig from './ListViewConfig';
import { Fonts } from '../Fonts';
import { useAppDispatch } from '../../../redux/hooks';
import {
setTheme,
setFont,
setDynamicBackground,
} from '../../../redux/miscSlice';
import { setTheme, setFont, setDynamicBackground } from '../../../redux/miscSlice';
import {
songColumnPicker,
songColumnList,
@ -35,10 +31,8 @@ const LookAndFeelConfig = () => {
const playlistCols: any = settings.getSync('playlistListColumns');
const miniCols: any = settings.getSync('miniListColumns');
const currentSongColumns = songCols?.map((column: any) => column.label) || [];
const currentAlbumColumns =
albumCols?.map((column: any) => column.label) || [];
const currentPlaylistColumns =
playlistCols?.map((column: any) => column.label) || [];
const currentAlbumColumns = albumCols?.map((column: any) => column.label) || [];
const currentPlaylistColumns = playlistCols?.map((column: any) => column.label) || [];
const currentMiniColumns = miniCols?.map((column: any) => column.label) || [];
return (
@ -62,15 +56,8 @@ const LookAndFeelConfig = () => {
<StyledCheckbox
defaultChecked={settings.getSync('dynamicBackground')}
onChange={() => {
settings.setSync(
'dynamicBackground',
!settings.getSync('dynamicBackground')
);
dispatch(
setDynamicBackground(
Boolean(settings.getSync('dynamicBackground'))
)
);
settings.setSync('dynamicBackground', !settings.getSync('dynamicBackground'));
dispatch(setDynamicBackground(Boolean(settings.getSync('dynamicBackground'))));
}}
>
Enable dynamic background

48
src/components/settings/ConfigPanels/PlaybackConfig.tsx

@ -4,10 +4,7 @@ import { ControlLabel, RadioGroup } from 'rsuite';
import { ConfigPanel } from '../styled';
import { StyledInputNumber, StyledRadio } from '../../shared/styled';
import { useAppDispatch, useAppSelector } from '../../../redux/hooks';
import {
setPlaybackSetting,
setPlayerVolume,
} from '../../../redux/playQueueSlice';
import { setPlaybackSetting, setPlayerVolume } from '../../../redux/playQueueSlice';
const PlaybackConfig = () => {
const dispatch = useAppDispatch();
@ -15,28 +12,25 @@ const PlaybackConfig = () => {
return (
<ConfigPanel header="Playback" bordered>
<p>
Fading works by polling the audio player on an interval to determine
when to start fading to the next track. Due to this, you may notice the
fade timing may not be 100% perfect. Lowering the player polling
interval can increase the accuracy of the fade, but may also decrease
application performance as calculations are running for the fade.
Fading works by polling the audio player on an interval to determine when to start fading to
the next track. Due to this, you may notice the fade timing may not be 100% perfect.
Lowering the player polling interval can increase the accuracy of the fade, but may also
decrease application performance as calculations are running for the fade.
</p>
<p>
If volume fade is disabled, then the fading-in track will start at the
specified crossfade duration at full volume.
If volume fade is disabled, then the fading-in track will start at the specified crossfade
duration at full volume.
</p>
<p>
Setting the crossfade duration to <code>0</code> will enable{' '}
<strong>gapless playback</strong>. All other playback settings except
the polling interval will be ignored. It is recommended that you use a
polling interval between <code>1</code> and <code>20</code> for
increased transition accuracy.
<strong>gapless playback</strong>. All other playback settings except the polling interval
will be ignored. It is recommended that you use a polling interval between <code>1</code>{' '}
and <code>20</code> for increased transition accuracy.
</p>
<p style={{ fontSize: 'smaller' }}>
*Enable the debug window if you want to view the differences between
each fade type
*Enable the debug window if you want to view the differences between each fade type
</p>
<div style={{ width: '300px', paddingTop: '20px' }}>
@ -57,12 +51,8 @@ const PlaybackConfig = () => {
);
if (Number(e) === 0) {
dispatch(
setPlayerVolume({ player: 1, volume: playQueue.volume })
);
dispatch(
setPlayerVolume({ player: 2, volume: playQueue.volume })
);
dispatch(setPlayerVolume({ player: 1, volume: playQueue.volume }));
dispatch(setPlayerVolume({ player: 2, volume: playQueue.volume }));
}
}}
/>
@ -100,15 +90,9 @@ const PlaybackConfig = () => {
<StyledRadio value="linear">Linear</StyledRadio>
<StyledRadio value="dipped">Dipped</StyledRadio>
<StyledRadio value="constantPower">Constant Power</StyledRadio>
<StyledRadio value="constantPowerSlowFade">
Constant Power (slow fade)
</StyledRadio>
<StyledRadio value="constantPowerSlowCut">
Constant Power (slow cut)
</StyledRadio>
<StyledRadio value="constantPowerFastCut">
Constant Power (fast cut)
</StyledRadio>
<StyledRadio value="constantPowerSlowFade">Constant Power (slow fade)</StyledRadio>
<StyledRadio value="constantPowerSlowCut">Constant Power (slow cut)</StyledRadio>
<StyledRadio value="constantPowerFastCut">Constant Power (fast cut)</StyledRadio>
</RadioGroup>
<br />
<ControlLabel>Volume fade</ControlLabel>

9
src/components/settings/ConfigPanels/PlayerConfig.tsx

@ -11,8 +11,8 @@ const PlayerConfig = () => {
return (
<ConfigPanel header="Player" bordered>
<p>
Configure the number of seconds to skip forwards/backwards by when
clicking the seek forward/backward buttons.
Configure the number of seconds to skip forwards/backwards by when clicking the seek
forward/backward buttons.
</p>
<br />
<ControlLabel>Seek forward (s)</ControlLabel>
@ -42,10 +42,7 @@ const PlayerConfig = () => {
<StyledCheckbox
defaultChecked={globalMediaHotkeys}
onChange={() => {
settings.setSync(
'globalMediaHotkeys',
!settings.getSync('globalMediaHotkeys')
);
settings.setSync('globalMediaHotkeys', !settings.getSync('globalMediaHotkeys'));
setGlobalMediaHotkeys(!globalMediaHotkeys);
}}
>

61
src/components/shared/ContextMenu.tsx

@ -79,21 +79,12 @@ export const GlobalContextMenu = () => {
const [shouldCreatePlaylist, setShouldCreatePlaylist] = useState(false);
const [newPlaylistName, setNewPlaylistName] = useState('');
const { data: playlists }: any = useQuery(['playlists', 'name'], () =>
getPlaylists('name')
);
const { data: playlists }: any = useQuery(['playlists', 'name'], () => getPlaylists('name'));
const handleAddToQueue = () => {
const entriesByRowIndexAsc = _.orderBy(
multiSelect.selected,
'rowIndex',
'asc'
);
const entriesByRowIndexAsc = _.orderBy(multiSelect.selected, 'rowIndex', 'asc');
notifyToast(
'info',
`Added ${multiSelect.selected.length} song(s) to the queue`
);
notifyToast('info', `Added ${multiSelect.selected.length} song(s) to the queue`);
dispatch(appendPlayQueue({ entries: entriesByRowIndexAsc }));
dispatch(setContextMenu({ show: false }));
@ -117,10 +108,7 @@ export const GlobalContextMenu = () => {
);
try {
const res = await updatePlaylistSongsLg(
localSelectedPlaylistId,
sortedEntries
);
const res = await updatePlaylistSongsLg(localSelectedPlaylistId, sortedEntries);
if (isFailedResponse(res)) {
notifyToast('error', errorMessages(res)[0]);
@ -130,11 +118,7 @@ export const GlobalContextMenu = () => {
<>
<p>
Added {sortedEntries.length} song(s) to playlist &quot;
{
playlists.find(
(playlist: any) => playlist.id === localSelectedPlaylistId
)?.name
}
{playlists.find((playlist: any) => playlist.id === localSelectedPlaylistId)?.name}
&quot;
</p>
<StyledButton
@ -215,9 +199,7 @@ export const GlobalContextMenu = () => {
const handleUnfavorite = async () => {
dispatch(setContextMenu({ show: false }));
const starredEntries = multiSelect.selected.filter(
(entry: any) => entry.starred
);
const starredEntries = multiSelect.selected.filter((entry: any) => entry.starred);
const ids = _.map(starredEntries, 'id');
@ -246,9 +228,7 @@ export const GlobalContextMenu = () => {
numOfButtons={6}
numOfDividers={3}
>
<ContextMenuButton
text={`Selected: ${multiSelect.selected.length}`}
/>
<ContextMenuButton text={`Selected: ${multiSelect.selected.length}`} />
<ContextMenuDivider />
<ContextMenuButton
text="Add to queue"
@ -258,9 +238,7 @@ export const GlobalContextMenu = () => {
<ContextMenuButton
text="Remove from current"
onClick={handleRemoveFromQueue}
disabled={misc.contextMenu.disabledOptions.includes(
'removeFromCurrent'
)}
disabled={misc.contextMenu.disabledOptions.includes('removeFromCurrent')}
/>
<ContextMenuDivider />
@ -282,12 +260,9 @@ export const GlobalContextMenu = () => {
/>
<StyledButton
disabled={
!selectedPlaylistId ||
misc.isProcessingPlaylist.includes(selectedPlaylistId)
!selectedPlaylistId || misc.isProcessingPlaylist.includes(selectedPlaylistId)
}
loading={misc.isProcessingPlaylist.includes(
selectedPlaylistId
)}
loading={misc.isProcessingPlaylist.includes(selectedPlaylistId)}
onClick={handleAddToPlaylist}
>
Add
@ -295,9 +270,7 @@ export const GlobalContextMenu = () => {
<div>
<StyledButton
appearance="link"
onClick={() =>
setShouldCreatePlaylist(!shouldCreatePlaylist)
}
onClick={() => setShouldCreatePlaylist(!shouldCreatePlaylist)}
>
Create new playlist
</StyledButton>
@ -338,25 +311,19 @@ export const GlobalContextMenu = () => {
? playlistTriggerRef.current.close()
: playlistTriggerRef.current.open()
}
disabled={misc.contextMenu.disabledOptions.includes(
'addToPlaylist'
)}
disabled={misc.contextMenu.disabledOptions.includes('addToPlaylist')}
/>
</Whisper>
<ContextMenuDivider />
<ContextMenuButton
text="Add to favorites"
onClick={handleFavorite}
disabled={misc.contextMenu.disabledOptions.includes(
'addToFavorites'
)}
disabled={misc.contextMenu.disabledOptions.includes('addToFavorites')}
/>
<ContextMenuButton
text="Remove from favorites"
onClick={handleUnfavorite}
disabled={misc.contextMenu.disabledOptions.includes(
'removeFromFavorites'
)}
disabled={misc.contextMenu.disabledOptions.includes('removeFromFavorites')}
/>
</ContextMenu>
)}

17
src/components/shared/ToolbarButtons.tsx

@ -29,15 +29,8 @@ export const PlayAppendButton = ({ ...rest }) => {
export const PlayShuffleAppendButton = ({ ...rest }) => {
return (
<CustomTooltip
text="Add shuffled to queue"
placement="bottom"
onClick={rest.onClick}
>
<StyledIconButton
tabIndex={0}
icon={<Icon icon="plus-square" {...rest} />}
/>
<CustomTooltip text="Add shuffled to queue" placement="bottom" onClick={rest.onClick}>
<StyledIconButton tabIndex={0} icon={<Icon icon="plus-square" {...rest} />} />
</CustomTooltip>
);
};
@ -89,11 +82,7 @@ export const FavoriteButton = ({ isFavorite, ...rest }: any) => {
export const DownloadButton = ({ ...rest }) => {
return (
<CustomTooltip text="Toggle favorite" placement="bottom">
<StyledIconButton
tabIndex={0}
icon={<Icon icon="download" />}
{...rest}
/>
<StyledIconButton tabIndex={0} icon={<Icon icon="download" />} {...rest} />
</CustomTooltip>
);
};

30
src/components/shared/styled.ts

@ -22,9 +22,7 @@ export const HeaderButton = styled(Button)`
export const StyledButton = styled(Button)<{ width: number }>`
background: ${(props) =>
props.appearance === 'primary'
? `${props.theme.primary.main} !important`
: undefined};
props.appearance === 'primary' ? `${props.theme.primary.main} !important` : undefined};
width: ${(props) => `${props.width}px`};
`;
@ -60,9 +58,7 @@ export const StyledCheckbox = styled(Checkbox)`
span {
&:before {
background-color: ${(props) =>
props.defaultChecked
? `${props.theme.primary.main} !important`
: undefined};
props.defaultChecked ? `${props.theme.primary.main} !important` : undefined};
}
&:after {
border: transparent !important;
@ -94,14 +90,12 @@ export const StyledIconButton = styled(IconButton)`
&:hover {
background: ${(props) =>
props.appearance === 'subtle' ? 'transparent !important' : undefined};
color: ${(props) =>
props.appearance === 'subtle' ? props.theme.primary.main : undefined};
color: ${(props) => (props.appearance === 'subtle' ? props.theme.primary.main : undefined)};
}
&:focus {
background: ${(props) =>
props.appearance === 'subtle' ? 'transparent !important' : undefined};
color: ${(props) =>
props.appearance === 'subtle' ? props.theme.primary.main : undefined};
color: ${(props) => (props.appearance === 'subtle' ? props.theme.primary.main : undefined)};
}
background-color: ${(props) =>
props.appearance === 'primary' ? props.theme.primary.main : undefined};
@ -110,8 +104,7 @@ export const StyledIconButton = styled(IconButton)`
export const StyledNavItem = styled(Nav.Item)`
a {
color: ${(props) =>
props.active ? `${props.theme.primary.main} !important;` : undefined};
color: ${(props) => (props.active ? `${props.theme.primary.main} !important;` : undefined)};
&:hover {
color: ${(props) => `${props.theme.primary.main} !important;`};
@ -122,9 +115,7 @@ export const StyledNavItem = styled(Nav.Item)`
export const StyledIconToggle = styled(Icon)<{ active: string }>`
cursor: pointer;
color: ${(props) =>
props.active === 'true'
? props.theme.primary.main
: props.theme.primary.text};
props.active === 'true' ? props.theme.primary.main : props.theme.primary.text};
`;
export const StyledRate = styled(Rate)`
@ -145,8 +136,7 @@ export const StyledInputPicker = styled(InputPicker)<{ width?: number }>`
}
.rs-btn-default {
background: ${(props) =>
`${props.theme.primary.inputBackground} !important`};
background: ${(props) => `${props.theme.primary.inputBackground} !important`};
}
width: ${(props) => `${props.width}px`};
@ -168,11 +158,7 @@ export const ContextMenuWindow = styled.div<{
top: ${(props) => `${props.yPos}px`};
left: ${(props) => `${props.xPos}px`};
height: ${(props) =>
`${
props.numOfButtons * 30 +
props.numOfDividers * 2 +
(props.hasTitle ? 16 : 0)
}px`};
`${props.numOfButtons * 30 + props.numOfDividers * 2 + (props.hasTitle ? 16 : 0)}px`};
width: ${(props) => `${props.width}px`};
margin: 0px;
white-space: normal;

5
src/components/shared/toast.ts

@ -1,9 +1,6 @@
import { Notification } from 'rsuite';
export const notifyToast = (
type: 'info' | 'success' | 'warning' | 'error',
message: any
) => {
export const notifyToast = (type: 'info' | 'success' | 'warning' | 'error', message: any) => {
Notification[type]({
title: `${type.charAt(0).toUpperCase()}${type.slice(1)}`,
description: message,

26
src/components/starred/StarredView.tsx

@ -5,10 +5,7 @@ import { Nav } from 'rsuite';
import settings from 'electron-settings';
import useSearchQuery from '../../hooks/useSearchQuery';
import { useAppDispatch } from '../../redux/hooks';
import {
fixPlayer2Index,
setPlayQueueByRowClick,
} from '../../redux/playQueueSlice';
import { fixPlayer2Index, setPlayQueueByRowClick } from '../../redux/playQueueSlice';
import {
clearSelected,
toggleSelected,
@ -28,21 +25,12 @@ const StarredView = () => {
const history = useHistory();
const dispatch = useAppDispatch();
const [currentPage, setCurrentPage] = useState('Tracks');
const [viewType, setViewType] = useState(
settings.getSync('albumViewType') || 'list'
);
const { isLoading, isError, data, error }: any = useQuery(
'starred',
getStarred
);
const [viewType, setViewType] = useState(settings.getSync('albumViewType') || 'list');
const { isLoading, isError, data, error }: any = useQuery('starred', getStarred);
const [searchQuery, setSearchQuery] = useState('');
const filteredData = useSearchQuery(
searchQuery,
currentPage === 'Tracks'
? data?.song
: currentPage === 'Albums'
? data?.album
: data?.song,
currentPage === 'Tracks' ? data?.song : currentPage === 'Albums' ? data?.album : data?.song,
['title', 'artist', 'album', 'name', 'genre']
);
@ -64,11 +52,7 @@ const StarredView = () => {
}
} else if (currentPage === 'Albums') {
dispatch(setRangeSelected(rowData));
dispatch(
toggleRangeSelected(
searchQuery !== '' ? filteredData : data?.album
)
);
dispatch(toggleRangeSelected(searchQuery !== '' ? filteredData : data?.album));
}
}
}, 100);

21
src/components/viewtypes/GridViewType.tsx

@ -29,23 +29,17 @@ const GridCard = ({ data, index, style }: any) => {
>
<Card
title={data.data[i][data.cardTitle.property]}
subtitle={`${data.data[i][data.cardSubtitle.property]}${
data.cardSubtitle.unit
}`}
subtitle={`${data.data[i][data.cardSubtitle.property]}${data.cardSubtitle.unit}`}
coverArt={data.data[i].image}
size={`${data.size}px`}
url={
data.cardTitle.urlProperty
? `${data.cardTitle.prefix}/${
data.data[i][data.cardTitle.urlProperty]
}`
? `${data.cardTitle.prefix}/${data.data[i][data.cardTitle.urlProperty]}`
: undefined
}
subUrl={
data.cardSubtitle.urlProperty
? `${data.cardSubtitle.prefix}/${
data.data[i][data.cardSubtitle.urlProperty]
}`
? `${data.cardSubtitle.prefix}/${data.data[i][data.cardSubtitle.urlProperty]}`
: undefined
}
lazyLoad
@ -134,14 +128,7 @@ function ListWrapper({
);
}
const GridViewType = ({
data,
cardTitle,
cardSubtitle,
playClick,
size,
cacheType,
}: any) => {
const GridViewType = ({ data, cardTitle, cardSubtitle, playClick, size, cacheType }: any) => {
return (
<AutoSizer>
{({ height, width }: any) => (

152
src/components/viewtypes/ListViewTable.tsx

@ -16,21 +16,11 @@ import {
StyledTableHeaderCell,
TableCellWrapper,
} from './styled';
import {
formatSongDuration,
isCached,
getImageCachePath,
formatDate,
} from '../../shared/utils';
import { formatSongDuration, isCached, getImageCachePath, formatDate } from '../../shared/utils';
import cacheImage from '../shared/cacheImage';
import { setRating, star, unstar } from '../../api/api';
import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import {
fixPlayer2Index,
setSort,
setStar,
sortPlayQueue,
} from '../../redux/playQueueSlice';
import { fixPlayer2Index, setSort, setStar, sortPlayQueue } from '../../redux/playQueueSlice';
import { StyledIconToggle, StyledRate } from '../shared/styled';
import { addModalPage, setContextMenu } from '../../redux/miscSlice';
import {
@ -170,9 +160,7 @@ const ListViewTable = ({
// to the mouse-entered row
const debouncedMouseEnterFn = _.debounce((rowData: any) => {
dispatch(setRangeSelected(rowData));
dispatch(
toggleRangeSelected(sortColumn && !nowPlaying ? sortedData : data)
);
dispatch(toggleRangeSelected(sortColumn && !nowPlaying ? sortedData : data));
}, 100);
const handleSelectMouseEnter = (rowData: any) => {
@ -185,13 +173,9 @@ const ListViewTable = ({
if (!nowPlaying) {
if (sortColumn && sortType) {
// Since the column title(id) won't always match the actual column dataKey, we need to match it
const normalizedSortColumn = columns.find(
(c: any) => c.id === sortColumn
);
const normalizedSortColumn = columns.find((c: any) => c.id === sortColumn);
const sortColumnDataKey =
normalizedSortColumn.dataKey === 'combinedtitle'
? 'title'
: normalizedSortColumn.dataKey;
normalizedSortColumn.dataKey === 'combinedtitle' ? 'title' : normalizedSortColumn.dataKey;
const sortData = _.orderBy(
data,
@ -213,13 +197,9 @@ const ListViewTable = ({
useEffect(() => {
if (nowPlaying) {
if (playQueue.sortColumn && playQueue.sortType) {
const actualSortColumn = columns.find(
(c: any) => c.id === playQueue.sortColumn
);
const actualSortColumn = columns.find((c: any) => c.id === playQueue.sortColumn);
const sortColumnDataKey =
actualSortColumn.dataKey === 'combinedtitle'
? 'title'
: actualSortColumn.dataKey;
actualSortColumn.dataKey === 'combinedtitle' ? 'title' : actualSortColumn.dataKey;
dispatch(
sortPlayQueue({
@ -271,11 +251,9 @@ const ListViewTable = ({
onRowContextMenu={(rowData: any, e: any) => {
e.preventDefault();
if (
(misc.contextMenu.show === false ||
misc.contextMenu.rowId !== rowData.uniqueId) &&
multiSelect.selected.filter(
(entry: any) => entry.uniqueId === rowData.uniqueId
).length > 0
(misc.contextMenu.show === false || misc.contextMenu.rowId !== rowData.uniqueId) &&
multiSelect.selected.filter((entry: any) => entry.uniqueId === rowData.uniqueId)
.length > 0
) {
dispatch(
setContextMenu({
@ -313,15 +291,9 @@ const ListViewTable = ({
);
if (!miniView) {
settings.setSync(
`${listType}ListColumns[${resizedColumnIndex}].width`,
width
);
settings.setSync(`${listType}ListColumns[${resizedColumnIndex}].width`, width);
} else {
settings.setSync(
`miniListColumns[${resizedColumnIndex}].width`,
width
);
settings.setSync(`miniListColumns[${resizedColumnIndex}].width`, width);
}
}}
>
@ -333,16 +305,13 @@ const ListViewTable = ({
return (
<TableCellWrapper
playing={
(rowData.uniqueId === playQueue?.currentSongUniqueId &&
nowPlaying) ||
(rowData.uniqueId === playQueue?.currentSongUniqueId && nowPlaying) ||
(!nowPlaying && rowData.id === playQueue?.currentSongId)
? 'true'
: 'false'
}
rowselected={
multiSelect?.selected.find(
(e: any) => e.uniqueId === rowData.uniqueId
)
multiSelect?.selected.find((e: any) => e.uniqueId === rowData.uniqueId)
? 'true'
: 'false'
}
@ -374,11 +343,7 @@ const ListViewTable = ({
}
}}
onMouseLeave={() => {
if (
(multiSelect.currentMouseOverId ||
multiSelect.isDragging) &&
dnd
) {
if ((multiSelect.currentMouseOverId || multiSelect.isDragging) && dnd) {
dispatch(
setCurrentMouseOverId({
uniqueId: undefined,
@ -395,10 +360,7 @@ const ListViewTable = ({
);
// Handle cases where we want to quickly drag/drop single rows
if (
multiSelect.selected.length <= 1 ||
!isSelected
) {
if (multiSelect.selected.length <= 1 || !isSelected) {
dispatch(setSelectedSingle(rowData));
dispatch(
setCurrentMouseOverId({
@ -447,9 +409,7 @@ const ListViewTable = ({
return (
<TableCellWrapper
rowselected={
multiSelect?.selected.find(
(e: any) => e.uniqueId === rowData.uniqueId
)
multiSelect?.selected.find((e: any) => e.uniqueId === rowData.uniqueId)
? 'true'
: 'false'
}
@ -465,9 +425,7 @@ const ListViewTable = ({
rowIndex,
})
}
onMouseDown={(e: any) =>
handleSelectMouseDown(e, rowData)
}
onMouseDown={(e: any) => handleSelectMouseDown(e, rowData)}
onMouseEnter={() => handleSelectMouseEnter(rowData)}
onMouseUp={() => handleSelectMouseUp()}
dragover={
@ -514,10 +472,7 @@ const ListViewTable = ({
`${cacheImages.cacheType}_${
rowData[cacheImages.cacheIdProperty]
}.jpg`,
rowData.image.replace(
/size=\d+/,
'size=500'
)
rowData.image.replace(/size=\d+/, 'size=500')
);
}
}}
@ -540,11 +495,9 @@ const ListViewTable = ({
>
<CombinedTitleTextWrapper
playing={
(rowData.uniqueId ===
playQueue?.currentSongUniqueId &&
(rowData.uniqueId === playQueue?.currentSongUniqueId &&
nowPlaying) ||
(!nowPlaying &&
rowData.id === playQueue?.currentSongId)
(!nowPlaying && rowData.id === playQueue?.currentSongId)
? 'true'
: 'false'
}
@ -584,9 +537,7 @@ const ListViewTable = ({
appearance="link"
onClick={() => {
if (rowData.artistId && !isModal) {
history.push(
`/library/artist/${rowData.artistId}`
);
history.push(`/library/artist/${rowData.artistId}`);
} else if (rowData.artistId && isModal) {
dispatch(
addModalPage({
@ -600,11 +551,9 @@ const ListViewTable = ({
fontSize: `${fontSize}px`,
}}
playing={
(rowData.uniqueId ===
playQueue?.currentSongUniqueId &&
(rowData.uniqueId === playQueue?.currentSongUniqueId &&
nowPlaying) ||
(!nowPlaying &&
rowData.id === playQueue?.currentSongId)
(!nowPlaying && rowData.id === playQueue?.currentSongId)
? 'true'
: 'false'
}
@ -626,16 +575,12 @@ const ListViewTable = ({
return (
<TableCellWrapper
rowselected={
multiSelect?.selected.find(
(e: any) => e.uniqueId === rowData.uniqueId
)
multiSelect?.selected.find((e: any) => e.uniqueId === rowData.uniqueId)
? 'true'
: 'false'
}
height={rowHeight}
onMouseDown={(e: any) =>
handleSelectMouseDown(e, rowData)
}
onMouseDown={(e: any) => handleSelectMouseDown(e, rowData)}
onMouseEnter={() => handleSelectMouseEnter(rowData)}
onMouseUp={() => handleSelectMouseUp()}
dragover={
@ -683,26 +628,19 @@ const ListViewTable = ({
return (
<TableCellWrapper
playing={
(rowData.uniqueId === playQueue?.currentSongUniqueId &&
nowPlaying) ||
(rowData.uniqueId === playQueue?.currentSongUniqueId && nowPlaying) ||
(!nowPlaying && rowData.id === playQueue?.currentSongId)
? 'true'
: 'false'
}
rowselected={
multiSelect?.selected.find(
(e: any) => e.uniqueId === rowData.uniqueId
)
multiSelect?.selected.find((e: any) => e.uniqueId === rowData.uniqueId)
? 'true'
: 'false'
}
height={rowHeight}
onClick={(e: any) => {
if (
!column.dataKey?.match(
/starred|songCount|duration|userRating/
)
) {
if (!column.dataKey?.match(/starred|songCount|duration|userRating/)) {
handleRowClick(e, {
...rowData,
rowIndex,
@ -710,20 +648,14 @@ const ListViewTable = ({
}
}}
onDoubleClick={() => {
if (
!column.dataKey?.match(
/starred|songCount|duration|userRating/
)
) {
if (!column.dataKey?.match(/starred|songCount|duration|userRating/)) {
handleRowDoubleClick({
...rowData,
rowIndex,
});
}
}}
onMouseDown={(e: any) =>
handleSelectMouseDown(e, rowData)
}
onMouseDown={(e: any) => handleSelectMouseDown(e, rowData)}
onMouseEnter={() => handleSelectMouseEnter(rowData)}
onMouseUp={() => handleSelectMouseUp()}
dragover={
@ -751,9 +683,7 @@ const ListViewTable = ({
onClick={() => {
if (column.dataKey === 'album') {
if (rowData.albumId && !isModal) {
history.push(
`/library/album/${rowData.albumId}`
);
history.push(`/library/album/${rowData.albumId}`);
} else if (rowData.albumId && isModal) {
dispatch(
addModalPage({
@ -764,9 +694,7 @@ const ListViewTable = ({
}
} else if (column.dataKey === 'artist') {
if (rowData.artistId && !isModal) {
history.push(
`/library/artist/${rowData.artistId}`
);
history.push(`/library/artist/${rowData.artistId}`);
} else if (rowData.artistId && isModal) {
dispatch(
addModalPage({
@ -778,11 +706,8 @@ const ListViewTable = ({
}
}}
playing={
(rowData.uniqueId ===
playQueue?.currentSongUniqueId &&
nowPlaying) ||
(!nowPlaying &&
rowData.id === playQueue?.currentSongId)
(rowData.uniqueId === playQueue?.currentSongUniqueId && nowPlaying) ||
(!nowPlaying && rowData.id === playQueue?.currentSongId)
? 'true'
: 'false'
}
@ -794,8 +719,7 @@ const ListViewTable = ({
</RsuiteLinkButton>
) : column.dataKey === 'duration' ? (
formatSongDuration(rowData[column.dataKey])
) : column.dataKey === 'changed' ||
column.dataKey === 'created' ? (
) : column.dataKey === 'changed' || column.dataKey === 'created' ? (
formatDate(rowData[column.dataKey])
) : column.dataKey === 'starred' ? (
<StyledIconToggle
@ -810,9 +734,7 @@ const ListViewTable = ({
<StyledRate
size="sm"
readOnly={false}
defaultValue={
rowData?.userRating ? rowData.userRating : 0
}
defaultValue={rowData?.userRating ? rowData.userRating : 0}
onChange={(e: any) => handleRating(rowData, e)}
/>
) : column.dataKey === 'bitRate' ? (

8
src/components/viewtypes/ListViewType.tsx

@ -1,13 +1,7 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
// Resize derived from @nimrod-cohen https://gitter.im/rsuite/rsuite?at=5e1cd3f165540a529a0f5deb
import React, {
useState,
useEffect,
useRef,
forwardRef,
useImperativeHandle,
} from 'react';
import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
import { DOMHelper } from 'rsuite';
import { useAppSelector } from '../../redux/hooks';
import PageLoader from '../loader/PageLoader';

6
src/components/viewtypes/ViewTypeButtons.tsx

@ -3,11 +3,7 @@ import { ButtonToolbar, ButtonGroup, Icon } from 'rsuite';
import settings from 'electron-settings';
import { StyledIconButton } from '../shared/styled';
const ViewTypeButtons = ({
handleListClick,
handleGridClick,
viewTypeSetting,
}: any) => {
const ViewTypeButtons = ({ handleListClick, handleGridClick, viewTypeSetting }: any) => {
return (
<ButtonToolbar>
<ButtonGroup>

10
src/components/viewtypes/styled.tsx

@ -34,13 +34,10 @@ export const TableCellWrapper = styled.div<{
}>`
background: ${(props) =>
props.rowselected === 'true' ? props.theme.primary.rowSelected : undefined};
color: ${(props) =>
props.playing === 'true' ? props.theme.primary.main : undefined};
color: ${(props) => (props.playing === 'true' ? props.theme.primary.main : undefined)};
line-height: ${(props) => (props.height ? `${props.height}px` : undefined)};
box-shadow: ${(props) =>
props.dragover === 'true'
? `inset 0px 5px 0px -3px ${props.theme.primary.main}`
: undefined};
props.dragover === 'true' ? `inset 0px 5px 0px -3px ${props.theme.primary.main}` : undefined};
cursor: ${(props) =>
props.dragover === 'true'
? 'grabbing'
@ -52,8 +49,7 @@ export const TableCellWrapper = styled.div<{
`;
export const CombinedTitleTextWrapper = styled.span<{ playing: string }>`
color: ${(props) =>
props.playing === 'true' ? props.theme.primary.main : undefined};
color: ${(props) => (props.playing === 'true' ? props.theme.primary.main : undefined)};
`;
export const StyledTableHeaderCell = styled(Table.HeaderCell)`

10
src/hooks/useSearchQuery.ts

@ -1,11 +1,7 @@
import { useState, useEffect, SetStateAction } from 'react';
import _ from 'lodash';
const useSearchQuery = (
searchQuery: string,
data: any[],
filterProperties: string[]
) => {
const useSearchQuery = (searchQuery: string, data: any[], filterProperties: string[]) => {
const [filteredData, setFilteredData] = useState<any[]>([]);
const [filterProps] = useState(filterProperties);
@ -15,9 +11,7 @@ const useSearchQuery = (
const matches: SetStateAction<any[]> = [];
filterProps.map((prop: string) => {
const filteredDataByProp = data.filter((entry: any) => {
return entry[prop]
?.toLowerCase()
.includes(searchQuery.toLowerCase());
return entry[prop]?.toLowerCase().includes(searchQuery.toLowerCase());
});
return filteredDataByProp.map((entry) => matches.push(entry));

4
src/index.html

@ -35,9 +35,7 @@
if (scripts.length) {
document.write(
scripts
.map((script) => `<script defer src="${script}"><\/script>`)
.join('')
scripts.map((script) => `<script defer src="${script}"><\/script>`).join('')
);
}
</script>

53
src/main.dev.js

@ -17,11 +17,7 @@ import electronLocalshortcut from 'electron-localshortcut';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import { configureStore } from '@reduxjs/toolkit';
import {
forwardToRenderer,
triggerAlias,
replayActionMain,
} from 'electron-redux';
import { forwardToRenderer, triggerAlias, replayActionMain } from 'electron-redux';
import playerReducer, { resetPlayer, setStatus } from './redux/playerSlice';
import playQueueReducer, {
decrementCurrentIndex,
@ -58,10 +54,7 @@ if (process.env.NODE_ENV === 'production') {
sourceMapSupport.install();
}
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
if (process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true') {
require('electron-debug')();
}
@ -79,10 +72,7 @@ const installExtensions = async () => {
};
const createWindow = async () => {
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
if (process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true') {
await installExtensions();
}
@ -114,9 +104,7 @@ const createWindow = async () => {
if (settings.getSync('globalMediaHotkeys')) {
globalShortcut.register('MediaStop', () => {
const storeValues = store.getState();
const currentEntryList = storeValues.playQueue.shuffle
? 'shuffledEntry'
: 'entry';
const currentEntryList = storeValues.playQueue.shuffle ? 'shuffledEntry' : 'entry';
if (storeValues.playQueue[currentEntryList].length > 0) {
store.dispatch(clearPlayQueue());
@ -127,9 +115,7 @@ const createWindow = async () => {
globalShortcut.register('MediaPlayPause', () => {
const storeValues = store.getState();
const currentEntryList = storeValues.playQueue.shuffle
? 'shuffledEntry'
: 'entry';
const currentEntryList = storeValues.playQueue.shuffle ? 'shuffledEntry' : 'entry';
if (storeValues.playQueue[currentEntryList].length > 0) {
if (storeValues.player.status === 'PAUSED') {
@ -142,9 +128,7 @@ const createWindow = async () => {
globalShortcut.register('MediaNextTrack', () => {
const storeValues = store.getState();
const currentEntryList = storeValues.playQueue.shuffle
? 'shuffledEntry'
: 'entry';
const currentEntryList = storeValues.playQueue.shuffle ? 'shuffledEntry' : 'entry';
if (storeValues.playQueue[currentEntryList].length > 0) {
store.dispatch(resetPlayer());
store.dispatch(incrementCurrentIndex('usingHotkey'));
@ -154,9 +138,7 @@ const createWindow = async () => {
globalShortcut.register('MediaPreviousTrack', () => {
const storeValues = store.getState();
const currentEntryList = storeValues.playQueue.shuffle
? 'shuffledEntry'
: 'entry';
const currentEntryList = storeValues.playQueue.shuffle ? 'shuffledEntry' : 'entry';
if (storeValues.playQueue[currentEntryList].length > 0) {
store.dispatch(resetPlayer());
store.dispatch(decrementCurrentIndex('usingHotkey'));
@ -167,9 +149,7 @@ const createWindow = async () => {
} else {
electronLocalshortcut.register(mainWindow, 'MediaStop', () => {
const storeValues = store.getState();
const currentEntryList = storeValues.playQueue.shuffle
? 'shuffledEntry'
: 'entry';
const currentEntryList = storeValues.playQueue.shuffle ? 'shuffledEntry' : 'entry';
if (storeValues.playQueue[currentEntryList].length > 0) {
store.dispatch(clearPlayQueue());
@ -180,9 +160,7 @@ const createWindow = async () => {
electronLocalshortcut.register(mainWindow, 'MediaPlayPause', () => {
const storeValues = store.getState();
const currentEntryList = storeValues.playQueue.shuffle
? 'shuffledEntry'
: 'entry';
const currentEntryList = storeValues.playQueue.shuffle ? 'shuffledEntry' : 'entry';
if (storeValues.playQueue[currentEntryList].length > 0) {
if (storeValues.player.status === 'PAUSED') {
@ -195,9 +173,7 @@ const createWindow = async () => {
electronLocalshortcut.register(mainWindow, 'MediaNextTrack', () => {
const storeValues = store.getState();
const currentEntryList = storeValues.playQueue.shuffle
? 'shuffledEntry'
: 'entry';
const currentEntryList = storeValues.playQueue.shuffle ? 'shuffledEntry' : 'entry';
if (storeValues.playQueue[currentEntryList].length > 0) {
store.dispatch(resetPlayer());
store.dispatch(incrementCurrentIndex('usingHotkey'));
@ -207,9 +183,7 @@ const createWindow = async () => {
electronLocalshortcut.register(mainWindow, 'MediaPreviousTrack', () => {
const storeValues = store.getState();
const currentEntryList = storeValues.playQueue.shuffle
? 'shuffledEntry'
: 'entry';
const currentEntryList = storeValues.playQueue.shuffle ? 'shuffledEntry' : 'entry';
if (storeValues.playQueue[currentEntryList].length > 0) {
store.dispatch(resetPlayer());
store.dispatch(decrementCurrentIndex('usingHotkey'));
@ -266,10 +240,7 @@ app.on('window-all-closed', () => {
}
});
app.commandLine.appendSwitch(
'disable-features',
'HardwareMediaKeyHandling,MediaSessionService'
);
app.commandLine.appendSwitch('disable-features', 'HardwareMediaKeyHandling,MediaSessionService');
app.whenReady().then(createWindow).catch(console.log);

39
src/menu.ts

@ -1,10 +1,4 @@
import {
app,
Menu,
shell,
BrowserWindow,
MenuItemConstructorOptions,
} from 'electron';
import { app, Menu, shell, BrowserWindow, MenuItemConstructorOptions } from 'electron';
interface DarwinMenuItemConstructorOptions extends MenuItemConstructorOptions {
selector?: string;
@ -19,17 +13,12 @@ export default class MenuBuilder {
}
buildMenu(): Menu {
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
if (process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true') {
this.setupDevelopmentEnvironment();
}
const template =
process.platform === 'darwin'
? this.buildDarwinTemplate()
: this.buildDefaultTemplate();
process.platform === 'darwin' ? this.buildDarwinTemplate() : this.buildDefaultTemplate();
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
@ -163,9 +152,7 @@ export default class MenuBuilder {
{
label: 'Documentation',
click() {
shell.openExternal(
'https://github.com/electron/electron/tree/master/docs#readme'
);
shell.openExternal('https://github.com/electron/electron/tree/master/docs#readme');
},
},
{
@ -184,8 +171,7 @@ export default class MenuBuilder {
};
const subMenuView =
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'
? subMenuViewDev
: subMenuViewProd;
@ -213,8 +199,7 @@ export default class MenuBuilder {
{
label: '&View',
submenu:
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'
? [
{
label: '&Reload',
@ -227,9 +212,7 @@ export default class MenuBuilder {
label: 'Toggle &Full Screen',
accelerator: 'F11',
click: () => {
this.mainWindow.setFullScreen(
!this.mainWindow.isFullScreen()
);
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
},
},
{
@ -245,9 +228,7 @@ export default class MenuBuilder {
label: 'Toggle &Full Screen',
accelerator: 'F11',
click: () => {
this.mainWindow.setFullScreen(
!this.mainWindow.isFullScreen()
);
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
},
},
],
@ -264,9 +245,7 @@ export default class MenuBuilder {
{
label: 'Documentation',
click() {
shell.openExternal(
'https://github.com/electron/electron/tree/master/docs#readme'
);
shell.openExternal('https://github.com/electron/electron/tree/master/docs#readme');
},
},
{

11
src/redux/miscSlice.ts

@ -2,8 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import settings from 'electron-settings';
import { mockSettings } from '../shared/mockSettings';
const parsedSettings =
process.env.NODE_ENV === 'test' ? mockSettings : settings.getSync();
const parsedSettings = process.env.NODE_ENV === 'test' ? mockSettings : settings.getSync();
export interface ModalPage {
pageType: string;
@ -83,9 +82,7 @@ const miscSlice = createSlice({
},
removeProcessingPlaylist: (state, action: PayloadAction<string>) => {
const filtered = state.isProcessingPlaylist.filter(
(id: string) => id !== action.payload
);
const filtered = state.isProcessingPlaylist.filter((id: string) => id !== action.payload);
state.isProcessingPlaylist = filtered;
},
@ -109,9 +106,7 @@ const miscSlice = createSlice({
if (
state.modalPages[
state.modal.currentPageIndex === undefined
? 0
: state.modal.currentPageIndex
state.modal.currentPageIndex === undefined ? 0 : state.modal.currentPageIndex
]?.id !== action.payload.id
) {
state.modalPages.push(action.payload);

16
src/redux/multiSelectSlice.ts

@ -72,9 +72,7 @@ const multiSelectSlice = createSlice({
lastRangeSelected: {},
};
if (
state.selected.find((item) => item.uniqueId === action.payload.uniqueId)
) {
if (state.selected.find((item) => item.uniqueId === action.payload.uniqueId)) {
state.selected = [];
} else {
state.selected = [];
@ -111,9 +109,7 @@ const multiSelectSlice = createSlice({
},
toggleSelected: (state, action: PayloadAction<any>) => {
if (
state.selected.find((item) => item.uniqueId === action.payload.uniqueId)
) {
if (state.selected.find((item) => item.uniqueId === action.payload.uniqueId)) {
const indexOfItem = state.selected.findIndex(
(item) => item.uniqueId === action.payload.uniqueId
);
@ -128,17 +124,13 @@ const multiSelectSlice = createSlice({
},
toggleRangeSelected: (state, action: PayloadAction<any[]>) => {
if (
state.lastSelected.uniqueId ===
state.lastRangeSelected.lastSelected.uniqueId
) {
if (state.lastSelected.uniqueId === state.lastRangeSelected.lastSelected.uniqueId) {
const beginningIndex = action.payload.findIndex(
(e) => e.uniqueId === state.lastSelected.uniqueId
);
const endingIndex = action.payload.findIndex(
(e) =>
e.uniqueId === state.lastRangeSelected.lastRangeSelected.uniqueId
(e) => e.uniqueId === state.lastRangeSelected.lastRangeSelected.uniqueId
);
// Handle both selection directions

144
src/redux/playQueueSlice.ts

@ -6,8 +6,7 @@ import arrayMove from 'array-move';
import { areConsecutive, consecutiveRanges } from '../shared/utils';
import { mockSettings } from '../shared/mockSettings';
const parsedSettings =
process.env.NODE_ENV === 'test' ? mockSettings : settings.getSync();
const parsedSettings = process.env.NODE_ENV === 'test' ? mockSettings : settings.getSync();
export interface Entry {
id: string;
@ -160,17 +159,9 @@ const removeItem = (array: any, index: any) => {
};
const entrySelect = (state: PlayQueue) =>
state.sortedEntry.length > 0
? 'sortedEntry'
: state.shuffle
? 'shuffledEntry'
: 'entry';
state.sortedEntry.length > 0 ? 'sortedEntry' : state.shuffle ? 'shuffledEntry' : 'entry';
const getNextPlayerIndex = (
length: number,
repeat: string,
currentIndex: number
) => {
const getNextPlayerIndex = (length: number, repeat: string, currentIndex: number) => {
if (length >= 2 && repeat !== 'one') {
if (currentIndex + 1 === length) {
return 0;
@ -187,10 +178,7 @@ export const getCurrentEntryIndex = (entries: any[], currentSongId: string) => {
return entries.findIndex((entry: any) => entry.id === currentSongId);
};
export const getCurrentEntryIndexByUID = (
entries: any[],
currentSongId: string
) => {
export const getCurrentEntryIndexByUID = (entries: any[], currentSongId: string) => {
return entries.findIndex((entry: any) => entry.uniqueId === currentSongId);
};
@ -204,10 +192,7 @@ const playQueueSlice = createSlice({
name: 'nowPlaying',
initialState,
reducers: {
setPlayerSrc: (
state,
action: PayloadAction<{ player: number; src: string }>
) => {
setPlayerSrc: (state, action: PayloadAction<{ player: number; src: string }>) => {
if (action.payload.player === 1) {
state.player1.src = action.payload.src;
} else {
@ -230,10 +215,7 @@ const playQueueSlice = createSlice({
state.currentIndex = newCurrentSongIndex;
},
setSort: (
state,
action: PayloadAction<{ sortColumn?: string; sortType: 'asc' | 'desc' }>
) => {
setSort: (state, action: PayloadAction<{ sortColumn?: string; sortType: 'asc' | 'desc' }>) => {
state.sortColumn = action.payload.sortColumn;
state.sortType = action.payload.sortType;
},
@ -259,9 +241,7 @@ const playQueueSlice = createSlice({
const currentEntry = entrySelect(state);
const newCurrentSongIndex = getCurrentEntryIndexByUID(
action.payload.columnDataKey !== ''
? state.sortedEntry
: state[currentEntry],
action.payload.columnDataKey !== '' ? state.sortedEntry : state[currentEntry],
state.currentSongUniqueId
);
@ -284,10 +264,7 @@ const playQueueSlice = createSlice({
state.currentSongUniqueId = state[currentEntry][0].uniqueId;
},
setPlaybackSetting: (
state,
action: PayloadAction<{ setting: string; value: any }>
) => {
setPlaybackSetting: (state, action: PayloadAction<{ setting: string; value: any }>) => {
switch (action.payload.setting) {
case 'fadeDuration':
state.fadeDuration = action.payload.value;
@ -325,15 +302,11 @@ const playQueueSlice = createSlice({
switch (action.payload.player) {
case 1:
state.player1.fadeData.volumeData.push(action.payload.volume || 0);
state.player1.fadeData.timeData.push(
action.payload.time?.toFixed(2) || '0'
);
state.player1.fadeData.timeData.push(action.payload.time?.toFixed(2) || '0');
break;
case 2:
state.player2.fadeData.volumeData.push(action.payload.volume || 0);
state.player2.fadeData.timeData.push(
action.payload.time?.toFixed(2) || '0'
);
state.player2.fadeData.timeData.push(action.payload.time?.toFixed(2) || '0');
break;
default:
break;
@ -389,10 +362,7 @@ const playQueueSlice = createSlice({
We want to swap the currentIndex over to the currently playing track since its row index
will change */
const currentEntryIndex = getCurrentEntryIndex(
state.entry,
state.currentSongId
);
const currentEntryIndex = getCurrentEntryIndex(state.entry, state.currentSongId);
/* Account for the currentPlayer and set the player indexes accordingly. Unfortunately
since we're updating the indexes here, the transition won't be seamless and the currently
@ -401,19 +371,11 @@ const playQueueSlice = createSlice({
state.player1.index =
state.currentPlayer === 1
? currentEntryIndex
: getNextPlayerIndex(
state.entry.length,
state.repeat,
state.currentIndex
);
: getNextPlayerIndex(state.entry.length, state.repeat, state.currentIndex);
state.player2.index =
state.currentPlayer === 2
? currentEntryIndex
: getNextPlayerIndex(
state.entry.length,
state.repeat,
state.currentIndex
);
: getNextPlayerIndex(state.entry.length, state.repeat, state.currentIndex);
// Free up memory by clearing out the shuffled entries
state.shuffledEntry = [];
@ -544,8 +506,7 @@ const playQueueSlice = createSlice({
handleGaplessPlayback(state);
state.current = { ...state[currentEntry][state.currentIndex] };
state.currentSongId = state[currentEntry][state.currentIndex].id;
state.currentSongUniqueId =
state[currentEntry][state.currentIndex].uniqueId;
state.currentSongUniqueId = state[currentEntry][state.currentIndex].uniqueId;
},
incrementPlayerIndex: (state, action: PayloadAction<number>) => {
@ -556,10 +517,7 @@ const playQueueSlice = createSlice({
without changing the index of either player */
if (state[currentEntry].length > 2 && state.repeat !== 'one') {
if (action.payload === 1) {
if (
state.player1.index + 1 === state[currentEntry].length &&
state.repeat === 'none'
) {
if (state.player1.index + 1 === state[currentEntry].length && state.repeat === 'none') {
// Reset the player on the end of the playlist if no repeat
resetPlayerDefaults(state);
handleGaplessPlayback(state);
@ -576,10 +534,7 @@ const playQueueSlice = createSlice({
}
state.currentPlayer = 2;
} else {
if (
state.player2.index + 1 === state[currentEntry].length &&
state.repeat === 'none'
) {
if (state.player2.index + 1 === state[currentEntry].length && state.repeat === 'none') {
// Reset the player on the end of the playlist if no repeat
resetPlayerDefaults(state);
handleGaplessPlayback(state);
@ -602,10 +557,7 @@ const playQueueSlice = createSlice({
setPlayerIndex: (state, action: PayloadAction<Entry>) => {
const currentEntry = entrySelect(state);
const findIndex = getCurrentEntryIndexByUID(
state[currentEntry],
action.payload.uniqueId
);
const findIndex = getCurrentEntryIndexByUID(state[currentEntry], action.payload.uniqueId);
state.isFading = false;
state.player1.index = findIndex;
@ -622,10 +574,7 @@ const playQueueSlice = createSlice({
state.currentSongUniqueId = action.payload.uniqueId;
},
setPlayerVolume: (
state,
action: PayloadAction<{ player: number; volume: number }>
) => {
setPlayerVolume: (state, action: PayloadAction<{ player: number; volume: number }>) => {
if (action.payload.player === 1) {
state.player1.volume = action.payload.volume;
} else {
@ -658,8 +607,7 @@ const playQueueSlice = createSlice({
handleGaplessPlayback(state);
state.current = { ...state[currentEntry][state.currentIndex] };
state.currentSongId = state[currentEntry][state.currentIndex].id;
state.currentSongUniqueId =
state[currentEntry][state.currentIndex].uniqueId;
state.currentSongUniqueId = state[currentEntry][state.currentIndex].uniqueId;
}
},
@ -689,10 +637,7 @@ const playQueueSlice = createSlice({
setCurrentIndex: (state, action: PayloadAction<Entry>) => {
const currentEntry = entrySelect(state);
const findIndex = getCurrentEntryIndexByUID(
state[currentEntry],
action.payload.uniqueId
);
const findIndex = getCurrentEntryIndexByUID(state[currentEntry], action.payload.uniqueId);
state.currentIndex = findIndex;
state.current = { ...action.payload };
@ -798,15 +743,10 @@ const playQueueSlice = createSlice({
}
},
removeFromPlayQueue: (
state,
action: PayloadAction<{ entries: Entry[] }>
) => {
removeFromPlayQueue: (state, action: PayloadAction<{ entries: Entry[] }>) => {
const uniqueIds = _.map(action.payload.entries, 'uniqueId');
state.entry = state.entry.filter(
(entry) => !uniqueIds.includes(entry.uniqueId)
);
state.entry = state.entry.filter((entry) => !uniqueIds.includes(entry.uniqueId));
state.shuffledEntry = (state.shuffledEntry || []).filter(
(entry) => !uniqueIds.includes(entry.uniqueId)
@ -847,11 +787,7 @@ const playQueueSlice = createSlice({
// We'll recalculate the currentSongIndex just in case the existing index was modified
// due to removing row entries that are before the current song
const newCurrentSongIndex = getCurrentEntryIndexByUID(
state.sortColumn
? state.sortedEntry
: state.shuffle
? state.shuffledEntry
: state.entry,
state.sortColumn ? state.sortedEntry : state.shuffle ? state.shuffledEntry : state.entry,
state.currentSongUniqueId
);
@ -883,10 +819,7 @@ const playQueueSlice = createSlice({
state.isFading = action.payload;
},
moveToIndex: (
state,
action: PayloadAction<{ entries: Entry[]; moveBeforeId: string }>
) => {
moveToIndex: (state, action: PayloadAction<{ entries: Entry[]; moveBeforeId: string }>) => {
const currentEntry = entrySelect(state);
const tempQueue = state[currentEntry].slice();
const uniqueIds = _.map(action.payload.entries, 'uniqueId');
@ -898,10 +831,7 @@ const playQueueSlice = createSlice({
/* Used if dragging onto the first selected row. We'll need to calculate the number of selected rows above the first selected row
so we can subtract it from the spliceIndexPre value when moving it into the newQueue, which has all selected entries removed */
const spliceIndexPre = getCurrentEntryIndexByUID(
tempQueue,
action.payload.moveBeforeId
);
const spliceIndexPre = getCurrentEntryIndexByUID(tempQueue, action.payload.moveBeforeId);
const queueAbovePre = tempQueue.slice(0, spliceIndexPre);
const selectedAbovePre = queueAbovePre.filter((entry: Entry) => {
@ -909,10 +839,7 @@ const playQueueSlice = createSlice({
});
// Used if dragging onto a non-selected row
const spliceIndexPost = getCurrentEntryIndexByUID(
newQueue,
action.payload.moveBeforeId
);
const spliceIndexPost = getCurrentEntryIndexByUID(newQueue, action.payload.moveBeforeId);
/* Used if dragging onto consecutive selected rows
If the moveBeforeId index is selected, then we find the first consecutive selected index to move to */
@ -948,9 +875,7 @@ const playQueueSlice = createSlice({
});
// Sort the entries by their rowIndex so that we can re-add them in the proper order
const sortedEntries = updatedEntries.sort(
(a, b) => a.rowIndex - b.rowIndex
);
const sortedEntries = updatedEntries.sort((a, b) => a.rowIndex - b.rowIndex);
// Splice the entries into the new queue array
newQueue.splice(spliceIndex, 0, ...sortedEntries);
@ -960,10 +885,7 @@ const playQueueSlice = createSlice({
// We'll need to fix the current player index after swapping the queue order
// This will be used in conjunction with fixPlayer2Index
const newCurrentSongIndex = getCurrentEntryIndexByUID(
newQueue,
state.currentSongUniqueId
);
const newCurrentSongIndex = getCurrentEntryIndexByUID(newQueue, state.currentSongUniqueId);
if (state.currentPlayer === 1) {
state.player1.index = newCurrentSongIndex;
@ -1008,10 +930,7 @@ const playQueueSlice = createSlice({
// We'll need to fix the current player index after swapping the queue order
// This will be used in conjunction with fixPlayer2Index
const newCurrentSongIndex = getCurrentEntryIndexByUID(
tempQueue,
state.currentSongUniqueId
);
const newCurrentSongIndex = getCurrentEntryIndexByUID(tempQueue, state.currentSongUniqueId);
if (state.currentPlayer === 1) {
state.player1.index = newCurrentSongIndex;
@ -1056,10 +975,7 @@ const playQueueSlice = createSlice({
// We'll need to fix the current player index after swapping the queue order
// This will be used in conjunction with fixPlayer2Index
const newCurrentSongIndex = getCurrentEntryIndexByUID(
tempQueue,
state.currentSongUniqueId
);
const newCurrentSongIndex = getCurrentEntryIndexByUID(tempQueue, state.currentSongUniqueId);
if (state.currentPlayer === 1) {
state.player1.index = newCurrentSongIndex;

44
src/shared/utils.ts

@ -89,10 +89,7 @@ export const shuffle = (array: any[]) => {
currentIndex -= 1;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex],
array[currentIndex],
];
[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
}
return array;
@ -219,11 +216,7 @@ export const consecutiveRanges = (a: number[]) => {
return list;
};
export const moveToIndex = (
entryData: any,
selectedEntries: any,
moveBeforeId: string
) => {
export const moveToIndex = (entryData: any, selectedEntries: any, moveBeforeId: string) => {
const uniqueIds: any[] = [];
selectedEntries.map((entry: any) => uniqueIds.push(entry.uniqueId));
@ -234,19 +227,13 @@ export const moveToIndex = (
// Used if dragging onto the first selected row. We'll need to calculate the number of selected rows above the first selected row
// so we can subtract it from the spliceIndexPre value when moving it into the newList, which has all selected entries removed
const spliceIndexPre = entryData.findIndex(
(entry: any) => entry.uniqueId === moveBeforeId
);
const spliceIndexPre = entryData.findIndex((entry: any) => entry.uniqueId === moveBeforeId);
const queueAbovePre = entryData.slice(0, spliceIndexPre);
const selectedAbovePre = queueAbovePre.filter((entry: any) =>
uniqueIds.includes(entry.uniqueId)
);
const selectedAbovePre = queueAbovePre.filter((entry: any) => uniqueIds.includes(entry.uniqueId));
// Used if dragging onto a non-selected row
const spliceIndexPost = newList.findIndex(
(entry: any) => entry.uniqueId === moveBeforeId
);
const spliceIndexPost = newList.findIndex((entry: any) => entry.uniqueId === moveBeforeId);
// Used if dragging onto consecutive selected rows
// If the moveBeforeId index is selected, then we find the first consecutive selected index to move to
@ -275,16 +262,12 @@ export const moveToIndex = (
// Get the updated entry rowIndexes since dragging an entry multiple times will change the existing selected rowIndex
const updatedEntries = selectedEntries.map((entry: any) => {
const findIndex = entryData.findIndex(
(item: any) => item.uniqueId === entry.uniqueId
);
const findIndex = entryData.findIndex((item: any) => item.uniqueId === entry.uniqueId);
return { ...entry, rowIndex: findIndex };
});
// Sort the entries by their rowIndex so that we can re-add them in the proper order
const sortedEntries = updatedEntries.sort(
(a: any, b: any) => a.rowIndex - b.rowIndex
);
const sortedEntries = updatedEntries.sort((a: any, b: any) => a.rowIndex - b.rowIndex);
// Splice the entries into the new queue array
newList.splice(spliceIndex, 0, ...sortedEntries);
@ -293,21 +276,14 @@ export const moveToIndex = (
return newList;
};
export const getUpdatedEntryRowIndex = (
selectedEntries: any,
entryData: any
) => {
export const getUpdatedEntryRowIndex = (selectedEntries: any, entryData: any) => {
const updatedEntries = selectedEntries.map((entry: any) => {
const findIndex = entryData.findIndex(
(item: any) => item.uniqueId === entry.uniqueId
);
const findIndex = entryData.findIndex((item: any) => item.uniqueId === entry.uniqueId);
return { ...entry, rowIndex: findIndex };
});
// Sort the entries by their rowIndex so that we can re-add them in the proper order
const sortedEntries = updatedEntries.sort(
(a: any, b: any) => a.rowIndex - b.rowIndex
);
const sortedEntries = updatedEntries.sort((a: any, b: any) => a.rowIndex - b.rowIndex);
return sortedEntries;
};

7
yarn.lock

@ -13004,12 +13004,7 @@ yargs-parser@^18.1.2:
camelcase "^5.0.0"
decamelize "^1.2.0"
yargs-parser@^20.2.2:
version "20.2.4"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
yargs-parser@^20.2.3:
yargs-parser@^20.2.2, yargs-parser@^20.2.3:
version "20.2.9"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==

Loading…
Cancel
Save