Skip to content

Commit b8c20e2

Browse files
committed
feat: v0.22.0 — 音效系统重构、UI 组件增强与 AI 余额查询
音效系统重构: - audioConfig / SoundPlayer 全面重构 - 新增 20+ 音效文件(UI 交互、反馈、同步等) - SoundSettings 音效设置优化 - generate-sounds 脚本 UI 组件增强: - Modal / Toast / CommandPalette / ConsentModal 优化 - BottomNav / Sidebar 布局组件更新 - FunctionalOverlay 功能覆盖层改进 功能模块优化: - Flashcards 卡片模块多页面增强 - Notes 笔记模块编辑与搜索优化 - Feynman 费曼页面改进 - Settings 设置页面全面更新(AI/Data/Sound/Flashcard) AI 与后端: - 新增 balance.py AI 余额查询路由 - useAIBalance hook - AIProviderSettings 优化 3D 与同步: - SpatialNav / MobileNavGrid 导航优化 - crdtEngine 协同引擎更新 - SyncStatusBar 同步状态优化 Electron: - mcpManager / windowManager 更新 其他: - AGENTS.md 项目智能体文档 - .gitignore 更新 - onboarding HelpCenter 优化 - website 版本号同步至 v0.22.0
1 parent 92487ee commit b8c20e2

92 files changed

Lines changed: 1940 additions & 130 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitignore‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,7 @@ logs/
4848
# Coverage
4949
coverage/
5050
.nyc_output/
51+
52+
# Scripts temp
53+
scripts/.mp3tmp/
54+
scripts/sounds_backup_original/

‎AGENTS.md‎

Lines changed: 80 additions & 0 deletions

‎client/electron/mcpManager.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,11 @@ class McpManager {
287287

288288
if (this.bridge) {
289289
try {
290-
// 给 bridge 3 秒时间优雅关闭
290+
// 给 bridge 1 秒时间优雅关闭(避免阻塞退出)
291291
await Promise.race([
292292
this.sendRequest('shutdown', {}),
293293
new Promise<void>((_, reject) =>
294-
setTimeout(() => reject(new Error('Shutdown timeout')), 3000),
294+
setTimeout(() => reject(new Error('Shutdown timeout')), 1000),
295295
),
296296
]);
297297
} catch {

‎client/electron/windowManager.ts‎

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* 及关闭行为偏好持久化。
66
*/
77

8-
import { BrowserWindow, app } from 'electron';
8+
import { BrowserWindow, app, shell } from 'electron';
99
import * as path from 'path';
1010
import { access, readFile, writeFile } from 'fs/promises';
1111
import { logger } from './logger.js';
@@ -34,7 +34,7 @@ let syncBeforeQuitCompleted = false;
3434
let syncTimeoutTimer: ReturnType<typeof setTimeout> | null = null;
3535

3636
/** 同步超时时间(毫秒):渲染进程未响应则强制继续退出 */
37-
const SYNC_BEFORE_QUIT_TIMEOUT_MS = 3000;
37+
const SYNC_BEFORE_QUIT_TIMEOUT_MS = 1500;
3838

3939
/** 读取保存的关闭选择 */
4040
export async function getCloseChoice(): Promise<string | null> {
@@ -102,6 +102,14 @@ export function createMainWindow(
102102
logger.info('[Window] Window shown (ready-to-show)');
103103
});
104104

105+
// 拦截外部链接:target="_blank" 或 window.open() 统一用系统默认浏览器打开
106+
win.webContents.setWindowOpenHandler(({ url }) => {
107+
if (url.startsWith('https://') || url.startsWith('http://')) {
108+
shell.openExternal(url);
109+
}
110+
return { action: 'deny' };
111+
});
112+
105113
// 窗口最大化状态变化时通知前端
106114
win.on('maximize', () => {
107115
win.webContents.send('window:maximized-changed', true);
@@ -180,7 +188,7 @@ export function createMainWindow(
180188

181189
/**
182190
* 退出前同步流程入口
183-
* 不立即设置退出标志,而是先触发渲染进程同步
191+
* 立即隐藏窗口(感知零延迟),后台执行同步再真正关闭
184192
* 附带超时保护:若渲染进程在 SYNC_BEFORE_QUIT_TIMEOUT_MS 内未响应,强制继续退出
185193
*/
186194
function syncAndQuit(
@@ -198,9 +206,13 @@ function syncAndQuit(
198206
onQuit();
199207
return;
200208
}
201-
// 首次触发:发送同步请求给渲染进程
209+
210+
// ✨ 立即隐藏窗口,用户感知零延迟退出
211+
win.hide();
212+
213+
// 后台触发同步
202214
syncBeforeQuitRequested = true;
203-
logger.info('[Window] Sync before quit: requesting renderer sync');
215+
logger.info('[Window] Sync before quit: window hidden, requesting renderer sync');
204216
win.webContents.send('sync:before-quit');
205217

206218
// 超时保护:渲染进程未响应时强制完成同步流程
@@ -228,8 +240,6 @@ export function completeSyncBeforeQuit(): void {
228240
}
229241

230242
logger.info('[Window] Sync before quit: completed, proceeding with quit');
231-
const win = BrowserWindow.getAllWindows()[0];
232-
if (win) {
233-
win.close();
234-
}
243+
// 直接调用 app.quit(),避免再次触发 win.close() 的 close 事件循环
244+
app.quit();
235245
}

‎client/public/audio/ambient.mp3‎

1.1 MB
Binary file not shown.

‎client/public/audio/cafe.mp3‎

1.1 MB
Binary file not shown.

‎client/public/audio/forest.mp3‎

1.1 MB
Binary file not shown.

‎client/public/audio/piano.mp3‎

1.13 MB
Binary file not shown.

‎client/public/audio/rain.mp3‎

1.1 MB
Binary file not shown.

‎client/public/audio/waves.mp3‎

1.1 MB
Binary file not shown.

0 commit comments

Comments
 (0)