diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
index c7a72218907..bba46638487 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
@@ -38,6 +38,7 @@
+
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Images/theme_selector.png b/Plugins/Flow.Launcher.Plugin.Sys/Images/theme_selector.png
new file mode 100644
index 00000000000..704e9474eb2
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.Sys/Images/theme_selector.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml
index 91f32a844f8..2a266f8f651 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml
@@ -27,6 +27,7 @@
Flow Launcher Tips
Flow Launcher UserData Folder
Toggle Game Mode
+ Set the Flow Launcher Theme
Shutdown Computer
@@ -49,8 +50,9 @@
Visit Flow Launcher's documentation for more help and how to use tips
Open the location where Flow Launcher's settings are stored
Toggle Game Mode
+ Quickly change the Flow Launcher theme
-
+
Success
All Flow Launcher settings saved
Reloaded all applicable plugin data
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
index 1ec07915d2b..0dbb46be9f2 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
@@ -18,9 +18,10 @@
namespace Flow.Launcher.Plugin.Sys
{
- public class Main : IPlugin, ISettingProvider, IPluginI18n
+ public class Main : IPlugin, ISettingProvider, IPluginI18n, IDisposable
{
private PluginInitContext context;
+ private ThemeSelector themeSelector;
private Dictionary KeywordTitleMappings = new Dictionary();
#region DllImport
@@ -58,6 +59,11 @@ public Control CreateSettingPanel()
public List Query(Query query)
{
+ if(query.Search.StartsWith(ThemeSelector.Keyword))
+ {
+ return themeSelector.Query(query);
+ }
+
var commands = Commands();
var results = new List();
foreach (var c in commands)
@@ -106,6 +112,7 @@ private string GetDynamicTitle(Query query, Result result)
public void Init(PluginInitContext context)
{
this.context = context;
+ themeSelector = new ThemeSelector(context);
KeywordTitleMappings = new Dictionary{
{"Shutdown", "flowlauncher_plugin_sys_shutdown_computer_cmd"},
{"Restart", "flowlauncher_plugin_sys_restart_computer_cmd"},
@@ -126,7 +133,8 @@ public void Init(PluginInitContext context)
{"Open Log Location", "flowlauncher_plugin_sys_open_log_location_cmd"},
{"Flow Launcher Tips", "flowlauncher_plugin_sys_open_docs_tips_cmd"},
{"Flow Launcher UserData Folder", "flowlauncher_plugin_sys_open_userdata_location_cmd"},
- {"Toggle Game Mode", "flowlauncher_plugin_sys_toggle_game_mode_cmd"}
+ {"Toggle Game Mode", "flowlauncher_plugin_sys_toggle_game_mode_cmd"},
+ {"Set Flow Launcher Theme", "flowlauncher_plugin_sys_theme_selector_cmd"}
};
}
@@ -426,6 +434,18 @@ private List Commands()
context.API.ToggleGameMode();
return true;
}
+ },
+ new Result
+ {
+ Title = "Set Flow Launcher Theme",
+ SubTitle = context.API.GetTranslation("flowlauncher_plugin_sys_theme_selector"),
+ IcoPath = "Images\\theme_selector.png",
+ Glyph = new GlyphInfo("/Resources/#Segoe Fluent Icons", "\ue790"),
+ Action = c =>
+ {
+ context.API.ChangeQuery($"{ThemeSelector.Keyword} ");
+ return false;
+ }
}
});
@@ -441,5 +461,10 @@ public string GetTranslatedPluginDescription()
{
return context.API.GetTranslation("flowlauncher_plugin_sys_plugin_description");
}
+
+ public void Dispose()
+ {
+ themeSelector.Dispose();
+ }
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs
new file mode 100644
index 00000000000..75825042153
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Flow.Launcher.Core.Resource;
+
+namespace Flow.Launcher.Plugin.Sys
+{
+ public class ThemeSelector : IDisposable
+ {
+ public const string Keyword = "fltheme";
+
+ private readonly PluginInitContext context;
+ private IEnumerable themes;
+
+ public ThemeSelector(PluginInitContext context)
+ {
+ this.context = context;
+ context.API.VisibilityChanged += OnVisibilityChanged;
+ }
+
+ public List Query(Query query)
+ {
+ if (query.IsReQuery)
+ {
+ LoadThemes();
+ }
+
+ string search = query.Search[(query.Search.IndexOf(Keyword, StringComparison.Ordinal) + Keyword.Length + 1)..];
+
+ if (string.IsNullOrWhiteSpace(search))
+ {
+ return themes.Select(CreateThemeResult)
+ .OrderBy(x => x.Title)
+ .ToList();
+ }
+
+ return themes.Select(theme => (theme, matchResult: context.API.FuzzySearch(search, theme)))
+ .Where(x => x.matchResult.IsSearchPrecisionScoreMet())
+ .Select(x => CreateThemeResult(x.theme, x.matchResult.Score, x.matchResult.MatchData))
+ .OrderBy(x => x.Title)
+ .ToList();
+ }
+
+ private void OnVisibilityChanged(object sender, VisibilityChangedEventArgs args)
+ {
+ if (args.IsVisible && !context.CurrentPluginMetadata.Disabled)
+ {
+ LoadThemes();
+ }
+ }
+
+ private void LoadThemes()
+ => themes = ThemeManager.Instance.LoadAvailableThemes().Select(Path.GetFileNameWithoutExtension);
+
+ private static Result CreateThemeResult(string theme) => CreateThemeResult(theme, 0, null);
+
+ private static Result CreateThemeResult(string theme, int score, IList highlightData)
+ {
+ string title;
+ if (theme == ThemeManager.Instance.Settings.Theme)
+ {
+ title = $"{theme} ★";
+ score = 2000;
+ }
+ else
+ {
+ title = theme;
+ }
+
+ return new Result
+ {
+ Title = title,
+ TitleHighlightData = highlightData,
+ Glyph = new GlyphInfo("/Resources/#Segoe Fluent Icons", "\ue790"),
+ Score = score,
+ Action = c =>
+ {
+ ThemeManager.Instance.ChangeTheme(theme);
+ return true;
+ }
+ };
+ }
+
+ public void Dispose()
+ {
+ if (context != null && context.API != null)
+ {
+ context.API.VisibilityChanged -= OnVisibilityChanged;
+ }
+ }
+ }
+}