mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-23 23:01:21 +08:00
199 lines
6.8 KiB
TypeScript
199 lines
6.8 KiB
TypeScript
import { BrowserWindow, ipcMain, screen } from 'electron'
|
|
import { join } from 'path'
|
|
import { ConfigService } from '../services/config'
|
|
|
|
let notificationWindow: BrowserWindow | null = null
|
|
let closeTimer: NodeJS.Timeout | null = null
|
|
|
|
export function createNotificationWindow() {
|
|
if (notificationWindow && !notificationWindow.isDestroyed()) {
|
|
return notificationWindow
|
|
}
|
|
|
|
const isDev = !!process.env.VITE_DEV_SERVER_URL
|
|
const iconPath = isDev
|
|
? join(__dirname, '../../public/icon.ico')
|
|
: join(process.resourcesPath, 'icon.ico')
|
|
|
|
console.log('[NotificationWindow] Creating window...')
|
|
const width = 344
|
|
const height = 114
|
|
|
|
// Update default creation size
|
|
notificationWindow = new BrowserWindow({
|
|
width: width,
|
|
height: height,
|
|
type: 'toolbar', // 有助于在某些操作系统上保持置顶
|
|
frame: false,
|
|
transparent: true,
|
|
resizable: false,
|
|
show: false,
|
|
alwaysOnTop: true,
|
|
skipTaskbar: true,
|
|
focusable: false, // 不抢占焦点
|
|
icon: iconPath,
|
|
webPreferences: {
|
|
preload: join(__dirname, 'preload.js'), // FIX: Use correct relative path (same dir in dist)
|
|
contextIsolation: true,
|
|
nodeIntegration: false,
|
|
// devTools: true // Enable DevTools
|
|
}
|
|
})
|
|
|
|
// notificationWindow.webContents.openDevTools({ mode: 'detach' }) // DEBUG: Force Open DevTools
|
|
notificationWindow.setIgnoreMouseEvents(true, { forward: true }) // 初始点击穿透
|
|
|
|
// 处理鼠标事件 (如果需要从渲染进程转发,但目前特定区域处理?)
|
|
// 实际上,我们希望窗口可点击。
|
|
// 我们将在显示时将忽略鼠标事件设为 false。
|
|
|
|
const loadUrl = isDev
|
|
? `${process.env.VITE_DEV_SERVER_URL}#/notification-window`
|
|
: `file://${join(__dirname, '../dist/index.html')}#/notification-window`
|
|
|
|
console.log('[NotificationWindow] Loading URL:', loadUrl)
|
|
notificationWindow.loadURL(loadUrl)
|
|
|
|
notificationWindow.on('closed', () => {
|
|
notificationWindow = null
|
|
})
|
|
|
|
return notificationWindow
|
|
}
|
|
|
|
export async function showNotification(data: any) {
|
|
// 先检查配置
|
|
const config = ConfigService.getInstance()
|
|
const enabled = await config.get('notificationEnabled')
|
|
if (enabled === false) return // 默认为 true
|
|
|
|
// 检查会话过滤
|
|
const filterMode = config.get('notificationFilterMode') || 'all'
|
|
const filterList = config.get('notificationFilterList') || []
|
|
const sessionId = data.sessionId
|
|
|
|
if (sessionId && filterMode !== 'all' && filterList.length > 0) {
|
|
const isInList = filterList.includes(sessionId)
|
|
if (filterMode === 'whitelist' && !isInList) {
|
|
// 白名单模式:不在列表中则不显示
|
|
return
|
|
}
|
|
if (filterMode === 'blacklist' && isInList) {
|
|
// 黑名单模式:在列表中则不显示
|
|
return
|
|
}
|
|
}
|
|
|
|
let win = notificationWindow
|
|
if (!win || win.isDestroyed()) {
|
|
win = createNotificationWindow()
|
|
}
|
|
|
|
if (!win) return
|
|
|
|
// 确保加载完成
|
|
if (win.webContents.isLoading()) {
|
|
win.once('ready-to-show', () => {
|
|
showAndSend(win!, data)
|
|
})
|
|
} else {
|
|
showAndSend(win, data)
|
|
}
|
|
}
|
|
|
|
let lastNotificationData: any = null
|
|
|
|
async function showAndSend(win: BrowserWindow, data: any) {
|
|
lastNotificationData = data
|
|
const config = ConfigService.getInstance()
|
|
const position = (await config.get('notificationPosition')) || 'top-right'
|
|
|
|
// 更新位置
|
|
const { width: screenWidth, height: screenHeight } = screen.getPrimaryDisplay().workAreaSize
|
|
const winWidth = 344
|
|
const winHeight = 114
|
|
const padding = 20
|
|
|
|
let x = 0
|
|
let y = 0
|
|
|
|
switch (position) {
|
|
case 'top-right':
|
|
x = screenWidth - winWidth - padding
|
|
y = padding
|
|
break
|
|
case 'bottom-right':
|
|
x = screenWidth - winWidth - padding
|
|
y = screenHeight - winHeight - padding
|
|
break
|
|
case 'top-left':
|
|
x = padding
|
|
y = padding
|
|
break
|
|
case 'bottom-left':
|
|
x = padding
|
|
y = screenHeight - winHeight - padding
|
|
break
|
|
}
|
|
|
|
win.setPosition(Math.floor(x), Math.floor(y))
|
|
win.setSize(winWidth, winHeight) // 确保尺寸
|
|
|
|
// 设为可交互
|
|
win.setIgnoreMouseEvents(false)
|
|
win.showInactive() // 显示但不聚焦
|
|
win.setAlwaysOnTop(true, 'screen-saver') // 最高层级
|
|
|
|
win.webContents.send('notification:show', data)
|
|
|
|
// 自动关闭计时器通常由渲染进程管理
|
|
// 渲染进程发送 'notification:close' 来隐藏窗口
|
|
}
|
|
|
|
export function registerNotificationHandlers() {
|
|
ipcMain.handle('notification:show', (_, data) => {
|
|
showNotification(data)
|
|
})
|
|
|
|
ipcMain.handle('notification:close', () => {
|
|
if (notificationWindow && !notificationWindow.isDestroyed()) {
|
|
notificationWindow.hide()
|
|
notificationWindow.setIgnoreMouseEvents(true, { forward: true })
|
|
}
|
|
})
|
|
|
|
// Handle renderer ready event (fix race condition)
|
|
ipcMain.on('notification:ready', (event) => {
|
|
console.log('[NotificationWindow] Renderer ready, checking cached data')
|
|
if (lastNotificationData && notificationWindow && !notificationWindow.isDestroyed()) {
|
|
console.log('[NotificationWindow] Re-sending cached data')
|
|
notificationWindow.webContents.send('notification:show', lastNotificationData)
|
|
}
|
|
})
|
|
|
|
// Handle resize request from renderer
|
|
ipcMain.on('notification:resize', (event, { width, height }) => {
|
|
if (notificationWindow && !notificationWindow.isDestroyed()) {
|
|
// Enforce max-height if needed, or trust renderer
|
|
// Ensure it doesn't go off screen bottom?
|
|
// Logic in showAndSend handles position, but we need to keep anchor point (top-right usually).
|
|
// If we resize, we should re-calculate position to keep it anchored?
|
|
// Actually, setSize changes size. If it's top-right, x/y stays same -> window grows down. That's fine for top-right.
|
|
// If bottom-right, growing down pushes it off screen.
|
|
|
|
// Simple version: just setSize. For V1 we assume Top-Right.
|
|
// But wait, the config supports bottom-right.
|
|
// We can re-call setPosition or just let it be.
|
|
// If bottom-right, y needs to prevent overflow.
|
|
|
|
// Ideally we get current config position
|
|
const bounds = notificationWindow.getBounds()
|
|
// Check if we need to adjust Y?
|
|
// For now, let's just set the size as requested.
|
|
notificationWindow.setSize(Math.round(width), Math.round(height))
|
|
}
|
|
})
|
|
|
|
// 'notification-clicked' 在 main.ts 中处理 (导航)
|
|
}
|