Files
OneCAD-Draft/src/app/config.rs
T
Hakan SevenandClaude Opus 4.8 dc7117f203 refactor(config): consolidate settings into one grouped settings.json
App preferences were spread across six flat plain-text files (settings.txt,
recent.txt, recent_limit.txt, statusbar.txt, ribbon.txt, plot.txt), each with a
bespoke line parser and no grouping. Replace them with a single grouped JSON,
serialized via serde (enabling the derive feature; serde_json was already a
dependency).

- New app/config.rs: AppConfig { settings, recent, statusbar, ribbon, plot } →
  <config>/settings.json (pretty JSON), load()/save().
- Make UserSettings, StatusBarConfig/StatusPill, CollapseMode and
  PlotDialogState serde-derived; #[serde(skip)] marks the plot dialog's runtime
  fields so only print preferences persist. Their bespoke .txt load/save is
  removed.
- App gains current_config/apply_config/save_config: one AppConfig::load at
  startup distributes into live state; every settings-change site
  (persist_settings_if_changed, recent add/remove/limit, status-bar pill
  toggle, ribbon density, plot commit) routes through save_config, which diffs
  against the last write to avoid thrashing.
- Clean start: the old flat files are ignored (no migration). ocad.pgp stays a
  separate hand-editable file.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-10 16:41:34 +03:00

95 lines
3.1 KiB
Rust

//! Consolidated user configuration — one grouped JSON file
//! (`<config>/OpenCADStudio/settings.json`) holding every app preference except
//! the command aliases (which stay in the hand-editable `ocad.pgp`). Serialized
//! via serde so the file is structured and grouped, replacing the former
//! scattered flat stores (`settings.txt` / `recent.txt` / `recent_limit.txt` /
//! `statusbar.txt` / `ribbon.txt` / `plot.txt`).
use serde::{Deserialize, Serialize};
use super::settings::UserSettings;
use crate::ui::ribbon::CollapseMode;
use crate::ui::statusbar::statusbar_config::StatusBarConfig;
use crate::ui::window::plot::PlotDialogState;
/// The whole persisted config, grouped into top-level sections.
#[derive(Clone, PartialEq, Serialize, Deserialize)]
#[serde(default)]
pub struct AppConfig {
/// Input modes, backup, plugin lists, viewport background colours, …
pub settings: UserSettings,
/// Recent-files list + retained count.
pub recent: RecentConfig,
/// Which status-bar pills the user has hidden.
pub statusbar: StatusBarConfig,
/// Ribbon collapse density.
pub ribbon: RibbonConfig,
/// Print dialog preferences (only the persisted fields; runtime state is
/// skipped by `PlotDialogState`'s serde attributes).
pub plot: PlotDialogState,
}
impl Default for AppConfig {
fn default() -> Self {
Self {
settings: UserSettings::default(),
recent: RecentConfig::default(),
statusbar: StatusBarConfig::default(),
ribbon: RibbonConfig::default(),
plot: PlotDialogState::default(),
}
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
#[serde(default)]
pub struct RecentConfig {
/// Recently opened file paths, newest first.
pub files: Vec<String>,
/// How many recent files to keep.
pub limit: usize,
}
impl Default for RecentConfig {
fn default() -> Self {
Self {
files: Vec::new(),
limit: super::recent::RECENT_DEFAULT,
}
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct RibbonConfig {
pub collapse: CollapseMode,
}
impl AppConfig {
/// Read the saved config, or all-defaults when the file is missing or
/// unreadable (fresh install / wasm). Unknown or missing fields fall back to
/// their section defaults via `#[serde(default)]`.
pub fn load() -> Self {
config_path()
.and_then(|p| std::fs::read_to_string(p).ok())
.and_then(|body| serde_json::from_str(&body).ok())
.unwrap_or_default()
}
/// Persist the config as pretty JSON. Best-effort; silent on failure
/// (read-only home, full disk, wasm — where `config_dir` is `None`).
pub fn save(&self) {
let Some(path) = config_path() else { return };
if let Some(dir) = path.parent() {
let _ = std::fs::create_dir_all(dir);
}
if let Ok(json) = serde_json::to_string_pretty(self) {
let _ = std::fs::write(path, json);
}
}
}
fn config_path() -> Option<std::path::PathBuf> {
Some(crate::config::config_dir()?.join("settings.json"))
}