pub mod apply;
mod defaults;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppSettings {
#[serde(default)]
pub zoom: ZoomSettings,
#[serde(default)]
pub theme: ThemeSettings,
#[serde(default)]
pub icons: IconSettings,
#[serde(default)]
pub font: FontSettings,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ZoomSettings {
pub scale: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ThemeMode {
System,
Light,
Dark,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThemeSettings {
pub mode: ThemeMode,
pub accent: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum IconStyle {
Filled,
Outlined,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IconSettings {
pub style: IconStyle,
pub color: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FontSettings {
pub family: Option<String>,
pub font_scale: f32,
}
impl AppSettings {
pub fn from_file(path: &std::path::Path) -> Result<Self, Box<dyn std::error::Error>> {
crate::gateway::settings::from_file(path)
}
pub fn from_file_or_default(path: &std::path::Path) -> Self {
crate::gateway::settings::from_file_or_default(path)
}
pub fn to_file(&self, path: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> {
crate::gateway::settings::to_file(self, path)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn settings_defaults() {
let s = AppSettings::default();
assert_eq!(s.zoom.scale, 1.0);
assert_eq!(s.theme.mode, ThemeMode::System);
assert!(s.theme.accent.is_none());
assert_eq!(s.icons.style, IconStyle::Filled);
assert_eq!(s.icons.color, "theme");
assert!(s.font.family.is_none());
assert_eq!(s.font.font_scale, 1.0);
}
#[test]
fn settings_toml_round_trip() {
let original = AppSettings {
zoom: ZoomSettings { scale: 1.5 },
theme: ThemeSettings { mode: ThemeMode::Dark, accent: Some("#ff6b35".into()) },
icons: IconSettings { style: IconStyle::Outlined, color: "accent".into() },
font: FontSettings { family: Some("Segoe UI".into()), font_scale: 1.1 },
};
let toml_str = toml::to_string_pretty(&original).unwrap();
let loaded: AppSettings = toml::from_str(&toml_str).unwrap();
assert!((loaded.zoom.scale - 1.5).abs() < 0.001);
assert_eq!(loaded.theme.mode, ThemeMode::Dark);
assert_eq!(loaded.theme.accent, Some("#ff6b35".into()));
assert_eq!(loaded.icons.style, IconStyle::Outlined);
assert_eq!(loaded.icons.color, "accent");
assert_eq!(loaded.font.family, Some("Segoe UI".into()));
assert!((loaded.font.font_scale - 1.1).abs() < 0.001);
}
#[test]
fn settings_file_round_trip() {
let path = std::env::temp_dir().join("slint_ui_test_settings.toml");
let original = AppSettings {
zoom: ZoomSettings { scale: 0.8 },
..AppSettings::default()
};
original.to_file(&path).unwrap();
let loaded = AppSettings::from_file(&path).unwrap();
assert!((loaded.zoom.scale - 0.8).abs() < 0.001);
}
}