Revert "Fixed theme service"

This reverts commit 2de78f520c.
This commit is contained in:
Aleh Khantsevich
2024-07-14 15:37:34 +02:00
parent 2de78f520c
commit 592e5d899e

View File

@@ -7,6 +7,7 @@ using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging;
using Newtonsoft.Json;
using Windows.Storage; using Windows.Storage;
using Windows.UI.ViewManagement; using Windows.UI.ViewManagement;
@@ -20,8 +21,6 @@ using Wino.Core.Messages.Shell;
using Wino.Core.UWP.Extensions; using Wino.Core.UWP.Extensions;
using Wino.Core.UWP.Models.Personalization; using Wino.Core.UWP.Models.Personalization;
using Wino.Core.UWP.Services; using Wino.Core.UWP.Services;
using System.Text.Json;
using Wino.Core.WinUI.Services;
#if NET8_0 #if NET8_0
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
@@ -39,28 +38,24 @@ using Windows.UI.Xaml;
using Windows.UI.Xaml.Markup; using Windows.UI.Xaml.Markup;
#endif #endif
namespace Wino.Services
namespace Wino.Services; {
/// <summary> /// <summary>
/// Class providing functionality around switching and restoring theme settings /// Class providing functionality around switching and restoring theme settings
/// </summary> /// </summary>
public class ThemeService(IConfigurationService configurationService, public class ThemeService : IThemeService
IUnderlyingThemeService underlyingThemeService,
IApplicationResourceManager<ResourceDictionary> applicationResourceManager,
IAppShellService appShellService) : IThemeService
{ {
public const string CustomThemeFolderName = "CustomThemes"; public const string CustomThemeFolderName = "CustomThemes";
private const string MicaThemeId = "a160b1b0-2ab8-4e97-a803-f4050f036e25"; private static string _micaThemeId = "a160b1b0-2ab8-4e97-a803-f4050f036e25";
private const string AcrylicThemeId = "fc08e58c-36fd-46e2-a562-26cf277f1467"; private static string _acrylicThemeId = "fc08e58c-36fd-46e2-a562-26cf277f1467";
private const string CloudsThemeId = "3b621cc2-e270-4a76-8477-737917cccda0"; private static string _cloudsThemeId = "3b621cc2-e270-4a76-8477-737917cccda0";
private const string ForestThemeId = "8bc89b37-a7c5-4049-86e2-de1ae8858dbd"; private static string _forestThemeId = "8bc89b37-a7c5-4049-86e2-de1ae8858dbd";
private const string NightyThemeId = "5b65e04e-fd7e-4c2d-8221-068d3e02d23a"; private static string _nightyThemeId = "5b65e04e-fd7e-4c2d-8221-068d3e02d23a";
private const string SnowflakeThemeId = "e143ddde-2e28-4846-9d98-dad63d6505f1"; private static string _snowflakeThemeId = "e143ddde-2e28-4846-9d98-dad63d6505f1";
private const string GardenThemeId = "698e4466-f88c-4799-9c61-f0ea1308ed49"; private static string _gardenThemeId = "698e4466-f88c-4799-9c61-f0ea1308ed49";
private Frame _mainApplicationFrame; private Frame mainApplicationFrame = null;
public event EventHandler<ApplicationElementTheme> ElementThemeChanged; public event EventHandler<ApplicationElementTheme> ElementThemeChanged;
public event EventHandler<string> AccentColorChanged; public event EventHandler<string> AccentColorChanged;
@@ -73,36 +68,49 @@ public class ThemeService(IConfigurationService configurationService,
public const string CustomThemeAccentColorKey = nameof(CustomThemeAccentColorKey); public const string CustomThemeAccentColorKey = nameof(CustomThemeAccentColorKey);
// Keep reference so it does not get optimized/garbage collected // Keep reference so it does not get optimized/garbage collected
private readonly UISettings _uiSettings = new(); private readonly UISettings uiSettings = new UISettings();
private readonly IConfigurationService _configurationService = configurationService; private readonly IConfigurationService _configurationService;
private readonly IUnderlyingThemeService _underlyingThemeService = underlyingThemeService; private readonly IUnderlyingThemeService _underlyingThemeService;
private readonly IApplicationResourceManager<ResourceDictionary> _applicationResourceManager = applicationResourceManager; private readonly IApplicationResourceManager<ResourceDictionary> _applicationResourceManager;
private readonly IAppShellService _appShellService = appShellService;
private List<AppThemeBase> _preDefinedThemes{ get; } = private List<AppThemeBase> preDefinedThemes { get; set; } = new List<AppThemeBase>()
[ {
new SystemAppTheme("Mica", Guid.Parse(MicaThemeId)), new SystemAppTheme("Mica", Guid.Parse(_micaThemeId)),
new SystemAppTheme("Acrylic", Guid.Parse(AcrylicThemeId)), new SystemAppTheme("Acrylic", Guid.Parse(_acrylicThemeId)),
new PreDefinedAppTheme("Nighty", Guid.Parse(NightyThemeId), "#e1b12c", ApplicationElementTheme.Dark), new PreDefinedAppTheme("Nighty", Guid.Parse(_nightyThemeId), "#e1b12c", ApplicationElementTheme.Dark),
new PreDefinedAppTheme("Forest", Guid.Parse(ForestThemeId), "#16a085", ApplicationElementTheme.Dark), new PreDefinedAppTheme("Forest", Guid.Parse(_forestThemeId), "#16a085", ApplicationElementTheme.Dark),
new PreDefinedAppTheme("Clouds", Guid.Parse(CloudsThemeId), "#0984e3", ApplicationElementTheme.Light), new PreDefinedAppTheme("Clouds", Guid.Parse(_cloudsThemeId), "#0984e3", ApplicationElementTheme.Light),
new PreDefinedAppTheme("Snowflake", Guid.Parse(SnowflakeThemeId), "#4a69bd", ApplicationElementTheme.Light), new PreDefinedAppTheme("Snowflake", Guid.Parse(_snowflakeThemeId), "#4a69bd", ApplicationElementTheme.Light),
new PreDefinedAppTheme("Garden", Guid.Parse(GardenThemeId), "#05c46b", ApplicationElementTheme.Light), new PreDefinedAppTheme("Garden", Guid.Parse(_gardenThemeId), "#05c46b", ApplicationElementTheme.Light),
]; };
public ThemeService(IConfigurationService configurationService,
IUnderlyingThemeService underlyingThemeService,
IApplicationResourceManager<ResourceDictionary> applicationResourceManager)
{
_configurationService = configurationService;
_underlyingThemeService = underlyingThemeService;
_applicationResourceManager = applicationResourceManager;
}
/// <summary> /// <summary>
/// Gets or sets (with LocalSettings persistence) the RequestedTheme of the root element. /// Gets or sets (with LocalSettings persistence) the RequestedTheme of the root element.
/// </summary> /// </summary>
public ApplicationElementTheme RootTheme public ApplicationElementTheme RootTheme
{ {
get => (_mainApplicationFrame?.RequestedTheme.ToWinoElementTheme()) ?? ApplicationElementTheme.Default; get
{
if (mainApplicationFrame == null) return ApplicationElementTheme.Default;
return mainApplicationFrame.RequestedTheme.ToWinoElementTheme();
}
set set
{ {
if (_mainApplicationFrame == null) if (mainApplicationFrame == null)
return; return;
_mainApplicationFrame.RequestedTheme = value.ToWindowsElementTheme(); mainApplicationFrame.RequestedTheme = value.ToWindowsElementTheme();
_configurationService.Set(UnderlyingThemeService.SelectedAppThemeKey, value); _configurationService.Set(UnderlyingThemeService.SelectedAppThemeKey, value);
@@ -113,26 +121,31 @@ public class ThemeService(IConfigurationService configurationService,
} }
} }
private Guid currentApplicationThemeId; private Guid currentApplicationThemeId;
public Guid CurrentApplicationThemeId public Guid CurrentApplicationThemeId
{ {
get => currentApplicationThemeId; get { return currentApplicationThemeId; }
set set
{ {
currentApplicationThemeId = value; currentApplicationThemeId = value;
_configurationService.Set(CurrentApplicationThemeKey, value); _configurationService.Set(CurrentApplicationThemeKey, value);
_ = _mainApplicationFrame.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.High, async () => await ApplyCustomThemeAsync(false)); _ = mainApplicationFrame.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, async () =>
{
await ApplyCustomThemeAsync(false);
});
} }
} }
private string accentColor; private string accentColor;
public string AccentColor public string AccentColor
{ {
get => accentColor; get { return accentColor; }
set set
{ {
accentColor = value; accentColor = value;
@@ -147,37 +160,40 @@ public class ThemeService(IConfigurationService configurationService,
public async Task InitializeAsync() public async Task InitializeAsync()
{ {
// Already initialized. There is no need. // Already initialized. There is no need.
if (_mainApplicationFrame != null) if (mainApplicationFrame != null)
return; return;
// Save reference as this might be null when the user is in another app // Save reference as this might be null when the user is in another app
#if NET8_0 #if NET8_0
_mainApplicationFrame = _appShellService.AppWindow.Content as Frame; // WinUI
#else #else
mainApplicationFrame = Window.Current.Content as Frame; mainApplicationFrame = Window.Current.Content as Frame;
#endif #endif
if (_mainApplicationFrame == null) return;
if (mainApplicationFrame == null) return;
RootTheme = _configurationService.Get(UnderlyingThemeService.SelectedAppThemeKey, ApplicationElementTheme.Default); RootTheme = _configurationService.Get(UnderlyingThemeService.SelectedAppThemeKey, ApplicationElementTheme.Default);
AccentColor = _configurationService.Get(AccentColorKey, string.Empty); AccentColor = _configurationService.Get(AccentColorKey, string.Empty);
// Set the current theme id. Default to Mica. // Set the current theme id. Default to Mica.
var applicationThemeGuid = _configurationService.Get(CurrentApplicationThemeKey, MicaThemeId); var applicationThemeGuid = _configurationService.Get(CurrentApplicationThemeKey, _micaThemeId);
currentApplicationThemeId = Guid.Parse(applicationThemeGuid); currentApplicationThemeId = Guid.Parse(applicationThemeGuid);
await ApplyCustomThemeAsync(true); await ApplyCustomThemeAsync(true);
// Registering to color changes, thus we notice when user changes theme system wide // Registering to color changes, thus we notice when user changes theme system wide
_uiSettings.ColorValuesChanged += UISettingsColorChanged; uiSettings.ColorValuesChanged += UISettingsColorChanged;
} }
private void NotifyThemeUpdate() private void NotifyThemeUpdate()
{ {
if (_mainApplicationFrame == null) return; if (mainApplicationFrame == null || mainApplicationFrame.Dispatcher == null) return;
_ = _mainApplicationFrame.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.High, () => _ = mainApplicationFrame.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
{ {
ElementThemeChanged?.Invoke(this, RootTheme); ElementThemeChanged?.Invoke(this, RootTheme);
WeakReferenceMessenger.Default.Send(new ApplicationThemeChanged(_underlyingThemeService.IsUnderlyingThemeDark())); WeakReferenceMessenger.Default.Send(new ApplicationThemeChanged(_underlyingThemeService.IsUnderlyingThemeDark()));
@@ -187,10 +203,11 @@ public class ThemeService(IConfigurationService configurationService,
private void UISettingsColorChanged(UISettings sender, object args) private void UISettingsColorChanged(UISettings sender, object args)
{ {
// Make sure we have a reference to our window so we dispatch a UI change // Make sure we have a reference to our window so we dispatch a UI change
if (_mainApplicationFrame != null) if (mainApplicationFrame != null)
{ {
// Dispatch on UI thread so that we have a current appbar to access and change // Dispatch on UI thread so that we have a current appbar to access and change
_ = _mainApplicationFrame.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.High, () =>
_ = mainApplicationFrame.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
{ {
UpdateSystemCaptionButtonColors(); UpdateSystemCaptionButtonColors();
@@ -204,17 +221,11 @@ public class ThemeService(IConfigurationService configurationService,
public void UpdateSystemCaptionButtonColors() public void UpdateSystemCaptionButtonColors()
{ {
if (_mainApplicationFrame == null) return; if (mainApplicationFrame == null) return;
_ = _mainApplicationFrame.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => _ = mainApplicationFrame.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{ {
ApplicationViewTitleBar titleBar = null; ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar;
try
{
// TODO: Should be removed after migration to native titlebar.
titleBar = ApplicationView.GetForCurrentView().TitleBar;
}
catch { }
if (titleBar == null) return; if (titleBar == null) return;
@@ -235,7 +246,7 @@ public class ThemeService(IConfigurationService configurationService,
if (!string.IsNullOrEmpty(hex)) if (!string.IsNullOrEmpty(hex))
{ {
#if NET8_0 #if NET8_0
var brush = new SolidColorBrush(hex.ToColor()); var brush = new SolidColorBrush(CommunityToolkit.WinUI.Helpers.ColorHelper.ToColor(hex));
#else #else
var brush = new SolidColorBrush(Microsoft.Toolkit.Uwp.Helpers.ColorHelper.ToColor(hex)); var brush = new SolidColorBrush(Microsoft.Toolkit.Uwp.Helpers.ColorHelper.ToColor(hex));
#endif #endif
@@ -252,24 +263,24 @@ public class ThemeService(IConfigurationService configurationService,
private void RefreshThemeResource() private void RefreshThemeResource()
{ {
if (_mainApplicationFrame == null) return; if (mainApplicationFrame == null) return;
if (_mainApplicationFrame.RequestedTheme == ElementTheme.Dark) if (mainApplicationFrame.RequestedTheme == ElementTheme.Dark)
{ {
_mainApplicationFrame.RequestedTheme = ElementTheme.Light; mainApplicationFrame.RequestedTheme = ElementTheme.Light;
_mainApplicationFrame.RequestedTheme = ElementTheme.Dark; mainApplicationFrame.RequestedTheme = ElementTheme.Dark;
} }
else if (_mainApplicationFrame.RequestedTheme == ElementTheme.Light) else if (mainApplicationFrame.RequestedTheme == ElementTheme.Light)
{ {
_mainApplicationFrame.RequestedTheme = ElementTheme.Dark; mainApplicationFrame.RequestedTheme = ElementTheme.Dark;
_mainApplicationFrame.RequestedTheme = ElementTheme.Light; mainApplicationFrame.RequestedTheme = ElementTheme.Light;
} }
else else
{ {
var isUnderlyingDark = _underlyingThemeService.IsUnderlyingThemeDark(); var isUnderlyingDark = _underlyingThemeService.IsUnderlyingThemeDark();
_mainApplicationFrame.RequestedTheme = isUnderlyingDark ? ElementTheme.Light : ElementTheme.Dark; mainApplicationFrame.RequestedTheme = isUnderlyingDark ? ElementTheme.Light : ElementTheme.Dark;
_mainApplicationFrame.RequestedTheme = ElementTheme.Default; mainApplicationFrame.RequestedTheme = ElementTheme.Default;
} }
} }
@@ -277,34 +288,35 @@ public class ThemeService(IConfigurationService configurationService,
{ {
AppThemeBase applyingTheme = null; AppThemeBase applyingTheme = null;
List<AppThemeBase> controlThemeList = [.. _preDefinedThemes]; var controlThemeList = new List<AppThemeBase>(preDefinedThemes);
// Don't search for custom themes if applying theme is already in pre-defined templates. // Don't search for custom themes if applying theme is already in pre-defined templates.
// This is important for startup performance because we won't be loading the custom themes on launch. // This is important for startup performance because we won't be loading the custom themes on launch.
bool isApplyingPreDefinedTheme = _preDefinedThemes.Exists(a => a.Id == currentApplicationThemeId); bool isApplyingPreDefinedTheme = preDefinedThemes.Exists(a => a.Id == currentApplicationThemeId);
if (isApplyingPreDefinedTheme) if (isApplyingPreDefinedTheme)
{ {
applyingTheme = _preDefinedThemes.Find(a => a.Id == currentApplicationThemeId); applyingTheme = preDefinedThemes.Find(a => a.Id == currentApplicationThemeId);
} }
else else
{ {
// User applied custom theme. Load custom themes and find it there. // User applied custom theme. Load custom themes and find it there.
// Fallback to Mica if nothing found. // Fallback to Mica if nothing found.
var customThemes = await GetCurrentCustomThemesAsync(); var customThemes = await GetCurrentCustomThemesAsync();
controlThemeList.AddRange(customThemes.Select(a => new CustomAppTheme(a))); controlThemeList.AddRange(customThemes.Select(a => new CustomAppTheme(a)));
applyingTheme = controlThemeList.Find(a => a.Id == currentApplicationThemeId) ?? _preDefinedThemes.First(a => a.Id == Guid.Parse(MicaThemeId)); applyingTheme = controlThemeList.Find(a => a.Id == currentApplicationThemeId) ?? preDefinedThemes.First(a => a.Id == Guid.Parse(_micaThemeId));
} }
try try
{ {
var existingThemeDictionary = _applicationResourceManager.GetLastResource(); var existingThemeDictionary = _applicationResourceManager.GetLastResource();
if (existingThemeDictionary == null || !existingThemeDictionary.TryGetValue("ThemeName", out object themeNameString)) return; if (existingThemeDictionary != null && existingThemeDictionary.TryGetValue("ThemeName", out object themeNameString))
{
var themeName = themeNameString.ToString(); var themeName = themeNameString.ToString();
// Applying different theme. // Applying different theme.
@@ -332,15 +344,15 @@ public class ThemeService(IConfigurationService configurationService,
// For system themes, set the RootElement theme from saved values. // For system themes, set the RootElement theme from saved values.
// Potential bug: When we set it to system default, theme is not applied when system and // Potential bug: When we set it to system default, theme is not applied when system and
// app element theme is different :) // app element theme is different :)
RootTheme = _configurationService.Get(UnderlyingThemeService.SelectedAppThemeKey, ApplicationElementTheme.Default);
var savedElement = _configurationService.Get(UnderlyingThemeService.SelectedAppThemeKey, ApplicationElementTheme.Default);
RootTheme = savedElement;
// Quickly switch theme to apply theme resource changes. // Quickly switch theme to apply theme resource changes.
RefreshThemeResource(); RefreshThemeResource();
} }
else else
{
RootTheme = applyingTheme.ForceElementTheme; RootTheme = applyingTheme.ForceElementTheme;
}
// Theme has accent color. Override. // Theme has accent color. Override.
if (!isInitializing) if (!isInitializing)
@@ -349,7 +361,6 @@ public class ThemeService(IConfigurationService configurationService,
} }
} }
else else
{
UpdateSystemCaptionButtonColors(); UpdateSystemCaptionButtonColors();
} }
} }
@@ -361,7 +372,7 @@ public class ThemeService(IConfigurationService configurationService,
public async Task<List<AppThemeBase>> GetAvailableThemesAsync() public async Task<List<AppThemeBase>> GetAvailableThemesAsync()
{ {
List<AppThemeBase> availableThemes = [.. _preDefinedThemes]; var availableThemes = new List<AppThemeBase>(preDefinedThemes);
var customThemes = await GetCurrentCustomThemesAsync(); var customThemes = await GetCurrentCustomThemesAsync();
@@ -403,11 +414,11 @@ public class ThemeService(IConfigurationService configurationService,
var thumbnail = await wallpaperFile.GetThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.PicturesView); var thumbnail = await wallpaperFile.GetThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.PicturesView);
var thumbnailFile = await themeFolder.CreateFileAsync($"{newTheme.Id}_preview.jpg", CreationCollisionOption.ReplaceExisting); var thumbnailFile = await themeFolder.CreateFileAsync($"{newTheme.Id}_preview.jpg", CreationCollisionOption.ReplaceExisting);
await using (var readerStream = thumbnail.AsStreamForRead()) using (var readerStream = thumbnail.AsStreamForRead())
{ {
byte[] bytes = new byte[readerStream.Length]; byte[] bytes = new byte[readerStream.Length];
await readerStream.ReadAsync(bytes); await readerStream.ReadAsync(bytes, 0, bytes.Length);
var buffer = bytes.AsBuffer(); var buffer = bytes.AsBuffer();
@@ -417,7 +428,7 @@ public class ThemeService(IConfigurationService configurationService,
// Save metadata. // Save metadata.
var metadataFile = await themeFolder.CreateFileAsync($"{newTheme.Id}.json", CreationCollisionOption.ReplaceExisting); var metadataFile = await themeFolder.CreateFileAsync($"{newTheme.Id}.json", CreationCollisionOption.ReplaceExisting);
var serialized = JsonSerializer.Serialize(newTheme); var serialized = JsonConvert.SerializeObject(newTheme);
await FileIO.WriteTextAsync(metadataFile, serialized); await FileIO.WriteTextAsync(metadataFile, serialized);
return newTheme; return newTheme;
@@ -445,13 +456,14 @@ public class ThemeService(IConfigurationService configurationService,
return results; return results;
} }
private static async Task<CustomThemeMetadata> GetCustomMetadataAsync(IStorageFile file) private async Task<CustomThemeMetadata> GetCustomMetadataAsync(IStorageFile file)
{ {
var fileContent = await FileIO.ReadTextAsync(file); var fileContent = await FileIO.ReadTextAsync(file);
return JsonSerializer.Deserialize<CustomThemeMetadata>(fileContent); return JsonConvert.DeserializeObject<CustomThemeMetadata>(fileContent);
} }
public string GetSystemAccentColorHex() public string GetSystemAccentColorHex()
=> _uiSettings.GetColorValue(UIColorType.Accent).ToHex(); => uiSettings.GetColorValue(UIColorType.Accent).ToHex();
}
} }