mirror of
https://github.com/jeffvli/feishin.git
synced 2024-11-20 06:27:09 +01:00
Add tray settings (#49)
This commit is contained in:
parent
eecbcddea3
commit
2b1c1d5e59
BIN
assets/pause-circle.png
Normal file
BIN
assets/pause-circle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 896 B |
BIN
assets/play-circle.png
Normal file
BIN
assets/play-circle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 971 B |
BIN
assets/skip-next.png
Normal file
BIN
assets/skip-next.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 479 B |
BIN
assets/skip-previous.png
Normal file
BIN
assets/skip-previous.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 524 B |
163
src/main/main.ts
163
src/main/main.ts
@ -9,7 +9,16 @@
|
|||||||
* `./src/main.js` using webpack. This gives us some performance wins.
|
* `./src/main.js` using webpack. This gives us some performance wins.
|
||||||
*/
|
*/
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { app, BrowserWindow, shell, ipcMain, globalShortcut } from 'electron';
|
import {
|
||||||
|
app,
|
||||||
|
BrowserWindow,
|
||||||
|
shell,
|
||||||
|
ipcMain,
|
||||||
|
globalShortcut,
|
||||||
|
Tray,
|
||||||
|
Menu,
|
||||||
|
nativeImage,
|
||||||
|
} from 'electron';
|
||||||
import electronLocalShortcut from 'electron-localshortcut';
|
import electronLocalShortcut from 'electron-localshortcut';
|
||||||
import log from 'electron-log';
|
import log from 'electron-log';
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
@ -18,7 +27,7 @@ import MpvAPI from 'node-mpv';
|
|||||||
import { disableMediaKeys, enableMediaKeys } from './features/core/player/media-keys';
|
import { disableMediaKeys, enableMediaKeys } from './features/core/player/media-keys';
|
||||||
import { store } from './features/core/settings/index';
|
import { store } from './features/core/settings/index';
|
||||||
import MenuBuilder from './menu';
|
import MenuBuilder from './menu';
|
||||||
import { resolveHtmlPath } from './utils';
|
import { isLinux, isMacOS, isWindows, resolveHtmlPath } from './utils';
|
||||||
import './features';
|
import './features';
|
||||||
|
|
||||||
declare module 'node-mpv';
|
declare module 'node-mpv';
|
||||||
@ -36,6 +45,9 @@ if (store.get('ignore_ssl')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mainWindow: BrowserWindow | null = null;
|
let mainWindow: BrowserWindow | null = null;
|
||||||
|
let tray: Tray | null = null;
|
||||||
|
let exitFromTray = false;
|
||||||
|
let forceQuit = false;
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
const sourceMapSupport = require('source-map-support');
|
const sourceMapSupport = require('source-map-support');
|
||||||
@ -67,19 +79,105 @@ if (!singleInstance) {
|
|||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RESOURCES_PATH = app.isPackaged
|
||||||
|
? path.join(process.resourcesPath, 'assets')
|
||||||
|
: path.join(__dirname, '../../assets');
|
||||||
|
|
||||||
|
const getAssetPath = (...paths: string[]): string => {
|
||||||
|
return path.join(RESOURCES_PATH, ...paths);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMainWindow = () => {
|
||||||
|
return mainWindow;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createWinThumbarButtons = () => {
|
||||||
|
if (isWindows()) {
|
||||||
|
console.log('setting buttons');
|
||||||
|
getMainWindow()?.setThumbarButtons([
|
||||||
|
{
|
||||||
|
click: () => getMainWindow()?.webContents.send('renderer-player-previous'),
|
||||||
|
icon: nativeImage.createFromPath(getAssetPath('skip-previous.png')),
|
||||||
|
tooltip: 'Previous Track',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
click: () => getMainWindow()?.webContents.send('renderer-player-play-pause'),
|
||||||
|
icon: nativeImage.createFromPath(getAssetPath('play-circle.png')),
|
||||||
|
tooltip: 'Play/Pause',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
click: () => getMainWindow()?.webContents.send('renderer-player-next'),
|
||||||
|
icon: nativeImage.createFromPath(getAssetPath('skip-next.png')),
|
||||||
|
tooltip: 'Next Track',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const createTray = () => {
|
||||||
|
if (isMacOS()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tray = isLinux() ? new Tray(getAssetPath('icon.png')) : new Tray(getAssetPath('icon.ico'));
|
||||||
|
const contextMenu = Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
click: () => {
|
||||||
|
getMainWindow()?.webContents.send('renderer-player-play-pause');
|
||||||
|
},
|
||||||
|
label: 'Play/Pause',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
click: () => {
|
||||||
|
getMainWindow()?.webContents.send('renderer-player-next');
|
||||||
|
},
|
||||||
|
label: 'Next Track',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
click: () => {
|
||||||
|
getMainWindow()?.webContents.send('renderer-player-previous');
|
||||||
|
},
|
||||||
|
label: 'Previous Track',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
click: () => {
|
||||||
|
getMainWindow()?.webContents.send('renderer-player-stop');
|
||||||
|
},
|
||||||
|
label: 'Stop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
click: () => {
|
||||||
|
mainWindow?.show();
|
||||||
|
createWinThumbarButtons();
|
||||||
|
},
|
||||||
|
label: 'Open main window',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
click: () => {
|
||||||
|
exitFromTray = true;
|
||||||
|
app.quit();
|
||||||
|
},
|
||||||
|
label: 'Quit',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
tray.on('double-click', () => {
|
||||||
|
mainWindow?.show();
|
||||||
|
createWinThumbarButtons();
|
||||||
|
});
|
||||||
|
|
||||||
|
tray.setToolTip('Feishin');
|
||||||
|
tray.setContextMenu(contextMenu);
|
||||||
|
};
|
||||||
|
|
||||||
const createWindow = async () => {
|
const createWindow = async () => {
|
||||||
if (isDevelopment) {
|
if (isDevelopment) {
|
||||||
await installExtensions();
|
await installExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
const RESOURCES_PATH = app.isPackaged
|
|
||||||
? path.join(process.resourcesPath, 'assets')
|
|
||||||
: path.join(__dirname, '../../assets');
|
|
||||||
|
|
||||||
const getAssetPath = (...paths: string[]): string => {
|
|
||||||
return path.join(RESOURCES_PATH, ...paths);
|
|
||||||
};
|
|
||||||
|
|
||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
frame: false,
|
frame: false,
|
||||||
height: 900,
|
height: 900,
|
||||||
@ -153,14 +251,41 @@ const createWindow = async () => {
|
|||||||
mainWindow.minimize();
|
mainWindow.minimize();
|
||||||
} else {
|
} else {
|
||||||
mainWindow.show();
|
mainWindow.show();
|
||||||
|
createWinThumbarButtons();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.on('closed', () => {
|
mainWindow.on('closed', () => {
|
||||||
// mainWindow?.webContents.send('renderer-player-quit');
|
|
||||||
mainWindow = null;
|
mainWindow = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mainWindow.on('close', (event) => {
|
||||||
|
if (!exitFromTray && store.get('window_exit_to_tray')) {
|
||||||
|
if (isMacOS() && !forceQuit) {
|
||||||
|
exitFromTray = true;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
mainWindow?.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mainWindow.on('minimize', (event: any) => {
|
||||||
|
if (store.get('window_minimize_to_tray') === true) {
|
||||||
|
event.preventDefault();
|
||||||
|
mainWindow?.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isWindows()) {
|
||||||
|
app.setAppUserModelId(process.execPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMacOS()) {
|
||||||
|
app.on('before-quit', () => {
|
||||||
|
forceQuit = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const menuBuilder = new MenuBuilder(mainWindow);
|
const menuBuilder = new MenuBuilder(mainWindow);
|
||||||
menuBuilder.buildMenu();
|
menuBuilder.buildMenu();
|
||||||
|
|
||||||
@ -175,16 +300,8 @@ const createWindow = async () => {
|
|||||||
new AppUpdater();
|
new AppUpdater();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Add event listeners...
|
|
||||||
*/
|
|
||||||
|
|
||||||
app.commandLine.appendSwitch('disable-features', 'HardwareMediaKeyHandling,MediaSessionService');
|
app.commandLine.appendSwitch('disable-features', 'HardwareMediaKeyHandling,MediaSessionService');
|
||||||
|
|
||||||
export const getMainWindow = () => {
|
|
||||||
return mainWindow;
|
|
||||||
};
|
|
||||||
|
|
||||||
const MPV_BINARY_PATH = store.get('mpv_path') as string | undefined;
|
const MPV_BINARY_PATH = store.get('mpv_path') as string | undefined;
|
||||||
const MPV_PARAMETERS = store.get('mpv_parameters') as Array<string> | undefined;
|
const MPV_PARAMETERS = store.get('mpv_parameters') as Array<string> | undefined;
|
||||||
|
|
||||||
@ -267,11 +384,10 @@ app.on('window-all-closed', () => {
|
|||||||
|
|
||||||
// Respect the OSX convention of having the application in memory even
|
// Respect the OSX convention of having the application in memory even
|
||||||
// after all windows have been closed
|
// after all windows have been closed
|
||||||
if (process.platform !== 'darwin') {
|
if (isMacOS()) {
|
||||||
app.quit();
|
|
||||||
} else {
|
|
||||||
mpv.stop();
|
|
||||||
mainWindow = null;
|
mainWindow = null;
|
||||||
|
} else {
|
||||||
|
app.quit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -279,6 +395,7 @@ app
|
|||||||
.whenReady()
|
.whenReady()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
createWindow();
|
createWindow();
|
||||||
|
createTray();
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
// On macOS it's common to re-create a window in the app when the
|
// On macOS it's common to re-create a window in the app when the
|
||||||
// dock icon is clicked and there are no other windows open.
|
// dock icon is clicked and there are no other windows open.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { lazy } from 'react';
|
import { lazy } from 'react';
|
||||||
import { Tabs } from '/@/renderer/components';
|
import { Tabs } from '/@/renderer/components';
|
||||||
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||||
|
import isElectron from 'is-electron';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
const GeneralTab = lazy(() =>
|
const GeneralTab = lazy(() =>
|
||||||
@ -44,7 +45,7 @@ export const SettingsContent = () => {
|
|||||||
<Tabs.List>
|
<Tabs.List>
|
||||||
<Tabs.Tab value="general">General</Tabs.Tab>
|
<Tabs.Tab value="general">General</Tabs.Tab>
|
||||||
<Tabs.Tab value="playback">Playback</Tabs.Tab>
|
<Tabs.Tab value="playback">Playback</Tabs.Tab>
|
||||||
<Tabs.Tab value="window">Window</Tabs.Tab>
|
{isElectron() && <Tabs.Tab value="window">Window</Tabs.Tab>}
|
||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
<Tabs.Panel value="general">
|
<Tabs.Panel value="general">
|
||||||
<GeneralTab />
|
<GeneralTab />
|
||||||
@ -52,9 +53,11 @@ export const SettingsContent = () => {
|
|||||||
<Tabs.Panel value="playback">
|
<Tabs.Panel value="playback">
|
||||||
<PlaybackTab />
|
<PlaybackTab />
|
||||||
</Tabs.Panel>
|
</Tabs.Panel>
|
||||||
|
{isElectron() && (
|
||||||
<Tabs.Panel value="window">
|
<Tabs.Panel value="window">
|
||||||
<ApplicationTab />
|
<ApplicationTab />
|
||||||
</Tabs.Panel>
|
</Tabs.Panel>
|
||||||
|
)}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</TabContainer>
|
</TabContainer>
|
||||||
);
|
);
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
SettingsSection,
|
SettingsSection,
|
||||||
SettingOption,
|
SettingOption,
|
||||||
} from '/@/renderer/features/settings/components/settings-section';
|
} from '/@/renderer/features/settings/components/settings-section';
|
||||||
import { Select } from '/@/renderer/components';
|
import { Select, Switch } from '/@/renderer/components';
|
||||||
|
|
||||||
const WINDOW_BAR_OPTIONS = [
|
const WINDOW_BAR_OPTIONS = [
|
||||||
{ label: 'Web (hidden)', value: Platform.WEB },
|
{ label: 'Web (hidden)', value: Platform.WEB },
|
||||||
@ -13,6 +13,8 @@ const WINDOW_BAR_OPTIONS = [
|
|||||||
{ label: 'macOS', value: Platform.MACOS },
|
{ label: 'macOS', value: Platform.MACOS },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const localSettings = isElectron() ? window.electron.localSettings : null;
|
||||||
|
|
||||||
export const WindowSettings = () => {
|
export const WindowSettings = () => {
|
||||||
const settings = useWindowSettings();
|
const settings = useWindowSettings();
|
||||||
const { setSettings } = useSettingsStoreActions();
|
const { setSettings } = useSettingsStoreActions();
|
||||||
@ -39,6 +41,50 @@ export const WindowSettings = () => {
|
|||||||
isHidden: !isElectron(),
|
isHidden: !isElectron(),
|
||||||
title: 'Window bar style',
|
title: 'Window bar style',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
control: (
|
||||||
|
<Switch
|
||||||
|
aria-label="Toggle minimize to tray"
|
||||||
|
defaultChecked={settings.exitToTray}
|
||||||
|
disabled={!isElectron()}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (!e) return;
|
||||||
|
localSettings?.set('window_minimize_to_tray', e.currentTarget.checked);
|
||||||
|
setSettings({
|
||||||
|
window: {
|
||||||
|
...settings,
|
||||||
|
minimizeToTray: e.currentTarget.checked,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description: 'Minimize the application to the system tray',
|
||||||
|
isHidden: !isElectron(),
|
||||||
|
title: 'Minimize to tray',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: (
|
||||||
|
<Switch
|
||||||
|
aria-label="Toggle exit to tray"
|
||||||
|
defaultChecked={settings.exitToTray}
|
||||||
|
disabled={!isElectron()}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (!e) return;
|
||||||
|
localSettings?.set('window_exit_to_tray', e.currentTarget.checked);
|
||||||
|
setSettings({
|
||||||
|
window: {
|
||||||
|
...settings,
|
||||||
|
exitToTray: e.currentTarget.checked,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description: 'Exit the application to the system tray',
|
||||||
|
isHidden: !isElectron(),
|
||||||
|
title: 'Exit to tray',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return <SettingsSection options={windowOptions} />;
|
return <SettingsSection options={windowOptions} />;
|
||||||
|
@ -71,6 +71,8 @@ export interface SettingsState {
|
|||||||
songs: DataTableProps;
|
songs: DataTableProps;
|
||||||
};
|
};
|
||||||
window: {
|
window: {
|
||||||
|
exitToTray: boolean;
|
||||||
|
minimizeToTray: boolean;
|
||||||
windowBarStyle: Platform;
|
windowBarStyle: Platform;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -243,6 +245,8 @@ export const useSettingsStore = create<SettingsSlice>()(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
window: {
|
window: {
|
||||||
|
exitToTray: false,
|
||||||
|
minimizeToTray: false,
|
||||||
windowBarStyle: Platform.WEB,
|
windowBarStyle: Platform.WEB,
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
|
Loading…
Reference in New Issue
Block a user