Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flow Launcher Theme Selector plugin #2448

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<ItemGroup>
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<system:String x:Key="flowlauncher_plugin_sys_open_docs_tips_cmd">Flow Launcher Tips</system:String>
<system:String x:Key="flowlauncher_plugin_sys_open_userdata_location_cmd">Flow Launcher UserData Folder</system:String>
<system:String x:Key="flowlauncher_plugin_sys_toggle_game_mode_cmd">Toggle Game Mode</system:String>
<system:String x:Key="flowlauncher_plugin_sys_theme_selector_cmd">Set the Flow Launcher Theme</system:String>

<!-- Command Descriptions -->
<system:String x:Key="flowlauncher_plugin_sys_shutdown_computer">Shutdown Computer</system:String>
Expand All @@ -49,8 +50,9 @@
<system:String x:Key="flowlauncher_plugin_sys_open_docs_tips">Visit Flow Launcher's documentation for more help and how to use tips</system:String>
<system:String x:Key="flowlauncher_plugin_sys_open_userdata_location">Open the location where Flow Launcher's settings are stored</system:String>
<system:String x:Key="flowlauncher_plugin_sys_toggle_game_mode">Toggle Game Mode</system:String>
<system:String x:Key="flowlauncher_plugin_sys_theme_selector">Quickly change the Flow Launcher theme</system:String>

<!-- Dialogs -->
<!-- Dialogs -->
<system:String x:Key="flowlauncher_plugin_sys_dlgtitle_success">Success</system:String>
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_all_settings_saved">All Flow Launcher settings saved</system:String>
<system:String x:Key="flowlauncher_plugin_sys_dlgtext_all_applicableplugins_reloaded">Reloaded all applicable plugin data</system:String>
Expand Down
29 changes: 27 additions & 2 deletions Plugins/Flow.Launcher.Plugin.Sys/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string> KeywordTitleMappings = new Dictionary<string, string>();

#region DllImport
Expand Down Expand Up @@ -58,6 +59,11 @@ public Control CreateSettingPanel()

public List<Result> Query(Query query)
{
if(query.Search.StartsWith(ThemeSelector.Keyword))
{
return themeSelector.Query(query);
}

var commands = Commands();
var results = new List<Result>();
foreach (var c in commands)
Expand Down Expand Up @@ -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<string, string>{
{"Shutdown", "flowlauncher_plugin_sys_shutdown_computer_cmd"},
{"Restart", "flowlauncher_plugin_sys_restart_computer_cmd"},
Expand All @@ -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"}
};
}

Expand Down Expand Up @@ -426,6 +434,18 @@ private List<Result> 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;
}
}
});

Expand All @@ -441,5 +461,10 @@ public string GetTranslatedPluginDescription()
{
return context.API.GetTranslation("flowlauncher_plugin_sys_plugin_description");
}

public void Dispose()
{
themeSelector.Dispose();
}
}
}
93 changes: 93 additions & 0 deletions Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs
Original file line number Diff line number Diff line change
@@ -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<string> themes;

public ThemeSelector(PluginInitContext context)
{
this.context = context;
context.API.VisibilityChanged += OnVisibilityChanged;
}

public List<Result> 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();
}
Comment on lines +22 to +43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Query method handles theme search effectively. However, consider caching the result of query.Search.IndexOf(Keyword, StringComparison.Ordinal) to avoid recalculating it multiple times.

- string search = query.Search[(query.Search.IndexOf(Keyword, StringComparison.Ordinal) + Keyword.Length + 1)..];
+ int keywordIndex = query.Search.IndexOf(Keyword, StringComparison.Ordinal);
+ string search = query.Search[(keywordIndex + Keyword.Length + 1)..];
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public List<Result> 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();
}
public List<Result> Query(Query query)
{
if (query.IsReQuery)
{
LoadThemes();
}
int keywordIndex = query.Search.IndexOf(Keyword, StringComparison.Ordinal);
string search = query.Search[(keywordIndex + 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);
Comment on lines +53 to +54
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

The LoadAvailableThemes method in Flow.Launcher.Core/Resource/Theme.cs currently does not include any exception handling for cases where the theme directories might not be accessible or other potential issues (e.g., IO exceptions). It would be prudent to add exception handling to ensure robustness.

  • Location: Flow.Launcher.Core/Resource/Theme.cs
  • Method: LoadAvailableThemes
Analysis chain

The method LoadThemes efficiently loads themes using LINQ. Ensure ThemeManager.Instance.LoadAvailableThemes() handles exceptions if the themes directory is not accessible.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Check if ThemeManager handles exceptions during theme loading.

cat Plugins/Flow.Launcher.Plugin.Sys/ThemeManager.cs | grep -A 10 "LoadAvailableThemes"

Length of output: 168



Script:

#!/bin/bash
# Locate the file containing the ThemeManager class
fd ThemeManager.cs

# Once located, inspect the LoadAvailableThemes method
ast-grep --lang cs --pattern 'class ThemeManager { $$$ LoadAvailableThemes() { $$$ } $$$ }'

Length of output: 503



Script:

#!/bin/bash
# Search for the LoadAvailableThemes method in the ThemeManager.cs file
rg 'LoadAvailableThemes' Flow.Launcher.Core/Resource/ThemeManager.cs -A 20

Length of output: 74



Script:

#!/bin/bash
# Search for all method definitions in the ThemeManager.cs file
rg '^\s*(public|private|protected|internal)\s+\w+\s+\w+\s*\(' Flow.Launcher.Core/Resource/ThemeManager.cs

Length of output: 107



Script:

#!/bin/bash
# Search for all method definitions across the entire repository to locate the correct method for loading themes
rg '^\s*(public|private|protected|internal)\s+\w+\s+\w+\s*\('

Length of output: 81184



Script:

#!/bin/bash
# Search for the LoadAvailableThemes method across the entire repository
rg 'LoadAvailableThemes'

Length of output: 431



Script:

#!/bin/bash
# Inspect the LoadAvailableThemes method in Flow.Launcher.Core/Resource/Theme.cs
rg 'LoadAvailableThemes' Flow.Launcher.Core/Resource/Theme.cs -A 20

Length of output: 882


private static Result CreateThemeResult(string theme) => CreateThemeResult(theme, 0, null);

private static Result CreateThemeResult(string theme, int score, IList<int> 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;
}
}
}
}
Loading