refactor: eliminate startup flicker — defer window show until overlay renders

- Remove Rust-side `eval(INITIAL_LOADING_OVERLAY)` that prematurely
  dismissed the overlay before React/MUI theme was ready
- Defer `window.show()` from Rust `activate_window` to an inline
  `<script>` in index.html, executed after the themed overlay is in DOM
- Remove `useAppInitialization` hook (duplicate of `useLoadingOverlay`
  with no themeReady gate)
- Simplify overlay to pure theme-colored background — no spinner or
  loading text — so fast startup feels instant
- Simplify `hideInitialOverlay` API and reduce overlay fade to 0.2s
- Clean up unused CSS variables (spinner-track, spinner-top, etc.)
This commit is contained in:
Tunglies
2026-04-06 01:53:40 +08:00
parent 04ce3d1772
commit ec82b69786
9 changed files with 43 additions and 201 deletions
+1 -6
View File
@@ -2,11 +2,7 @@ use dark_light::{Mode as SystemTheme, detect as detect_system_theme};
use tauri::utils::config::Color;
use tauri::{Theme, WebviewWindow};
use crate::{
config::Config,
core::handle,
utils::resolve::window_script::{INITIAL_LOADING_OVERLAY, build_window_initial_script},
};
use crate::{config::Config, core::handle, utils::resolve::window_script::build_window_initial_script};
use clash_verge_logging::{Type, logging_error};
const DARK_BACKGROUND_COLOR: Color = Color(46, 48, 61, 255); // #2E303D
@@ -82,7 +78,6 @@ pub async fn build_new_window() -> Result<WebviewWindow, String> {
match builder.build() {
Ok(window) => {
logging_error!(Type::Window, window.set_background_color(Some(background_color)));
logging_error!(Type::Window, window.eval(INITIAL_LOADING_OVERLAY));
Ok(window)
}
Err(e) => Err(e.to_string()),
@@ -91,11 +91,3 @@ pub const WINDOW_INITIAL_SCRIPT: &str = r##"
console.log('[Tauri] 窗口初始化脚本执行完成');
"##;
pub const INITIAL_LOADING_OVERLAY: &str = r"
const overlay = document.getElementById('initial-loading-overlay');
if (overlay) {
overlay.style.opacity = '0';
setTimeout(() => overlay.remove(), 300);
}
";
+12 -12
View File
@@ -285,6 +285,7 @@ impl WindowManager {
}
/// 创建新窗口,防抖避免重复调用
/// 窗口创建后保持隐藏,由前端 index.html 在 overlay 渲染后调用 show,避免主题闪烁
pub fn create_window(is_show: bool) -> Pin<Box<dyn Future<Output = bool> + Send>> {
Box::pin(async move {
logging!(info, Type::Window, "开始创建/显示主窗口, is_show={}", is_show);
@@ -293,23 +294,22 @@ impl WindowManager {
return false;
}
let window = match build_new_window().await {
Ok(window) => {
logging!(info, Type::Window, "新窗口创建成功");
window
match build_new_window().await {
Ok(_) => {
logging!(info, Type::Window, "新窗口创建成功,等待前端渲染后显示");
#[cfg(target_os = "macos")]
{
handle::Handle::global().set_activation_policy_regular();
}
true
}
Err(e) => {
logging!(error, Type::Window, "新窗口创建失败: {}", e);
return false;
false
}
};
// 直接激活刚创建的窗口,避免因防抖导致首次显示被跳过
if WindowOperationResult::Failed == Self::activate_window(&window) {
return false;
}
true
})
}