Browse Source

Add context menu option to view song in folder

master
jeffvli 3 years ago
committed by Jeff
parent
commit
d74345f5ee
  1. 7
      src/components/library/AlbumList.tsx
  2. 7
      src/components/library/ArtistList.tsx
  3. 7
      src/components/library/ArtistView.tsx
  4. 16
      src/components/library/FolderList.tsx
  5. 1
      src/components/library/GenreList.tsx
  6. 1
      src/components/playlist/PlaylistList.tsx
  7. 180
      src/components/shared/ContextMenu.tsx
  8. 2
      src/components/viewtypes/ListViewTable.tsx
  9. 1
      src/redux/miscSlice.ts

7
src/components/library/AlbumList.tsx

@ -188,7 +188,12 @@ const AlbumList = () => {
}} }}
listType="album" listType="album"
virtualized virtualized
disabledContextMenuOptions={['moveSelectedTo', 'removeFromCurrent', 'deletePlaylist']} disabledContextMenuOptions={[
'moveSelectedTo',
'removeFromCurrent',
'deletePlaylist',
'viewInFolder',
]}
handleFavorite={handleRowFavorite} handleFavorite={handleRowFavorite}
/> />
)} )}

7
src/components/library/ArtistList.tsx

@ -131,7 +131,12 @@ const ArtistList = () => {
}} }}
listType="artist" listType="artist"
virtualized virtualized
disabledContextMenuOptions={['moveSelectedTo', 'removeFromCurrent', 'deletePlaylist']} disabledContextMenuOptions={[
'moveSelectedTo',
'removeFromCurrent',
'deletePlaylist',
'viewInFolder',
]}
handleFavorite={handleRowFavorite} handleFavorite={handleRowFavorite}
/> />
)} )}

7
src/components/library/ArtistView.tsx

@ -283,7 +283,12 @@ const ArtistView = ({ ...rest }: any) => {
}} }}
listType="album" listType="album"
isModal={rest.isModal} isModal={rest.isModal}
disabledContextMenuOptions={['removeFromCurrent', 'moveSelectedTo', 'deletePlaylist']} disabledContextMenuOptions={[
'removeFromCurrent',
'moveSelectedTo',
'deletePlaylist',
'viewInFolder',
]}
handleFavorite={handleRowFavorite} handleFavorite={handleRowFavorite}
/> />
)} )}

16
src/components/library/FolderList.tsx

@ -1,6 +1,7 @@
import React, { useState } from 'react'; import React, { useEffect, useState } from 'react';
import settings from 'electron-settings'; import settings from 'electron-settings';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
import { useHistory } from 'react-router-dom';
import { ButtonToolbar, Icon } from 'rsuite'; import { ButtonToolbar, Icon } from 'rsuite';
import { getIndexes, getMusicDirectory } from '../../api/api'; import { getIndexes, getMusicDirectory } from '../../api/api';
import PageLoader from '../loader/PageLoader'; import PageLoader from '../loader/PageLoader';
@ -19,9 +20,12 @@ import { fixPlayer2Index, setPlayQueueByRowClick } from '../../redux/playQueueSl
import { setStatus } from '../../redux/playerSlice'; import { setStatus } from '../../redux/playerSlice';
import useSearchQuery from '../../hooks/useSearchQuery'; import useSearchQuery from '../../hooks/useSearchQuery';
import { setFolder } from '../../redux/folderSlice'; import { setFolder } from '../../redux/folderSlice';
import useRouterQuery from '../../hooks/useRouterQuery';
const FolderList = () => { const FolderList = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const history = useHistory();
const query = useRouterQuery();
const folder = useAppSelector((state) => state.folder); const folder = useAppSelector((state) => state.folder);
const { isLoading, isError, data, error }: any = useQuery(['folders'], () => getIndexes(), { const { isLoading, isError, data, error }: any = useQuery(['folders'], () => getIndexes(), {
refetchOnReconnect: false, refetchOnReconnect: false,
@ -46,6 +50,12 @@ const FolderList = () => {
'path', 'path',
]); ]);
useEffect(() => {
if (query.get('folderId') !== 'null') {
dispatch(setFolder({ id: query.get('folderId') || undefined }));
}
}, [dispatch, query]);
let timeout: any = null; let timeout: any = null;
const handleRowClick = (e: any, rowData: any) => { const handleRowClick = (e: any, rowData: any) => {
if (timeout === null) { if (timeout === null) {
@ -68,6 +78,7 @@ const FolderList = () => {
dispatch(clearSelected()); dispatch(clearSelected());
if (rowData.isDir) { if (rowData.isDir) {
history.push(`/library/folder?folderId=${rowData.id}`);
dispatch(setFolder({ id: rowData.id })); dispatch(setFolder({ id: rowData.id }));
} else { } else {
dispatch( dispatch(
@ -108,6 +119,7 @@ const FolderList = () => {
valueKey="id" valueKey="id"
virtualized virtualized
onChange={(e: string) => { onChange={(e: string) => {
history.push(`/library/folder?folderId=${e}`);
dispatch(setFolder({ id: e })); dispatch(setFolder({ id: e }));
}} }}
/> />
@ -117,6 +129,7 @@ const FolderList = () => {
disabled={!folderData?.parent} disabled={!folderData?.parent}
onClick={() => { onClick={() => {
if (folderData?.parent) { if (folderData?.parent) {
history.push(`/library/folder?folderId=${folderData?.parent}`);
dispatch(setFolder({ id: folderData?.parent })); dispatch(setFolder({ id: folderData?.parent }));
} }
}} }}
@ -151,6 +164,7 @@ const FolderList = () => {
'moveSelectedTo', 'moveSelectedTo',
'removeFromCurrent', 'removeFromCurrent',
'deletePlaylist', 'deletePlaylist',
'viewInFolder',
]} ]}
/> />
</GenericPage> </GenericPage>

1
src/components/library/GenreList.tsx

@ -87,6 +87,7 @@ const GenreList = () => {
'addToFavorites', 'addToFavorites',
'removeFromFavorites', 'removeFromFavorites',
'viewInModal', 'viewInModal',
'viewInFolder',
]} ]}
/> />
)} )}

1
src/components/playlist/PlaylistList.tsx

@ -179,6 +179,7 @@ const PlaylistList = () => {
'addToFavorites', 'addToFavorites',
'removeFromFavorites', 'removeFromFavorites',
'removeFromCurrent', 'removeFromCurrent',
'viewInFolder',
]} ]}
/> />
)} )}

