diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 3cd1d056..383c5dc8 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -8,6 +8,7 @@ "deselectAll": "deselect all", "editPlaylist": "edit $t(entity.playlist_one)", "goToPage": "go to page", + "moveToNext": "move to next", "moveToBottom": "move to bottom", "moveToTop": "move to top", "refresh": "$t(common.refresh)", @@ -335,6 +336,7 @@ "deletePlaylist": "$t(action.deletePlaylist)", "deselectAll": "$t(action.deselectAll)", "download": "download", + "moveToNext": "$t(action.moveToNext)", "moveToBottom": "$t(action.moveToBottom)", "moveToTop": "$t(action.moveToTop)", "numberSelected": "{{count}} selected", diff --git a/src/renderer/features/context-menu/context-menu-items.tsx b/src/renderer/features/context-menu/context-menu-items.tsx index 12eb1673..9adfbd0a 100644 --- a/src/renderer/features/context-menu/context-menu-items.tsx +++ b/src/renderer/features/context-menu/context-menu-items.tsx @@ -2,6 +2,7 @@ import { SetContextMenuItems } from '/@/renderer/features/context-menu/events'; export const QUEUE_CONTEXT_MENU_ITEMS: SetContextMenuItems = [ { divider: true, id: 'removeFromQueue' }, + { id: 'moveToNextOfQueue' }, { id: 'moveToBottomOfQueue' }, { divider: true, id: 'moveToTopOfQueue' }, { divider: true, id: 'addToPlaylist' }, diff --git a/src/renderer/features/context-menu/context-menu-provider.tsx b/src/renderer/features/context-menu/context-menu-provider.tsx index c4cc6b80..9a9065a3 100644 --- a/src/renderer/features/context-menu/context-menu-provider.tsx +++ b/src/renderer/features/context-menu/context-menu-provider.tsx @@ -18,6 +18,7 @@ import { RiAddBoxFill, RiAddCircleFill, RiArrowDownLine, + RiArrowGoForwardLine, RiArrowRightSFill, RiArrowUpLine, RiDeleteBinFill, @@ -609,7 +610,19 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => { ); 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 uniqueIds = ctx.dataNodes?.map((row) => row.data.uniqueId); @@ -758,6 +771,12 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => { leftIcon: , onClick: handleMoveToBottom, }, + moveToNextOfQueue: { + id: 'moveToNext', + label: t('page.contextMenu.moveToNext', { postProcess: 'sentenceCase' }), + leftIcon: , + onClick: handleMoveToNext, + }, moveToTopOfQueue: { id: 'moveToTopOfQueue', label: t('page.contextMenu.moveToTop', { postProcess: 'sentenceCase' }), @@ -904,6 +923,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => { handleDeselectAll, ctx.data, handleDownload, + handleMoveToNext, handleMoveToBottom, handleMoveToTop, handleSimilar, diff --git a/src/renderer/features/context-menu/events.ts b/src/renderer/features/context-menu/events.ts index 35884fbb..a31949d8 100644 --- a/src/renderer/features/context-menu/events.ts +++ b/src/renderer/features/context-menu/events.ts @@ -32,6 +32,7 @@ export type ContextMenuItemType = | 'shareItem' | 'deletePlaylist' | 'createPlaylist' + | 'moveToNextOfQueue' | 'moveToBottomOfQueue' | 'moveToTopOfQueue' | 'removeFromQueue' diff --git a/src/renderer/features/now-playing/components/play-queue-list-controls.tsx b/src/renderer/features/now-playing/components/play-queue-list-controls.tsx index e69e25fb..eb42bde0 100644 --- a/src/renderer/features/now-playing/components/play-queue-list-controls.tsx +++ b/src/renderer/features/now-playing/components/play-queue-list-controls.tsx @@ -6,6 +6,7 @@ import isElectron from 'is-electron'; import { useTranslation } from 'react-i18next'; import { RiArrowDownLine, + RiArrowGoForwardLine, RiArrowUpLine, RiShuffleLine, RiDeleteBinLine, @@ -30,14 +31,32 @@ interface PlayQueueListOptionsProps { export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsProps) => { const { t } = useTranslation(); - const { clearQueue, moveToBottomOfQueue, moveToTopOfQueue, shuffleQueue, removeFromQueue } = - useQueueControls(); + const { + clearQueue, + moveToBottomOfQueue, + moveToNextOfQueue, + moveToTopOfQueue, + shuffleQueue, + removeFromQueue, + } = useQueueControls(); const { pause } = usePlayerControls(); const playbackType = usePlaybackType(); 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 selectedRows = tableRef?.current?.grid.api.getSelectedRows(); const uniqueIds = selectedRows?.map((row) => row.uniqueId); @@ -124,6 +143,15 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr > +