using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Windows.Storage; using Microsoft.UI.Xaml; using Uno.Extensions.Toolkit; namespace Marechai.App.Services; public interface IColorThemeService { string CurrentColorTheme { get; } IReadOnlyList AvailableColorThemes { get; } void ApplyColorTheme(string themeName); void SetThemeService(IThemeService themeService); void ReapplyCurrentTheme(); } public class ColorThemeService : IColorThemeService { private const string COLOR_THEME_KEY = "ColorTheme"; private const string DEFAULT_THEME = "Default"; private IThemeService _themeService; public ColorThemeService() { LoadSavedTheme(); } public string CurrentColorTheme { get; private set; } = DEFAULT_THEME; public IReadOnlyList AvailableColorThemes => new List { DEFAULT_THEME, "Windows311", "MacOS9", "DOS", "Amiga", "CDE" }; public void SetThemeService(IThemeService themeService) { _themeService = themeService; // Reapply the current theme now that we have the theme service if(CurrentColorTheme != DEFAULT_THEME) ReapplyCurrentTheme(); } public void ReapplyCurrentTheme() { // Force refresh of the current theme ApplyColorTheme(CurrentColorTheme); } public void ApplyColorTheme(string themeName) { if(!AvailableColorThemes.Contains(themeName)) return; CurrentColorTheme = themeName; // Save preference try { ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; localSettings.Values[COLOR_THEME_KEY] = themeName; } catch { // Silently fail } // Apply the theme by rebuilding merged dictionaries Application app = Application.Current; if(app?.Resources == null) return; // Store the existing merged dictionaries (except color overrides) var existingDictionaries = app.Resources.MergedDictionaries .Where(d => d.Source?.OriginalString?.Contains("ColorPalette") != true) .ToList(); // Clear all merged dictionaries app.Resources.MergedDictionaries.Clear(); // Re-add the existing dictionaries foreach(ResourceDictionary dict in existingDictionaries) app.Resources.MergedDictionaries.Add(dict); // Add the new color theme if not default if(themeName != DEFAULT_THEME) { string themeFile = themeName switch { "Windows311" => "ms-appx:///Styles/Win311ColorPalette.xaml", "MacOS9" => "ms-appx:///Styles/MacOS9ColorPalette.xaml", "DOS" => "ms-appx:///Styles/DOSColorPalette.xaml", "Amiga" => "ms-appx:///Styles/AmigaColorPalette.xaml", "CDE" => "ms-appx:///Styles/CDEColorPalette.xaml", _ => null }; if(themeFile != null) { var newDictionary = new ResourceDictionary { Source = new Uri(themeFile) }; app.Resources.MergedDictionaries.Add(newDictionary); } } // Force UI refresh by toggling the theme temporarily ForceThemeRefresh(); } private void LoadSavedTheme() { try { ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; if(localSettings.Values.ContainsKey(COLOR_THEME_KEY)) { var savedTheme = localSettings.Values[COLOR_THEME_KEY] as string; if(!string.IsNullOrEmpty(savedTheme) && AvailableColorThemes.Contains(savedTheme)) { CurrentColorTheme = savedTheme; ApplyColorTheme(CurrentColorTheme); } } } catch { // If loading fails, use default theme } } private async void ForceThemeRefresh() { if(_themeService == null) return; try { // Get current theme AppTheme currentTheme = _themeService.Theme; // Toggle to opposite theme briefly AppTheme tempTheme = currentTheme == AppTheme.Light ? AppTheme.Dark : AppTheme.Light; await _themeService.SetThemeAsync(tempTheme); // Small delay to ensure the change is applied await Task.Delay(50); // Switch back to original theme await _themeService.SetThemeAsync(currentTheme); } catch { // Silently fail } } }