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
>
+