Fix/about section UI (#419)

* fix(ui): improve AboutSection styling and version detection

- Add framer-motion animations for smooth page transitions
- Unify button sizes and add icons for consistency
- Add gradient backgrounds and hover effects to cards
- Add notInstalled i18n translations (zh/en/ja)
- Fix version detection when stdout/stderr is empty

* fix(proxy): persist per-app takeover state across app restarts

- Fix proxy toggle color to reflect current app's takeover state only
- Restore proxy service on startup if Live config is still in takeover state
- Preserve per-app backup records instead of clearing all on restart
- Only recover Live config when proxy service fails to start
This commit is contained in:
YoVinchen
2025-12-19 20:40:11 +08:00
committed by GitHub
parent 6bdbb4df23
commit 5bce6d6020
7 changed files with 270 additions and 120 deletions

View File

@@ -155,11 +155,17 @@ fn try_get_version(tool: &str) -> (Option<String>, Option<String>) {
match output {
Ok(out) => {
let stdout = String::from_utf8_lossy(&out.stdout).trim().to_string();
let stderr = String::from_utf8_lossy(&out.stderr).trim().to_string();
if out.status.success() {
let raw = String::from_utf8_lossy(&out.stdout).trim().to_string();
(Some(extract_version(&raw)), None)
let raw = if stdout.is_empty() { &stderr } else { &stdout };
if raw.is_empty() {
(None, Some("未安装或无法执行".to_string()))
} else {
(Some(extract_version(raw)), None)
}
} else {
let err = String::from_utf8_lossy(&out.stderr).trim().to_string();
let err = if stderr.is_empty() { stdout } else { stderr };
(
None,
Some(if err.is_empty() {
@@ -239,9 +245,13 @@ fn scan_cli_version(tool: &str) -> (Option<String>, Option<String>) {
.output();
if let Ok(out) = output {
let stdout = String::from_utf8_lossy(&out.stdout).trim().to_string();
let stderr = String::from_utf8_lossy(&out.stderr).trim().to_string();
if out.status.success() {
let raw = String::from_utf8_lossy(&out.stdout).trim().to_string();
return (Some(extract_version(&raw)), None);
let raw = if stdout.is_empty() { &stderr } else { &stdout };
if !raw.is_empty() {
return (Some(extract_version(raw)), None);
}
}
}
}

View File

@@ -529,61 +529,64 @@ pub fn run() {
tauri::async_runtime::spawn(async move {
let state = app_handle.state::<AppState>();
// 1. 检测异常退出并恢复 Live 配置
let is_proxy_running = state.proxy_service.is_running().await;
if !is_proxy_running {
let takeover_flag = match state.db.is_live_takeover_active().await {
Ok(active) => active,
Err(e) => {
log::error!("检查接管状态失败: {e}");
false
}
};
// 检查是否有 Live 备份(表示上次有接管状态)
let has_backups = match state.db.has_any_live_backup().await {
Ok(v) => v,
Err(e) => {
log::error!("检查 Live 备份失败: {e}");
false
}
};
let has_backups = match state.db.has_any_live_backup().await {
Ok(v) => v,
Err(e) => {
log::error!("检查 Live 备份失败: {e}");
false
}
};
// 获取代理配置
let proxy_config = match state.db.get_proxy_config().await {
Ok(config) => Some(config),
Err(e) => {
log::error!("启动时获取代理配置失败: {e}");
None
}
};
// 兜底检测:旧版本/极端窗口期可能出现“标志未写入,但 Live 已被写成占位符”的残留状态。
// 只有在存在备份时才检查占位符,避免误判覆盖用户正常配置。
let live_taken_over =
has_backups && state.proxy_service.detect_takeover_in_live_configs();
if has_backups {
// 有备份说明上次退出时有接管状态
// 检查 Live 配置是否仍处于被接管状态(包含占位符)
let live_taken_over = state.proxy_service.detect_takeover_in_live_configs();
if takeover_flag || live_taken_over {
log::warn!("检测到上次异常退出或残留接管状态,正在恢复 Live 配置...");
if let Err(e) = state.proxy_service.recover_from_crash().await {
log::error!("恢复 Live 配置失败: {e}");
} else {
log::info!("Live 配置已从异常退出中恢复");
if live_taken_over {
// Live 配置仍是接管状态,尝试重新启动代理服务以恢复接管
log::info!("检测到上次接管状态,正在重新启动代理服务...");
match state.proxy_service.start(false).await {
Ok(info) => {
log::info!("代理服务器已恢复启动: {}:{}", info.address, info.port);
}
Err(e) => {
// 启动失败,恢复 Live 配置
log::error!("恢复代理服务失败: {e},正在恢复 Live 配置...");
if let Err(e) = state.proxy_service.recover_from_crash().await {
log::error!("恢复 Live 配置失败: {e}");
} else {
log::info!("Live 配置已恢复");
}
}
}
} else if has_backups {
// 备份残留但 Live 未处于接管状态清理敏感备份,避免长期存储 Token
} else {
// Live 配置已经是正常状态清理残留备份
log::info!("Live 配置已是正常状态,清理残留备份...");
if let Err(e) = state.db.delete_all_live_backups().await {
log::warn!("清理残留 Live 备份失败: {e}");
}
}
}
// 2. 自动启动代理服务器(如果配置为启用)
match state.db.get_proxy_config().await {
Ok(config) => {
if config.enabled {
log::info!("代理服务配置为启用,正在启动...");
match state.proxy_service.start(true).await {
Ok(info) => log::info!(
"代理服务器自动启动成功: {}:{}",
info.address,
info.port
),
Err(e) => log::error!("代理服务器自动启动失败: {e}"),
} else if let Some(config) = proxy_config {
// 没有备份,检查是否需要自动启动代理服务器(总开关)
if config.enabled {
log::info!("代理服务配置为启用,正在启动...");
match state.proxy_service.start(true).await {
Ok(info) => {
log::info!("代理服务器自动启动成功: {}:{}", info.address, info.port)
}
Err(e) => log::error!("代理服务器自动启动失败: {e}"),
}
}
Err(e) => log::error!("启动时获取代理配置失败: {e}"),
}
});