180
src/components/shared/ContextMenu.tsx

@ -514,6 +514,15 @@ export const GlobalContextMenu = () => {
} }
}; };
const handleViewInFolder = () => {
dispatch(setContextMenu({ show: false }));
if (misc.contextMenu.type.match('music|nowPlaying') && multiSelect.selected.length === 1) {
history.push(`/library/folder?folderId=${multiSelect.selected[0].parent}`);
} else {
notifyToast('error', 'Select only one row');
}
};
return ( return (
<> <>
{misc.contextMenu.show && ( {misc.contextMenu.show && (
@ -521,7 +530,7 @@ export const GlobalContextMenu = () => {
xPos={misc.contextMenu.xPos} xPos={misc.contextMenu.xPos}
yPos={misc.contextMenu.yPos} yPos={misc.contextMenu.yPos}
width={190} width={190}
numOfButtons={10} numOfButtons={11}
numOfDividers={3} numOfDividers={3}
> >
<ContextMenuButton <ContextMenuButton
@ -544,6 +553,90 @@ export const GlobalContextMenu = () => {
onClick={handleRemoveFromCurrent} onClick={handleRemoveFromCurrent}
disabled={misc.contextMenu.disabledOptions.includes('removeFromCurrent')} disabled={misc.contextMenu.disabledOptions.includes('removeFromCurrent')}
/> />
<Whisper
enterable
placement="autoHorizontalStart"
trigger="hover"
speaker={
<StyledPopover>
<Form>
<StyledInputGroup>
<StyledInputNumber
defaultValue={0}
min={0}
max={
misc.contextMenu.type === 'nowPlaying'
? playQueue[getCurrentEntryList(playQueue)]?.length
: playlist.entry?.length
}
value={indexToMoveTo}
onChange={(e: number) => setIndexToMoveTo(e)}
/>
<StyledButton
type="submit"
onClick={handleMoveSelectedToIndex}
disabled={
(misc.contextMenu.type === 'nowPlaying'
? indexToMoveTo > playQueue[getCurrentEntryList(playQueue)]?.length
: indexToMoveTo > playlist.entry?.length) || indexToMoveTo < 0
}
>
Go
</StyledButton>
</StyledInputGroup>
</Form>
<Grid fluid>
<Row>
<Col xs={12}>
<StyledIconButton
icon={<Icon icon="angle-double-up" />}
onClick={handleMoveToTop}
block
>
Top
</StyledIconButton>
</Col>
<Col xs={12}>
<StyledIconButton
icon={<Icon icon="angle-up" />}
onClick={handleMoveUpOne}
block
>
Up
</StyledIconButton>
</Col>
</Row>
<Row>
<Col xs={12}>
<StyledIconButton
icon={<Icon icon="angle-double-down" />}
onClick={handleMoveToBottom}
block
>
Bottom
</StyledIconButton>
</Col>
<Col xs={12}>
<StyledIconButton
icon={<Icon icon="angle-down" />}
onClick={handleMoveDownOne}
block
>
Down
</StyledIconButton>
</Col>
</Row>
</Grid>
</StyledPopover>
}
>
<ContextMenuButton
text="Move selected to [...]"
disabled={misc.contextMenu.disabledOptions.includes('moveSelectedTo')}
/>
</Whisper>
<ContextMenuDivider /> <ContextMenuDivider />
<Whisper <Whisper
@ -663,90 +756,11 @@ export const GlobalContextMenu = () => {
onClick={handleViewInModal} onClick={handleViewInModal}
disabled={misc.contextMenu.disabledOptions.includes('viewInModal')} disabled={misc.contextMenu.disabledOptions.includes('viewInModal')}
/> />
<Whisper
enterable
placement="autoHorizontalStart"
trigger="hover"
speaker={
<StyledPopover>
<Form>
<StyledInputGroup>
<StyledInputNumber
defaultValue={0}
min={0}
max={
misc.contextMenu.type === 'nowPlaying'
? playQueue[getCurrentEntryList(playQueue)]?.length
: playlist.entry?.length
}
value={indexToMoveTo}
onChange={(e: number) => setIndexToMoveTo(e)}
/>
<StyledButton
type="submit"
onClick={handleMoveSelectedToIndex}
disabled={
(misc.contextMenu.type === 'nowPlaying'
? indexToMoveTo > playQueue[getCurrentEntryList(playQueue)]?.length
: indexToMoveTo > playlist.entry?.length) || indexToMoveTo < 0
}
>
Go
</StyledButton>
</StyledInputGroup>
</Form>
<Grid fluid>
<Row>
<Col xs={12}>
<StyledIconButton
icon={<Icon icon="angle-double-up" />}
onClick={handleMoveToTop}
block
>
Top
</StyledIconButton>
</Col>
<Col xs={12}>
<StyledIconButton
icon={<Icon icon="angle-up" />}
onClick={handleMoveUpOne}
block
>
Up
</StyledIconButton>
</Col>
</Row>
<Row>
<Col xs={12}>
<StyledIconButton
icon={<Icon icon="angle-double-down" />}
onClick={handleMoveToBottom}
block
>
Bottom
</StyledIconButton>
</Col>
<Col xs={12}>
<StyledIconButton
icon={<Icon icon="angle-down" />}
onClick={handleMoveDownOne}
block
>
Down
</StyledIconButton>
</Col>
</Row>
</Grid>
</StyledPopover>
}
>
<ContextMenuButton <ContextMenuButton
text="Move selected to [...]" text="View in folder"
disabled={misc.contextMenu.disabledOptions.includes('moveSelectedTo')} onClick={handleViewInFolder}
disabled={misc.contextMenu.disabledOptions.includes('viewInFolder')}
/> />
</Whisper>
</ContextMenu> </ContextMenu>
)} )}
</> </>

2
src/components/viewtypes/ListViewTable.tsx

@ -290,7 +290,7 @@ const ListViewTable = ({
// Use the calculated ContextMenu height // Use the calculated ContextMenu height
// numOfButtons * 30 + props.numOfDividers * 1.5 // numOfButtons * 30 + props.numOfDividers * 1.5
const contextMenuHeight = 9 * 30 + 3 * 1.5; const contextMenuHeight = 11 * 30 + 3 * 1.5;
if (e.pageY + contextMenuHeight >= window.innerHeight) { if (e.pageY + contextMenuHeight >= window.innerHeight) {
pageY = e.pageY - contextMenuHeight; pageY = e.pageY - contextMenuHeight;
} else { } else {

1
src/redux/miscSlice.ts

@ -26,6 +26,7 @@ type ContextMenuOptions =
| 'addToFavorites' | 'addToFavorites'
| 'removeFromFavorites' | 'removeFromFavorites'
| 'viewInModal' | 'viewInModal'
| 'viewInFolder'
| 'moveSelectedTo'; | 'moveSelectedTo';
export interface ContextMenu { export interface ContextMenu {

Loading…
Cancel
Save