Theme aware plugin (#4499)

* Migrate theme manager to infrastructure and added it as input to public API instance

* Working event-delegate for PublicAPIInstance

* Theme aware UWP applications

* Theme aware program plugin

* Update query icon on theme change

* Theme aware calculator plugin

* Fix issue with query running before theme change

* Theme based changes in ImageLoader

* Removed ErrorIcon direct references and added references from ImageLoader

* Nit fixes

* Removed unnecessary TODO in UWP.cs

* Added preference to theme based icons

* Added IDisposable interfaces to unsubscribe events
This commit is contained in:
Divyansh Srivastava 2020-06-26 17:42:06 -07:00 committed by GitHub
parent d9597d5ad5
commit d3b10d0d4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 255 additions and 41 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

View File

@ -1,4 +1,6 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
@ -8,7 +10,7 @@ using Wox.Plugin;
namespace Microsoft.Plugin.Calculator namespace Microsoft.Plugin.Calculator
{ {
public class Main : IPlugin, IPluginI18n public class Main : IPlugin, IPluginI18n, IDisposable
{ {
private static readonly Regex RegValidExpressChar = new Regex( private static readonly Regex RegValidExpressChar = new Regex(
@"^(" + @"^(" +
@ -22,6 +24,8 @@ namespace Microsoft.Plugin.Calculator
private static readonly Regex RegBrackets = new Regex(@"[\(\)\[\]]", RegexOptions.Compiled); private static readonly Regex RegBrackets = new Regex(@"[\(\)\[\]]", RegexOptions.Compiled);
private static readonly Engine MagesEngine; private static readonly Engine MagesEngine;
private PluginInitContext Context { get; set; } private PluginInitContext Context { get; set; }
private string IconPath { get; set; }
private bool _disposed = false;
static Main() static Main()
{ {
@ -58,7 +62,7 @@ namespace Microsoft.Plugin.Calculator
new Result new Result
{ {
Title = result.ToString(), Title = result.ToString(),
IcoPath = "Images/calculator.png", IcoPath = IconPath,
Score = 300, Score = 300,
SubTitle = Context.API.GetTranslation("wox_plugin_calculator_copy_number_to_clipboard"), SubTitle = Context.API.GetTranslation("wox_plugin_calculator_copy_number_to_clipboard"),
Action = c => Action = c =>
@ -115,6 +119,26 @@ namespace Microsoft.Plugin.Calculator
public void Init(PluginInitContext context) public void Init(PluginInitContext context)
{ {
Context = context; Context = context;
Context.API.ThemeChanged += OnThemeChanged;
UpdateIconPath(Context.API.GetCurrentTheme());
}
// Todo : Update with theme based IconPath
private void UpdateIconPath(Theme theme)
{
if (theme == Theme.Light || theme == Theme.HighContrastWhite)
{
IconPath = "Images/calculator_light.png";
}
else
{
IconPath = "Images/calculator_dark.png";
}
}
private void OnThemeChanged(Theme _, Theme newTheme)
{
UpdateIconPath(newTheme);
} }
public string GetTranslatedPluginTitle() public string GetTranslatedPluginTitle()
@ -126,5 +150,23 @@ namespace Microsoft.Plugin.Calculator
{ {
return Context.API.GetTranslation("wox_plugin_calculator_plugin_description"); return Context.API.GetTranslation("wox_plugin_calculator_plugin_description");
} }
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
Context.API.ThemeChanged -= OnThemeChanged;
_disposed = true;
}
}
}
} }
} }

View File

@ -49,7 +49,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Images\calculator.png"> <None Include="Images\calculator_light.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
@ -107,5 +107,11 @@
<PackageReference Include="Mages" Version="1.6.0" /> <PackageReference Include="Mages" Version="1.6.0" />
<PackageReference Include="System.Runtime" Version="4.3.1" /> <PackageReference Include="System.Runtime" Version="4.3.1" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Update="Images\calculator_dark.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project> </Project>

View File

@ -13,11 +13,11 @@ using Wox.Plugin;
using Microsoft.Plugin.Program.Views; using Microsoft.Plugin.Program.Views;
using Stopwatch = Wox.Infrastructure.Stopwatch; using Stopwatch = Wox.Infrastructure.Stopwatch;
using Microsoft.Plugin.Program.Programs;
namespace Microsoft.Plugin.Program namespace Microsoft.Plugin.Program
{ {
public class Main : ISettingProvider, IPlugin, IPluginI18n, IContextMenu, ISavable, IReloadable public class Main : ISettingProvider, IPlugin, IPluginI18n, IContextMenu, ISavable, IReloadable, IDisposable
{ {
private static readonly object IndexLock = new object(); private static readonly object IndexLock = new object();
internal static Programs.Win32[] _win32s { get; set; } internal static Programs.Win32[] _win32s { get; set; }
@ -34,6 +34,7 @@ namespace Microsoft.Plugin.Program
private static BinaryStorage<Programs.Win32[]> _win32Storage; private static BinaryStorage<Programs.Win32[]> _win32Storage;
private static BinaryStorage<Programs.UWP.Application[]> _uwpStorage; private static BinaryStorage<Programs.UWP.Application[]> _uwpStorage;
private readonly PluginJsonStorage<Settings> _settingsStorage; private readonly PluginJsonStorage<Settings> _settingsStorage;
private bool _disposed = false;
public Main() public Main()
{ {
@ -104,6 +105,21 @@ namespace Microsoft.Plugin.Program
public void Init(PluginInitContext context) public void Init(PluginInitContext context)
{ {
_context = context; _context = context;
_context.API.ThemeChanged += OnThemeChanged;
UpdateUWPIconPath(_context.API.GetCurrentTheme());
}
public void OnThemeChanged(Theme _, Theme currentTheme)
{
UpdateUWPIconPath(currentTheme);
}
public void UpdateUWPIconPath(Theme theme)
{
foreach (UWP.Application app in _uwps)
{
app.UpdatePath(theme);
}
} }
public static void IndexWin32Programs() public static void IndexWin32Programs()
@ -186,6 +202,25 @@ namespace Microsoft.Plugin.Program
public void UpdateSettings(PowerLauncherSettings settings) public void UpdateSettings(PowerLauncherSettings settings)
{ {
} }
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.API.ThemeChanged -= OnThemeChanged;
_disposed = true;
}
}
}
void InitializeFileWatchers() void InitializeFileWatchers()
{ {
// Create a new FileSystemWatcher and set its properties. // Create a new FileSystemWatcher and set its properties.

View File

@ -21,6 +21,7 @@ using System.Windows.Input;
using System.Runtime.InteropServices.ComTypes; using System.Runtime.InteropServices.ComTypes;
using Wox.Plugin.SharedCommands; using Wox.Plugin.SharedCommands;
using System.Reflection; using System.Reflection;
using Wox.Infrastructure.Image;
namespace Microsoft.Plugin.Program.Programs namespace Microsoft.Plugin.Program.Programs
{ {
@ -404,7 +405,6 @@ namespace Microsoft.Plugin.Program.Programs
DisplayName = ResourceFromPri(package.FullName, DisplayName); DisplayName = ResourceFromPri(package.FullName, DisplayName);
Description = ResourceFromPri(package.FullName, Description); Description = ResourceFromPri(package.FullName, Description);
LogoUri = LogoUriFromManifest(manifestApp); LogoUri = LogoUriFromManifest(manifestApp);
LogoPath = LogoPathFromUri(LogoUri);
Enabled = true; Enabled = true;
CanRunElevated = IfApplicationcanRunElevated(); CanRunElevated = IfApplicationcanRunElevated();
@ -516,7 +516,19 @@ namespace Microsoft.Plugin.Program.Programs
} }
} }
internal string LogoPathFromUri(string uri) public void UpdatePath(Theme theme)
{
if (theme == Theme.Light || theme == Theme.HighContrastWhite)
{
LogoPath = LogoPathFromUri(LogoUri, "contrast-white");
}
else
{
LogoPath = LogoPathFromUri(LogoUri, "contrast-black");
}
}
internal string LogoPathFromUri(string uri, string theme)
{ {
// all https://msdn.microsoft.com/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets // all https://msdn.microsoft.com/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets
// windows 10 https://msdn.microsoft.com/en-us/library/windows/apps/dn934817.aspx // windows 10 https://msdn.microsoft.com/en-us/library/windows/apps/dn934817.aspx
@ -539,11 +551,7 @@ namespace Microsoft.Plugin.Program.Programs
{ {
var end = path.Length - extension.Length; var end = path.Length - extension.Length;
var prefix = path.Substring(0, end); var prefix = path.Substring(0, end);
var paths = new List<string> { path }; var paths = new List<string> { path };
// TODO: This value must be set in accordance to the WPF theme (work in progress).
// Must be set to `contrast-white` for light theme and to `contrast-black` for dark theme to get an icon of the contrasting color.
var theme = "contrast-black";
var scaleFactors = new Dictionary<PackageVersion, List<int>> var scaleFactors = new Dictionary<PackageVersion, List<int>>
{ {
@ -563,6 +571,7 @@ namespace Microsoft.Plugin.Program.Programs
} }
} }
paths = paths.OrderByDescending(x => x.Contains(theme)).ToList();
var selected = paths.FirstOrDefault(File.Exists); var selected = paths.FirstOrDefault(File.Exists);
if (!string.IsNullOrEmpty(selected)) if (!string.IsNullOrEmpty(selected))
{ {
@ -589,6 +598,7 @@ namespace Microsoft.Plugin.Program.Programs
pathFactorPairs.Add(prefixThemePath, factor); pathFactorPairs.Add(prefixThemePath, factor);
} }
paths = paths.OrderByDescending(x => x.Contains(theme)).ToList();
var selectedIconPath = paths.OrderBy(x => Math.Abs(pathFactorPairs.GetValueOrDefault(x) - appIconSize)).FirstOrDefault(File.Exists); var selectedIconPath = paths.OrderBy(x => Math.Abs(pathFactorPairs.GetValueOrDefault(x) - appIconSize)).FirstOrDefault(File.Exists);
if (!string.IsNullOrEmpty(selectedIconPath)) if (!string.IsNullOrEmpty(selectedIconPath))
{ {
@ -630,7 +640,7 @@ namespace Microsoft.Plugin.Program.Programs
ProgramLogger.LogException($"|UWP|ImageFromPath|{path}" + ProgramLogger.LogException($"|UWP|ImageFromPath|{path}" +
$"|Unable to get logo for {UserModelId} from {path} and" + $"|Unable to get logo for {UserModelId} from {path} and" +
$" located in {Package.Location}", new FileNotFoundException()); $" located in {Package.Location}", new FileNotFoundException());
return new BitmapImage(new Uri(Constant.ErrorIcon)); return new BitmapImage(new Uri(ImageLoader.ErrorIconPath));
} }
} }

View File

@ -17,6 +17,7 @@ using Wox.Infrastructure.Http;
using Wox.Infrastructure.Image; using Wox.Infrastructure.Image;
using Wox.Infrastructure.Logger; using Wox.Infrastructure.Logger;
using Wox.Infrastructure.UserSettings; using Wox.Infrastructure.UserSettings;
using Wox.Plugin;
using Wox.ViewModel; using Wox.ViewModel;
using Stopwatch = Wox.Infrastructure.Stopwatch; using Stopwatch = Wox.Infrastructure.Stopwatch;
@ -31,6 +32,7 @@ namespace PowerLauncher
private Settings _settings; private Settings _settings;
private MainViewModel _mainVM; private MainViewModel _mainVM;
private MainWindow _mainWindow; private MainWindow _mainWindow;
private ThemeManager _themeManager;
private SettingWindowViewModel _settingsVM; private SettingWindowViewModel _settingsVM;
private readonly Alphabet _alphabet = new Alphabet(); private readonly Alphabet _alphabet = new Alphabet();
private StringMatcher _stringMatcher; private StringMatcher _stringMatcher;
@ -70,7 +72,8 @@ namespace PowerLauncher
RegisterAppDomainExceptions(); RegisterAppDomainExceptions();
RegisterDispatcherUnhandledException(); RegisterDispatcherUnhandledException();
ImageLoader.Initialize(); _themeManager = new ThemeManager(this);
ImageLoader.Initialize(_themeManager.GetCurrentTheme());
_settingsVM = new SettingWindowViewModel(); _settingsVM = new SettingWindowViewModel();
_settings = _settingsVM.Settings; _settings = _settingsVM.Settings;
@ -80,11 +83,10 @@ namespace PowerLauncher
StringMatcher.Instance = _stringMatcher; StringMatcher.Instance = _stringMatcher;
_stringMatcher.UserSettingSearchPrecision = _settings.QuerySearchPrecision; _stringMatcher.UserSettingSearchPrecision = _settings.QuerySearchPrecision;
ThemeManager themeManager = new ThemeManager(this);
PluginManager.LoadPlugins(_settings.PluginSettings); PluginManager.LoadPlugins(_settings.PluginSettings);
_mainVM = new MainViewModel(_settings); _mainVM = new MainViewModel(_settings);
_mainWindow = new MainWindow(_settings, _mainVM); _mainWindow = new MainWindow(_settings, _mainVM);
API = new PublicAPIInstance(_settingsVM, _mainVM, _alphabet); API = new PublicAPIInstance(_settingsVM, _mainVM, _alphabet, _themeManager);
PluginManager.InitializePlugins(API); PluginManager.InitializePlugins(API);
Current.MainWindow = _mainWindow; Current.MainWindow = _mainWindow;
@ -105,6 +107,7 @@ namespace PowerLauncher
_mainVM.MainWindowVisibility = Visibility.Visible; _mainVM.MainWindowVisibility = Visibility.Visible;
_mainVM.ColdStartFix(); _mainVM.ColdStartFix();
_themeManager.ThemeChanged += OnThemeChanged;
Log.Info("|App.OnStartup|End PowerToys Run startup ---------------------------------------------------- "); Log.Info("|App.OnStartup|End PowerToys Run startup ---------------------------------------------------- ");
bootTime.Stop(); bootTime.Stop();
@ -125,6 +128,17 @@ namespace PowerLauncher
Current.SessionEnding += (s, e) => Dispose(); Current.SessionEnding += (s, e) => Dispose();
} }
/// <summary>
/// Callback when windows theme is changed.
/// </summary>
/// <param name="oldTheme">Previous Theme</param>
/// <param name="newTheme">Current Theme</param>
private void OnThemeChanged(Theme oldTheme, Theme newTheme)
{
ImageLoader.UpdateIconPath(newTheme);
_mainVM.Query();
}
/// <summary> /// <summary>
/// let exception throw as normal is better for Debug /// let exception throw as normal is better for Debug
/// </summary> /// </summary>
@ -158,9 +172,13 @@ namespace PowerLauncher
Log.Info("|App.OnExit| Start PowerToys Run Exit---------------------------------------------------- "); Log.Info("|App.OnExit| Start PowerToys Run Exit---------------------------------------------------- ");
if (disposing) if (disposing)
{ {
_mainWindow.Dispose(); _themeManager.ThemeChanged -= OnThemeChanged;
API.SaveAppAllSettings(); API.SaveAppAllSettings();
PluginManager.Dispose();
_mainWindow.Dispose();
API.Dispose();
_mainVM.Dispose(); _mainVM.Dispose();
_themeManager.Dispose();
_disposed = true; _disposed = true;
} }

View File

@ -287,5 +287,14 @@ namespace Wox.Core.Plugin
RemoveActionKeyword(id, oldActionKeyword); RemoveActionKeyword(id, oldActionKeyword);
} }
} }
public static void Dispose()
{
foreach (var plugin in AllPlugins)
{
var disposablePlugin = plugin as IDisposable;
disposablePlugin?.Dispose();
}
}
} }
} }

