diff --git a/AutoTrackR2/AutoTrackR2.csproj b/AutoTrackR2/AutoTrackR2.csproj index 78fb40b..aec2eac 100644 --- a/AutoTrackR2/AutoTrackR2.csproj +++ b/AutoTrackR2/AutoTrackR2.csproj @@ -33,6 +33,9 @@ <None Remove="config.ini" /> <None Remove="Fonts\Orbitron-Bold.ttf" /> <None Remove="Fonts\Roboto-Regular.ttf" /> + <None Update="themes.json"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> </ItemGroup> <ItemGroup> diff --git a/AutoTrackR2/ConfigPage.xaml.cs b/AutoTrackR2/ConfigPage.xaml.cs index a5f5b21..72db98f 100644 --- a/AutoTrackR2/ConfigPage.xaml.cs +++ b/AutoTrackR2/ConfigPage.xaml.cs @@ -4,6 +4,7 @@ using System.Net.Http.Headers; using System.Net.Http; using System.Text.RegularExpressions; using System.Text; +using System.Text.Json; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -11,643 +12,431 @@ using System.Windows.Media.Effects; using System.Windows.Threading; using Microsoft.Win32; -namespace AutoTrackR2 +namespace AutoTrackR2; + +public partial class ConfigPage : UserControl { - public partial class ConfigPage : UserControl + // Store the current slider value + private double savedSliderValue = 0; + + private MainWindow mainWindow; + + Dictionary<string, Theme>? _themes = null; + + public ConfigPage(MainWindow mainWindow) { - // Store the current slider value - private double savedSliderValue = 0; + InitializeComponent(); + this.mainWindow = mainWindow; - private MainWindow mainWindow; + LogFilePath.Text = ConfigManager.LogFile; + ApiUrl.Text = ConfigManager.ApiUrl; + ApiKey.Password = ConfigManager.ApiKey; + VideoPath.Text = ConfigManager.VideoPath; + VisorWipeSlider.Value = ConfigManager.VisorWipe; + VideoRecordSlider.Value = ConfigManager.VideoRecord; + OfflineModeSlider.Value = ConfigManager.OfflineMode; + ThemeSlider.Value = ConfigManager.Theme; - public ConfigPage(MainWindow mainWindow) + ApplyToggleModeStyle(OfflineModeSlider.Value, VisorWipeSlider.Value, VideoRecordSlider.Value); + + + const string themeJsonPath = "themes.json"; + var themeJson = File.ReadAllText(themeJsonPath); + _themes = JsonSerializer.Deserialize<Dictionary<string, Theme>>(themeJson); + } + + // Method to change the logo image in MainWindow + public void ChangeLogo(string imagePath, Color? glowColor = null) + { + // Update the logo from ConfigPage + mainWindow.ChangeLogoImage(imagePath); + + if (glowColor.HasValue) { - InitializeComponent(); - this.mainWindow = mainWindow; - - LogFilePath.Text = ConfigManager.LogFile; - ApiUrl.Text = ConfigManager.ApiUrl; - ApiKey.Password = ConfigManager.ApiKey; - VideoPath.Text = ConfigManager.VideoPath; - VisorWipeSlider.Value = ConfigManager.VisorWipe; - VideoRecordSlider.Value = ConfigManager.VideoRecord; - OfflineModeSlider.Value = ConfigManager.OfflineMode; - ThemeSlider.Value = ConfigManager.Theme; - - ApplyToggleModeStyle(OfflineModeSlider.Value, VisorWipeSlider.Value, VideoRecordSlider.Value); - } - - // Method to change the logo image in MainWindow - public void ChangeLogo(string imagePath, Color? glowColor = null) - { - // Update the logo from ConfigPage - mainWindow.ChangeLogoImage(imagePath); - - if (glowColor.HasValue) + // Add the glow effect to the logo in MainWindow + DropShadowEffect glowEffect = new DropShadowEffect { - // Add the glow effect to the logo in MainWindow - DropShadowEffect glowEffect = new DropShadowEffect - { - Color = glowColor.Value, // Glow color - ShadowDepth = 0, // Centered glow - BlurRadius = 20, // Glow spread - Opacity = 0.8 // Intensity - }; - - // Apply the effect to the logo - mainWindow.Logo.Effect = glowEffect; - } - else - { - mainWindow.Logo.Effect = null; - } - } - - // This method will set the loaded config values to the UI controls - public void SetConfigValues(string logFile, string apiUrl, string apiKey, string videoPath, - int visorWipe, int videoRecord, int offlineMode, int theme) - { - // Set the textboxes with the loaded values - LogFilePath.Text = logFile; - ApiUrl.Text = apiUrl; - ApiKey.Password = apiKey; - VideoPath.Text = videoPath; - - // Set the sliders with the loaded values - VideoRecordSlider.Value = videoRecord; - VisorWipeSlider.Value = visorWipe; - OfflineModeSlider.Value = offlineMode; - - // Handle themes - if (theme >= 0 && theme <= 3) - { - ThemeSlider.Value = theme; // Set slider only for visible themes - } - else - { - ApplyTheme(theme); // Apply hidden themes directly - } - } - - private void ApplyToggleModeStyle(double offlineModeValue, double visorWipeValue, double videoRecordValue) - { - // Get the slider - Slider offlineModeSlider = OfflineModeSlider; - Slider visorWipeSlider = VisorWipeSlider; - Slider videoRecordSlider = VideoRecordSlider; - - // Set the appropriate style based on the offlineMode value (0 or 1) - if (offlineModeValue == 0) - { - offlineModeSlider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); - } - - if (visorWipeValue == 0) - { - visorWipeSlider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); - } - - if (videoRecordValue == 0) - { - videoRecordSlider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); - } - } - - private void ThemeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) - { - // Save the current slider value when it changes - savedSliderValue = e.NewValue; - - // Get the slider value (0, 1, or 2) - int themeIndex = (int)savedSliderValue; - - // Apply the selected theme - ApplyTheme(themeIndex); - - mainWindow.UpdateTabVisuals(); - } - - private void ApplyTheme(int themeIndex) - { - switch (themeIndex) - { - case 0: // Default Blue Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#00A9E0"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#0F1A2B"), // Button - (Color)ColorConverter.ConvertFromString("#1D2D44"), // Background - (Color)ColorConverter.ConvertFromString("#FFFFFF"), // Text - (Color)ColorConverter.ConvertFromString("#A88F2C") // AltText - ); - ChangeLogo("/Assets/AutoTrackR.png"); - break; - case 1: // Green Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#1D9F00"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#262424"), // Button - (Color)ColorConverter.ConvertFromString("#072501"), // Background - (Color)ColorConverter.ConvertFromString("#D7AF3C"), // Text - (Color)ColorConverter.ConvertFromString("#DCD6C4") // AltText - ); - ChangeLogo("/Assets/AutoTrackR.png"); - break; - case 2: // Red Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#D32F2F"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#424242"), // Button - (Color)ColorConverter.ConvertFromString("#212121"), // Light Background - (Color)ColorConverter.ConvertFromString("#E0E0E0"), // Text - (Color)ColorConverter.ConvertFromString("#A88F2C") // AltText - ); - ChangeLogo("/Assets/AutoTrackR.png"); - break; - case 3: // Purple Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#32CD32"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#33065F"), // Button - (Color)ColorConverter.ConvertFromString("#43065F"), // Background - (Color)ColorConverter.ConvertFromString("#00FF00"), // Text - (Color)ColorConverter.ConvertFromString("#B3976E") // AltText - ); - ChangeLogo("/Assets/AutoTrackR.png"); - break; - case 4: // GN Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#FF0000"), // Accent/Border - Pure red for maximum impact - (Color)ColorConverter.ConvertFromString("#1A0000"), // Button - Deep black-red - (Color)ColorConverter.ConvertFromString("#0A0000"), // Background - Near black - (Color)ColorConverter.ConvertFromString("#FFD700"), // Text - Gold for high visibility - (Color)ColorConverter.ConvertFromString("#FF4500") // AltText - Orange-red for contrast - ); - ChangeLogo("/Assets/GN.png", (Color)ColorConverter.ConvertFromString("#FF0000")); - break; - case 5: // NW Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#B92D2D"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#1C1C1C"), // Button - (Color)ColorConverter.ConvertFromString("#262424"), // Background - (Color)ColorConverter.ConvertFromString("#01DDDA"), // Text - (Color)ColorConverter.ConvertFromString("#A88F2C") // AltText - ); - ChangeLogo("/Assets/NW.png", (Color)ColorConverter.ConvertFromString("#01DDDA")); - break; - case 6: // D3VL Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#AA0000"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#333333"), // Button - (Color)ColorConverter.ConvertFromString("#220000"), // Background - (Color)ColorConverter.ConvertFromString("#FF0000"), // Text - (Color)ColorConverter.ConvertFromString("#A88F2C") // AltText - ); - ChangeLogo("/Assets/D3VL.png", (Color)ColorConverter.ConvertFromString("#CC0000")); - break; - case 7: // HIT Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#B92D2D"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#1C1C1C"), // Button - (Color)ColorConverter.ConvertFromString("#262424"), // Background - (Color)ColorConverter.ConvertFromString("#7d7d7d"), // Text - (Color)ColorConverter.ConvertFromString("#A88F2C") // AltText - ); - ChangeLogo("/Assets/HIT.png"); - break; - case 8: // WRAITH Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#ff0000"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#2a2a2a"), // Button - (Color)ColorConverter.ConvertFromString("#0a0a0a"), // Background - (Color)ColorConverter.ConvertFromString("#DFDFDF"), // Text - (Color)ColorConverter.ConvertFromString("#8B0000") // AltText - ); - ChangeLogo("/Assets/WRITH.png", (Color)ColorConverter.ConvertFromString("#ff0000")); - break; - case 9: // Cinderborn Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#FF4500"), // Accent/Border - Bright fiery orange-red - (Color)ColorConverter.ConvertFromString("#2A0A0A"), // Button - Deep blood red - (Color)ColorConverter.ConvertFromString("#1A0000"), // Background - Darkest red-black - (Color)ColorConverter.ConvertFromString("#FF8C42"), // Text - Warm orange - (Color)ColorConverter.ConvertFromString("#FF6B35") // AltText - Slightly darker orange - ); - ChangeLogo("/Assets/cinderborn.png", (Color)ColorConverter.ConvertFromString("#FF4500")); - break; - case 10: // EMP Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#F5721C"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#535353"), // Button - (Color)ColorConverter.ConvertFromString("#080000"), // Background - (Color)ColorConverter.ConvertFromString("#FFFFFF"), // Text - (Color)ColorConverter.ConvertFromString("#CEA75B") // AltText - ); - ChangeLogo("/Assets/EMP.png", (Color)ColorConverter.ConvertFromString("#F3BD9B")); - break; - case 11: // AVS Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#00BFFF"), // Accent/Border - Deep Sky Blue - (Color)ColorConverter.ConvertFromString("#001F3F"), // Button - Dark Navy - (Color)ColorConverter.ConvertFromString("#000B1A"), // Background - Darker Navy - (Color)ColorConverter.ConvertFromString("#FFFFFF"), // Text - Pure White - (Color)ColorConverter.ConvertFromString("#87CEEB") // AltText - Sky Blue - ); - ChangeLogo("/Assets/AVSQN.png", (Color)ColorConverter.ConvertFromString("#00BFFF")); - break; - case 12: // HEX Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#00FF00"), // Accent/Border - Bright Green - (Color)ColorConverter.ConvertFromString("#001A00"), // Button - Deep Forest Green - (Color)ColorConverter.ConvertFromString("#000D00"), // Background - Darker Forest Green - (Color)ColorConverter.ConvertFromString("#FFFFFF"), // Text - Pure White - (Color)ColorConverter.ConvertFromString("#39FF14") // AltText - Neon Green - ); - ChangeLogo("/Assets/HEX.png", (Color)ColorConverter.ConvertFromString("#00FF00")); - break; - case 13: // Mammon Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#FFD700"), // Accent/Border - Royal Gold - (Color)ColorConverter.ConvertFromString("#2C2C2C"), // Button - Dark Gray - (Color)ColorConverter.ConvertFromString("#1A1A1A"), // Background - Rich Black - (Color)ColorConverter.ConvertFromString("#FFFFFF"), // Text - White - (Color)ColorConverter.ConvertFromString("#DAA520") // AltText - Golden Rod - ); - ChangeLogo("/Assets/MAMMON.png", (Color)ColorConverter.ConvertFromString("#FFD700")); - break; - case 14: // Shadow Moses Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#FF69B4"), // Accent/Border - Hot Pink - (Color)ColorConverter.ConvertFromString("#2C2C2C"), // Button - Dark Gray - (Color)ColorConverter.ConvertFromString("#2C1F28"), // Background - Dark Pink-Gray - (Color)ColorConverter.ConvertFromString("#E6E6E6"), // Text - Light Gray - (Color)ColorConverter.ConvertFromString("#FF1493") // AltText - Deep Pink - ); - ChangeLogo("/Assets/ShadowMoses.png", (Color)ColorConverter.ConvertFromString("#FF69B4")); - break; - case 15: // Mongrel Squad - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#00BFFF"), // Accent/Border - Deep Sky Blue - (Color)ColorConverter.ConvertFromString("#003366"), // Button - Dark Navy - (Color)ColorConverter.ConvertFromString("#001F3F"), // Background - Darker Navy - (Color)ColorConverter.ConvertFromString("#E6F3FF"), // Text - Light Sky Blue - (Color)ColorConverter.ConvertFromString("#87CEEB") // AltText - Sky Blue - ); - ChangeLogo("/Assets/BOBGREL.png", (Color)ColorConverter.ConvertFromString("#00BFFF")); - break; - case 16: // Feezy - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#FFA500"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#1B0C04"), // Button - (Color)ColorConverter.ConvertFromString("#1B0C04"), // Background - (Color)ColorConverter.ConvertFromString("#FFE4B5"), // Text - (Color)ColorConverter.ConvertFromString("#A88F2C") // AltText - ); - ChangeLogo("/Assets/chibifox.png", (Color)ColorConverter.ConvertFromString("#FFA500")); - break; - case 17: // NMOS - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#EAB787"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#601C1B"), // Button - (Color)ColorConverter.ConvertFromString("#170402"), // Background - (Color)ColorConverter.ConvertFromString("#F6DBAD"), // Text - (Color)ColorConverter.ConvertFromString("#EBCAA0") // AltText - ); - ChangeLogo("/Assets/NMOS.png", (Color)ColorConverter.ConvertFromString("#EAB787")); - break; - case 18: // Rakk Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#FF00FF"), // Accent/Border - Magenta - (Color)ColorConverter.ConvertFromString("#1C1C1C"), // Button - Dark Gray - (Color)ColorConverter.ConvertFromString("#0A0A0A"), // Background - Nearly Black - (Color)ColorConverter.ConvertFromString("#E6E6E6"), // Text - Light Gray - (Color)ColorConverter.ConvertFromString("#00BFFF") // AltText - Deep Sky Blue - ); - ChangeLogo("/Assets/RACKETEERS.png", (Color)ColorConverter.ConvertFromString("#FF00FF")); - break; - case 19: // Blightveil Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#8B4AC6"), // Accent/Border - Purple from the logo border - (Color)ColorConverter.ConvertFromString("#2A2035"), // Button - Darker purple for buttons - (Color)ColorConverter.ConvertFromString("#1A1621"), // Background - Very dark purple/black - (Color)ColorConverter.ConvertFromString("#FFFFFF"), // Text - White like the logo text - (Color)ColorConverter.ConvertFromString("#FF3333") // AltText - Red like the eyes - ); - ChangeLogo("/Assets/Blightveil.png", (Color)ColorConverter.ConvertFromString("#8B4AC6")); - break; - case 20: // Gankhub Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#ffa500"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#2C2C2C"), // Button - (Color)ColorConverter.ConvertFromString("#1b1b1b"), // Background - (Color)ColorConverter.ConvertFromString("#FFFFFF"), // Text - (Color)ColorConverter.ConvertFromString("#ffa500") // AltText - ); - ChangeLogo("/Assets/Gankhub.png"); - break; - case 21: // IronPoint - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#FF0000"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#1C1C1C"), // Button - (Color)ColorConverter.ConvertFromString("#000000"), // Background - (Color)ColorConverter.ConvertFromString("#FFFFFF"), // Text - (Color)ColorConverter.ConvertFromString("#A88F2C") // AltText - ); - ChangeLogo("/Assets/IP.png", (Color)ColorConverter.ConvertFromString("#FF0000")); - break; - case 22: // Shadow Guardian Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#8B0000"), // Accent/Border - Dark blood red - (Color)ColorConverter.ConvertFromString("#1A0000"), // Button - Deep black-red - (Color)ColorConverter.ConvertFromString("#0A0000"), // Background - Near black - (Color)ColorConverter.ConvertFromString("#D3D3D3"), // Text - Light silver - (Color)ColorConverter.ConvertFromString("#B22222") // AltText - Firebrick red - ); - ChangeLogo("/Assets/shadowguard.png", (Color)ColorConverter.ConvertFromString("#8B0000")); - break; - case 23: // VOX Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#C0C0C0"), // Accent/Border - (Color)ColorConverter.ConvertFromString("#1C1C1C"), // Button - (Color)ColorConverter.ConvertFromString("#424242"), // Background - (Color)ColorConverter.ConvertFromString("#FFD700"), // Text - (Color)ColorConverter.ConvertFromString("#817E79") // AltText - ); - ChangeLogo("/Assets/VOX.png", (Color)ColorConverter.ConvertFromString("#FFD700")); - break; - case 24: // Zap Theme - UpdateThemeColors( - (Color)ColorConverter.ConvertFromString("#FFD700"), // Accent/Border - Electric Yellow - (Color)ColorConverter.ConvertFromString("#1A1A1A"), // Button - Deep Black - (Color)ColorConverter.ConvertFromString("#0A0A0A"), // Background - Near Black - (Color)ColorConverter.ConvertFromString("#FFFFFF"), // Text - Pure White - (Color)ColorConverter.ConvertFromString("#FFA500") // AltText - Electric Orange - ); - ChangeLogo("/Assets/ZAP.png", (Color)ColorConverter.ConvertFromString("#FFD700")); - break; - } - } - - // Helper method to update both Color and Brush resources - private void UpdateThemeColors(Color accent, Color backgroundDark, Color backgroundLight, Color text, Color altText) - { - // Update color resources - Application.Current.Resources["AccentColor"] = accent; - Application.Current.Resources["BackgroundDarkColor"] = backgroundDark; - Application.Current.Resources["BackgroundLightColor"] = backgroundLight; - Application.Current.Resources["TextColor"] = text; - Application.Current.Resources["AltTextColor"] = altText; - - // Update SolidColorBrush resources - Application.Current.Resources["AccentBrush"] = new SolidColorBrush(accent); - Application.Current.Resources["BackgroundDarkBrush"] = new SolidColorBrush(backgroundDark); - Application.Current.Resources["BackgroundLightBrush"] = new SolidColorBrush(backgroundLight); - Application.Current.Resources["TextBrush"] = new SolidColorBrush(text); - Application.Current.Resources["AltTextBrush"] = new SolidColorBrush(altText); - } - - // This method will be called when switching tabs to restore the saved slider position. - public void RestoreSliderValue() - { - // Set the slider back to the previously saved value - ThemeSlider.Value = savedSliderValue; - } - - // Log File Browse Button Handler - private void LogFileBrowseButton_Click(object sender, RoutedEventArgs e) - { - var dialog = new Microsoft.Win32.OpenFileDialog(); - dialog.Filter = "Log files (*.log)|*.log|All files (*.*)|*.*"; // Adjust as needed - - if (dialog.ShowDialog() == true) - { - LogFilePath.Text = dialog.FileName; // Set the selected file path to the TextBox - } - } - - // Video Path Browse Button Handler - private void VideoPathBrowseButton_Click(object sender, RoutedEventArgs e) - { - var dialog = new OpenFileDialog(); - dialog.CheckFileExists = false; - dialog.ValidateNames = false; - dialog.Filter = "All files|*.*"; - - if (dialog.ShowDialog() == true && dialog.FileName != null) - { - // Extract only the directory path from the file - string? selectedFolder = Path.GetDirectoryName(dialog.FileName); - if (selectedFolder != null) - { - VideoPath.Text = selectedFolder; // Set the folder path - } - } - } - - private void VisorWipeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) - { - Slider slider = (Slider)sender; - - // Build the dynamic file path for the current user - if (string.IsNullOrEmpty(ConfigManager.AHKScriptFolder)) - { - MessageBox.Show("AHK script folder path is not configured.", "Configuration Error", MessageBoxButton.OK, MessageBoxImage.Warning); - return; - } - string filePath = Path.Combine( - ConfigManager.AHKScriptFolder, - "visorwipe.ahk" - ); - - // Get the current value of the slider (0 or 1) - ConfigManager.VisorWipe = (int)slider.Value; - - if (ConfigManager.VisorWipe == 1) - { - // Check if the file exists - if (File.Exists(filePath)) - { - // Apply the enabled style if the file exists - slider.Style = (Style)Application.Current.FindResource("ToggleSliderStyle"); - } - else - { - // File does not exist; revert the toggle to 0 - ConfigManager.VisorWipe = 0; - slider.Value = 0; // Revert the slider value - slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); - - // Optionally, display a message to the user - MessageBox.Show($"Visor wipe script not found. Please ensure the file exists at:\n{filePath}", - "File Missing", MessageBoxButton.OK, MessageBoxImage.Warning); - } - } - else - { - // Apply the disabled style - slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); - } - } - - private void VideoRecordSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) - { - Slider slider = (Slider)sender; - - // Build the dynamic file path for the current user - string filePath = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "AutoTrackR2", - "videorecord.ahk" - ); - - // Get the current value of the slider (0 or 1) - ConfigManager.VideoRecord = (int)slider.Value; - - if (ConfigManager.VideoRecord == 1) - { - // Check if the file exists - if (File.Exists(filePath)) - { - // Apply the enabled style if the file exists - slider.Style = (Style)Application.Current.FindResource("ToggleSliderStyle"); - } - else - { - // File does not exist; revert the toggle to 0 - ConfigManager.VideoRecord = 0; - slider.Value = 0; // Revert the slider value - slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); - - // Optionally, display a message to the user - MessageBox.Show($"Video record script not found. Please ensure the file exists at:\n{filePath}", - "File Missing", MessageBoxButton.OK, MessageBoxImage.Warning); - } - } - else - { - // Apply the disabled style - slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); - } - } - - private void OfflineModeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) - { - Slider slider = (Slider)sender; - ConfigManager.OfflineMode = (int)slider.Value; // 0 or 1 - - // Check if the value is 0 or 1 and apply the corresponding style - if (ConfigManager.OfflineMode == 0) - { - slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); // Apply FalseToggleStyle - } - else - { - slider.Style = (Style)Application.Current.FindResource("ToggleSliderStyle"); // Apply ToggleSliderStyle - } - } - - - private void SaveButton_Click(object sender, RoutedEventArgs e) - { - - ConfigManager.ApiKey = ApiKey.Password; - ConfigManager.ApiUrl = ApiUrl.Text; - ConfigManager.LogFile = LogFilePath.Text; - ConfigManager.VideoPath = VideoPath.Text; - ConfigManager.VisorWipe = (int)VisorWipeSlider.Value; - ConfigManager.VideoRecord = (int)VideoRecordSlider.Value; - ConfigManager.OfflineMode = (int)OfflineModeSlider.Value; - ConfigManager.Theme = (int)ThemeSlider.Value; - // Save the current config values - ConfigManager.SaveConfig(); - // Start the flashing effect - FlashSaveButton(); - } - - private void FlashSaveButton() - { - string? originalText = SaveButton.Content?.ToString() ?? string.Empty; - SaveButton.Content = "Saved"; - - // Save button color change effect - var originalColor = SaveButton.Background; - var accentColor = (Color)Application.Current.Resources["AccentColor"]; - SaveButton.Background = new SolidColorBrush(accentColor); // Change color to accent color - - // Apply glow effect - SaveButton.Effect = new DropShadowEffect - { - Color = accentColor, - BlurRadius = 15, // Add subtle blur - ShadowDepth = 0, // Set shadow depth to 0 for a pure glow effect - Opacity = 0.8, // Set opacity for glow visibility - Direction = 0 // Direction doesn't matter for glow + Color = glowColor.Value, // Glow color + ShadowDepth = 0, // Centered glow + BlurRadius = 20, // Glow spread + Opacity = 0.8 // Intensity }; - // Create a DispatcherTimer to reset everything after the effect - DispatcherTimer timer = new DispatcherTimer - { - Interval = TimeSpan.FromMilliseconds(600) // Interval for flash effect - }; + // Apply the effect to the logo + mainWindow.Logo.Effect = glowEffect; + } + else + { + mainWindow.Logo.Effect = null; + } + } - int flashCount = 0; - timer.Tick += (sender, e) => - { - if (flashCount < 2) // Flash effect (flash 2 times) - { - flashCount++; - } - else - { - // Stop the timer and restore the original button state - timer.Stop(); - SaveButton.Content = originalText; - SaveButton.Background = originalColor; // Restore the original button color - SaveButton.Effect = null; // Remove the glow effect - } - }; + // This method will set the loaded config values to the UI controls + public void SetConfigValues(string logFile, string apiUrl, string apiKey, string videoPath, + int visorWipe, int videoRecord, int offlineMode, int theme) + { + // Set the textboxes with the loaded values + LogFilePath.Text = logFile; + ApiUrl.Text = apiUrl; + ApiKey.Password = apiKey; + VideoPath.Text = videoPath; - // Start the timer - timer.Start(); + // Set the sliders with the loaded values + VideoRecordSlider.Value = videoRecord; + VisorWipeSlider.Value = visorWipe; + OfflineModeSlider.Value = offlineMode; + + // Handle themes + ApplyTheme(theme); + + } + + private void ApplyToggleModeStyle(double offlineModeValue, double visorWipeValue, double videoRecordValue) + { + // Get the slider + Slider offlineModeSlider = OfflineModeSlider; + Slider visorWipeSlider = VisorWipeSlider; + Slider videoRecordSlider = VideoRecordSlider; + + // Set the appropriate style based on the offlineMode value (0 or 1) + if (offlineModeValue == 0) + { + offlineModeSlider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); } - private async void TestApiButton_Click(object sender, RoutedEventArgs e) + if (visorWipeValue == 0) { - string apiUrl = ApiUrl.Text; - string modifiedUrl = Regex.Replace(apiUrl, @"(https?://[^/]+)/?.*", "$1/test"); - string apiKey = ApiKey.Password; - Debug.WriteLine($"Sending to {modifiedUrl}"); + visorWipeSlider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); + } - try + if (videoRecordValue == 0) + { + videoRecordSlider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); + } + } + + private void ThemeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) + { + // Save the current slider value when it changes + savedSliderValue = e.NewValue; + + // Get the slider value (0, 1, or 2) + int themeIndex = (int)savedSliderValue; + + // Apply the selected theme + ApplyTheme(themeIndex); + + mainWindow.UpdateTabVisuals(); + } + + private void ApplyTheme(int themeIndex) + { + var theme = _themes?.Values.ElementAtOrDefault(themeIndex); + if (theme == null) return; + + // Update the logo + if (theme.Logo != null && theme.Logo.LogoPath != null) + { + ChangeLogo(theme.Logo.LogoPath, Colors.Transparent); + } + + // Update the colors + if (theme.Colors != null) + { + var accent = (Color)ColorConverter.ConvertFromString(theme.Colors.Accent); + var button = (Color)ColorConverter.ConvertFromString(theme.Colors.Button); + var backgroundDark = (Color)ColorConverter.ConvertFromString(theme.Colors.Background); + var text = (Color)ColorConverter.ConvertFromString(theme.Colors.Text); + var altText = (Color)ColorConverter.ConvertFromString(theme.Colors.AltText); + + UpdateThemeColors(accent, button, backgroundDark, text, altText); + } + } + + // Helper method to update both Color and Brush resources + private void UpdateThemeColors(Color accent, Color backgroundDark, Color backgroundLight, Color text, Color altText) + { + // Update color resources + Application.Current.Resources["AccentColor"] = accent; + Application.Current.Resources["BackgroundDarkColor"] = backgroundDark; + Application.Current.Resources["BackgroundLightColor"] = backgroundLight; + Application.Current.Resources["TextColor"] = text; + Application.Current.Resources["AltTextColor"] = altText; + + // Update SolidColorBrush resources + Application.Current.Resources["AccentBrush"] = new SolidColorBrush(accent); + Application.Current.Resources["BackgroundDarkBrush"] = new SolidColorBrush(backgroundDark); + Application.Current.Resources["BackgroundLightBrush"] = new SolidColorBrush(backgroundLight); + Application.Current.Resources["TextBrush"] = new SolidColorBrush(text); + Application.Current.Resources["AltTextBrush"] = new SolidColorBrush(altText); + } + + // This method will be called when switching tabs to restore the saved slider position. + public void RestoreSliderValue() + { + // Set the slider back to the previously saved value + ThemeSlider.Value = savedSliderValue; + } + + // Log File Browse Button Handler + private void LogFileBrowseButton_Click(object sender, RoutedEventArgs e) + { + var dialog = new Microsoft.Win32.OpenFileDialog(); + dialog.Filter = "Log files (*.log)|*.log|All files (*.*)|*.*"; // Adjust as needed + + if (dialog.ShowDialog() == true) + { + LogFilePath.Text = dialog.FileName; // Set the selected file path to the TextBox + } + } + + // Video Path Browse Button Handler + private void VideoPathBrowseButton_Click(object sender, RoutedEventArgs e) + { + var dialog = new OpenFileDialog(); + dialog.CheckFileExists = false; + dialog.ValidateNames = false; + dialog.Filter = "All files|*.*"; + + if (dialog.ShowDialog() == true && dialog.FileName != null) + { + // Extract only the directory path from the file + string? selectedFolder = Path.GetDirectoryName(dialog.FileName); + if (selectedFolder != null) { - // Configure HttpClient with TLS 1.2 - var handler = new HttpClientHandler - { - SslProtocols = System.Security.Authentication.SslProtocols.Tls12 - }; - - using (var client = new HttpClient(handler)) - { - // Set headers - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); - client.DefaultRequestHeaders.UserAgent.ParseAdd("AutoTrackR"); - - // Empty JSON body - var content = new StringContent("{}", Encoding.UTF8, "application/json"); - - // Send POST - var response = await client.PostAsync(modifiedUrl, content); - - if (response.IsSuccessStatusCode) - { - MessageBox.Show("API Test Success."); - } - else - { - MessageBox.Show($"Error: {response.StatusCode} - {response.ReasonPhrase}"); - } - } - } - catch (Exception ex) - { - MessageBox.Show($"API Test Failure. {ex.Message}"); + VideoPath.Text = selectedFolder; // Set the folder path } } } + + private void VisorWipeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) + { + Slider slider = (Slider)sender; + + // Build the dynamic file path for the current user + if (string.IsNullOrEmpty(ConfigManager.AHKScriptFolder)) + { + MessageBox.Show("AHK script folder path is not configured.", "Configuration Error", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + string filePath = Path.Combine( + ConfigManager.AHKScriptFolder, + "visorwipe.ahk" + ); + + // Get the current value of the slider (0 or 1) + ConfigManager.VisorWipe = (int)slider.Value; + + if (ConfigManager.VisorWipe == 1) + { + // Check if the file exists + if (File.Exists(filePath)) + { + // Apply the enabled style if the file exists + slider.Style = (Style)Application.Current.FindResource("ToggleSliderStyle"); + } + else + { + // File does not exist; revert the toggle to 0 + ConfigManager.VisorWipe = 0; + slider.Value = 0; // Revert the slider value + slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); + + // Optionally, display a message to the user + MessageBox.Show($"Visor wipe script not found. Please ensure the file exists at:\n{filePath}", + "File Missing", MessageBoxButton.OK, MessageBoxImage.Warning); + } + } + else + { + // Apply the disabled style + slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); + } + } + + private void VideoRecordSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) + { + Slider slider = (Slider)sender; + + // Build the dynamic file path for the current user + string filePath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "AutoTrackR2", + "videorecord.ahk" + ); + + // Get the current value of the slider (0 or 1) + ConfigManager.VideoRecord = (int)slider.Value; + + if (ConfigManager.VideoRecord == 1) + { + // Check if the file exists + if (File.Exists(filePath)) + { + // Apply the enabled style if the file exists + slider.Style = (Style)Application.Current.FindResource("ToggleSliderStyle"); + } + else + { + // File does not exist; revert the toggle to 0 + ConfigManager.VideoRecord = 0; + slider.Value = 0; // Revert the slider value + slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); + + // Optionally, display a message to the user + MessageBox.Show($"Video record script not found. Please ensure the file exists at:\n{filePath}", + "File Missing", MessageBoxButton.OK, MessageBoxImage.Warning); + } + } + else + { + // Apply the disabled style + slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); + } + } + + private void OfflineModeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) + { + Slider slider = (Slider)sender; + ConfigManager.OfflineMode = (int)slider.Value; // 0 or 1 + + // Check if the value is 0 or 1 and apply the corresponding style + if (ConfigManager.OfflineMode == 0) + { + slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); // Apply FalseToggleStyle + } + else + { + slider.Style = (Style)Application.Current.FindResource("ToggleSliderStyle"); // Apply ToggleSliderStyle + } + } + + + private void SaveButton_Click(object sender, RoutedEventArgs e) + { + + ConfigManager.ApiKey = ApiKey.Password; + ConfigManager.ApiUrl = ApiUrl.Text; + ConfigManager.LogFile = LogFilePath.Text; + ConfigManager.VideoPath = VideoPath.Text; + ConfigManager.VisorWipe = (int)VisorWipeSlider.Value; + ConfigManager.VideoRecord = (int)VideoRecordSlider.Value; + ConfigManager.OfflineMode = (int)OfflineModeSlider.Value; + ConfigManager.Theme = (int)ThemeSlider.Value; + // Save the current config values + ConfigManager.SaveConfig(); + // Start the flashing effect + FlashSaveButton(); + } + + private void FlashSaveButton() + { + string? originalText = SaveButton.Content?.ToString() ?? string.Empty; + SaveButton.Content = "Saved"; + + // Save button color change effect + var originalColor = SaveButton.Background; + var accentColor = (Color)Application.Current.Resources["AccentColor"]; + SaveButton.Background = new SolidColorBrush(accentColor); // Change color to accent color + + // Apply glow effect + SaveButton.Effect = new DropShadowEffect + { + Color = accentColor, + BlurRadius = 15, // Add subtle blur + ShadowDepth = 0, // Set shadow depth to 0 for a pure glow effect + Opacity = 0.8, // Set opacity for glow visibility + Direction = 0 // Direction doesn't matter for glow + }; + + // Create a DispatcherTimer to reset everything after the effect + DispatcherTimer timer = new DispatcherTimer + { + Interval = TimeSpan.FromMilliseconds(600) // Interval for flash effect + }; + + int flashCount = 0; + timer.Tick += (sender, e) => + { + if (flashCount < 2) // Flash effect (flash 2 times) + { + flashCount++; + } + else + { + // Stop the timer and restore the original button state + timer.Stop(); + SaveButton.Content = originalText; + SaveButton.Background = originalColor; // Restore the original button color + SaveButton.Effect = null; // Remove the glow effect + } + }; + + // Start the timer + timer.Start(); + } + + private async void TestApiButton_Click(object sender, RoutedEventArgs e) + { + string apiUrl = ApiUrl.Text; + string modifiedUrl = Regex.Replace(apiUrl, @"(https?://[^/]+)/?.*", "$1/test"); + string apiKey = ApiKey.Password; + Debug.WriteLine($"Sending to {modifiedUrl}"); + + try + { + // Configure HttpClient with TLS 1.2 + var handler = new HttpClientHandler + { + SslProtocols = System.Security.Authentication.SslProtocols.Tls12 + }; + + using (var client = new HttpClient(handler)) + { + // Set headers + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); + client.DefaultRequestHeaders.UserAgent.ParseAdd("AutoTrackR"); + + // Empty JSON body + var content = new StringContent("{}", Encoding.UTF8, "application/json"); + + // Send POST + var response = await client.PostAsync(modifiedUrl, content); + + if (response.IsSuccessStatusCode) + { + MessageBox.Show("API Test Success."); + } + else + { + MessageBox.Show($"Error: {response.StatusCode} - {response.ReasonPhrase}"); + } + } + } + catch (Exception ex) + { + MessageBox.Show($"API Test Failure. {ex.Message}"); + } + } +} + +public class Theme +{ + public ThemeColors? Colors { get; set; } + public ThemeLogo? Logo { get; set; } +} + +public class ThemeColors +{ + public string? Accent { get; set; } + public string? Button { get; set; } + public string? Background { get; set; } + public string? Text { get; set; } + public string? AltText { get; set; } +} + +public class ThemeLogo +{ + public string? LogoPath { get; set; } + public string? Primary { get; set; } // Optional: null if not used } diff --git a/AutoTrackR2/themes.json b/AutoTrackR2/themes.json new file mode 100644 index 0000000..0d2c96d --- /dev/null +++ b/AutoTrackR2/themes.json @@ -0,0 +1,321 @@ +{ + "Blue": { + "Colors": { + "Accent": "#00A9E0", + "Button": "#0F1A2B", + "Background": "#1D2D44", + "Text": "#FFFFFF", + "AltText": "#A88F2C" + }, + "Logo": { + "Path": "/Assets/AutoTrackR.png" + } + }, + "Green": { + "Colors": { + "Accent": "#1D9F00", + "Button": "#262424", + "Background": "#072501", + "Text": "#D7AF3C", + "AltText": "#DCD6C4" + }, + "Logo": { + "Path": "/Assets/AutoTrackR.png" + } + }, + "Red": { + "Colors": { + "Accent": "#D32F2F", + "Button": "#424242", + "Background": "#212121", + "Text": "#E0E0E0", + "AltText": "#A88F2C" + }, + "Logo": { + "Path": "/Assets/AutoTrackR.png" + } + }, + "Purple": { + "Colors": { + "Accent": "#32CD32", + "Button": "#33065F", + "Background": "#43065F", + "Text": "#00FF00", + "AltText": "#B3976E" + }, + "Logo": { + "Path": "/Assets/AutoTrackR.png" + } + }, + "GN": { + "Colors": { + "Accent": "#FF0000", + "Button": "#1A0000", + "Background": "#0A0000", + "Text": "#FFD700", + "AltText": "#FF4500" + }, + "Logo": { + "Path": "/Assets/GN.png", + "primary": "#FF0000" + } + }, + "NW": { + "Colors": { + "Accent": "#B92D2D", + "Button": "#1C1C1C", + "Background": "#262424", + "Text": "#01DDDA", + "AltText": "#A88F2C" + }, + "Logo": { + "Path": "/Assets/NW.png", + "primary": "#01DDDA" + } + }, + "D3VL": { + "Colors": { + "Accent": "#AA0000", + "Button": "#333333", + "Background": "#220000", + "Text": "#FF0000", + "AltText": "#A88F2C" + }, + "Logo": { + "Path": "/Assets/D3VL.png", + "primary": "#CC0000" + } + }, + "HIT": { + "Colors": { + "Accent": "#B92D2D", + "Button": "#1C1C1C", + "Background": "#262424", + "Text": "#7d7d7d", + "AltText": "#A88F2C" + }, + "Logo": { + "Path": "/Assets/HIT.png" + } + }, + "WRAITH": { + "Colors": { + "Accent": "#ff0000", + "Button": "#2a2a2a", + "Background": "#0a0a0a", + "Text": "#DFDFDF", + "AltText": "#8B0000" + }, + "Logo": { + "Path": "/Assets/WRITH.png", + "primary": "#ff0000" + } + }, + "Cinderborn": { + "Colors": { + "Accent": "#FF4500", + "Button": "#2A0A0A", + "Background": "#1A0000", + "Text": "#FF8C42", + "AltText": "#FF6B35" + }, + "Logo": { + "Path": "/Assets/cinderborn.png", + "primary": "#FF4500" + } + }, + "EMP": { + "Colors": { + "Accent": "#F5721C", + "Button": "#535353", + "Background": "#080000", + "Text": "#FFFFFF", + "AltText": "#CEA75B" + }, + "Logo": { + "Path": "/Assets/EMP.png", + "primary": "#F3BD9B" + } + }, + "AVS": { + "Colors": { + "Accent": "#00BFFF", + "Button": "#001F3F", + "Background": "#000B1A", + "Text": "#FFFFFF", + "AltText": "#87CEEB" + }, + "Logo": { + "Path": "/Assets/AVSQN.png", + "primary": "#00BFFF" + } + }, + "HEX": { + "Colors": { + "Accent": "#00FF00", + "Button": "#001A00", + "Background": "#000D00", + "Text": "#FFFFFF", + "AltText": "#39FF14" + }, + "Logo": { + "Path": "/Assets/HEX.png", + "primary": "#00FF00" + } + }, + "Mammon": { + "Colors": { + "Accent": "#FFD700", + "Button": "#2C2C2C", + "Background": "#1A1A1A", + "Text": "#FFFFFF", + "AltText": "#DAA520" + }, + "Logo": { + "Path": "/Assets/MAMMON.png", + "primary": "#FFD700" + } + }, + "Shadow Moses": { + "Colors": { + "Accent": "#FF69B4", + "Button": "#2C2C2C", + "Background": "#2C1F28", + "Text": "#E6E6E6", + "AltText": "#FF1493" + }, + "Logo": { + "Path": "/Assets/ShadowMoses.png", + "primary": "#FF69B4" + } + }, + "Mongrel Squad": { + "Colors": { + "Accent": "#00BFFF", + "Button": "#003366", + "Background": "#001F3F", + "Text": "#E6F3FF", + "AltText": "#87CEEB" + }, + "Logo": { + "Path": "/Assets/BOBGREL.png", + "primary": "#00BFFF" + } + }, + "Feezy": { + "Colors": { + "Accent": "#FFA500", + "Button": "#1B0C04", + "Background": "#1B0C04", + "Text": "#FFE4B5", + "AltText": "#A88F2C" + }, + "Logo": { + "Path": "/Assets/chibifox.png", + "primary": "#FFA500" + } + }, + "NMOS": { + "Colors": { + "Accent": "#EAB787", + "Button": "#601C1B", + "Background": "#170402", + "Text": "#F6DBAD", + "AltText": "#EBCAA0" + }, + "Logo": { + "Path": "/Assets/NMOS.png", + "primary": "#EAB787" + } + }, + "Rakk": { + "Colors": { + "Accent": "#FF00FF", + "Button": "#1C1C1C", + "Background": "#0A0A0A", + "Text": "#E6E6E6", + "AltText": "#00BFFF" + }, + "Logo": { + "Path": "/Assets/RACKETEERS.png", + "primary": "#FF00FF" + } + }, + "Blightveil": { + "Colors": { + "Accent": "#8B4AC6", + "Button": "#2A2035", + "Background": "#1A1621", + "Text": "#FFFFFF", + "AltText": "#FF3333" + }, + "Logo": { + "Path": "/Assets/Blightveil.png", + "primary": "#8B4AC6" + } + }, + "Gankhub": { + "Colors": { + "Accent": "#ffa500", + "Button": "#2C2C2C", + "Background": "#1b1b1b", + "Text": "#FFFFFF", + "AltText": "#ffa500" + }, + "Logo": { + "Path": "/Assets/Gankhub.png" + } + }, + "IronPoint": { + "Colors": { + "Accent": "#FF0000", + "Button": "#1C1C1C", + "Background": "#000000", + "Text": "#FFFFFF", + "AltText": "#A88F2C" + }, + "Logo": { + "Path": "/Assets/IP.png", + "primary": "#FF0000" + } + }, + "Shadow Guardian": { + "Colors": { + "Accent": "#8B0000", + "Button": "#1A0000", + "Background": "#0A0000", + "Text": "#D3D3D3", + "AltText": "#B22222" + }, + "Logo": { + "Path": "/Assets/shadowguard.png", + "primary": "#8B0000" + } + }, + "VOX": { + "Colors": { + "Accent": "#C0C0C0", + "Button": "#1C1C1C", + "Background": "#424242", + "Text": "#FFD700", + "AltText": "#817E79" + }, + "Logo": { + "Path": "/Assets/VOX.png", + "primary": "#FFD700" + } + }, + "Zap": { + "Colors": { + "Accent": "#FFD700", + "Button": "#1A1A1A", + "Background": "#0A0A0A", + "Text": "#FFFFFF", + "AltText": "#FFA500" + }, + "Logo": { + "Path": "/Assets/ZAP.png", + "primary": "#FFD700" + } + } +} \ No newline at end of file