Files
iboard/src-tauri/src/shell/config.rs
T

161 lines
6.2 KiB
Rust

// 澶栧3璁剧疆鎸佷箙鍖?(W-CFG-01~03): %APPDATA%\com.iboard.app\shell-config.json
// - 涓庡墠绔处鍙?鏈嶅姟绔棤鍏? 绂荤嚎鍙敤;
// - 瀛楁缂哄け/鎹熷潖鏃跺洖閫€榛樿鍊?(serde(default) + 瀹芥澗鍔犺浇);
// - 鍐欏叆閲囩敤 涓存椂鏂囦欢 + 鏇挎崲 鐨勫師瀛愯涔夈€?
use serde::{Deserialize, Serialize};
use std::path::Path;
pub const FILE_NAME: &str = "shell-config.json";
/// 璁捐鍩哄噯灏哄 (绉诲姩绔竷灞€鍙e緞): 绐楀彛姣斾緥閿佹涓?405:720
pub const DESIGN_WIDTH: f64 = 405.0;
pub const DESIGN_HEIGHT: f64 = 720.0;
/// 窗口宽度可配置范围 (逻辑像素); 高度由比例推导, 不接受单独配置
pub const WIDTH_MIN: f64 = 242.0;
pub const WIDTH_MAX: f64 = 620.0;
/// 鎸夐攣瀹氭瘮渚嬬敱瀹藉害鎺ㄥ楂樺害 (鍞竴灏哄鍏ュ彛)
pub fn height_for_width(width: f64) -> f64 {
let w = width.clamp(WIDTH_MIN, WIDTH_MAX);
(w * DESIGN_HEIGHT / DESIGN_WIDTH).round()
}
/// 鍚搁檮杈?(W-SNP-01: 鍥涜竟)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum Edge {
#[default]
Left,
Right,
Top,
Bottom,
}
impl Edge {
pub fn css(&self) -> &'static str {
match self {
Edge::Left => "left",
Edge::Right => "right",
Edge::Top => "top",
Edge::Bottom => "bottom",
}
}
}
/// 涓荤獥鍙h蹇?(W-WIN-07): 灏哄涓洪€昏緫鍍忕礌 (DPI 绋冲畾), 浣嶇疆涓虹墿鐞嗗儚绱?(鍔犺浇鏃舵牎楠屽す鍙?
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct WindowCfg {
pub width: f64,
pub height: f64,
pub x: Option<i32>,
pub y: Option<i32>,
}
impl Default for WindowCfg {
fn default() -> Self {
// 323x574 = 405:720 姣斾緥 (0.797x of 405x720, 2026-10-26 鏀惧ぇ 12%)
Self { width: 323.0, height: height_for_width(323.0), x: None, y: None }
}
}
/// 鎮诞鐞冨仠闈?(W-SNP-02/12): 杈?+ 娌胯竟浣嶇疆 (鎮诞鐞冧腑蹇? 鐗╃悊鍍忕礌)
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct DockCfg {
pub edge: Edge,
pub offset: i32,
}
impl Default for DockCfg {
fn default() -> Self {
Self { edge: Edge::Left, offset: 360 }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ShellConfig {
/// 鍚搁檮鎬诲紑鍏?(W-SNP-09, 榛樿寮€鍚?
pub snap_enabled: bool,
pub window: WindowCfg,
pub dock: DockCfg,
/// 绐楀彛瀹藉害 (閫昏緫鍍忕礌) 鈥斺€?**鍞竴灏哄閰嶇疆椤?*銆? /// 楂樺害鎸?405:720 閿佸畾姣斾緥鑷姩鎺ㄥ, 鏃犻渶涔熸棤娉曞崟鐙厤缃?
/// 鐣欑┖鏃跺洖钀藉埌 window.width銆? #[serde(default)]
pub window_width: Option<f64>,
/// 閰嶇疆缁撴瀯鐗堟湰: 0 = 鏃х増 (绐楀彛灏哄鎸?405x720 鍙e緞淇濆瓨),
/// 1 = 鏁翠綋缂╁皬 30% (288 鍙e緞), 2 = 鏀惧ぇ 12% (323 鍙e緞) + 鍗曞€煎搴﹂厤缃€? /// load 鏃跺仛涓€娆℃€ц縼绉汇€? /// 娉ㄦ剰蹇呴』鐢ㄥ瓧娈电骇 serde(default) (u8 鈫?0): 瀹瑰櫒绾?default 浼氬彇
/// ShellConfig::default() 鐨?2, 鏃ч厤缃枃浠跺氨姘歌繙涓嶈縼绉讳簡銆? #[serde(default)]
pub cfg_version: u8,
}
impl Default for ShellConfig {
fn default() -> Self {
Self {
snap_enabled: true,
window: WindowCfg::default(),
dock: DockCfg::default(),
window_width: Some(WindowCfg::default().width),
cfg_version: 2,
}
}
}
/// 杩佺Щ鍓嶇殑绐楀彛瀹藉害 (鏃у彛寰?, 渚?load 浣跨敤
impl WindowCfg {
/// 搴旂敤閿佸畾姣斾緥: 瀹藉害澶瑰彇鍒板悎娉曡寖鍥? 楂樺害鐢卞搴︽帹瀵?(蹇界暐瀛樼洏楂樺害)
pub(crate) fn normalize(&mut self) {
self.width = self.width.clamp(WIDTH_MIN, WIDTH_MAX);
self.height = height_for_width(self.width);
}
}
impl ShellConfig {
pub fn load(dir: &Path) -> ShellConfig {
let path = dir.join(FILE_NAME);
let mut cfg = match std::fs::read_to_string(&path) {
Ok(text) => match serde_json::from_str::<ShellConfig>(&text) {
Ok(cfg) => cfg,
Err(_) => ShellConfig::default(), // 鍐欏潖 JSON 鈫?榛樿鍊?(W-CFG-03)
},
Err(_) => ShellConfig::default(),
};
// 一次性迁移
if cfg.cfg_version < 1 {
// v0 (405 鍙e緞) 鈫?v1: 鏁翠綋缂╁皬 30%
cfg.window.width = (cfg.window.width * 0.7).max(216.0);
cfg.window.height = (cfg.window.height * 0.7).max(384.0);
cfg.cfg_version = 1;
}
if cfg.cfg_version < 2 {
// v1 (288 口径) -> v2: 放大 12% (323 口径), 引入单值宽度配置
cfg.window.width = (cfg.window.width * 1.12).max(WIDTH_MIN);
cfg.window.height = height_for_width(cfg.window.width);
cfg.cfg_version = 2;
}
// 鍗曞€煎搴︿紭鍏? 楂樺害涓€寰嬫寜閿佸畾姣斾緥鎺ㄥ (蹇界暐瀛樼洏楂樺害)
if let Some(w) = cfg.window_width {
cfg.window.width = w;
}
cfg.window.normalize();
cfg.window_width = Some(cfg.window.width);
cfg.save(dir);
cfg
}
pub fn save(&self, dir: &Path) {
let path = dir.join(FILE_NAME);
let tmp = dir.join(format!("{FILE_NAME}.tmp"));
let text = match serde_json::to_string_pretty(self) {
Ok(t) => t,
Err(_) => return,
};
if std::fs::write(&tmp, text).is_ok() {
// Windows 上 rename 不能覆盖已存在文件, 先移除
let _ = std::fs::remove_file(&path);
let _ = std::fs::rename(&tmp, &path);
}
// 鍐欏け璐ヤ繚鎸侀潤榛?(W-CFG-04): 杩愯涓殑澶栧3涓嶅彈褰卞搷
}
}