feat(ui): add cross-platform window control styles

Persist automatic and explicit macOS, Windows, GNOME, and minimal control presets with localized settings and platform-aware fallback.

Refs #31
This commit is contained in:
NimBold
2026-07-23 16:25:39 +03:30
parent 6adbccdf43
commit 4e3ceb21a5
18 changed files with 294 additions and 6 deletions
+19
View File
@@ -214,6 +214,23 @@ pub enum Theme {
Nord,
}
#[derive(Clone, Debug, Serialize, Deserialize, TS)]
#[serde(rename_all = "lowercase")]
#[ts(export, export_to = "../../src/bindings/")]
pub enum WindowControlStyle {
Auto,
Macos,
Windows,
Gnome,
Minimal,
}
impl Default for WindowControlStyle {
fn default() -> Self {
Self::Auto
}
}
#[derive(Clone, Debug, Serialize, Deserialize, TS)]
#[serde(rename_all = "lowercase")]
#[ts(export, export_to = "../../src/bindings/")]
@@ -295,6 +312,8 @@ pub struct SchedulerSettings {
pub struct PersistedSettings {
pub theme: Theme,
#[serde(default)]
pub window_control_style: WindowControlStyle,
#[serde(default)]
pub calendar_preference: CalendarPreference,
#[serde(default = "default_language_preference")]
pub language: String,
+23 -1
View File
@@ -1,6 +1,6 @@
use crate::ipc::{
AppFontSize, CalendarPreference, ListRowDensity, MediaCookieSource, PersistedSettings,
PostQueueAction, ProxyMode, SchedulerSettings, SettingsTab, Theme,
PostQueueAction, ProxyMode, SchedulerSettings, SettingsTab, Theme, WindowControlStyle,
};
use serde_json::{Map, Value};
use std::collections::HashMap;
@@ -192,6 +192,11 @@ fn sanitize_persisted_setting_values(state: &mut Value) {
"theme",
&["system", "light", "dark", "dracula", "nord"],
);
sanitize_allowed_string(
state,
"windowControlStyle",
&["auto", "macos", "windows", "gnome", "minimal"],
);
sanitize_allowed_string(
state,
"language",
@@ -417,6 +422,7 @@ fn derived_location_path(base: &str, subfolder: &str) -> String {
fn default_settings() -> PersistedSettings {
PersistedSettings {
theme: Theme::System,
window_control_style: WindowControlStyle::Auto,
calendar_preference: CalendarPreference::Gregorian,
language: "system".to_string(),
base_download_folder: "~/Downloads".to_string(),
@@ -472,6 +478,7 @@ fn default_settings() -> PersistedSettings {
#[cfg(test)]
mod tests {
use crate::ipc::WindowControlStyle;
use super::{
decode_stored_settings, default_settings, preserve_portable_pairing_token,
preserve_scheduler_runtime_keys,
@@ -678,6 +685,21 @@ mod tests {
assert_eq!(settings.sidebar_position, "auto");
}
#[test]
fn invalid_window_control_style_uses_automatic_layout() {
let stored = json!({
"state": {"windowControlStyle": "neon"},
"version": 5
});
let settings = decode_stored_settings(&Value::String(stored.to_string())).unwrap();
assert!(matches!(
settings.window_control_style,
WindowControlStyle::Auto
));
}
#[test]
fn clamps_out_of_range_download_settings() {
let stored = json!({