chenbhao commited on
Commit
50af4e4
·
1 Parent(s): 5663b68

fix: esc in /friend start

Browse files

1. 启动 Tauri 窗口(异步,后台运行)
2. 渲染 FriendStartView 组件,显示状态信息
3. 按 Esc 或 Enter 关闭 TUI 面板,Tauri 窗口继续在后台运行

launchTauri 之前用了 await 会阻塞 UI,现在改成了直接调用让它在后台异步运行。试试 /friend start 看看效果

src/commands/friend/friend.tsx CHANGED
@@ -32,23 +32,8 @@ export async function call(
32
 
33
  if (trimmed === 'start') {
34
  updatePrefs({ enabled: true })
35
- const alreadyRunning = !!getTauriProcess()
36
- if (alreadyRunning) {
37
- return (
38
- <Box flexDirection="column">
39
- <Text>Friend is already running.</Text>
40
- <Text dimColor>Open {FRIEND_URL} in your browser.</Text>
41
- </Box>
42
- )
43
- }
44
- await launchTauri(logger())
45
- return (
46
- <Box flexDirection="column">
47
- <Text>Starting Friend VRM companion...</Text>
48
- <Text dimColor>A Tauri window will open.</Text>
49
- <Text dimColor>Also available at: {FRIEND_URL}</Text>
50
- </Box>
51
- )
52
  }
53
 
54
  if (trimmed === 'stop') {
@@ -99,6 +84,30 @@ function FriendManager({ onDone }: { onDone: LocalJSXCommandOnDone }) {
99
  )
100
  }
101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  function FriendStatus({
103
  prefs,
104
  compact,
 
32
 
33
  if (trimmed === 'start') {
34
  updatePrefs({ enabled: true })
35
+ launchTauri(logger())
36
+ return <FriendStartView onDone={() => onDone?.()} />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
 
39
  if (trimmed === 'stop') {
 
84
  )
85
  }
86
 
87
+ function FriendStartView({ onDone }: { onDone: () => void }) {
88
+ const [dismissed, setDismissed] = useState(false)
89
+
90
+ useInput((_input, key) => {
91
+ if (key.escape || key.return) setDismissed(true)
92
+ })
93
+
94
+ if (dismissed) {
95
+ onDone()
96
+ return null
97
+ }
98
+
99
+ return (
100
+ <Box flexDirection="column">
101
+ <Text>Starting Friend VRM companion...</Text>
102
+ <Text dimColor>A Tauri window will open.</Text>
103
+ <Text dimColor>Also available at: {FRIEND_URL}</Text>
104
+ <Box marginTop={1}>
105
+ <Text dimColor>Press Esc or Enter to close.</Text>
106
+ </Box>
107
+ </Box>
108
+ )
109
+ }
110
+
111
  function FriendStatus({
112
  prefs,
113
  compact,
src/components/friend/frontend/src-tauri/src/lib.rs CHANGED
@@ -1,4 +1,4 @@
1
- use tauri::Manager;
2
 
3
  #[cfg_attr(mobile, tauri::mobile_entry_point)]
4
  pub fn run() {
@@ -10,6 +10,14 @@ pub fn run() {
10
  window.eval("window.location.replace('http://127.0.0.1:3456/friend/')")
11
  .map_err(|e| eprintln!("Failed to set URL: {e}")).ok();
12
  Ok(())
 
 
 
 
 
 
 
 
13
  });
14
 
15
  builder.run(tauri::generate_context!())
 
1
+ use tauri::{Manager, WindowEvent};
2
 
3
  #[cfg_attr(mobile, tauri::mobile_entry_point)]
4
  pub fn run() {
 
10
  window.eval("window.location.replace('http://127.0.0.1:3456/friend/')")
11
  .map_err(|e| eprintln!("Failed to set URL: {e}")).ok();
12
  Ok(())
13
+ })
14
+ .on_window_event(|window, event| {
15
+ if let WindowEvent::CloseRequested { .. } = event {
16
+ // Notify backend that Friend window is closing
17
+ let _ = window.eval(
18
+ "fetch('http://127.0.0.1:3456/friend/api/window-close', {method:'POST'})",
19
+ );
20
+ }
21
  });
22
 
23
  builder.run(tauri::generate_context!())
src/server/api/friend.ts CHANGED
@@ -624,6 +624,13 @@ export async function handleFriendApi(req: Request, url: URL): Promise<Response>
624
  }
625
  }
626
 
 
 
 
 
 
 
 
627
  return jsonResponse({ error: 'Not Found' }, 404);
628
  }
629
 
 
624
  }
625
  }
626
 
627
+ // ── Window close (POST /friend/api/window-close) — called by Tauri on close ──
628
+ if ((pathname === '/friend/api/window-close' || pathname === '/plugins/friend/api/window-close') && method === 'POST') {
629
+ // Emit a global event that tauri-launcher.ts can listen to
630
+ process.emit('friend:window-close' as any);
631
+ return jsonResponse({ ok: true });
632
+ }
633
+
634
  return jsonResponse({ error: 'Not Found' }, 404);
635
  }
636