Skip to content

Commit 72e998c

Browse files
committed
feat: floating button show main window
1 parent 97691dd commit 72e998c

File tree

8 files changed

+109
-399
lines changed

8 files changed

+109
-399
lines changed

electron.vite.config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ export default defineConfig({
3333
alias: {
3434
'@shared': resolve('src/shared')
3535
}
36+
},
37+
build: {
38+
rollupOptions: {
39+
input: {
40+
index: resolve('src/preload/index.ts'),
41+
floating: resolve('src/preload/floating-preload.ts')
42+
}
43+
}
3644
}
3745
},
3846
renderer: {

src/main/events.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,10 @@ export const TRAY_EVENTS = {
164164
export const MEETING_EVENTS = {
165165
INSTRUCTION: 'mcp:meeting-instruction', // 主进程向渲染进程发送指令
166166
}
167+
168+
// 悬浮按钮相关事件
169+
export const FLOATING_BUTTON_EVENTS = {
170+
CLICKED: 'floating-button:clicked', // 悬浮按钮被点击
171+
VISIBILITY_CHANGED: 'floating-button:visibility-changed', // 悬浮按钮显示状态改变
172+
POSITION_CHANGED: 'floating-button:position-changed' // 悬浮按钮位置改变
173+
}

src/main/index.ts

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ProxyMode, proxyConfig } from './presenter/proxyConfig'
55
import path from 'path'
66
import fs from 'fs'
77
import { eventBus } from './eventbus'
8-
import { WINDOW_EVENTS, TRAY_EVENTS } from './events'
8+
import { WINDOW_EVENTS, TRAY_EVENTS, FLOATING_BUTTON_EVENTS } from './events'
99
import { setLoggingEnabled } from '@shared/logger'
1010
import { is } from '@electron-toolkit/utils' // 确保导入 is
1111
import { floatingButtonPresenter } from './presenter/floatingButtonPresenter' // 导入悬浮按钮 presenter
@@ -115,36 +115,47 @@ app.whenReady().then(async () => {
115115
}
116116

117117
// 设置悬浮按钮点击事件的 IPC 处理器
118-
ipcMain.on('floating-button-click', () => {
119-
console.log('Main: Floating button clicked via IPC')
120-
// 触发内置事件处理器
121-
app.emit('floating-button-clicked' as any)
118+
// 先移除可能存在的旧监听器
119+
ipcMain.removeAllListeners(FLOATING_BUTTON_EVENTS.CLICKED)
120+
ipcMain.on(FLOATING_BUTTON_EVENTS.CLICKED, () => {
121+
try {
122+
// 触发内置事件处理器
123+
handleShowHiddenWindow(true)
124+
} catch (error) {
125+
}
122126
})
123127

124-
// 监听悬浮按钮点击事件
125-
app.on('floating-button-clicked' as any, () => {
128+
function handleShowHiddenWindow(mustShow: boolean) {
126129
const allWindows = presenter.windowPresenter.getAllWindows()
127130
if (allWindows.length === 0) {
128-
// 如果没有窗口,创建新窗口
129131
presenter.windowPresenter.createShellWindow({
130132
initialTab: {
131133
url: 'local://chat'
132134
}
133135
})
134136
} else {
135-
// 显示并聚焦第一个窗口
137+
// 查找目标窗口 (焦点窗口或第一个窗口)
136138
const targetWindow = presenter.windowPresenter.getFocusedWindow() || allWindows[0]
139+
137140
if (!targetWindow.isDestroyed()) {
138-
presenter.windowPresenter.show(targetWindow.id)
139-
targetWindow.focus()
141+
// 逻辑: 如果窗口可见且不是从托盘点击触发,则隐藏;否则显示并置顶
142+
if (targetWindow.isVisible() && !mustShow) {
143+
presenter.windowPresenter.hide(targetWindow.id)
144+
} else {
145+
presenter.windowPresenter.show(targetWindow.id)
146+
targetWindow.focus() // 确保窗口置顶
147+
}
140148
} else {
141-
// 如果窗口已销毁,创建新窗口
149+
console.warn('Target window for SHOW_HIDDEN_WINDOW event is destroyed.') // 保持 warn
150+
// 如果目标窗口已销毁,创建新窗口
142151
presenter.windowPresenter.createShellWindow({
143-
initialTab: { url: 'local://chat' }
152+
initialTab: {
153+
url: 'local://chat'
154+
}
144155
})
145156
}
146157
}
147-
})
158+
}
148159

149160
// 监听窗口显示/隐藏状态变化
150161
const handleWindowVisibilityChange = () => {
@@ -173,38 +184,8 @@ app.whenReady().then(async () => {
173184
presenter.upgradePresenter.checkUpdate()
174185
})
175186

176-
// 监听显示/隐藏窗口事件 (从托盘或快捷键触发)
177-
eventBus.on(TRAY_EVENTS.SHOW_HIDDEN_WINDOW, (trayClick: boolean) => {
178-
const allWindows = presenter.windowPresenter.getAllWindows()
179-
if (allWindows.length === 0) {
180-
presenter.windowPresenter.createShellWindow({
181-
initialTab: {
182-
url: 'local://chat'
183-
}
184-
})
185-
} else {
186-
// 查找目标窗口 (焦点窗口或第一个窗口)
187-
const targetWindow = presenter.windowPresenter.getFocusedWindow() || allWindows[0]
188-
189-
if (!targetWindow.isDestroyed()) {
190-
// 逻辑: 如果窗口可见且不是从托盘点击触发,则隐藏;否则显示并置顶
191-
if (targetWindow.isVisible() && !trayClick) {
192-
presenter.windowPresenter.hide(targetWindow.id)
193-
} else {
194-
presenter.windowPresenter.show(targetWindow.id)
195-
targetWindow.focus() // 确保窗口置顶
196-
}
197-
} else {
198-
console.warn('Target window for SHOW_HIDDEN_WINDOW event is destroyed.') // 保持 warn
199-
// 如果目标窗口已销毁,创建新窗口
200-
presenter.windowPresenter.createShellWindow({
201-
initialTab: {
202-
url: 'local://chat'
203-
}
204-
})
205-
}
206-
}
207-
})
187+
// 监听显示/隐藏窗口事件 (从托盘或快捷键或悬浮窗口触发)
188+
eventBus.on(TRAY_EVENTS.SHOW_HIDDEN_WINDOW, handleShowHiddenWindow)
208189

209190
// 监听浏览器窗口获得焦点事件
210191
app.on('browser-window-focus', () => {

src/main/presenter/floatingButtonPresenter/FloatingButtonWindow.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { BrowserWindow, screen } from 'electron';
22
import path from 'path';
3+
import fs from 'fs';
34
import { FloatingButtonConfig, FloatingButtonState } from './types';
45
import logger from '../../../shared/logger';
56

@@ -32,6 +33,12 @@ export class FloatingButtonWindow {
3233
try {
3334
const position = this.calculatePosition();
3435

36+
// 根据环境选择正确的预加载脚本路径
37+
const isDev = process.env.NODE_ENV === 'development';
38+
const preloadPath = isDev
39+
? path.join(process.cwd(), 'out/preload/floating.mjs')
40+
: path.join(__dirname, '../../preload/floating.mjs');
41+
3542
this.window = new BrowserWindow({
3643
width: this.config.size.width,
3744
height: this.config.size.height,
@@ -50,18 +57,21 @@ export class FloatingButtonWindow {
5057
webPreferences: {
5158
nodeIntegration: false,
5259
contextIsolation: true,
53-
preload: path.join(__dirname, '../../preload/floating.mjs'),
54-
webSecurity: true
60+
preload: preloadPath,
61+
webSecurity: false, // 开发模式下允许跨域
62+
devTools: true, // 开发模式下启用开发者工具
63+
sandbox: false // 禁用沙盒模式,确保预加载脚本能正常工作
5564
}
5665
});
5766

5867
// 设置窗口透明度
5968
this.window.setOpacity(this.config.opacity);
6069

6170
// 加载悬浮按钮页面
62-
const isDev = process.env.NODE_ENV === 'development';
6371
if (isDev) {
64-
await this.window.loadURL('http://localhost:5173/floating/index.html');
72+
await this.window.loadURL('http://localhost:5173/floating/');
73+
// 开发模式下可选择性打开开发者工具(暂时禁用,避免影响拖拽)
74+
this.window.webContents.openDevTools({ mode: 'detach' });
6575
} else {
6676
await this.window.loadFile(path.join(__dirname, '../../../renderer/floating/index.html'));
6777
}

src/preload/floating-preload.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
import { FLOATING_BUTTON_EVENTS } from '@/events';
12
import { contextBridge, ipcRenderer } from 'electron';
23

34
// 定义悬浮按钮的 API
45
const floatingButtonAPI = {
56
// 通知主进程悬浮按钮被点击
67
onClick: () => {
7-
ipcRenderer.send('floating-button-click');
8+
try {
9+
ipcRenderer.send(FLOATING_BUTTON_EVENTS.CLICKED);
10+
} catch (error) {
11+
console.error('FloatingPreload: Error sending IPC message:', error);
12+
}
813
},
914

1015
// 监听来自主进程的事件
@@ -16,9 +21,22 @@ const floatingButtonAPI = {
1621

1722
// 移除事件监听器
1823
removeAllListeners: () => {
24+
console.log('FloatingPreload: Removing all listeners');
1925
ipcRenderer.removeAllListeners('floating-button-config-update');
2026
}
2127
};
2228

23-
// 将 API 暴露给渲染进程
24-
contextBridge.exposeInMainWorld('floatingButtonAPI', floatingButtonAPI);
29+
// 尝试不同的方式暴露API
30+
if (process.contextIsolated) {
31+
try {
32+
contextBridge.exposeInMainWorld('floatingButtonAPI', floatingButtonAPI);
33+
} catch (error) {
34+
console.error('=== FloatingPreload: Error exposing API via contextBridge ===:', error);
35+
}
36+
} else {
37+
try {
38+
(window as any).floatingButtonAPI = floatingButtonAPI;
39+
} catch (error) {
40+
console.error('=== FloatingPreload: Error attaching API to window ===:', error);
41+
}
42+
}

0 commit comments

Comments
 (0)