fix: 字体选择列表加载不了的问题

feat: 整理项目文件
This commit is contained in:
NanGua-QWQ
2026-03-31 19:28:34 +08:00
parent 9a022f3b31
commit c015ff3768
15 changed files with 316 additions and 44 deletions
Binary file not shown.
+134
View File
@@ -1,6 +1,8 @@
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use std::collections::BTreeSet;
use std::process::Command;
use std::sync::Arc;
use tauri::{AppHandle, Emitter, State};
@@ -158,3 +160,135 @@ pub async fn settings_set(
Ok(IpcResponse::success(()))
}
fn fallback_font_families() -> Vec<String> {
vec![
"系统默认".to_string(),
"Microsoft YaHei UI".to_string(),
"Microsoft YaHei".to_string(),
"PingFang SC".to_string(),
"Noto Sans CJK SC".to_string(),
"Source Han Sans SC".to_string(),
"Segoe UI".to_string(),
"Arial".to_string(),
"Helvetica Neue".to_string(),
]
}
fn normalize_font_name(value: &str) -> String {
value
.trim()
.trim_start_matches('@')
.replace(" (TrueType)", "")
.replace(" (OpenType)", "")
.replace(" (All res)", "")
.trim()
.to_string()
}
#[cfg(target_os = "windows")]
fn query_system_fonts() -> Vec<String> {
let output = Command::new("reg")
.args([
"query",
r"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts",
])
.output();
let Ok(output) = output else {
return Vec::new();
};
if !output.status.success() {
return Vec::new();
}
let mut families = BTreeSet::new();
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
if !line.contains("REG_") {
continue;
}
let Some((left, _)) = line.split_once("REG_") else {
continue;
};
let name = normalize_font_name(left);
if !name.is_empty() {
families.insert(name);
}
}
families.into_iter().collect()
}
#[cfg(target_os = "linux")]
fn query_system_fonts() -> Vec<String> {
let output = Command::new("fc-list").args([":", "family"]).output();
let Ok(output) = output else {
return Vec::new();
};
if !output.status.success() {
return Vec::new();
}
let mut families = BTreeSet::new();
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
for part in line.split(',') {
let name = normalize_font_name(part);
if !name.is_empty() {
families.insert(name);
}
}
}
families.into_iter().collect()
}
#[cfg(target_os = "macos")]
fn query_system_fonts() -> Vec<String> {
let output = Command::new("system_profiler")
.args(["SPFontsDataType", "-detailLevel", "mini"])
.output();
let Ok(output) = output else {
return Vec::new();
};
if !output.status.success() {
return Vec::new();
}
let mut families = BTreeSet::new();
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
let trimmed = line.trim();
if let Some(name) = trimmed.strip_prefix("Full Name:") {
let normalized = normalize_font_name(name);
if !normalized.is_empty() {
families.insert(normalized);
}
}
}
families.into_iter().collect()
}
#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
fn query_system_fonts() -> Vec<String> {
Vec::new()
}
#[tauri::command]
pub async fn settings_get_system_fonts() -> Result<IpcResponse<Vec<String>>, String> {
let mut fonts = query_system_fonts();
if fonts.is_empty() {
fonts = fallback_font_families();
} else {
let mut merged = BTreeSet::new();
for item in fallback_font_families() {
merged.insert(item);
}
for item in fonts {
merged.insert(item);
}
fonts = merged.into_iter().collect();
}
Ok(IpcResponse::success(fonts))
}
+6 -1
View File
@@ -68,6 +68,7 @@ pub fn run() {
settings_get_all,
settings_get,
settings_set,
settings_get_system_fonts,
auth_get_status,
auth_login,
auth_logout,
@@ -155,7 +156,11 @@ fn setup_deep_link(app: &mut App) -> Result<(), Box<dyn std::error::Error>> {
use tauri_plugin_deep_link::DeepLinkExt;
app.deep_link().on_open_url(move |event| {
let url = event.urls().first().map(|u| u.to_string()).unwrap_or_default();
let url = event
.urls()
.first()
.map(|u| u.to_string())
.unwrap_or_default();
if !url.is_empty() {
let _ = handle.emit("deep-link://new-url", url);
}
+25
View File
@@ -10,6 +10,7 @@ pub struct SettingsSpec {
pub window_zoom: f64,
pub search_keyboard_layout: String,
pub disable_search_keyboard: bool,
pub font_family: String,
pub themes_custom: JsonValue,
pub auto_score_enabled: bool,
pub auto_score_rules: JsonValue,
@@ -28,6 +29,7 @@ impl Default for SettingsSpec {
window_zoom: 1.0,
search_keyboard_layout: "qwerty26".to_string(),
disable_search_keyboard: false,
font_family: "system".to_string(),
themes_custom: JsonValue::Array(vec![]),
auto_score_enabled: false,
auto_score_rules: JsonValue::Array(vec![]),
@@ -58,6 +60,7 @@ pub enum SettingsKey {
WindowZoom,
SearchKeyboardLayout,
DisableSearchKeyboard,
FontFamily,
ThemesCustom,
AutoScoreEnabled,
AutoScoreRules,
@@ -76,6 +79,7 @@ impl SettingsKey {
SettingsKey::WindowZoom => "window_zoom",
SettingsKey::SearchKeyboardLayout => "search_keyboard_layout",
SettingsKey::DisableSearchKeyboard => "disable_search_keyboard",
SettingsKey::FontFamily => "font_family",
SettingsKey::ThemesCustom => "themes_custom",
SettingsKey::AutoScoreEnabled => "auto_score_enabled",
SettingsKey::AutoScoreRules => "auto_score_rules",
@@ -94,6 +98,7 @@ impl SettingsKey {
"window_zoom" => Some(SettingsKey::WindowZoom),
"search_keyboard_layout" => Some(SettingsKey::SearchKeyboardLayout),
"disable_search_keyboard" => Some(SettingsKey::DisableSearchKeyboard),
"font_family" => Some(SettingsKey::FontFamily),
"themes_custom" => Some(SettingsKey::ThemesCustom),
"auto_score_enabled" => Some(SettingsKey::AutoScoreEnabled),
"auto_score_rules" => Some(SettingsKey::AutoScoreRules),
@@ -327,6 +332,22 @@ impl SettingsService {
},
);
defs.insert(
SettingsKey::FontFamily,
SettingDefinition {
kind: SettingValueKind::String,
default_value: SettingsValue::String("system".to_string()),
write_permission: PermissionRequirement::Admin,
validate: Some(|v| {
if let SettingsValue::String(s) = v {
!s.trim().is_empty()
} else {
false
}
}),
},
);
defs.insert(
SettingsKey::ThemesCustom,
SettingDefinition {
@@ -549,6 +570,10 @@ impl SettingsService {
SettingsValue::Boolean(b) => b,
_ => false,
},
font_family: match self.get_value(SettingsKey::FontFamily) {
SettingsValue::String(s) => s,
_ => "system".to_string(),
},
themes_custom: match self.get_value(SettingsKey::ThemesCustom) {
SettingsValue::Json(j) => j,
_ => JsonValue::Array(vec![]),