| | | 1 | | using System; |
| | | 2 | | using System.Collections.Generic; |
| | | 3 | | using System.Linq; |
| | | 4 | | using System.Windows; |
| | | 5 | | using System.Windows.Media; |
| | | 6 | | using Color = System.Windows.Media.Color; |
| | | 7 | | using ColorConverter = System.Windows.Media.ColorConverter; |
| | | 8 | | |
| | | 9 | | namespace SwitchBlade.Services |
| | | 10 | | { |
| | | 11 | | public class ThemeInfo |
| | | 12 | | { |
| | 981 | 13 | | public string Name { get; set; } = ""; |
| | 668 | 14 | | public ResourceDictionary Resources { get; set; } = new ResourceDictionary(); |
| | | 15 | | } |
| | | 16 | | |
| | | 17 | | public class ThemeService |
| | | 18 | | { |
| | | 19 | | private readonly ISettingsService _settingsService; |
| | | 20 | | private readonly IApplicationResourceHandler _resourceHandler; |
| | | 21 | | private ResourceDictionary? _currentThemeDictionary; |
| | | 22 | | public List<ThemeInfo> AvailableThemes { get; private set; } = new List<ThemeInfo>(); |
| | | 23 | | |
| | | 24 | | public ThemeService(ISettingsService settingsService, IApplicationResourceHandler? resourceHandler = null) |
| | | 25 | | { |
| | | 26 | | _settingsService = settingsService; |
| | | 27 | | _resourceHandler = resourceHandler ?? new WpfApplicationResourceHandler(); |
| | | 28 | | InitializeThemes(); |
| | | 29 | | } |
| | | 30 | | |
| | | 31 | | private void InitializeThemes() |
| | | 32 | | { |
| | | 33 | | AvailableThemes = new List<ThemeInfo> |
| | | 34 | | { |
| | | 35 | | // Sleek Dark (Default) |
| | | 36 | | CreateTheme("Dark", "#1E1E1E", "#2D2D30", "#DDDDDD", "#3E3E42"), |
| | | 37 | | // Cyberpunk (High Contrast Neon) |
| | | 38 | | CreateTheme("Cyberpunk", "#09080D", "#13111A", "#00FF9F", "#FF003C"), |
| | | 39 | | // Deep Ocean (Blue/Black) |
| | | 40 | | CreateTheme("Deep Ocean", "#0F1724", "#172336", "#E6F1FF", "#1E2D45"), |
| | | 41 | | // Moonlight (Cool Grey) |
| | | 42 | | CreateTheme("Moonlight", "#22252A", "#2C3038", "#AABBC3", "#3C424D"), |
| | | 43 | | // Dracula (Classic) |
| | | 44 | | CreateTheme("Dracula", "#282a36", "#44475a", "#f8f8f2", "#7b88bd"), |
| | | 45 | | // Light (Clean) |
| | | 46 | | CreateTheme("Light", "#F5F5F5", "#FFFFFF", "#333333", "#E0E0E0"), |
| | | 47 | | // Super Light (Pure White) |
| | | 48 | | CreateTheme("Super Light", "#FFFFFF", "#FFFFFF", "#111111", "#F0F0F0"), |
| | | 49 | | }; |
| | | 50 | | } |
| | | 51 | | |
| | | 52 | | private static ThemeInfo CreateTheme(string name, string background, string controlBackground, string foreground |
| | | 53 | | { |
| | | 54 | | var dict = new ResourceDictionary(); |
| | | 55 | | |
| | | 56 | | // Background with 85% opacity for Glass effect |
| | | 57 | | var bgCol = (Color)ColorConverter.ConvertFromString(background); |
| | | 58 | | bgCol.A = 217; // ~85% |
| | | 59 | | dict["WindowBackground"] = new SolidColorBrush(bgCol); |
| | | 60 | | |
| | | 61 | | // Control background with 60% opacity |
| | | 62 | | var ctrlCol = (Color)ColorConverter.ConvertFromString(controlBackground); |
| | | 63 | | ctrlCol.A = 153; // ~60% |
| | | 64 | | dict["ControlBackground"] = new SolidColorBrush(ctrlCol); |
| | | 65 | | |
| | | 66 | | dict["ForegroundBrush"] = new SolidColorBrush((Color)ColorConverter.ConvertFromString(foreground)); |
| | | 67 | | |
| | | 68 | | // Border with 60% opacity (Upgraded from 30% for secondary text contrast) |
| | | 69 | | var borderCol = (Color)ColorConverter.ConvertFromString(border); |
| | | 70 | | borderCol.A = 153; // ~60% |
| | | 71 | | dict["BorderBrush"] = new SolidColorBrush(borderCol); |
| | | 72 | | |
| | | 73 | | // Highlight: Use border color with more opacity for better hover contrast |
| | | 74 | | var highlightCol = (Color)ColorConverter.ConvertFromString(border); |
| | | 75 | | highlightCol.A = 150; // ~60% for better contrast |
| | | 76 | | dict["HighlightBrush"] = new SolidColorBrush(highlightCol); |
| | | 77 | | |
| | | 78 | | // Accent Brush (Blue-ish defaults, can be customized per theme) |
| | | 79 | | dict["AccentBrush"] = new SolidColorBrush(Color.FromRgb(0, 120, 215)); |
| | | 80 | | |
| | | 81 | | return new ThemeInfo { Name = name, Resources = dict }; |
| | | 82 | | } |
| | | 83 | | |
| | | 84 | | public void ApplyTheme(string themeName) |
| | | 85 | | { |
| | | 86 | | var theme = AvailableThemes.FirstOrDefault(t => t.Name == themeName) ?? AvailableThemes.First(); |
| | | 87 | | |
| | | 88 | | // Remove the previously applied theme dictionary |
| | | 89 | | if (_currentThemeDictionary != null) |
| | | 90 | | { |
| | | 91 | | _resourceHandler.RemoveMergedDictionary(_currentThemeDictionary); |
| | | 92 | | } |
| | | 93 | | |
| | | 94 | | // apply new one |
| | | 95 | | _currentThemeDictionary = theme.Resources; |
| | | 96 | | _resourceHandler.AddMergedDictionary(_currentThemeDictionary); |
| | | 97 | | |
| | | 98 | | if (_settingsService.Settings.CurrentTheme != themeName) |
| | | 99 | | { |
| | | 100 | | _settingsService.Settings.CurrentTheme = themeName; |
| | | 101 | | _settingsService.SaveSettings(); |
| | | 102 | | } |
| | | 103 | | } |
| | | 104 | | |
| | | 105 | | public void LoadCurrentTheme() |
| | | 106 | | { |
| | | 107 | | ApplyTheme(_settingsService.Settings.CurrentTheme); |
| | | 108 | | } |
| | | 109 | | } |
| | | 110 | | } |