Files
clash-verge-rev/src-tauri/src/utils/resolve/window.rs
T

140 lines
4.4 KiB
Rust

use dark_light::{Mode as SystemTheme, detect as detect_system_theme};
use tauri::utils::config::Color;
use tauri::webview::PageLoadEvent;
use tauri::{Theme, WebviewWindow};
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
const LIGHT_BACKGROUND_COLOR: Color = Color(245, 245, 245, 255); // #F5F5F5
const DARK_BACKGROUND_HEX: &str = "#2E303D";
const LIGHT_BACKGROUND_HEX: &str = "#F5F5F5";
// 定义默认窗口尺寸常量
const DEFAULT_WIDTH: f64 = 940.0;
const DEFAULT_HEIGHT: f64 = 700.0;
const MINIMAL_WIDTH: f64 = 520.0;
const MINIMAL_HEIGHT: f64 = 520.0;
#[cfg(target_os = "linux")]
const DEFAULT_DECORATIONS: bool = false;
#[cfg(not(target_os = "linux"))]
const DEFAULT_DECORATIONS: bool = true;
const fn restored_window_size_is_too_small(width: u32, height: u32) -> bool {
width < MINIMAL_WIDTH as u32 || height < MINIMAL_HEIGHT as u32
}
fn restore_default_size_if_needed(window: &WebviewWindow) {
let Ok(size) = window.outer_size() else {
return;
};
if !restored_window_size_is_too_small(size.width, size.height) {
return;
}
logging_error!(
Type::Window,
window.set_size(tauri::LogicalSize::new(DEFAULT_WIDTH, DEFAULT_HEIGHT))
);
logging_error!(Type::Window, window.center());
}
/// 构建新的 WebView 窗口
pub async fn build_new_window() -> Result<WebviewWindow, String> {
let app_handle = handle::Handle::app_handle();
let config = Config::verge().await;
let latest = config.latest_arc();
let start_page = latest.start_page.as_deref().unwrap_or("/");
let initial_theme_mode = match latest.theme_mode.as_deref() {
Some("dark") => "dark",
Some("light") => "light",
_ => "system",
};
let resolved_theme = match initial_theme_mode {
"dark" => Some(Theme::Dark),
"light" => Some(Theme::Light),
_ => None,
};
let prefers_dark_background = match resolved_theme {
Some(Theme::Dark) => true,
Some(Theme::Light) => false,
_ => !matches!(detect_system_theme().ok(), Some(SystemTheme::Light)),
};
let background_color = if prefers_dark_background {
DARK_BACKGROUND_COLOR
} else {
LIGHT_BACKGROUND_COLOR
};
let initial_script = build_window_initial_script(initial_theme_mode, DARK_BACKGROUND_HEX, LIGHT_BACKGROUND_HEX);
let mut builder = tauri::WebviewWindowBuilder::new(
app_handle,
"main", /* the unique window label */
tauri::WebviewUrl::App(start_page.into()),
)
.title("Clash Verge")
.center()
.decorations(DEFAULT_DECORATIONS)
.fullscreen(false)
.inner_size(DEFAULT_WIDTH, DEFAULT_HEIGHT)
.min_inner_size(MINIMAL_WIDTH, MINIMAL_HEIGHT)
.visible(false) // 等待主题色准备好后再展示,避免启动色差
.initialization_script(&initial_script)
.general_autofill_enabled(false) // 禁用自动填充
.on_page_load(move |window, payload| {
if payload.event() != PageLoadEvent::Finished {
return;
}
logging_error!(Type::Window, window.show());
logging_error!(Type::Window, window.set_focus());
});
if let Some(theme) = resolved_theme {
builder = builder.theme(Some(theme));
}
builder = builder.background_color(background_color);
match builder.build() {
Ok(window) => {
logging_error!(Type::Window, window.set_background_color(Some(background_color)));
restore_default_size_if_needed(&window);
Ok(window)
}
Err(e) => Err(e.to_string()),
}
}
#[cfg(test)]
mod tests {
use super::restored_window_size_is_too_small;
#[test]
fn restored_window_size_rejects_zero_dimensions() {
assert!(restored_window_size_is_too_small(0, 700));
assert!(restored_window_size_is_too_small(940, 0));
}
#[test]
fn restored_window_size_rejects_dimensions_below_minimum() {
assert!(restored_window_size_is_too_small(519, 700));
assert!(restored_window_size_is_too_small(940, 519));
}
#[test]
fn restored_window_size_accepts_minimum_or_larger_dimensions() {
assert!(!restored_window_size_is_too_small(520, 520));
assert!(!restored_window_size_is_too_small(940, 700));
}
}