fix: esc in /friend start
Browse files1. 启动 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 |
-
|
| 36 |
-
|
| 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 |
|