Browse Source

Add actions to add and remove context menu buttons

master
jeffvli 3 years ago
parent
commit
2e78f5f136
  1. 87
      src/components/shared/ContextMenu.tsx
  2. 59
      src/redux/playQueueSlice.ts

87
src/components/shared/ContextMenu.tsx

@ -1,5 +1,6 @@
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
import React, { useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
import _ from 'lodash';
import { useQuery, useQueryClient } from 'react-query'; import { useQuery, useQueryClient } from 'react-query';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { Popover, Whisper } from 'rsuite'; import { Popover, Whisper } from 'rsuite';
@ -10,7 +11,12 @@ import {
removeProcessingPlaylist, removeProcessingPlaylist,
setContextMenu, setContextMenu,
} from '../../redux/miscSlice'; } from '../../redux/miscSlice';
import { setStar } from '../../redux/playQueueSlice'; import {
appendPlayQueue,
fixPlayer2Index,
removeFromPlayQueue,
setStar,
} from '../../redux/playQueueSlice';
import { import {
ContextMenuDivider, ContextMenuDivider,
ContextMenuWindow, ContextMenuWindow,
@ -20,11 +26,13 @@ import {
} from './styled'; } from './styled';
import { notifyToast } from './toast'; import { notifyToast } from './toast';
import { sleep } from '../../shared/utils'; import { sleep } from '../../shared/utils';
import { setStatus } from '../../redux/playerSlice';
export const ContextMenuButton = ({ children, ...rest }: any) => { export const ContextMenuButton = ({ text, children, ...rest }: any) => {
return ( return (
<StyledContextMenuButton {...rest} appearance="subtle" size="sm" block> <StyledContextMenuButton {...rest} appearance="subtle" size="sm" block>
{children} {children}
{text}
</StyledContextMenuButton> </StyledContextMenuButton>
); );
}; };
@ -56,6 +64,7 @@ export const GlobalContextMenu = () => {
const history = useHistory(); const history = useHistory();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const playQueue = useAppSelector((state) => state.playQueue);
const misc = useAppSelector((state) => state.misc); const misc = useAppSelector((state) => state.misc);
const multiSelect = useAppSelector((state) => state.multiSelect); const multiSelect = useAppSelector((state) => state.multiSelect);
const playlistTriggerRef = useRef<any>(); const playlistTriggerRef = useRef<any>();
@ -65,6 +74,40 @@ export const GlobalContextMenu = () => {
getPlaylists('name') getPlaylists('name')
); );
const handleAddToQueue = () => {
const entriesByRowIndexAsc = _.orderBy(
multiSelect.selected,
'rowIndex',
'asc'
);
notifyToast(
'info',
`Added ${multiSelect.selected.length} song(s) to the queue`
);
dispatch(appendPlayQueue({ entries: entriesByRowIndexAsc }));
dispatch(setContextMenu({ show: false }));
};
const handleRemoveFromQueue = async () => {
dispatch(removeFromPlayQueue({ entries: multiSelect.selected }));
if (playQueue.currentPlayer === 1) {
dispatch(fixPlayer2Index());
}
dispatch(setContextMenu({ show: false }));
// If the currently playing song is removed, then the player will autostart because
// the player src changed. If that happens, automatically set the playing status
if (
_.map(multiSelect.selected, 'uniqueId').includes(
playQueue.current.uniqueId
)
) {
setTimeout(() => dispatch(setStatus('PLAYING')), 50);
}
};
const handleAddToPlaylist = async () => { const handleAddToPlaylist = async () => {
// If the window is closed, the selectedPlaylistId will be deleted // If the window is closed, the selectedPlaylistId will be deleted
const localSelectedPlaylistId = selectedPlaylistId; const localSelectedPlaylistId = selectedPlaylistId;
@ -173,12 +216,15 @@ export const GlobalContextMenu = () => {
numOfButtons={7} numOfButtons={7}
numOfDividers={3} numOfDividers={3}
> >
<ContextMenuButton> <ContextMenuButton
Selected: {multiSelect.selected.length} text={`Selected: ${multiSelect.selected.length}`}
</ContextMenuButton> />
<ContextMenuDivider /> <ContextMenuDivider />
<ContextMenuButton>Add to queue</ContextMenuButton> <ContextMenuButton text="Add to queue" onClick={handleAddToQueue} />
<ContextMenuButton>Remove from current</ContextMenuButton> <ContextMenuButton
text="Remove from current"
onClick={handleRemoveFromQueue}
/>
<ContextMenuDivider /> <ContextMenuDivider />
<Whisper <Whisper
@ -213,26 +259,27 @@ export const GlobalContextMenu = () => {
} }
> >
<ContextMenuButton <ContextMenuButton
text="Add to playlist"
onClick={() => onClick={() =>
playlistTriggerRef.current.state.isOverlayShown playlistTriggerRef.current.state.isOverlayShown
? playlistTriggerRef.current.close() ? playlistTriggerRef.current.close()
: playlistTriggerRef.current.open() : playlistTriggerRef.current.open()
} }
> />
Add to playlist
</ContextMenuButton>
</Whisper> </Whisper>
<ContextMenuDivider /> <ContextMenuDivider />
<ContextMenuButton onClick={() => handleFavorite(false)}> <ContextMenuButton
Add to favorites text="Add to favorites"
</ContextMenuButton> onClick={() => handleFavorite(false)}
<ContextMenuButton onClick={() => handleFavorite(true)}> />
Add to favorites (ordered) <ContextMenuButton
</ContextMenuButton> text="Add to favorites (ordered)"
<ContextMenuButton onClick={handleUnfavorite}> onClick={() => handleFavorite(true)}
Remove from favorites />
</ContextMenuButton> <ContextMenuButton
text="Remove from favorites"
onClick={handleUnfavorite}
/>
</ContextMenu> </ContextMenu>
</> </>
)} )}

