using System.Windows; using System.Windows.Media; using Microsoft.Win32; using TaskbarLauncher.Models; using MediaColor = System.Windows.Media.Color; namespace TaskbarLauncher.Services; public static class ThemeService { private const string PersonalizeKey = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"; private const string DwmKey = @"Software\Microsoft\Windows\DWM"; public static void Apply(LauncherThemeScheme scheme = LauncherThemeScheme.MarkHaven) { bool isLight = IsLightTheme(); ThemePalette palette = GetPalette(scheme, isLight); MediaColor accent = palette.Accent; MediaColor selectedText = IsDark(accent) ? System.Windows.Media.Colors.White : System.Windows.Media.Colors.Black; SetBrush("AppWindowBrush", palette.Window); SetBrush("AppSurfaceBrush", palette.Surface); SetBrush("AppPanelBrush", palette.Panel); SetBrush("AppControlBrush", palette.Control); SetBrush("AppControlHoverBrush", palette.Hover); SetBrush("AppTextBrush", palette.Text); SetBrush("AppMutedTextBrush", palette.Muted); SetBrush("AppBorderBrush", palette.Border); SetBrush("AppAccentBrush", accent); SetBrush("AppAccentSoftBrush", palette.AccentSoft); SetBrush("AppOrangeBrush", palette.Orange); SetBrush("AppOrangeSoftBrush", palette.OrangeSoft); SetBrush("AppSelectedTextBrush", selectedText); SetBrush(System.Windows.SystemColors.WindowBrushKey, palette.Surface); SetBrush(System.Windows.SystemColors.WindowTextBrushKey, palette.Text); SetBrush(System.Windows.SystemColors.ControlBrushKey, palette.Control); SetBrush(System.Windows.SystemColors.ControlTextBrushKey, palette.Text); SetBrush(System.Windows.SystemColors.ControlDarkBrushKey, palette.Border); SetBrush(System.Windows.SystemColors.HighlightBrushKey, accent); SetBrush(System.Windows.SystemColors.HighlightTextBrushKey, selectedText); } private static bool IsLightTheme() { object? value = Registry.CurrentUser.OpenSubKey(PersonalizeKey)?.GetValue("AppsUseLightTheme"); return value is null || Convert.ToInt32(value) != 0; } private static MediaColor GetAccentColor() { object? value = Registry.CurrentUser.OpenSubKey(DwmKey)?.GetValue("AccentColor"); if (value is int colorValue) { byte r = (byte)(colorValue & 0xFF); byte g = (byte)((colorValue >> 8) & 0xFF); byte b = (byte)((colorValue >> 16) & 0xFF); return MediaColor.FromRgb(r, g, b); } return MediaColor.FromRgb(0x00, 0x78, 0xD4); } private static ThemePalette GetPalette(LauncherThemeScheme scheme, bool isLight) { MediaColor windowsAccent = GetAccentColor(); MediaColor orange = MediaColor.FromRgb(0xD8, 0x78, 0x1D); return scheme switch { LauncherThemeScheme.System => CreatePalette( isLight, windowsAccent, orange, window: LightDark(isLight, 0xF7F7F7, 0x202020), surface: LightDark(isLight, 0xFFFFFF, 0x2B2B2B), panel: LightDark(isLight, 0xF3F3F3, 0x333333), control: LightDark(isLight, 0xF3F3F3, 0x333333), hover: LightDark(isLight, 0xEAF3FF, 0x3B4A5C), text: LightDark(isLight, 0x1A1A1A, 0xF3F3F3), muted: LightDark(isLight, 0x666666, 0xB8B8B8), border: LightDark(isLight, 0xC8C8C8, 0x555555)), LauncherThemeScheme.WindowsClassic => CreatePalette( isLight, windowsAccent, orange, window: LightDark(isLight, 0xF0F0F0, 0x1F1F1F), surface: LightDark(isLight, 0xFAFAFA, 0x2D2D30), panel: LightDark(isLight, 0xFFFFFF, 0x252526), control: LightDark(isLight, 0xF5F5F5, 0x333337), hover: LightDark(isLight, 0xEDEDED, 0x3E3E42), text: LightDark(isLight, 0x111111, 0xF1F1F1), muted: LightDark(isLight, 0x5F5F5F, 0xBDBDBD), border: LightDark(isLight, 0xD0D0D0, 0x565656)), LauncherThemeScheme.MGETOrange => CreatePalette( isLight, orange, orange, window: LightDark(isLight, 0xF6F1EA, 0x181614), surface: LightDark(isLight, 0xFFFCF8, 0x221F1B), panel: LightDark(isLight, 0xFFF7EE, 0x2A241E), control: LightDark(isLight, 0xFAF1E7, 0x322B24), hover: LightDark(isLight, 0xFFEDDA, 0x423428), text: LightDark(isLight, 0x241D17, 0xF8F2EA), muted: LightDark(isLight, 0x75685C, 0xC3B5A6), border: LightDark(isLight, 0xE4D1BC, 0x5B4B3C)), _ => CreatePalette( isLight, LightDark(isLight, 0x146B52, 0x58D0A3), LightDark(isLight, 0xB56B08, 0xF4BD54), window: LightDark(isLight, 0xEEF1F0, 0x111816), surface: LightDark(isLight, 0xFFFFFF, 0x18201E), panel: LightDark(isLight, 0xFBFCFB, 0x15201D), control: LightDark(isLight, 0xEEF3F0, 0x1A2A24), hover: LightDark(isLight, 0xE2F3EC, 0x183B30), text: LightDark(isLight, 0x1B2824, 0xEDF5F2), muted: LightDark(isLight, 0x66746F, 0x9CAAA5), border: LightDark(isLight, 0xDCE3E0, 0x33423D)) }; } private static ThemePalette CreatePalette( bool isLight, MediaColor accent, MediaColor orange, MediaColor window, MediaColor surface, MediaColor panel, MediaColor control, MediaColor hover, MediaColor text, MediaColor muted, MediaColor border) { return new ThemePalette( window, surface, panel, control, hover, text, muted, border, accent, Blend(accent, surface, isLight ? 0.14 : 0.24), orange, Blend(orange, surface, isLight ? 0.16 : 0.30)); } private static MediaColor LightDark(bool isLight, int lightRgb, int darkRgb) { int rgb = isLight ? lightRgb : darkRgb; return MediaColor.FromRgb((byte)(rgb >> 16), (byte)(rgb >> 8), (byte)rgb); } private static MediaColor Blend(MediaColor foreground, MediaColor background, double foregroundAmount) { double amount = Math.Clamp(foregroundAmount, 0, 1); byte r = (byte)Math.Round((foreground.R * amount) + (background.R * (1 - amount))); byte g = (byte)Math.Round((foreground.G * amount) + (background.G * (1 - amount))); byte b = (byte)Math.Round((foreground.B * amount) + (background.B * (1 - amount))); return MediaColor.FromRgb(r, g, b); } private static void SetBrush(string key, MediaColor color) { SolidColorBrush brush = new(color); brush.Freeze(); System.Windows.Application.Current.Resources[key] = brush; } private static void SetBrush(ResourceKey key, MediaColor color) { SolidColorBrush brush = new(color); brush.Freeze(); System.Windows.Application.Current.Resources[key] = brush; } private static bool IsDark(MediaColor color) { double luminance = (0.299 * color.R) + (0.587 * color.G) + (0.114 * color.B); return luminance < 140; } private sealed record ThemePalette( MediaColor Window, MediaColor Surface, MediaColor Panel, MediaColor Control, MediaColor Hover, MediaColor Text, MediaColor Muted, MediaColor Border, MediaColor Accent, MediaColor AccentSoft, MediaColor Orange, MediaColor OrangeSoft); }