using System.IO; using System.Text.Json; using System.Windows; namespace SheetMe.Designer.Services; /// /// 라이트/다크 테마 전환 — App.Resources 의 토큰 사전(Tokens.Dark↔Light)을 교체하면 /// {DynamicResource B.*} 를 참조하는 모든 스타일이 라이브 리스킨된다([200]SheetMe SwapThemeTokens 이식). /// 선택은 %LocalAppData%\SheetMe\theme.json 에 보존. /// public static class ThemeManager { #region Member Fields private static readonly string SettingsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SheetMe", "theme.json"); #endregion #region Properties /// 현재 라이트 테마 여부(기본 다크 — [200]SheetMe 기본값과 동일) public static bool IsLight { get; private set; } #endregion #region Methods /// 시작 시 저장된 테마 적용 public static void LoadSaved() { try { if (File.Exists(SettingsPath) && JsonDocument.Parse(File.ReadAllText(SettingsPath)).RootElement.TryGetProperty("theme", out var theme) && theme.GetString() == "light") { Apply(light: true); } } catch { // 설정 손상 시 기본(다크) 유지 } } /// 라이트↔다크 토글 public static void Toggle() => Apply(!IsLight); /// /// 열려 있는 모든 창의 제목 표시줄을 지금 테마에 맞춘다. /// /// 제목 표시줄은 창 안쪽 자원(B.*)이 아니라 OS 가 그리므로 사전을 바꿔도 따라오지 않는다. /// 테마를 바꾼 순간 이미 떠 있는 창들도 함께 맞춰 줘야 위쪽만 밝은 창이 남지 않는다. /// public static void ApplyChromeToOpenWindows() { foreach (Window window in Application.Current.Windows) { WindowChromeTheme.Apply(window, !IsLight); } } /// 테마 적용 — App.Resources 병합 사전에서 토큰 dict 를 찾아 교체 public static void Apply(bool light) { IsLight = light; var dictionaries = Application.Current.Resources.MergedDictionaries; var tokensUri = new Uri($"/Themes/Tokens.{(light ? "Light" : "Dark")}.xaml", UriKind.Relative); for (var i = 0; i < dictionaries.Count; i++) { var source = dictionaries[i].Source?.OriginalString ?? string.Empty; if (source.EndsWith("Tokens.Dark.xaml", StringComparison.OrdinalIgnoreCase) || source.EndsWith("Tokens.Light.xaml", StringComparison.OrdinalIgnoreCase)) { dictionaries[i] = new ResourceDictionary { Source = tokensUri }; Save(); ApplyChromeToOpenWindows(); return; } } dictionaries.Add(new ResourceDictionary { Source = tokensUri }); Save(); ApplyChromeToOpenWindows(); } private static void Save() { try { Directory.CreateDirectory(Path.GetDirectoryName(SettingsPath)!); File.WriteAllText(SettingsPath, JsonSerializer.Serialize(new { theme = IsLight ? "light" : "dark" })); } catch { // 저장 실패는 무시(다음 실행 기본 테마) } } #endregion }