using System.Text.Json; using System.Text.Json.Serialization; using ClaudeDo.Data; namespace ClaudeDo.Ui; public sealed class AppSettings { public string DbPath { get; set; } = "~/.claudeDo/todo.db"; public string SignalRUrl { get; set; } = "http://127.0.0.1:47821/hub"; public string Language { get; set; } = ""; public string AccentPreset { get; set; } = ""; /// Diff viewer layout: "unified" or "split". A view preference, so it lives here in /// ui.config.json rather than in the worker-owned AppSettingsEntity. public string DiffViewMode { get; set; } = "unified"; public bool DiffWrapLines { get; set; } /// Mission Control overview column count; 0 = auto (derived from the pane count). public int MissionControlColumns { get; set; } private static readonly string DefaultConfigPath = Paths.Expand("~/.claudeDo/ui.config.json"); /// Where this instance persists. Instance-level (not static) so tests can redirect it — /// the diff-viewer toggles call Save() on every flip. [JsonIgnore] public string ConfigPath { get; set; } = DefaultConfigPath; public static AppSettings Load(string? configPath = null) { var path = configPath ?? DefaultConfigPath; try { if (File.Exists(path)) { var json = File.ReadAllText(path); var loaded = JsonSerializer.Deserialize(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); if (loaded is not null) { loaded.ConfigPath = path; return loaded; } } } catch { // Fall through to defaults } return new AppSettings { ConfigPath = path }; } public void Save() { var dir = Path.GetDirectoryName(ConfigPath); if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir); var json = JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(ConfigPath, json); } }