返回 AiToEarn
index.ts
1 import { app, BrowserWindow, shell, ipcMain, nativeTheme } from 'electron';
2 import { fileURLToPath } from 'node:url';
3 import path from 'node:path';
4 import os from 'node:os';
5 import { update } from './update';
6 import { SystemTray } from '../tray/systemTray';
7 import { views } from './views';
8 import App from './app';
9 import { getAssetPath } from '../util/index';
10 import windowOperate from '../util/windowOperate';
11 import { logger } from '../global/log';
12 import { SplashWindow } from './splash';
13 import dotenv from 'dotenv';
14 import KwaiPubListener from './plat/platforms/Kwai/KwaiPubListener';
15 import { registerContextMenuListener } from '@electron-uikit/contextmenu';
16 import { dialog } from 'electron';
17
18 const platform = process.platform;
19 dotenv.config();
20
21 const __dirname = path.dirname(fileURLToPath(import.meta.url));
22
23 process.env.APP_ROOT = path.join(__dirname, '../..');
24
25 export const MAIN_DIST = path.join(process.env.APP_ROOT, 'dist-electron');
26 export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist');
27 export const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL;
28
29 dialog.showErrorBox = (title, content) => {
30 console.error(`Error: ${title}\n${content}`);
31 };
32
33 process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL
34 ? path.join(process.env.APP_ROOT, 'public')
35 : RENDERER_DIST;
36
37 // Disable GPU Acceleration for Windows 7
38 if (os.release().startsWith('6.1')) app.disableHardwareAcceleration();
39 // Set application name for Windows 10+ notifications
40 if (process.platform === 'win32') app.setAppUserModelId(app.getName());
41
42 // 单例锁
43 // if (!app.requestSingleInstanceLock()) {
44 // app.quit();
45 // process.exit(0);
46 // }
47
48 let win: BrowserWindow | null = null;
49 let splashWindow: SplashWindow | null = null;
50 const preload = path.join(__dirname, '../preload/index.mjs');
51 const indexHtml = path.join(RENDERER_DIST, 'index.html');
52
53 async function createWindow() {
54 // 创建启动窗口
55 splashWindow = new SplashWindow();
56 splashWindow.create();
57
58 // 等待一会儿确保启动窗口显示
59 await new Promise((resolve) => setTimeout(resolve, 500));
60
61 // 创建主窗口但先不显示
62 win = new BrowserWindow({
63 title: '哎哟赚AiToEarn',
64 icon: path.join(getAssetPath('favicon.ico')),
65 width: 2350,
66 height: 1280,
67 minWidth: 1280,
68 minHeight: 800,
69 titleBarStyle: 'hidden',
70 show: false,
71 titleBarOverlay:
72 platform === 'win32'
73 ? undefined
74 : {
75 color: 'rgba(0,0,0,0)',
76 height: 64,
77 symbolColor: '#595959',
78 },
79 webPreferences: {
80 preload,
81 webviewTag: true,
82 webSecurity: true,
83 nodeIntegration: false,
84 contextIsolation: true,
85 },
86 });
87
88 // 强制使用非黑暗模式
89 nativeTheme.themeSource = 'light';
90
91 try {
92 const tray = new SystemTray(win);
93 tray.create();
94 } catch (error) {
95 logger.error('系统托盘启动失败', error);
96 }
97
98 // 等待主窗口加载完成
99 if (VITE_DEV_SERVER_URL) {
100 await win.loadURL(VITE_DEV_SERVER_URL);
101 } else {
102 await win.loadFile(indexHtml);
103 }
104
105 // 延长启动窗口显示时间
106 KwaiPubListener.start();
107 setTimeout(() => {
108 if (splashWindow) {
109 win?.show();
110 // 在主窗口显示后再打开开发者工具
111 // win?.webContents.openDevTools({ mode: 'right' });
112
113 if (process.env.NODE_ENV === 'development') {
114 win?.webContents.openDevTools({ mode: 'right' });
115 }
116
117 // if (VITE_DEV_SERVER_URL) {
118 // win?.webContents.openDevTools({ mode: 'bottom' });
119 // }
120 setTimeout(() => {
121 if (splashWindow) {
122 splashWindow.close();
123 splashWindow = null;
124 }
125 }, 100);
126 }
127 }, 500);
128
129 // 隐藏菜单栏
130 win.setMenu(null);
131
132 // Test actively push message to the Electron-Renderer
133 win.webContents.on('did-finish-load', () => {
134 win?.webContents.send('main-process-message', new Date().toLocaleString());
135 });
136
137 // Make all links open with the browser, not with the application
138 win.webContents.setWindowOpenHandler(({ url }) => {
139 if (url.startsWith('https:')) shell.openExternal(url);
140 return { action: 'deny' };
141 });
142
143 return win;
144 }
145
146 app.whenReady().then(async () => {
147 try {
148 registerContextMenuListener();
149
150 // 创建应用实例,挂载功能
151 new App();
152
153 // 创建窗口
154 const bWin = await createWindow();
155
156 // 挂载其他功能
157 update(bWin);
158 views(bWin);
159 windowOperate.init(bWin);
160 } catch (error) {
161 logger.error('Failed to start application:', error);
162 app.quit();
163 }
164 });
165
166 /**
167 * Quit when all windows are closed, except on macOS. There, it's common
168 */
169 app.on('window-all-closed', () => {
170 win = null;
171 if (process.platform !== 'darwin') app.quit();
172 });
173
174 // 处理第二个实例
175 app.on('second-instance', () => {
176 if (win) {
177 // Focus on the main window if the user tried to open another
178 if (win.isMinimized()) win.restore();
179 win.focus();
180 }
181 });
182
183 // 处理激活
184 app.on('activate', () => {
185 const allWindows = BrowserWindow.getAllWindows();
186 if (allWindows.length) {
187 allWindows[0].focus();
188 } else {
189 createWindow();
190 }
191 });
192
193 // 打开新窗口
194 ipcMain.handle('open-win', (_, arg) => {
195 const childWindow = new BrowserWindow({
196 webPreferences: {
197 preload,
198 nodeIntegration: true,
199 contextIsolation: false,
200 },
201 });
202
203 if (VITE_DEV_SERVER_URL) {
204 childWindow.loadURL(`${VITE_DEV_SERVER_URL}#${arg}`);
205 } else {
206 childWindow.loadFile(indexHtml, { hash: arg });
207 }
208 });
209
209 lines TYPESCRIPT