View File

@ -57,7 +57,6 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" /> <PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
<PackageReference Include="MahApps.Metro" Version="2.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="PropertyChanged.Fody" Version="3.2.8" /> <PackageReference Include="PropertyChanged.Fody" Version="3.2.8" />
<PackageReference Include="SharpZipLib" Version="1.2.0" /> <PackageReference Include="SharpZipLib" Version="1.2.0" />

View File

@ -8,6 +8,7 @@ using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Wox.Infrastructure.Logger; using Wox.Infrastructure.Logger;
using Wox.Infrastructure.Storage; using Wox.Infrastructure.Storage;
using Wox.Plugin;
namespace Wox.Infrastructure.Image namespace Wox.Infrastructure.Image
{ {
@ -17,7 +18,8 @@ namespace Wox.Infrastructure.Image
private static BinaryStorage<Dictionary<string, int>> _storage; private static BinaryStorage<Dictionary<string, int>> _storage;
private static readonly ConcurrentDictionary<string, string> GuidToKey = new ConcurrentDictionary<string, string>(); private static readonly ConcurrentDictionary<string, string> GuidToKey = new ConcurrentDictionary<string, string>();
private static IImageHashGenerator _hashGenerator; private static IImageHashGenerator _hashGenerator;
public static string ErrorIconPath;
public static string DefaultIconPath;
private static readonly string[] ImageExtensions = private static readonly string[] ImageExtensions =
{ {
@ -31,18 +33,20 @@ namespace Wox.Infrastructure.Image
}; };
public static void Initialize() public static void Initialize(Theme theme)
{ {
_storage = new BinaryStorage<Dictionary<string, int>>("Image"); _storage = new BinaryStorage<Dictionary<string, int>>("Image");
_hashGenerator = new ImageHashGenerator(); _hashGenerator = new ImageHashGenerator();
ImageCache.SetUsageAsDictionary(_storage.TryLoad(new Dictionary<string, int>())); ImageCache.SetUsageAsDictionary(_storage.TryLoad(new Dictionary<string, int>()));
// Todo : Add error and default icon specific to each theme
foreach (var icon in new[] { Constant.DefaultIcon, Constant.ErrorIcon }) foreach (var icon in new[] { Constant.DefaultIcon, Constant.ErrorIcon })
{ {
ImageSource img = new BitmapImage(new Uri(icon)); ImageSource img = new BitmapImage(new Uri(icon));
img.Freeze(); img.Freeze();
ImageCache[icon] = img; ImageCache[icon] = img;
} }
UpdateIconPath(theme);
Task.Run(() => Task.Run(() =>
{ {
Stopwatch.Normal("|ImageLoader.Initialize|Preload images cost", () => Stopwatch.Normal("|ImageLoader.Initialize|Preload images cost", () =>
@ -62,6 +66,21 @@ namespace Wox.Infrastructure.Image
_storage.Save(ImageCache.GetUsageAsDictionary()); _storage.Save(ImageCache.GetUsageAsDictionary());
} }
//Todo : Update it with icons specific to each theme.
public static void UpdateIconPath(Theme theme)
{
if (theme == Theme.Light || theme == Theme.HighContrastWhite)
{
ErrorIconPath = Constant.ErrorIcon;
DefaultIconPath = Constant.DefaultIcon;
}
else
{
ErrorIconPath = Constant.ErrorIcon;
DefaultIconPath = Constant.DefaultIcon;
}
}
private class ImageResult private class ImageResult
{ {
public ImageResult(ImageSource imageSource, ImageType imageType) public ImageResult(ImageSource imageSource, ImageType imageType)
@ -92,7 +111,7 @@ namespace Wox.Infrastructure.Image
{ {
if (string.IsNullOrEmpty(path)) if (string.IsNullOrEmpty(path))
{ {
return new ImageResult(ImageCache[Constant.ErrorIcon], ImageType.Error); return new ImageResult(ImageCache[ErrorIconPath], ImageType.Error);
} }
if (ImageCache.ContainsKey(path)) if (ImageCache.ContainsKey(path))
{ {
@ -154,8 +173,8 @@ namespace Wox.Infrastructure.Image
} }
else else
{ {
image = ImageCache[Constant.ErrorIcon]; image = ImageCache[ErrorIconPath];
path = Constant.ErrorIcon; path = ErrorIconPath;
} }
if (type != ImageType.Error) if (type != ImageType.Error)
@ -167,7 +186,7 @@ namespace Wox.Infrastructure.Image
{ {
Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path}", e); Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path}", e);
type = ImageType.Error; type = ImageType.Error;
image = ImageCache[Constant.ErrorIcon]; image = ImageCache[ErrorIconPath];
ImageCache[path] = image; ImageCache[path] = image;
} }
return new ImageResult(image, type); return new ImageResult(image, type);

View File

@ -57,6 +57,16 @@ namespace Wox.Plugin
[Obsolete] [Obsolete]
void ShowApp(); void ShowApp();
/// <summary>
/// Get current theme
/// </summary>
Theme GetCurrentTheme();
/// <summary>
/// Theme change event
/// </summary>
event ThemeChangedHandler ThemeChanged;
/// <summary> /// <summary>
/// Save all Wox settings /// Save all Wox settings
/// </summary> /// </summary>

View File

@ -6,12 +6,13 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
namespace Wox.Core.Resource namespace Wox.Plugin
{ {
public class ThemeManager public class ThemeManager : IDisposable
{ {
private Theme currentTheme; private Theme currentTheme;
private readonly Application App; private readonly Application App;
private bool _disposed = false;
private readonly string LightTheme = "Light.Accent1"; private readonly string LightTheme = "Light.Accent1";
private readonly string DarkTheme = "Dark.Accent1"; private readonly string DarkTheme = "Dark.Accent1";
private readonly string HighContrastOneTheme = "HighContrast.Accent2"; private readonly string HighContrastOneTheme = "HighContrast.Accent2";
@ -19,6 +20,8 @@ namespace Wox.Core.Resource
private readonly string HighContrastBlackTheme = "HighContrast.Accent4"; private readonly string HighContrastBlackTheme = "HighContrast.Accent4";
private readonly string HighContrastWhiteTheme = "HighContrast.Accent5"; private readonly string HighContrastWhiteTheme = "HighContrast.Accent5";
public event ThemeChangedHandler ThemeChanged;
public ThemeManager(Application app) public ThemeManager(Application app)
{ {
this.App = app; this.App = app;
@ -52,17 +55,23 @@ namespace Wox.Core.Resource
ResetTheme(); ResetTheme();
ControlzEx.Theming.ThemeManager.Current.ThemeSyncMode = ThemeSyncMode.SyncWithAppMode; ControlzEx.Theming.ThemeManager.Current.ThemeSyncMode = ThemeSyncMode.SyncWithAppMode;
ControlzEx.Theming.ThemeManager.Current.ThemeChanged += Current_ThemeChanged; ControlzEx.Theming.ThemeManager.Current.ThemeChanged += Current_ThemeChanged;
SystemParameters.StaticPropertyChanged += (sender, args) => SystemParameters.StaticPropertyChanged += SystemParameters_StaticPropertyChanged;
}
private void SystemParameters_StaticPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(SystemParameters.HighContrast))
{ {
if (args.PropertyName == nameof(SystemParameters.HighContrast)) ResetTheme();
{ }
ResetTheme(); }
}
}; public Theme GetCurrentTheme()
{
return currentTheme;
} }
private static Theme GetHighContrastBaseType()
public static Theme GetHighContrastBaseType()
{ {
string RegistryKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes"; string RegistryKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes";
string theme = (string) Registry.GetValue(RegistryKey, "CurrentTheme", string.Empty); string theme = (string) Registry.GetValue(RegistryKey, "CurrentTheme", string.Empty);
@ -80,7 +89,7 @@ namespace Wox.Core.Resource
return Theme.None; return Theme.None;
} }
public void ResetTheme() private void ResetTheme()
{ {
if (SystemParameters.HighContrast) if (SystemParameters.HighContrast)
{ {
@ -96,6 +105,7 @@ namespace Wox.Core.Resource
private void ChangeTheme(Theme theme) private void ChangeTheme(Theme theme)
{ {
Theme oldTheme = currentTheme;
if (theme == currentTheme) if (theme == currentTheme)
return; return;
if (theme == Theme.HighContrastOne) if (theme == Theme.HighContrastOne)
@ -132,15 +142,36 @@ namespace Wox.Core.Resource
{ {
currentTheme = Theme.None; currentTheme = Theme.None;
} }
Debug.WriteLine("Theme Changed to :" + currentTheme); ThemeChanged?.Invoke(oldTheme, currentTheme);
} }
private void Current_ThemeChanged(object sender, ThemeChangedEventArgs e) private void Current_ThemeChanged(object sender, ThemeChangedEventArgs e)
{ {
ResetTheme(); ResetTheme();
} }
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
ControlzEx.Theming.ThemeManager.Current.ThemeChanged -= Current_ThemeChanged;
SystemParameters.StaticPropertyChanged -= SystemParameters_StaticPropertyChanged;
_disposed = true;
}
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
} }
public delegate void ThemeChangedHandler(Theme oldTheme, Theme newTheme);
public enum Theme public enum Theme
{ {
None, None,

View File

@ -57,6 +57,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" /> <PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
<PackageReference Include="MahApps.Metro" Version="2.1.0" />
<PackageReference Include="ControlzEx" Version="4.3.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.2" /> <PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="PropertyChanged.Fody" Version="3.2.8" /> <PackageReference Include="PropertyChanged.Fody" Version="3.2.8" />

View File

@ -14,19 +14,25 @@ using Wox.ViewModel;
namespace Wox namespace Wox
{ {
public class PublicAPIInstance : IPublicAPI public class PublicAPIInstance : IPublicAPI, IDisposable
{ {
private readonly SettingWindowViewModel _settingsVM; private readonly SettingWindowViewModel _settingsVM;
private readonly MainViewModel _mainVM; private readonly MainViewModel _mainVM;
private readonly Alphabet _alphabet; private readonly Alphabet _alphabet;
private bool _disposed = false;
private readonly ThemeManager _themeManager;
public event ThemeChangedHandler ThemeChanged;
#region Constructor #region Constructor
public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM, Alphabet alphabet) public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM, Alphabet alphabet, ThemeManager themeManager)
{ {
_settingsVM = settingsVM; _settingsVM = settingsVM;
_mainVM = mainVM; _mainVM = mainVM;
_alphabet = alphabet; _alphabet = alphabet;
_themeManager = themeManager;
_themeManager.ThemeChanged += OnThemeChanged;
WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
} }
@ -138,10 +144,37 @@ namespace Wox
}); });
} }
public Theme GetCurrentTheme()
{
return _themeManager.GetCurrentTheme();
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
#endregion #endregion
#region Private Methods #region Protected Methods
protected void OnThemeChanged(Theme oldTheme, Theme newTheme)
{
ThemeChanged?.Invoke(oldTheme, newTheme);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_themeManager.ThemeChanged -= OnThemeChanged;
_disposed = true;
}
}
}
#endregion #endregion
} }
} }

View File

@ -172,7 +172,7 @@ namespace Wox.ViewModel
catch (Exception e) catch (Exception e)
{ {
Log.Exception($"|ResultViewModel.Image|IcoPath is empty and exception when calling Icon() for result <{Result.Title}> of plugin <{Result.PluginDirectory}>", e); Log.Exception($"|ResultViewModel.Image|IcoPath is empty and exception when calling Icon() for result <{Result.Title}> of plugin <{Result.PluginDirectory}>", e);
imagePath = Constant.ErrorIcon; imagePath = ImageLoader.ErrorIconPath;
} }
} }