using System.IO; using System.Text.Json; namespace TeamsISO.App.Services; /// /// Persistent UI-side toggles that don't belong in /// (which is the engine's domain model — framerate, NDI groups, ISO assignments). /// /// Each toggle is a property on a single record persisted as JSON at /// %LOCALAPPDATA%\TeamsISO\ui-prefs.json. Defaults match the original /// in-memory behavior: HideLocalSelf=true (filter the operator's own preview /// out of the participants list) and AutoDisableOnDeparture=false (a participant /// going offline doesn't tear down their pipeline by default — operators /// usually want to keep the routing in case they reconnect). /// /// Centralizing these here means the settings VM doesn't have to plumb /// individual Set methods to dedicated services for every new bool. /// public static class UIPreferences { private static readonly object _gate = new(); private static string PrefsPath => Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TeamsISO", "ui-prefs.json"); /// /// Sort modes for the participants DataGrid. is the default /// and matches the engine's discovery order (operators with custom Stream Deck /// layouts sometimes prefer Alphabetical for stability across meetings). /// public enum SortMode { JoinOrder, Alphabetical, OnlineFirst } /// The on-disk shape. New fields added here become opt-in for older files via default values. public sealed record Prefs( bool HideLocalSelf = true, bool AutoDisableOnDeparture = false, SortMode ParticipantSort = SortMode.JoinOrder, bool MinimizeToTray = false); public static Prefs Load() { try { if (!File.Exists(PrefsPath)) return new Prefs(); var json = File.ReadAllText(PrefsPath); return JsonSerializer.Deserialize(json) ?? new Prefs(); } catch { return new Prefs(); } } public static void Save(Prefs prefs) { try { lock (_gate) { var dir = Path.GetDirectoryName(PrefsPath); if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir); var json = JsonSerializer.Serialize(prefs, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(PrefsPath, json); } } catch { // Disk full / permission denied — in-memory state still holds for this session. } } }