Add "Move to next" button to queue (#781)

This commit is contained in:
Trevor 2024-10-09 18:00:25 -07:00 committed by GitHub
parent 5e628d96c7
commit a00385e78f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 85 additions and 3 deletions

View File

@ -8,6 +8,7 @@
"deselectAll": "deselect all", "deselectAll": "deselect all",
"editPlaylist": "edit $t(entity.playlist_one)", "editPlaylist": "edit $t(entity.playlist_one)",
"goToPage": "go to page", "goToPage": "go to page",
"moveToNext": "move to next",
"moveToBottom": "move to bottom", "moveToBottom": "move to bottom",
"moveToTop": "move to top", "moveToTop": "move to top",
"refresh": "$t(common.refresh)", "refresh": "$t(common.refresh)",
@ -335,6 +336,7 @@
"deletePlaylist": "$t(action.deletePlaylist)", "deletePlaylist": "$t(action.deletePlaylist)",
"deselectAll": "$t(action.deselectAll)", "deselectAll": "$t(action.deselectAll)",
"download": "download", "download": "download",
"moveToNext": "$t(action.moveToNext)",
"moveToBottom": "$t(action.moveToBottom)", "moveToBottom": "$t(action.moveToBottom)",
"moveToTop": "$t(action.moveToTop)", "moveToTop": "$t(action.moveToTop)",
"numberSelected": "{{count}} selected", "numberSelected": "{{count}} selected",

View File

@ -2,6 +2,7 @@ import { SetContextMenuItems } from '/@/renderer/features/context-menu/events';
export const QUEUE_CONTEXT_MENU_ITEMS: SetContextMenuItems = [ export const QUEUE_CONTEXT_MENU_ITEMS: SetContextMenuItems = [
{ divider: true, id: 'removeFromQueue' }, { divider: true, id: 'removeFromQueue' },
{ id: 'moveToNextOfQueue' },
{ id: 'moveToBottomOfQueue' }, { id: 'moveToBottomOfQueue' },
{ divider: true, id: 'moveToTopOfQueue' }, { divider: true, id: 'moveToTopOfQueue' },
{ divider: true, id: 'addToPlaylist' }, { divider: true, id: 'addToPlaylist' },

View File

@ -18,6 +18,7 @@ import {
RiAddBoxFill, RiAddBoxFill,
RiAddCircleFill, RiAddCircleFill,
RiArrowDownLine, RiArrowDownLine,
RiArrowGoForwardLine,
RiArrowRightSFill, RiArrowRightSFill,
RiArrowUpLine, RiArrowUpLine,
RiDeleteBinFill, RiDeleteBinFill,
@ -609,7 +610,19 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
); );
const playbackType = usePlaybackType(); const playbackType = usePlaybackType();
const { moveToBottomOfQueue, moveToTopOfQueue, removeFromQueue } = useQueueControls(); const { moveToNextOfQueue, moveToBottomOfQueue, moveToTopOfQueue, removeFromQueue } =
useQueueControls();
const handleMoveToNext = useCallback(() => {
const uniqueIds = ctx.dataNodes?.map((row) => row.data.uniqueId);
if (!uniqueIds?.length) return;
const playerData = moveToNextOfQueue(uniqueIds);
if (playbackType === PlaybackType.LOCAL) {
setQueueNext(playerData);
}
}, [ctx.dataNodes, moveToNextOfQueue, playbackType]);
const handleMoveToBottom = useCallback(() => { const handleMoveToBottom = useCallback(() => {
const uniqueIds = ctx.dataNodes?.map((row) => row.data.uniqueId); const uniqueIds = ctx.dataNodes?.map((row) => row.data.uniqueId);
@ -758,6 +771,12 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
leftIcon: <RiArrowDownLine size="1.1rem" />, leftIcon: <RiArrowDownLine size="1.1rem" />,
onClick: handleMoveToBottom, onClick: handleMoveToBottom,
}, },
moveToNextOfQueue: {
id: 'moveToNext',
label: t('page.contextMenu.moveToNext', { postProcess: 'sentenceCase' }),
leftIcon: <RiArrowGoForwardLine size="1.1rem" />,
onClick: handleMoveToNext,
},
moveToTopOfQueue: { moveToTopOfQueue: {
id: 'moveToTopOfQueue', id: 'moveToTopOfQueue',
label: t('page.contextMenu.moveToTop', { postProcess: 'sentenceCase' }), label: t('page.contextMenu.moveToTop', { postProcess: 'sentenceCase' }),
@ -904,6 +923,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
handleDeselectAll, handleDeselectAll,
ctx.data, ctx.data,
handleDownload, handleDownload,
handleMoveToNext,
handleMoveToBottom, handleMoveToBottom,
handleMoveToTop, handleMoveToTop,
handleSimilar, handleSimilar,

View File

@ -32,6 +32,7 @@ export type ContextMenuItemType =
| 'shareItem' | 'shareItem'
| 'deletePlaylist' | 'deletePlaylist'
| 'createPlaylist' | 'createPlaylist'
| 'moveToNextOfQueue'
| 'moveToBottomOfQueue' | 'moveToBottomOfQueue'
| 'moveToTopOfQueue' | 'moveToTopOfQueue'
| 'removeFromQueue' | 'removeFromQueue'

View File

@ -6,6 +6,7 @@ import isElectron from 'is-electron';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
RiArrowDownLine, RiArrowDownLine,
RiArrowGoForwardLine,
RiArrowUpLine, RiArrowUpLine,
RiShuffleLine, RiShuffleLine,
RiDeleteBinLine, RiDeleteBinLine,
@ -30,14 +31,32 @@ interface PlayQueueListOptionsProps {
export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsProps) => { export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { clearQueue, moveToBottomOfQueue, moveToTopOfQueue, shuffleQueue, removeFromQueue } = const {
useQueueControls(); clearQueue,
moveToBottomOfQueue,
moveToNextOfQueue,
moveToTopOfQueue,
shuffleQueue,
removeFromQueue,
} = useQueueControls();
const { pause } = usePlayerControls(); const { pause } = usePlayerControls();
const playbackType = usePlaybackType(); const playbackType = usePlaybackType();
const setCurrentTime = useSetCurrentTime(); const setCurrentTime = useSetCurrentTime();
const handleMoveToNext = () => {
const selectedRows = tableRef?.current?.grid.api.getSelectedRows();
const uniqueIds = selectedRows?.map((row) => row.uniqueId);
if (!uniqueIds?.length) return;
const playerData = moveToNextOfQueue(uniqueIds);
if (playbackType === PlaybackType.LOCAL) {
setQueueNext(playerData);
}
};
const handleMoveToBottom = () => { const handleMoveToBottom = () => {
const selectedRows = tableRef?.current?.grid.api.getSelectedRows(); const selectedRows = tableRef?.current?.grid.api.getSelectedRows();
const uniqueIds = selectedRows?.map((row) => row.uniqueId); const uniqueIds = selectedRows?.map((row) => row.uniqueId);
@ -124,6 +143,15 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
> >
<RiShuffleLine size="1.1rem" /> <RiShuffleLine size="1.1rem" />
</Button> </Button>
<Button
compact
size="md"
tooltip={{ label: t('action.moveToNext', { postProcess: 'sentenceCase' }) }}
variant="default"
onClick={handleMoveToNext}
>
<RiArrowGoForwardLine size="1.1rem" />
</Button>
<Button <Button
compact compact
size="md" size="md"

View File

@ -72,6 +72,7 @@ export interface PlayerSlice extends PlayerState {
getQueueData: () => QueueData; getQueueData: () => QueueData;
incrementPlayCount: (ids: string[]) => string[]; incrementPlayCount: (ids: string[]) => string[];
moveToBottomOfQueue: (uniqueIds: string[]) => PlayerData; moveToBottomOfQueue: (uniqueIds: string[]) => PlayerData;
moveToNextOfQueue: (uniqueIds: string[]) => PlayerData;
moveToTopOfQueue: (uniqueIds: string[]) => PlayerData; moveToTopOfQueue: (uniqueIds: string[]) => PlayerData;
next: () => PlayerData; next: () => PlayerData;
pause: () => void; pause: () => void;
@ -536,6 +537,34 @@ export const usePlayerStore = create<PlayerSlice>()(
return get().actions.getPlayerData(); return get().actions.getPlayerData();
}, },
moveToNextOfQueue: (uniqueIds) => {
const queue = get().queue.default;
const songsToMove = queue.filter((song) =>
uniqueIds.includes(song.uniqueId),
);
const currentSong = get().current.song;
const currentPosition =
get().current.index -
queue
.slice(0, get().current.index)
.filter((song) => uniqueIds.includes(song.uniqueId)).length;
const songsToStay = queue.filter(
(song) => !uniqueIds.includes(song.uniqueId),
);
const newQueue = [
...songsToStay.slice(0, currentPosition + 1),
...songsToMove,
...songsToStay.slice(currentPosition + 1),
];
const newCurrentSongIndex = newQueue.findIndex(
(song) => song.uniqueId === currentSong?.uniqueId,
);
set((state) => {
state.queue.default = newQueue;
state.current.index = newCurrentSongIndex;
});
return get().actions.getPlayerData();
},
moveToTopOfQueue: (uniqueIds) => { moveToTopOfQueue: (uniqueIds) => {
const queue = get().queue.default; const queue = get().queue.default;
@ -1076,6 +1105,7 @@ export const useQueueControls = () =>
addToQueue: state.actions.addToQueue, addToQueue: state.actions.addToQueue,
clearQueue: state.actions.clearQueue, clearQueue: state.actions.clearQueue,
moveToBottomOfQueue: state.actions.moveToBottomOfQueue, moveToBottomOfQueue: state.actions.moveToBottomOfQueue,
moveToNextOfQueue: state.actions.moveToNextOfQueue,
moveToTopOfQueue: state.actions.moveToTopOfQueue, moveToTopOfQueue: state.actions.moveToTopOfQueue,
removeFromQueue: state.actions.removeFromQueue, removeFromQueue: state.actions.removeFromQueue,
reorderQueue: state.actions.reorderQueue, reorderQueue: state.actions.reorderQueue,