59
src/redux/playQueueSlice.ts

@ -774,13 +774,67 @@ const playQueueSlice = createSlice({
}, },
appendPlayQueue: (state, action: PayloadAction<{ entries: Entry[] }>) => { appendPlayQueue: (state, action: PayloadAction<{ entries: Entry[] }>) => {
action.payload.entries.map((entry: any) => state.entry.push(entry)); // We'll need to update the uniqueId otherwise selecting a song with duplicates
// will select them all at once
const refreshedEntries = action.payload.entries.map((entry: any) => {
return {
...entry,
uniqueId: nanoid(),
};
});
refreshedEntries.map((entry: any) => state.entry.push(entry));
if (state.shuffle) { if (state.shuffle) {
const shuffledEntries = _.shuffle(action.payload.entries); const shuffledEntries = _.shuffle(refreshedEntries);
shuffledEntries.map((entry: any) => state.shuffledEntry.push(entry)); shuffledEntries.map((entry: any) => state.shuffledEntry.push(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.shuffledEntry = (state.shuffledEntry || []).filter(
(entry) => !uniqueIds.includes(entry.uniqueId)
);
state.sortedEntry = (state.sortedEntry || []).filter(
(entry) => !uniqueIds.includes(entry.uniqueId)
);
// If the current song is removed, then reset to the first entry
if (uniqueIds.includes(state.currentSongUniqueId)) {
if (state.sortColumn) {
state.current = { ...state.sortedEntry[0] };
state.currentSongId = state.sortedEntry[0].id;
state.currentSongUniqueId = state.sortedEntry[0].uniqueId;
} else if (state.shuffle) {
state.current = { ...state.shuffledEntry[0] };
state.currentSongId = state.shuffledEntry[0].id;
state.currentSongUniqueId = state.shuffledEntry[0].uniqueId;
} else {
state.current = { ...state.entry[0] };
state.currentSongId = state.entry[0].id;
state.currentSongUniqueId = state.entry[0].uniqueId;
}
if (state.currentPlayer === 1) {
state.player1.index = 0;
} else {
state.player2.index = 0;
}
state.currentIndex = 0;
}
},
clearPlayQueue: (state) => { clearPlayQueue: (state) => {
state.entry = []; state.entry = [];
state.shuffledEntry = []; state.shuffledEntry = [];
@ -1006,6 +1060,7 @@ export const {
setPlayQueue, setPlayQueue,
setPlayQueueByRowClick, setPlayQueueByRowClick,
appendPlayQueue, appendPlayQueue,
removeFromPlayQueue,
clearPlayQueue, clearPlayQueue,
setIsLoading, setIsLoading,
setIsLoaded, setIsLoaded,

Loading…
Cancel
Save