79 lines
2.7 KiB
TypeScript
79 lines
2.7 KiB
TypeScript
|
|
import { app, Menu, nativeImage, Tray } from 'electron';
|
|||
|
|
import log from 'electron-log/main';
|
|||
|
|
|
|||
|
|
import { getAutoLaunchEnabled, setAutoLaunchEnabled } from './auto-launch';
|
|||
|
|
import { getResourcePath } from './config';
|
|||
|
|
import { checkForUpdates } from './updater';
|
|||
|
|
import { markQuitting, showMainWindow } from './window';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 系统托盘:应用常驻入口
|
|||
|
|
* - Windows 单击托盘图标恢复主窗口;mac 单击弹出菜单(跟随平台惯例)
|
|||
|
|
* - 菜单:显示主窗口 / 开机自启开关 / 检查更新 / 退出
|
|||
|
|
* 注意:托盘实例必须保持模块级引用,否则会被 GC 导致图标消失(Electron 经典坑)
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
let tray: Tray | null = null;
|
|||
|
|
|
|||
|
|
/** 构建托盘菜单:开机自启是动态勾选项,每次状态变化后需重建菜单 */
|
|||
|
|
function buildTrayMenu(): Menu {
|
|||
|
|
return Menu.buildFromTemplate([
|
|||
|
|
{
|
|||
|
|
label: '显示主窗口',
|
|||
|
|
click: () => showMainWindow(),
|
|||
|
|
},
|
|||
|
|
{ type: 'separator' },
|
|||
|
|
{
|
|||
|
|
label: '开机自启',
|
|||
|
|
type: 'checkbox',
|
|||
|
|
checked: getAutoLaunchEnabled(),
|
|||
|
|
// 开发模式登录项无意义,置灰避免误操作
|
|||
|
|
enabled: app.isPackaged,
|
|||
|
|
click: (menuItem) => {
|
|||
|
|
setAutoLaunchEnabled(menuItem.checked);
|
|||
|
|
refreshTrayMenu();
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
label: '检查更新',
|
|||
|
|
click: () => checkForUpdates(true),
|
|||
|
|
},
|
|||
|
|
{ type: 'separator' },
|
|||
|
|
{
|
|||
|
|
label: '退出',
|
|||
|
|
click: () => {
|
|||
|
|
// 先标记退出,放行主窗口 close 拦截,再走正常退出流程
|
|||
|
|
markQuitting();
|
|||
|
|
app.quit();
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 刷新托盘菜单(开机自启状态从渲染端 IPC 修改后也要同步勾选态) */
|
|||
|
|
export function refreshTrayMenu(): void {
|
|||
|
|
tray?.setContextMenu(buildTrayMenu());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 创建系统托盘
|
|||
|
|
* 图标用打包的应用图标缩放(mac 菜单栏建议 18px、Windows 托盘 16px 的倍数由系统处理)
|
|||
|
|
* TODO(待确认):正式图标到位后,mac 建议换单色 Template 图以适配深浅菜单栏
|
|||
|
|
*/
|
|||
|
|
export function createTray(): void {
|
|||
|
|
try {
|
|||
|
|
const icon = nativeImage.createFromPath(getResourcePath('icon.png'));
|
|||
|
|
const trayIcon = process.platform === 'darwin' ? icon.resize({ width: 18, height: 18 }) : icon.resize({ width: 16, height: 16 });
|
|||
|
|
tray = new Tray(trayIcon);
|
|||
|
|
tray.setToolTip('萧康云医');
|
|||
|
|
tray.setContextMenu(buildTrayMenu());
|
|||
|
|
// Windows 单击直接唤起主窗口;mac 上设置了 contextMenu 后单击默认弹菜单,不重复绑定
|
|||
|
|
if (process.platform === 'win32') {
|
|||
|
|
tray.on('click', () => showMainWindow());
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
// 托盘创建失败(图标缺失等)不阻塞应用启动,仅损失常驻入口
|
|||
|
|
log.error('创建系统托盘失败', error);
|
|||
|
|
}
|
|||
|
|
}
|