feat: improve native macOS application menu (#2242)

This commit is contained in:
York
2026-07-18 10:20:17 +08:00
committed by GitHub
parent 75bdf60912
commit 7cff72910e
4 changed files with 215 additions and 132 deletions
+24 -15
View File
@@ -328,7 +328,7 @@ ipcMain.on('input-focus-state', (_event, focused: boolean) => {
if (inputFocused === next) return; if (inputFocused === next) return;
inputFocused = next; inputFocused = next;
if (isMacOS()) { if (isMacOS()) {
rebuildMainMenu(); updateMainMenu();
} }
}); });
@@ -387,11 +387,9 @@ export const getMainWindow = () => {
return mainWindow; return mainWindow;
}; };
const rebuildMainMenu = () => { const getMainMenuState = (): MenuPlaybackState => ({
if (!menuBuilder || !mainWindow) return; accelerators: playbackMenuAccelerators,
inputFocused,
menuBuilder.buildMenu({
accelerators: inputFocused ? {} : playbackMenuAccelerators,
playbackStatus: currentPlaybackStatus, playbackStatus: currentPlaybackStatus,
privateMode: currentPrivateMode, privateMode: currentPrivateMode,
repeatMode: currentRepeatMode, repeatMode: currentRepeatMode,
@@ -399,11 +397,22 @@ const rebuildMainMenu = () => {
sidebarCollapsed: currentSidebarCollapsed, sidebarCollapsed: currentSidebarCollapsed,
}); });
const rebuildMainMenu = () => {
if (!menuBuilder || !mainWindow) return;
menuBuilder.buildMenu(getMainMenuState());
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
Menu.setApplicationMenu(null); Menu.setApplicationMenu(null);
} }
}; };
const updateMainMenu = () => {
if (!menuBuilder || !mainWindow) return;
menuBuilder.updateMenu(getMainMenuState());
};
export const sendToastToRenderer = ({ export const sendToastToRenderer = ({
message, message,
type, type,
@@ -961,11 +970,11 @@ ipcMain.on(
} }
playbackMenuAccelerators = { playbackMenuAccelerators = {
globalSearch: getMenuAccelerator(data, BindingActions.GLOBAL_SEARCH),
next: getMenuAccelerator(data, BindingActions.NEXT), next: getMenuAccelerator(data, BindingActions.NEXT),
playPause: pause: getMenuAccelerator(data, BindingActions.PAUSE),
getMenuAccelerator(data, BindingActions.PLAY_PAUSE) || play: getMenuAccelerator(data, BindingActions.PLAY),
getMenuAccelerator(data, BindingActions.PLAY) || playPause: getMenuAccelerator(data, BindingActions.PLAY_PAUSE),
getMenuAccelerator(data, BindingActions.PAUSE),
previous: getMenuAccelerator(data, BindingActions.PREVIOUS), previous: getMenuAccelerator(data, BindingActions.PREVIOUS),
repeat: getMenuAccelerator(data, BindingActions.TOGGLE_REPEAT), repeat: getMenuAccelerator(data, BindingActions.TOGGLE_REPEAT),
seekBackward: getMenuAccelerator(data, BindingActions.SKIP_BACKWARD), seekBackward: getMenuAccelerator(data, BindingActions.SKIP_BACKWARD),
@@ -1186,7 +1195,7 @@ ipcMain.on('update-playback', (_event, status: PlayerStatus) => {
if (!isMacOS()) return; if (!isMacOS()) return;
rebuildMainMenu(); updateMainMenu();
}); });
ipcMain.on('update-repeat', (_event, repeat: PlayerRepeat) => { ipcMain.on('update-repeat', (_event, repeat: PlayerRepeat) => {
@@ -1194,7 +1203,7 @@ ipcMain.on('update-repeat', (_event, repeat: PlayerRepeat) => {
if (!isMacOS()) return; if (!isMacOS()) return;
rebuildMainMenu(); updateMainMenu();
}); });
ipcMain.on('update-shuffle', (_event, shuffle: boolean) => { ipcMain.on('update-shuffle', (_event, shuffle: boolean) => {
@@ -1202,7 +1211,7 @@ ipcMain.on('update-shuffle', (_event, shuffle: boolean) => {
if (!isMacOS()) return; if (!isMacOS()) return;
rebuildMainMenu(); updateMainMenu();
}); });
ipcMain.on('update-private-mode', (_event, privateMode: boolean) => { ipcMain.on('update-private-mode', (_event, privateMode: boolean) => {
@@ -1210,7 +1219,7 @@ ipcMain.on('update-private-mode', (_event, privateMode: boolean) => {
if (!isMacOS()) return; if (!isMacOS()) return;
rebuildMainMenu(); updateMainMenu();
}); });
ipcMain.on('update-sidebar-collapsed', (_event, collapsedSidebar: boolean) => { ipcMain.on('update-sidebar-collapsed', (_event, collapsedSidebar: boolean) => {
@@ -1218,5 +1227,5 @@ ipcMain.on('update-sidebar-collapsed', (_event, collapsedSidebar: boolean) => {
if (!isMacOS()) return; if (!isMacOS()) return;
rebuildMainMenu(); updateMainMenu();
}); });
+165 -113
View File
@@ -1,4 +1,4 @@
import { app, BrowserWindow, Menu, MenuItemConstructorOptions, shell } from 'electron'; import { BrowserWindow, Menu, MenuItemConstructorOptions, shell } from 'electron';
import packageJson from '../../package.json'; import packageJson from '../../package.json';
@@ -6,7 +6,10 @@ import { PlayerRepeat, PlayerStatus } from '/@/shared/types/types';
export type MenuPlaybackState = { export type MenuPlaybackState = {
accelerators?: { accelerators?: {
globalSearch?: string;
next?: string; next?: string;
pause?: string;
play?: string;
playPause?: string; playPause?: string;
previous?: string; previous?: string;
repeat?: string; repeat?: string;
@@ -17,6 +20,7 @@ export type MenuPlaybackState = {
volumeDown?: string; volumeDown?: string;
volumeUp?: string; volumeUp?: string;
}; };
inputFocused?: boolean;
playbackStatus?: PlayerStatus; playbackStatus?: PlayerStatus;
privateMode?: boolean; privateMode?: boolean;
repeatMode?: PlayerRepeat; repeatMode?: PlayerRepeat;
@@ -24,12 +28,53 @@ export type MenuPlaybackState = {
sidebarCollapsed?: boolean; sidebarCollapsed?: boolean;
}; };
interface DarwinMenuItemConstructorOptions extends MenuItemConstructorOptions { const MENU_ITEM_IDS = {
selector?: string; next: 'playback-next',
submenu?: DarwinMenuItemConstructorOptions[] | Menu; pause: 'playback-pause',
play: 'playback-play',
previous: 'playback-previous',
privateMode: 'app-private-mode',
repeat: 'playback-repeat',
seekBackward: 'playback-seek-backward',
seekForward: 'playback-seek-forward',
shuffle: 'playback-shuffle',
sidebarCollapsed: 'view-sidebar-collapsed',
stop: 'playback-stop',
volumeDown: 'playback-volume-down',
volumeUp: 'playback-volume-up',
} as const;
const NON_TYPING_MODIFIERS = new Set([
'alt',
'cmd',
'command',
'commandorcontrol',
'control',
'ctrl',
'meta',
'option',
'super',
]);
const hasTypingSensitiveAccelerator = (accelerator?: string): boolean => {
if (!accelerator) return false;
const parts = accelerator.toLowerCase().split('+');
const key = parts.at(-1) || '';
if (/^f(?:[1-9]|1\d|2[0-4])$/.test(key) || /^(?:media|volume)/.test(key)) {
return false;
} }
return !parts.some((part) => NON_TYPING_MODIFIERS.has(part));
};
const isPlaybackItemEnabled = (inputFocused: boolean, accelerator?: string): boolean => {
return !inputFocused || !hasTypingSensitiveAccelerator(accelerator);
};
export default class MenuBuilder { export default class MenuBuilder {
applicationMenu: Menu | null = null;
developmentEnvironmentSetup = false; developmentEnvironmentSetup = false;
mainWindow: BrowserWindow; mainWindow: BrowserWindow;
@@ -39,6 +84,7 @@ export default class MenuBuilder {
buildDarwinTemplate({ buildDarwinTemplate({
accelerators, accelerators,
inputFocused = false,
playbackStatus = PlayerStatus.PAUSED, playbackStatus = PlayerStatus.PAUSED,
privateMode = false, privateMode = false,
repeatMode = PlayerRepeat.NONE, repeatMode = PlayerRepeat.NONE,
@@ -48,13 +94,10 @@ export default class MenuBuilder {
const isPlaying = playbackStatus === PlayerStatus.PLAYING; const isPlaying = playbackStatus === PlayerStatus.PLAYING;
const isRepeatEnabled = repeatMode !== PlayerRepeat.NONE; const isRepeatEnabled = repeatMode !== PlayerRepeat.NONE;
const subMenuAbout: DarwinMenuItemConstructorOptions = { const subMenuAbout: MenuItemConstructorOptions = {
label: 'Electron', label: 'Electron',
submenu: [ submenu: [
{ { role: 'about' },
label: 'About Feishin',
selector: 'orderFrontStandardAboutPanel:',
},
{ type: 'separator' }, { type: 'separator' },
{ {
accelerator: 'Command+,', accelerator: 'Command+,',
@@ -68,61 +111,44 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-open-manage-servers'); this.mainWindow.webContents.send('renderer-open-manage-servers');
}, },
label: 'Manage servers', label: 'Manage Servers',
}, },
{ {
checked: privateMode, checked: privateMode,
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-toggle-private-mode'); this.mainWindow.webContents.send('renderer-toggle-private-mode');
}, },
label: 'Private session', id: MENU_ITEM_IDS.privateMode,
label: 'Private Session',
type: 'checkbox', type: 'checkbox',
}, },
{ type: 'separator' }, { type: 'separator' },
{ label: 'Services', submenu: [] }, { role: 'services' },
{ type: 'separator' }, { type: 'separator' },
{ { role: 'hide' },
accelerator: 'Command+H', { role: 'hideOthers' },
label: 'Hide Feishin', { role: 'unhide' },
selector: 'hide:',
},
{
accelerator: 'Command+Shift+H',
label: 'Hide Others',
selector: 'hideOtherApplications:',
},
{ label: 'Show All', selector: 'unhideAllApplications:' },
{ type: 'separator' }, { type: 'separator' },
{ { role: 'quit' },
accelerator: 'Command+Q',
click: () => {
app.quit();
},
label: 'Quit',
},
], ],
}; };
const subMenuEdit: DarwinMenuItemConstructorOptions = { const subMenuFile: MenuItemConstructorOptions = {
label: 'Edit', label: 'File',
submenu: [ submenu: [
{ accelerator: 'Command+Z', label: 'Undo', selector: 'undo:' },
{ accelerator: 'Shift+Command+Z', label: 'Redo', selector: 'redo:' },
{ type: 'separator' },
{ accelerator: 'Command+X', label: 'Cut', selector: 'cut:' },
{ accelerator: 'Command+C', label: 'Copy', selector: 'copy:' },
{ accelerator: 'Command+V', label: 'Paste', selector: 'paste:' },
{ {
accelerator: 'Command+A', click: () => {
label: 'Select All', this.mainWindow.webContents.send('renderer-open-create-playlist');
selector: 'selectAll:', },
label: 'Create Playlist...',
}, },
], ],
}; };
const subMenuViewDev: MenuItemConstructorOptions = { const subMenuEdit: MenuItemConstructorOptions = { role: 'editMenu' };
const subMenuView: MenuItemConstructorOptions = {
label: 'View', label: 'View',
submenu: [ submenu: [
{ {
accelerator: 'Command+K', accelerator: accelerators?.globalSearch,
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-open-command-palette'); this.mainWindow.webContents.send('renderer-open-command-palette');
}, },
@@ -133,83 +159,47 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-toggle-sidebar'); this.mainWindow.webContents.send('renderer-toggle-sidebar');
}, },
label: 'Collapse sidebar', id: MENU_ITEM_IDS.sidebarCollapsed,
label: 'Collapse Sidebar',
type: 'checkbox', type: 'checkbox',
}, },
{ type: 'separator' }, { type: 'separator' },
{ role: 'togglefullscreen' },
{ {
accelerator: 'Command+R', label: 'Developer',
click: () => { submenu: [{ role: 'reload' }, { role: 'toggleDevTools' }],
this.mainWindow.webContents.reload();
},
label: 'Reload',
},
{
accelerator: 'Ctrl+Command+F',
click: () => {
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
},
label: 'Toggle Full Screen',
},
{
accelerator: 'Alt+Command+I',
click: () => {
this.mainWindow.webContents.toggleDevTools();
},
label: 'Toggle Developer Tools',
}, },
], ],
}; };
const subMenuViewProd: MenuItemConstructorOptions = { const subMenuWindow: MenuItemConstructorOptions = { role: 'windowMenu' };
label: 'View',
submenu: [
{
accelerator: 'Command+K',
click: () => {
this.mainWindow.webContents.send('renderer-open-command-palette');
},
label: 'Command Palette...',
},
{
checked: sidebarCollapsed,
click: () => {
this.mainWindow.webContents.send('renderer-toggle-sidebar');
},
label: 'Collapse sidebar',
type: 'checkbox',
},
{ type: 'separator' },
{
accelerator: 'Ctrl+Command+F',
click: () => {
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
},
label: 'Toggle Full Screen',
},
],
};
const subMenuWindow: DarwinMenuItemConstructorOptions = {
label: 'Window',
submenu: [
{
accelerator: 'Command+M',
label: 'Minimize',
selector: 'performMiniaturize:',
},
{ accelerator: 'Command+W', label: 'Close', selector: 'performClose:' },
{ type: 'separator' },
{ label: 'Bring All to Front', selector: 'arrangeInFront:' },
],
};
const subMenuPlayback: MenuItemConstructorOptions = { const subMenuPlayback: MenuItemConstructorOptions = {
label: 'Playback', label: 'Playback',
submenu: [ submenu: [
{ {
accelerator: accelerators?.playPause, accelerator: accelerators?.play || accelerators?.playPause,
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-player-play-pause'); this.mainWindow.webContents.send('renderer-player-play');
}, },
label: isPlaying ? 'Pause' : 'Play', enabled: isPlaybackItemEnabled(
inputFocused,
accelerators?.play || accelerators?.playPause,
),
id: MENU_ITEM_IDS.play,
label: 'Play',
visible: !isPlaying,
},
{
accelerator: accelerators?.pause || accelerators?.playPause,
click: () => {
this.mainWindow.webContents.send('renderer-player-pause');
},
enabled: isPlaybackItemEnabled(
inputFocused,
accelerators?.pause || accelerators?.playPause,
),
id: MENU_ITEM_IDS.pause,
label: 'Pause',
visible: isPlaying,
}, },
{ type: 'separator' }, { type: 'separator' },
{ {
@@ -217,6 +207,8 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-player-next'); this.mainWindow.webContents.send('renderer-player-next');
}, },
enabled: isPlaybackItemEnabled(inputFocused, accelerators?.next),
id: MENU_ITEM_IDS.next,
label: 'Next', label: 'Next',
}, },
{ {
@@ -224,6 +216,8 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-player-previous'); this.mainWindow.webContents.send('renderer-player-previous');
}, },
enabled: isPlaybackItemEnabled(inputFocused, accelerators?.previous),
id: MENU_ITEM_IDS.previous,
label: 'Previous', label: 'Previous',
}, },
{ {
@@ -231,6 +225,8 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-player-skip-forward'); this.mainWindow.webContents.send('renderer-player-skip-forward');
}, },
enabled: isPlaybackItemEnabled(inputFocused, accelerators?.seekForward),
id: MENU_ITEM_IDS.seekForward,
label: 'Seek Forward', label: 'Seek Forward',
}, },
{ {
@@ -238,6 +234,8 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-player-skip-backward'); this.mainWindow.webContents.send('renderer-player-skip-backward');
}, },
enabled: isPlaybackItemEnabled(inputFocused, accelerators?.seekBackward),
id: MENU_ITEM_IDS.seekBackward,
label: 'Seek Backforward', label: 'Seek Backforward',
}, },
{ type: 'separator' }, { type: 'separator' },
@@ -247,6 +245,8 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-player-toggle-shuffle'); this.mainWindow.webContents.send('renderer-player-toggle-shuffle');
}, },
enabled: isPlaybackItemEnabled(inputFocused, accelerators?.shuffle),
id: MENU_ITEM_IDS.shuffle,
label: 'Shuffle', label: 'Shuffle',
type: 'checkbox', type: 'checkbox',
}, },
@@ -256,6 +256,8 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-player-toggle-repeat'); this.mainWindow.webContents.send('renderer-player-toggle-repeat');
}, },
enabled: isPlaybackItemEnabled(inputFocused, accelerators?.repeat),
id: MENU_ITEM_IDS.repeat,
label: 'Repeat', label: 'Repeat',
type: 'checkbox', type: 'checkbox',
}, },
@@ -265,6 +267,8 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-player-stop'); this.mainWindow.webContents.send('renderer-player-stop');
}, },
enabled: isPlaybackItemEnabled(inputFocused, accelerators?.stop),
id: MENU_ITEM_IDS.stop,
label: 'Stop', label: 'Stop',
}, },
{ type: 'separator' }, { type: 'separator' },
@@ -273,6 +277,8 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-player-volume-up'); this.mainWindow.webContents.send('renderer-player-volume-up');
}, },
enabled: isPlaybackItemEnabled(inputFocused, accelerators?.volumeUp),
id: MENU_ITEM_IDS.volumeUp,
label: 'Volume Up', label: 'Volume Up',
}, },
{ {
@@ -280,12 +286,14 @@ export default class MenuBuilder {
click: () => { click: () => {
this.mainWindow.webContents.send('renderer-player-volume-down'); this.mainWindow.webContents.send('renderer-player-volume-down');
}, },
enabled: isPlaybackItemEnabled(inputFocused, accelerators?.volumeDown),
id: MENU_ITEM_IDS.volumeDown,
label: 'Volume Down', label: 'Volume Down',
}, },
], ],
}; };
const subMenuHelp: MenuItemConstructorOptions = { const subMenuHelp: MenuItemConstructorOptions = {
label: 'Help', role: 'help',
submenu: [ submenu: [
{ {
click() { click() {
@@ -323,13 +331,9 @@ export default class MenuBuilder {
], ],
}; };
const subMenuView =
process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'
? subMenuViewDev
: subMenuViewProd;
return [ return [
subMenuAbout, subMenuAbout,
subMenuFile,
subMenuEdit, subMenuEdit,
subMenuView, subMenuView,
subMenuPlayback, subMenuPlayback,
@@ -452,6 +456,7 @@ export default class MenuBuilder {
: this.buildDefaultTemplate(); : this.buildDefaultTemplate();
const menu = Menu.buildFromTemplate(template); const menu = Menu.buildFromTemplate(template);
this.applicationMenu = menu;
Menu.setApplicationMenu(menu); Menu.setApplicationMenu(menu);
return menu; return menu;
@@ -478,4 +483,51 @@ export default class MenuBuilder {
]).popup({ window: this.mainWindow }); ]).popup({ window: this.mainWindow });
}); });
} }
updateMenu({
accelerators,
inputFocused = false,
playbackStatus = PlayerStatus.PAUSED,
privateMode = false,
repeatMode = PlayerRepeat.NONE,
shuffleEnabled = false,
sidebarCollapsed = false,
}: MenuPlaybackState = {}): void {
if (process.platform !== 'darwin' || !this.applicationMenu) {
return;
}
const privateModeItem = this.applicationMenu.getMenuItemById(MENU_ITEM_IDS.privateMode);
const sidebarItem = this.applicationMenu.getMenuItemById(MENU_ITEM_IDS.sidebarCollapsed);
const pauseItem = this.applicationMenu.getMenuItemById(MENU_ITEM_IDS.pause);
const playItem = this.applicationMenu.getMenuItemById(MENU_ITEM_IDS.play);
const repeatItem = this.applicationMenu.getMenuItemById(MENU_ITEM_IDS.repeat);
const shuffleItem = this.applicationMenu.getMenuItemById(MENU_ITEM_IDS.shuffle);
if (privateModeItem) privateModeItem.checked = privateMode;
if (sidebarItem) sidebarItem.checked = sidebarCollapsed;
if (pauseItem) pauseItem.visible = playbackStatus === PlayerStatus.PLAYING;
if (playItem) playItem.visible = playbackStatus !== PlayerStatus.PLAYING;
if (repeatItem) repeatItem.checked = repeatMode !== PlayerRepeat.NONE;
if (shuffleItem) shuffleItem.checked = shuffleEnabled;
const playbackAccelerators = [
[MENU_ITEM_IDS.play, accelerators?.play || accelerators?.playPause],
[MENU_ITEM_IDS.pause, accelerators?.pause || accelerators?.playPause],
[MENU_ITEM_IDS.next, accelerators?.next],
[MENU_ITEM_IDS.previous, accelerators?.previous],
[MENU_ITEM_IDS.seekForward, accelerators?.seekForward],
[MENU_ITEM_IDS.seekBackward, accelerators?.seekBackward],
[MENU_ITEM_IDS.shuffle, accelerators?.shuffle],
[MENU_ITEM_IDS.repeat, accelerators?.repeat],
[MENU_ITEM_IDS.stop, accelerators?.stop],
[MENU_ITEM_IDS.volumeUp, accelerators?.volumeUp],
[MENU_ITEM_IDS.volumeDown, accelerators?.volumeDown],
] as const;
for (const [id, accelerator] of playbackAccelerators) {
const item = this.applicationMenu.getMenuItemById(id);
if (item) item.enabled = isPlaybackItemEnabled(inputFocused, accelerator);
}
}
} }
+5
View File
@@ -138,6 +138,10 @@ const rendererOpenManageServers = (cb: () => void) => {
ipcRenderer.on('renderer-open-manage-servers', () => cb()); ipcRenderer.on('renderer-open-manage-servers', () => cb());
}; };
const rendererOpenCreatePlaylist = (cb: () => void) => {
ipcRenderer.on('renderer-open-create-playlist', () => cb());
};
const rendererTogglePrivateMode = (cb: () => void) => { const rendererTogglePrivateMode = (cb: () => void) => {
ipcRenderer.on('renderer-toggle-private-mode', cb); ipcRenderer.on('renderer-toggle-private-mode', cb);
}; };
@@ -175,6 +179,7 @@ export const utils = {
readLocalImage, readLocalImage,
readSongMetadataBatch, readSongMetadataBatch,
rendererOpenCommandPalette, rendererOpenCommandPalette,
rendererOpenCreatePlaylist,
rendererOpenManageServers, rendererOpenManageServers,
rendererOpenReleaseNotes, rendererOpenReleaseNotes,
rendererOpenSettings, rendererOpenSettings,
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';
import packageJson from '../../../package.json'; import packageJson from '../../../package.json';
import { openCreatePlaylistModal } from '/@/renderer/features/playlists/components/create-playlist-form';
import { ServerList } from '/@/renderer/features/servers/components/server-list'; import { ServerList } from '/@/renderer/features/servers/components/server-list';
import { openSettingsModal } from '/@/renderer/features/settings/utils/open-settings-modal'; import { openSettingsModal } from '/@/renderer/features/settings/utils/open-settings-modal';
import { openReleaseNotesModal } from '/@/renderer/release-notes-modal'; import { openReleaseNotesModal } from '/@/renderer/release-notes-modal';
@@ -12,6 +13,7 @@ import {
useAppStore, useAppStore,
useAppStoreActions, useAppStoreActions,
useCommandPalette, useCommandPalette,
useCurrentServer,
usePlayerHydrated, usePlayerHydrated,
usePlayerRepeat, usePlayerRepeat,
usePlayerShuffle, usePlayerShuffle,
@@ -27,6 +29,7 @@ export const useNativeMenuSync = () => {
const sidebar = useAppStore((state) => state.sidebar); const sidebar = useAppStore((state) => state.sidebar);
const { setPrivateMode, setSideBar } = useAppStoreActions(); const { setPrivateMode, setSideBar } = useAppStoreActions();
const { open: openCommandPalette } = useCommandPalette(); const { open: openCommandPalette } = useCommandPalette();
const server = useCurrentServer();
const playerHydrated = usePlayerHydrated(); const playerHydrated = usePlayerHydrated();
const playerRepeat = usePlayerRepeat(); const playerRepeat = usePlayerRepeat();
const playerShuffle = usePlayerShuffle(); const playerShuffle = usePlayerShuffle();
@@ -60,6 +63,20 @@ export const useNativeMenuSync = () => {
}; };
}, [openCommandPalette]); }, [openCommandPalette]);
useEffect(() => {
if (!isElectron()) {
return undefined;
}
window.api.utils.rendererOpenCreatePlaylist(() => {
openCreatePlaylistModal(server);
});
return () => {
ipc?.removeAllListeners('renderer-open-create-playlist');
};
}, [server]);
useEffect(() => { useEffect(() => {
if (!isElectron()) { if (!isElectron()) {
return undefined; return undefined;