mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Resolve conflicts
This commit is contained in:
commit
cdf02d588f
40 changed files with 484 additions and 265 deletions
|
|
@ -44,8 +44,10 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
private string SettingConfigurationPath =>
|
private string SettingConfigurationPath =>
|
||||||
Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "SettingsTemplate.yaml");
|
Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "SettingsTemplate.yaml");
|
||||||
|
|
||||||
private string SettingPath => Path.Combine(DataLocation.PluginSettingsDirectory,
|
private string SettingDirectory => Path.Combine(DataLocation.PluginSettingsDirectory,
|
||||||
Context.CurrentPluginMetadata.Name, "Settings.json");
|
Context.CurrentPluginMetadata.Name);
|
||||||
|
|
||||||
|
private string SettingPath => Path.Combine(SettingDirectory, "Settings.json");
|
||||||
|
|
||||||
public abstract List<Result> LoadContextMenus(Result selectedResult);
|
public abstract List<Result> LoadContextMenus(Result selectedResult);
|
||||||
|
|
||||||
|
|
@ -159,5 +161,13 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
return Settings.CreateSettingPanel();
|
return Settings.CreateSettingPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeletePluginSettingsDirectory()
|
||||||
|
{
|
||||||
|
if (Directory.Exists(SettingDirectory))
|
||||||
|
{
|
||||||
|
Directory.Delete(SettingDirectory, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
public Control CreateSettingPanel()
|
public Control CreateSettingPanel()
|
||||||
{
|
{
|
||||||
if (Settings == null || Settings.Count == 0)
|
if (Settings == null || Settings.Count == 0)
|
||||||
return new();
|
return null;
|
||||||
|
|
||||||
var settingWindow = new UserControl();
|
var settingWindow = new UserControl();
|
||||||
var mainPanel = new Grid { Margin = settingPanelMargin, VerticalAlignment = VerticalAlignment.Center };
|
var mainPanel = new Grid { Margin = settingPanelMargin, VerticalAlignment = VerticalAlignment.Center };
|
||||||
|
|
|
||||||
|
|
@ -112,10 +112,15 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
RPC.StartListening();
|
RPC.StartListening();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Task ReloadDataAsync()
|
public virtual async Task ReloadDataAsync()
|
||||||
{
|
{
|
||||||
SetupJsonRPC();
|
try
|
||||||
return Task.CompletedTask;
|
{
|
||||||
|
await RPC.InvokeAsync("reload_data", Context);
|
||||||
|
}
|
||||||
|
catch (RemoteMethodNotFoundException e)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async ValueTask DisposeAsync()
|
public virtual async ValueTask DisposeAsync()
|
||||||
|
|
|
||||||
|
|
@ -210,9 +210,9 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
var failed = string.Join(",", failedPlugins.Select(x => x.Metadata.Name));
|
var failed = string.Join(",", failedPlugins.Select(x => x.Metadata.Name));
|
||||||
API.ShowMsg(
|
API.ShowMsg(
|
||||||
InternationalizationManager.Instance.GetTranslation("failedToInitializePluginsTitle"),
|
API.GetTranslation("failedToInitializePluginsTitle"),
|
||||||
string.Format(
|
string.Format(
|
||||||
InternationalizationManager.Instance.GetTranslation("failedToInitializePluginsMessage"),
|
API.GetTranslation("failedToInitializePluginsMessage"),
|
||||||
failed
|
failed
|
||||||
),
|
),
|
||||||
"",
|
"",
|
||||||
|
|
@ -281,7 +281,7 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdatePluginMetadata(List<Result> results, PluginMetadata metadata, Query query)
|
public static void UpdatePluginMetadata(IReadOnlyList<Result> results, PluginMetadata metadata, Query query)
|
||||||
{
|
{
|
||||||
foreach (var r in results)
|
foreach (var r in results)
|
||||||
{
|
{
|
||||||
|
|
@ -439,7 +439,7 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
public static void UpdatePlugin(PluginMetadata existingVersion, UserPlugin newVersion, string zipFilePath)
|
public static void UpdatePlugin(PluginMetadata existingVersion, UserPlugin newVersion, string zipFilePath)
|
||||||
{
|
{
|
||||||
InstallPlugin(newVersion, zipFilePath, checkModified:false);
|
InstallPlugin(newVersion, zipFilePath, checkModified:false);
|
||||||
UninstallPlugin(existingVersion, removeSettings:false, checkModified:false);
|
UninstallPlugin(existingVersion, removePluginFromSettings:false, removePluginSettings:false, checkModified: false);
|
||||||
_modifiedPlugins.Add(existingVersion.ID);
|
_modifiedPlugins.Add(existingVersion.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -454,9 +454,9 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uninstall a plugin.
|
/// Uninstall a plugin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void UninstallPlugin(PluginMetadata plugin, bool removeSettings = true)
|
public static void UninstallPlugin(PluginMetadata plugin, bool removePluginFromSettings = true, bool removePluginSettings = false)
|
||||||
{
|
{
|
||||||
UninstallPlugin(plugin, removeSettings, true);
|
UninstallPlugin(plugin, removePluginFromSettings, removePluginSettings, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
@ -521,7 +521,15 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
|
|
||||||
FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => API.ShowMsgBox(s));
|
FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => API.ShowMsgBox(s));
|
||||||
|
|
||||||
Directory.Delete(tempFolderPluginPath, true);
|
try
|
||||||
|
{
|
||||||
|
if (Directory.Exists(tempFolderPluginPath))
|
||||||
|
Directory.Delete(tempFolderPluginPath, true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Exception($"|PluginManager.InstallPlugin|Failed to delete temp folder {tempFolderPluginPath}", e);
|
||||||
|
}
|
||||||
|
|
||||||
if (checkModified)
|
if (checkModified)
|
||||||
{
|
{
|
||||||
|
|
@ -529,14 +537,62 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void UninstallPlugin(PluginMetadata plugin, bool removeSettings, bool checkModified)
|
internal static void UninstallPlugin(PluginMetadata plugin, bool removePluginFromSettings, bool removePluginSettings, bool checkModified)
|
||||||
{
|
{
|
||||||
if (checkModified && PluginModified(plugin.ID))
|
if (checkModified && PluginModified(plugin.ID))
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"Plugin {plugin.Name} has been modified");
|
throw new ArgumentException($"Plugin {plugin.Name} has been modified");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (removeSettings)
|
if (removePluginSettings)
|
||||||
|
{
|
||||||
|
if (AllowedLanguage.IsDotNet(plugin.Language)) // for the plugin in .NET, we can use assembly loader
|
||||||
|
{
|
||||||
|
var assemblyLoader = new PluginAssemblyLoader(plugin.ExecuteFilePath);
|
||||||
|
var assembly = assemblyLoader.LoadAssemblyAndDependencies();
|
||||||
|
var assemblyName = assembly.GetName().Name;
|
||||||
|
|
||||||
|
// if user want to remove the plugin settings, we cannot call save method for the plugin json storage instance of this plugin
|
||||||
|
// so we need to remove it from the api instance
|
||||||
|
var method = API.GetType().GetMethod("RemovePluginSettings");
|
||||||
|
var pluginJsonStorage = method?.Invoke(API, new object[] { assemblyName });
|
||||||
|
|
||||||
|
// if there exists a json storage for current plugin, we need to delete the directory path
|
||||||
|
if (pluginJsonStorage != null)
|
||||||
|
{
|
||||||
|
var deleteMethod = pluginJsonStorage.GetType().GetMethod("DeleteDirectory");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
deleteMethod?.Invoke(pluginJsonStorage, null);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Exception($"|PluginManager.UninstallPlugin|Failed to delete plugin json folder for {plugin.Name}", e);
|
||||||
|
API.ShowMsg(API.GetTranslation("failedToRemovePluginSettingsTitle"),
|
||||||
|
string.Format(API.GetTranslation("failedToRemovePluginSettingsMessage"), plugin.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // the plugin with json prc interface
|
||||||
|
{
|
||||||
|
var pluginPair = AllPlugins.FirstOrDefault(p => p.Metadata.ID == plugin.ID);
|
||||||
|
if (pluginPair != null && pluginPair.Plugin is JsonRPCPlugin jsonRpcPlugin)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
jsonRpcPlugin.DeletePluginSettingsDirectory();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Exception($"|PluginManager.UninstallPlugin|Failed to delete plugin json folder for {plugin.Name}", e);
|
||||||
|
API.ShowMsg(API.GetTranslation("failedToRemovePluginSettingsTitle"),
|
||||||
|
string.Format(API.GetTranslation("failedToRemovePluginSettingsMessage"), plugin.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removePluginFromSettings)
|
||||||
{
|
{
|
||||||
Settings.Plugins.Remove(plugin.ID);
|
Settings.Plugins.Remove(plugin.ID);
|
||||||
AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID);
|
AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID);
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,17 @@ using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
|
|
||||||
namespace Flow.Launcher.Infrastructure.Storage
|
namespace Flow.Launcher.Infrastructure.Storage
|
||||||
{
|
{
|
||||||
public class PluginJsonStorage<T> :JsonStorage<T> where T : new()
|
public class PluginJsonStorage<T> : JsonStorage<T> where T : new()
|
||||||
{
|
{
|
||||||
|
// Use assembly name to check which plugin is using this storage
|
||||||
|
public readonly string AssemblyName;
|
||||||
|
|
||||||
public PluginJsonStorage()
|
public PluginJsonStorage()
|
||||||
{
|
{
|
||||||
// C# related, add python related below
|
// C# related, add python related below
|
||||||
var dataType = typeof(T);
|
var dataType = typeof(T);
|
||||||
var assemblyName = dataType.Assembly.GetName().Name;
|
AssemblyName = dataType.Assembly.GetName().Name;
|
||||||
DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Plugins, assemblyName);
|
DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Plugins, AssemblyName);
|
||||||
Helper.ValidateDirectory(DirectoryPath);
|
Helper.ValidateDirectory(DirectoryPath);
|
||||||
|
|
||||||
FilePath = Path.Combine(DirectoryPath, $"{dataType.Name}{FileSuffix}");
|
FilePath = Path.Combine(DirectoryPath, $"{dataType.Name}{FileSuffix}");
|
||||||
|
|
@ -20,6 +23,13 @@ namespace Flow.Launcher.Infrastructure.Storage
|
||||||
{
|
{
|
||||||
Data = data;
|
Data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeleteDirectory()
|
||||||
|
{
|
||||||
|
if (Directory.Exists(DirectoryPath))
|
||||||
|
{
|
||||||
|
Directory.Delete(DirectoryPath, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ namespace Flow.Launcher.Plugin
|
||||||
public interface IPublicAPI
|
public interface IPublicAPI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change Flow.Launcher query
|
/// Change Flow.Launcher query.
|
||||||
|
/// When current results are from context menu or history, it will go back to query results before changing query.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="query">query text</param>
|
/// <param name="query">query text</param>
|
||||||
/// <param name="requery">
|
/// <param name="requery">
|
||||||
|
|
@ -299,7 +300,7 @@ namespace Flow.Launcher.Plugin
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reloads the query.
|
/// Reloads the query.
|
||||||
/// This method should run when selected item is from query results.
|
/// When current results are from context menu or history, it will go back to query results before requerying.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="reselect">Choose the first result after reload if true; keep the last selected result if false. Default is true.</param>
|
/// <param name="reselect">Choose the first result after reload if true; keep the last selected result if false. Default is true.</param>
|
||||||
public void ReQuery(bool reselect = true);
|
public void ReQuery(bool reselect = true);
|
||||||
|
|
|
||||||
|
|
@ -266,8 +266,9 @@ namespace Flow.Launcher.Plugin
|
||||||
/// The key to identify the record. This is used when FL checks whether the result is the topmost record. Or FL calculates the hashcode of the result for user selected records.
|
/// The key to identify the record. This is used when FL checks whether the result is the topmost record. Or FL calculates the hashcode of the result for user selected records.
|
||||||
/// This can be useful when your plugin will change the Title or SubTitle of the result dynamically.
|
/// This can be useful when your plugin will change the Title or SubTitle of the result dynamically.
|
||||||
/// If the plugin does not specific this, FL just uses Title and SubTitle to identify this result.
|
/// If the plugin does not specific this, FL just uses Title and SubTitle to identify this result.
|
||||||
|
/// Note: Because old data does not have this key, we should use null as the default value for consistency.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string RecordKey { get; set; } = string.Empty;
|
public string RecordKey { get; set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Info of the preview section of a <see cref="Result"/>
|
/// Info of the preview section of a <see cref="Result"/>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Flow.Launcher.Plugin.SharedCommands;
|
using Flow.Launcher.Plugin.SharedCommands;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Legacy;
|
||||||
|
|
||||||
namespace Flow.Launcher.Test
|
namespace Flow.Launcher.Test
|
||||||
{
|
{
|
||||||
|
|
@ -35,7 +36,7 @@ namespace Flow.Launcher.Test
|
||||||
[TestCase(@"c:\barr", @"c:\foo\..\bar\baz", false)]
|
[TestCase(@"c:\barr", @"c:\foo\..\bar\baz", false)]
|
||||||
public void GivenTwoPaths_WhenCheckPathContains_ThenShouldBeExpectedResult(string parentPath, string path, bool expectedResult)
|
public void GivenTwoPaths_WhenCheckPathContains_ThenShouldBeExpectedResult(string parentPath, string path, bool expectedResult)
|
||||||
{
|
{
|
||||||
Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path));
|
ClassicAssert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equality
|
// Equality
|
||||||
|
|
@ -47,7 +48,7 @@ namespace Flow.Launcher.Test
|
||||||
[TestCase(@"c:\foo", @"c:\foo\", true)]
|
[TestCase(@"c:\foo", @"c:\foo\", true)]
|
||||||
public void GivenTwoPathsAreTheSame_WhenCheckPathContains_ThenShouldBeExpectedResult(string parentPath, string path, bool expectedResult)
|
public void GivenTwoPathsAreTheSame_WhenCheckPathContains_ThenShouldBeExpectedResult(string parentPath, string path, bool expectedResult)
|
||||||
{
|
{
|
||||||
Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path, allowEqual: expectedResult));
|
ClassicAssert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path, allowEqual: expectedResult));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Moq" Version="4.18.4" />
|
<PackageReference Include="Moq" Version="4.18.4" />
|
||||||
<PackageReference Include="nunit" Version="3.14.0" />
|
<PackageReference Include="nunit" Version="4.3.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0">
|
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Legacy;
|
||||||
using Flow.Launcher.Infrastructure;
|
using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
|
|
@ -36,7 +37,7 @@ namespace Flow.Launcher.Test
|
||||||
OneOneOneOne
|
OneOneOneOne
|
||||||
};
|
};
|
||||||
|
|
||||||
public List<int> GetPrecisionScores()
|
public static List<int> GetPrecisionScores()
|
||||||
{
|
{
|
||||||
var listToReturn = new List<int>();
|
var listToReturn = new List<int>();
|
||||||
|
|
||||||
|
|
@ -73,10 +74,10 @@ namespace Flow.Launcher.Test
|
||||||
|
|
||||||
results = results.Where(x => x.Score > 0).OrderByDescending(x => x.Score).ToList();
|
results = results.Where(x => x.Score > 0).OrderByDescending(x => x.Score).ToList();
|
||||||
|
|
||||||
Assert.IsTrue(results.Count == 3);
|
ClassicAssert.IsTrue(results.Count == 3);
|
||||||
Assert.IsTrue(results[0].Title == "Inste");
|
ClassicAssert.IsTrue(results[0].Title == "Inste");
|
||||||
Assert.IsTrue(results[1].Title == "Install Package");
|
ClassicAssert.IsTrue(results[1].Title == "Install Package");
|
||||||
Assert.IsTrue(results[2].Title == "file open in browser-test");
|
ClassicAssert.IsTrue(results[2].Title == "file open in browser-test");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("Chrome")]
|
[TestCase("Chrome")]
|
||||||
|
|
@ -86,7 +87,7 @@ namespace Flow.Launcher.Test
|
||||||
var matcher = new StringMatcher(alphabet);
|
var matcher = new StringMatcher(alphabet);
|
||||||
var scoreResult = matcher.FuzzyMatch(searchString, compareString).RawScore;
|
var scoreResult = matcher.FuzzyMatch(searchString, compareString).RawScore;
|
||||||
|
|
||||||
Assert.True(scoreResult == 0);
|
ClassicAssert.True(scoreResult == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("chr")]
|
[TestCase("chr")]
|
||||||
|
|
@ -127,7 +128,7 @@ namespace Flow.Launcher.Test
|
||||||
Debug.WriteLine("###############################################");
|
Debug.WriteLine("###############################################");
|
||||||
Debug.WriteLine("");
|
Debug.WriteLine("");
|
||||||
|
|
||||||
Assert.IsFalse(filteredResult.Any(x => x.Score < precisionScore));
|
ClassicAssert.IsFalse(filteredResult.Any(x => x.Score < precisionScore));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,7 +154,7 @@ namespace Flow.Launcher.Test
|
||||||
var rawScore = matcher.FuzzyMatch(queryString, compareString).RawScore;
|
var rawScore = matcher.FuzzyMatch(queryString, compareString).RawScore;
|
||||||
|
|
||||||
// Should
|
// Should
|
||||||
Assert.AreEqual(expectedScore, rawScore,
|
ClassicAssert.AreEqual(expectedScore, rawScore,
|
||||||
$"Expected score for compare string '{compareString}': {expectedScore}, Actual: {rawScore}");
|
$"Expected score for compare string '{compareString}': {expectedScore}, Actual: {rawScore}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,12 +193,12 @@ namespace Flow.Launcher.Test
|
||||||
Debug.WriteLine("###############################################");
|
Debug.WriteLine("###############################################");
|
||||||
Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}");
|
Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}");
|
||||||
Debug.WriteLine(
|
Debug.WriteLine(
|
||||||
$"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionScore} ({(int) expectedPrecisionScore})");
|
$"RAW SCORE: {matchResult.RawScore}, PrecisionLevelSetAt: {expectedPrecisionScore} ({(int) expectedPrecisionScore})");
|
||||||
Debug.WriteLine("###############################################");
|
Debug.WriteLine("###############################################");
|
||||||
Debug.WriteLine("");
|
Debug.WriteLine("");
|
||||||
|
|
||||||
// Should
|
// Should
|
||||||
Assert.AreEqual(expectedPrecisionResult, matchResult.IsSearchPrecisionScoreMet(),
|
ClassicAssert.AreEqual(expectedPrecisionResult, matchResult.IsSearchPrecisionScoreMet(),
|
||||||
$"Query: {queryString}{Environment.NewLine} " +
|
$"Query: {queryString}{Environment.NewLine} " +
|
||||||
$"Compare: {compareString}{Environment.NewLine}" +
|
$"Compare: {compareString}{Environment.NewLine}" +
|
||||||
$"Raw Score: {matchResult.RawScore}{Environment.NewLine}" +
|
$"Raw Score: {matchResult.RawScore}{Environment.NewLine}" +
|
||||||
|
|
@ -243,12 +244,12 @@ namespace Flow.Launcher.Test
|
||||||
Debug.WriteLine("###############################################");
|
Debug.WriteLine("###############################################");
|
||||||
Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}");
|
Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}");
|
||||||
Debug.WriteLine(
|
Debug.WriteLine(
|
||||||
$"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionScore} ({(int) expectedPrecisionScore})");
|
$"RAW SCORE: {matchResult.RawScore}, PrecisionLevelSetAt: {expectedPrecisionScore} ({(int) expectedPrecisionScore})");
|
||||||
Debug.WriteLine("###############################################");
|
Debug.WriteLine("###############################################");
|
||||||
Debug.WriteLine("");
|
Debug.WriteLine("");
|
||||||
|
|
||||||
// Should
|
// Should
|
||||||
Assert.AreEqual(expectedPrecisionResult, matchResult.IsSearchPrecisionScoreMet(),
|
ClassicAssert.AreEqual(expectedPrecisionResult, matchResult.IsSearchPrecisionScoreMet(),
|
||||||
$"Query:{queryString}{Environment.NewLine} " +
|
$"Query:{queryString}{Environment.NewLine} " +
|
||||||
$"Compare:{compareString}{Environment.NewLine}" +
|
$"Compare:{compareString}{Environment.NewLine}" +
|
||||||
$"Raw Score: {matchResult.RawScore}{Environment.NewLine}" +
|
$"Raw Score: {matchResult.RawScore}{Environment.NewLine}" +
|
||||||
|
|
@ -279,7 +280,7 @@ namespace Flow.Launcher.Test
|
||||||
Debug.WriteLine("");
|
Debug.WriteLine("");
|
||||||
|
|
||||||
// Should
|
// Should
|
||||||
Assert.True(compareString1Result.Score > compareString2Result.Score,
|
ClassicAssert.True(compareString1Result.Score > compareString2Result.Score,
|
||||||
$"Query: \"{queryString}\"{Environment.NewLine} " +
|
$"Query: \"{queryString}\"{Environment.NewLine} " +
|
||||||
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
|
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
|
||||||
$"Should be greater than{Environment.NewLine}" +
|
$"Should be greater than{Environment.NewLine}" +
|
||||||
|
|
@ -312,7 +313,7 @@ namespace Flow.Launcher.Test
|
||||||
Debug.WriteLine("");
|
Debug.WriteLine("");
|
||||||
|
|
||||||
// Should
|
// Should
|
||||||
Assert.True(compareString1Result.Score > compareString2Result.Score,
|
ClassicAssert.True(compareString1Result.Score > compareString2Result.Score,
|
||||||
$"Query: \"{queryString}\"{Environment.NewLine} " +
|
$"Query: \"{queryString}\"{Environment.NewLine} " +
|
||||||
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
|
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
|
||||||
$"Should be greater than{Environment.NewLine}" +
|
$"Should be greater than{Environment.NewLine}" +
|
||||||
|
|
@ -338,7 +339,7 @@ namespace Flow.Launcher.Test
|
||||||
var secondScore = new[] {secondNameMatch, secondDescriptionMatch, secondExecutableNameMatch}.Max();
|
var secondScore = new[] {secondNameMatch, secondDescriptionMatch, secondExecutableNameMatch}.Max();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsTrue(firstScore > secondScore,
|
ClassicAssert.IsTrue(firstScore > secondScore,
|
||||||
$"Query: \"{queryString}\"{Environment.NewLine} " +
|
$"Query: \"{queryString}\"{Environment.NewLine} " +
|
||||||
$"Name of first: \"{firstName}\", Final Score: {firstScore}{Environment.NewLine}" +
|
$"Name of first: \"{firstName}\", Final Score: {firstScore}{Environment.NewLine}" +
|
||||||
$"Should be greater than{Environment.NewLine}" +
|
$"Should be greater than{Environment.NewLine}" +
|
||||||
|
|
@ -362,7 +363,7 @@ namespace Flow.Launcher.Test
|
||||||
{
|
{
|
||||||
var matcher = new StringMatcher(alphabet);
|
var matcher = new StringMatcher(alphabet);
|
||||||
var score = matcher.FuzzyMatch(queryString, compareString).Score;
|
var score = matcher.FuzzyMatch(queryString, compareString).Score;
|
||||||
Assert.IsTrue(score == desiredScore,
|
ClassicAssert.IsTrue(score == desiredScore,
|
||||||
$@"Query: ""{queryString}""
|
$@"Query: ""{queryString}""
|
||||||
CompareString: ""{compareString}""
|
CompareString: ""{compareString}""
|
||||||
Score: {score}
|
Score: {score}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Legacy;
|
||||||
using System;
|
using System;
|
||||||
using Flow.Launcher.Infrastructure.UserSettings;
|
using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
using Flow.Launcher.Infrastructure.Http;
|
using Flow.Launcher.Infrastructure.Http;
|
||||||
|
|
@ -16,16 +17,16 @@ namespace Flow.Launcher.Test
|
||||||
|
|
||||||
proxy.Enabled = true;
|
proxy.Enabled = true;
|
||||||
proxy.Server = "127.0.0.1";
|
proxy.Server = "127.0.0.1";
|
||||||
Assert.AreEqual(Http.WebProxy.Address, new Uri($"http://{proxy.Server}:{proxy.Port}"));
|
ClassicAssert.AreEqual(Http.WebProxy.Address, new Uri($"http://{proxy.Server}:{proxy.Port}"));
|
||||||
Assert.IsNull(Http.WebProxy.Credentials);
|
ClassicAssert.IsNull(Http.WebProxy.Credentials);
|
||||||
|
|
||||||
proxy.UserName = "test";
|
proxy.UserName = "test";
|
||||||
Assert.NotNull(Http.WebProxy.Credentials);
|
ClassicAssert.NotNull(Http.WebProxy.Credentials);
|
||||||
Assert.AreEqual(Http.WebProxy.Credentials.GetCredential(Http.WebProxy.Address, "Basic").UserName, proxy.UserName);
|
ClassicAssert.AreEqual(Http.WebProxy.Credentials.GetCredential(Http.WebProxy.Address, "Basic").UserName, proxy.UserName);
|
||||||
Assert.AreEqual(Http.WebProxy.Credentials.GetCredential(Http.WebProxy.Address, "Basic").Password, "");
|
ClassicAssert.AreEqual(Http.WebProxy.Credentials.GetCredential(Http.WebProxy.Address, "Basic").Password, "");
|
||||||
|
|
||||||
proxy.Password = "test password";
|
proxy.Password = "test password";
|
||||||
Assert.AreEqual(Http.WebProxy.Credentials.GetCredential(Http.WebProxy.Address, "Basic").Password, proxy.Password);
|
ClassicAssert.AreEqual(Http.WebProxy.Credentials.GetCredential(Http.WebProxy.Address, "Basic").Password, proxy.Password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Legacy;
|
||||||
using Flow.Launcher.Core.Plugin;
|
using Flow.Launcher.Core.Plugin;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
@ -15,37 +16,37 @@ namespace Flow.Launcher.Test
|
||||||
// Given
|
// Given
|
||||||
var duplicateList = new List<PluginMetadata>
|
var duplicateList = new List<PluginMetadata>
|
||||||
{
|
{
|
||||||
new PluginMetadata
|
new()
|
||||||
{
|
{
|
||||||
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
|
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
|
||||||
Version = "1.0.0"
|
Version = "1.0.0"
|
||||||
},
|
},
|
||||||
new PluginMetadata
|
new()
|
||||||
{
|
{
|
||||||
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
|
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
|
||||||
Version = "1.0.1"
|
Version = "1.0.1"
|
||||||
},
|
},
|
||||||
new PluginMetadata
|
new()
|
||||||
{
|
{
|
||||||
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
|
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
|
||||||
Version = "1.0.2"
|
Version = "1.0.2"
|
||||||
},
|
},
|
||||||
new PluginMetadata
|
new()
|
||||||
{
|
{
|
||||||
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
|
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
|
||||||
Version = "1.0.0"
|
Version = "1.0.0"
|
||||||
},
|
},
|
||||||
new PluginMetadata
|
new()
|
||||||
{
|
{
|
||||||
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
|
ID = "CEA0TYUC6D3B4085823D60DC76F28855",
|
||||||
Version = "1.0.0"
|
Version = "1.0.0"
|
||||||
},
|
},
|
||||||
new PluginMetadata
|
new()
|
||||||
{
|
{
|
||||||
ID = "ABC0TYUC6D3B7855823D60DC76F28855",
|
ID = "ABC0TYUC6D3B7855823D60DC76F28855",
|
||||||
Version = "1.0.0"
|
Version = "1.0.0"
|
||||||
},
|
},
|
||||||
new PluginMetadata
|
new()
|
||||||
{
|
{
|
||||||
ID = "ABC0TYUC6D3B7855823D60DC76F28855",
|
ID = "ABC0TYUC6D3B7855823D60DC76F28855",
|
||||||
Version = "1.0.0"
|
Version = "1.0.0"
|
||||||
|
|
@ -56,11 +57,11 @@ namespace Flow.Launcher.Test
|
||||||
(var unique, var duplicates) = PluginConfig.GetUniqueLatestPluginMetadata(duplicateList);
|
(var unique, var duplicates) = PluginConfig.GetUniqueLatestPluginMetadata(duplicateList);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.True(unique.FirstOrDefault().ID == "CEA0TYUC6D3B4085823D60DC76F28855" && unique.FirstOrDefault().Version == "1.0.2");
|
ClassicAssert.True(unique.FirstOrDefault().ID == "CEA0TYUC6D3B4085823D60DC76F28855" && unique.FirstOrDefault().Version == "1.0.2");
|
||||||
Assert.True(unique.Count() == 1);
|
ClassicAssert.True(unique.Count == 1);
|
||||||
|
|
||||||
Assert.False(duplicates.Any(x => x.Version == "1.0.2" && x.ID == "CEA0TYUC6D3B4085823D60DC76F28855"));
|
ClassicAssert.False(duplicates.Any(x => x.Version == "1.0.2" && x.ID == "CEA0TYUC6D3B4085823D60DC76F28855"));
|
||||||
Assert.True(duplicates.Count() == 6);
|
ClassicAssert.True(duplicates.Count == 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
@ -69,12 +70,12 @@ namespace Flow.Launcher.Test
|
||||||
// Given
|
// Given
|
||||||
var duplicateList = new List<PluginMetadata>
|
var duplicateList = new List<PluginMetadata>
|
||||||
{
|
{
|
||||||
new PluginMetadata
|
new()
|
||||||
{
|
{
|
||||||
ID = "CEA0TYUC6D3B7855823D60DC76F28855",
|
ID = "CEA0TYUC6D3B7855823D60DC76F28855",
|
||||||
Version = "1.0.0"
|
Version = "1.0.0"
|
||||||
},
|
},
|
||||||
new PluginMetadata
|
new()
|
||||||
{
|
{
|
||||||
ID = "CEA0TYUC6D3B7855823D60DC76F28855",
|
ID = "CEA0TYUC6D3B7855823D60DC76F28855",
|
||||||
Version = "1.0.0"
|
Version = "1.0.0"
|
||||||
|
|
@ -85,8 +86,8 @@ namespace Flow.Launcher.Test
|
||||||
(var unique, var duplicates) = PluginConfig.GetUniqueLatestPluginMetadata(duplicateList);
|
(var unique, var duplicates) = PluginConfig.GetUniqueLatestPluginMetadata(duplicateList);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.True(unique.Count() == 0);
|
ClassicAssert.True(unique.Count == 0);
|
||||||
Assert.True(duplicates.Count() == 2);
|
ClassicAssert.True(duplicates.Count == 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,10 @@ using Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo;
|
||||||
using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
|
using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
|
||||||
using Flow.Launcher.Plugin.SharedCommands;
|
using Flow.Launcher.Plugin.SharedCommands;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Legacy;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using static Flow.Launcher.Plugin.Explorer.Search.SearchManager;
|
using static Flow.Launcher.Plugin.Explorer.Search.SearchManager;
|
||||||
|
|
||||||
namespace Flow.Launcher.Test.Plugins
|
namespace Flow.Launcher.Test.Plugins
|
||||||
|
|
@ -22,28 +20,6 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ExplorerTest
|
public class ExplorerTest
|
||||||
{
|
{
|
||||||
#pragma warning disable CS1998 // async method with no await (more readable to leave it async to match the tested signature)
|
|
||||||
private async Task<List<Result>> MethodWindowsIndexSearchReturnsZeroResultsAsync(Query dummyQuery, string dummyString, CancellationToken dummyToken)
|
|
||||||
{
|
|
||||||
return new List<Result>();
|
|
||||||
}
|
|
||||||
#pragma warning restore CS1998
|
|
||||||
|
|
||||||
private List<Result> MethodDirectoryInfoClassSearchReturnsTwoResults(Query dummyQuery, string dummyString, CancellationToken token)
|
|
||||||
{
|
|
||||||
return new List<Result>
|
|
||||||
{
|
|
||||||
new Result
|
|
||||||
{
|
|
||||||
Title = "Result 1"
|
|
||||||
},
|
|
||||||
new Result
|
|
||||||
{
|
|
||||||
Title = "Result 2"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool PreviousLocationExistsReturnsTrue(string dummyString) => true;
|
private bool PreviousLocationExistsReturnsTrue(string dummyString) => true;
|
||||||
|
|
||||||
private bool PreviousLocationNotExistReturnsFalse(string dummyString) => false;
|
private bool PreviousLocationNotExistReturnsFalse(string dummyString) => false;
|
||||||
|
|
@ -57,7 +33,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var result = QueryConstructor.TopLevelDirectoryConstraint(folderPath);
|
var result = QueryConstructor.TopLevelDirectoryConstraint(folderPath);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.IsTrue(result == expectedString,
|
ClassicAssert.IsTrue(result == expectedString,
|
||||||
$"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
|
$"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
|
||||||
$"Actual: {result}{Environment.NewLine}");
|
$"Actual: {result}{Environment.NewLine}");
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +50,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var queryString = queryConstructor.Directory(folderPath);
|
var queryString = queryConstructor.Directory(folderPath);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.IsTrue(queryString.Replace(" ", " ") == expectedString.Replace(" ", " "),
|
ClassicAssert.IsTrue(queryString.Replace(" ", " ") == expectedString.Replace(" ", " "),
|
||||||
$"Expected string: {expectedString}{Environment.NewLine} " +
|
$"Expected string: {expectedString}{Environment.NewLine} " +
|
||||||
$"Actual string was: {queryString}{Environment.NewLine}");
|
$"Actual string was: {queryString}{Environment.NewLine}");
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +70,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var queryString = queryConstructor.Directory(folderPath, userSearchString);
|
var queryString = queryConstructor.Directory(folderPath, userSearchString);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.AreEqual(expectedString, queryString);
|
ClassicAssert.AreEqual(expectedString, queryString);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows7.0")]
|
[SupportedOSPlatform("windows7.0")]
|
||||||
|
|
@ -105,7 +81,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
const string resultString = QueryConstructor.RestrictionsForAllFilesAndFoldersSearch;
|
const string resultString = QueryConstructor.RestrictionsForAllFilesAndFoldersSearch;
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.AreEqual(expectedString, resultString);
|
ClassicAssert.AreEqual(expectedString, resultString);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows7.0")]
|
[SupportedOSPlatform("windows7.0")]
|
||||||
|
|
@ -128,7 +104,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var resultString = queryConstructor.FilesAndFolders(userSearchString);
|
var resultString = queryConstructor.FilesAndFolders(userSearchString);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.AreEqual(expectedString, resultString);
|
ClassicAssert.AreEqual(expectedString, resultString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -138,13 +114,13 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
string querySearchString, string expectedString)
|
string querySearchString, string expectedString)
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var queryConstructor = new QueryConstructor(new Settings());
|
_ = new QueryConstructor(new Settings());
|
||||||
|
|
||||||
//When
|
//When
|
||||||
var resultString = QueryConstructor.RestrictionsForFileContentSearch(querySearchString);
|
var resultString = QueryConstructor.RestrictionsForFileContentSearch(querySearchString);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.IsTrue(resultString == expectedString,
|
ClassicAssert.IsTrue(resultString == expectedString,
|
||||||
$"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
|
$"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
|
||||||
$"Actual string was: {resultString}{Environment.NewLine}");
|
$"Actual string was: {resultString}{Environment.NewLine}");
|
||||||
}
|
}
|
||||||
|
|
@ -162,12 +138,12 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var resultString = queryConstructor.FileContent(userSearchString);
|
var resultString = queryConstructor.FileContent(userSearchString);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.IsTrue(resultString == expectedString,
|
ClassicAssert.IsTrue(resultString == expectedString,
|
||||||
$"Expected query string: {expectedString}{Environment.NewLine} " +
|
$"Expected query string: {expectedString}{Environment.NewLine} " +
|
||||||
$"Actual string was: {resultString}{Environment.NewLine}");
|
$"Actual string was: {resultString}{Environment.NewLine}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GivenQuery_WhenActionKeywordForFileContentSearchExists_ThenFileContentSearchRequiredShouldReturnTrue()
|
public static void GivenQuery_WhenActionKeywordForFileContentSearchExists_ThenFileContentSearchRequiredShouldReturnTrue()
|
||||||
{
|
{
|
||||||
// Given
|
// Given
|
||||||
var query = new Query
|
var query = new Query
|
||||||
|
|
@ -181,7 +157,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var result = searchManager.IsFileContentSearch(query.ActionKeyword);
|
var result = searchManager.IsFileContentSearch(query.ActionKeyword);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.IsTrue(result,
|
ClassicAssert.IsTrue(result,
|
||||||
$"Expected True for file content search. {Environment.NewLine} " +
|
$"Expected True for file content search. {Environment.NewLine} " +
|
||||||
$"Actual result was: {result}{Environment.NewLine}");
|
$"Actual result was: {result}{Environment.NewLine}");
|
||||||
}
|
}
|
||||||
|
|
@ -206,7 +182,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var result = FilesFolders.IsLocationPathString(querySearchString);
|
var result = FilesFolders.IsLocationPathString(querySearchString);
|
||||||
|
|
||||||
//Then
|
//Then
|
||||||
Assert.IsTrue(result == expectedResult,
|
ClassicAssert.IsTrue(result == expectedResult,
|
||||||
$"Expected query search string check result is: {expectedResult} {Environment.NewLine} " +
|
$"Expected query search string check result is: {expectedResult} {Environment.NewLine} " +
|
||||||
$"Actual check result is {result} {Environment.NewLine}");
|
$"Actual check result is {result} {Environment.NewLine}");
|
||||||
|
|
||||||
|
|
@ -233,7 +209,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var previousDirectoryPath = FilesFolders.GetPreviousExistingDirectory(previousLocationExists, path);
|
var previousDirectoryPath = FilesFolders.GetPreviousExistingDirectory(previousLocationExists, path);
|
||||||
|
|
||||||
//Then
|
//Then
|
||||||
Assert.IsTrue(previousDirectoryPath == expectedString,
|
ClassicAssert.IsTrue(previousDirectoryPath == expectedString,
|
||||||
$"Expected path string: {expectedString} {Environment.NewLine} " +
|
$"Expected path string: {expectedString} {Environment.NewLine} " +
|
||||||
$"Actual path string is {previousDirectoryPath} {Environment.NewLine}");
|
$"Actual path string is {previousDirectoryPath} {Environment.NewLine}");
|
||||||
}
|
}
|
||||||
|
|
@ -246,7 +222,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var returnedPath = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(path);
|
var returnedPath = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(path);
|
||||||
|
|
||||||
//Then
|
//Then
|
||||||
Assert.IsTrue(returnedPath == expectedString,
|
ClassicAssert.IsTrue(returnedPath == expectedString,
|
||||||
$"Expected path string: {expectedString} {Environment.NewLine} " +
|
$"Expected path string: {expectedString} {Environment.NewLine} " +
|
||||||
$"Actual path string is {returnedPath} {Environment.NewLine}");
|
$"Actual path string is {returnedPath} {Environment.NewLine}");
|
||||||
}
|
}
|
||||||
|
|
@ -260,7 +236,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var resultString = QueryConstructor.RecursiveDirectoryConstraint(path);
|
var resultString = QueryConstructor.RecursiveDirectoryConstraint(path);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.AreEqual(expectedString, resultString);
|
ClassicAssert.AreEqual(expectedString, resultString);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows7.0")]
|
[SupportedOSPlatform("windows7.0")]
|
||||||
|
|
@ -274,7 +250,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var resultString = DirectoryInfoSearch.ConstructSearchCriteria(path);
|
var resultString = DirectoryInfoSearch.ConstructSearchCriteria(path);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.AreEqual(expectedString, resultString);
|
ClassicAssert.AreEqual(expectedString, resultString);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("c:\\somefolder\\someotherfolder", ResultType.Folder, "irrelevant", false, true, "c:\\somefolder\\someotherfolder\\")]
|
[TestCase("c:\\somefolder\\someotherfolder", ResultType.Folder, "irrelevant", false, true, "c:\\somefolder\\someotherfolder\\")]
|
||||||
|
|
@ -305,7 +281,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var result = ResultManager.GetPathWithActionKeyword(path, type, actionKeyword);
|
var result = ResultManager.GetPathWithActionKeyword(path, type, actionKeyword);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.AreEqual(result, expectedResult);
|
ClassicAssert.AreEqual(result, expectedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("c:\\somefolder\\somefile", ResultType.File, "irrelevant", false, true, "e c:\\somefolder\\somefile")]
|
[TestCase("c:\\somefolder\\somefile", ResultType.File, "irrelevant", false, true, "e c:\\somefolder\\somefile")]
|
||||||
|
|
@ -334,7 +310,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var result = ResultManager.GetPathWithActionKeyword(path, type, actionKeyword);
|
var result = ResultManager.GetPathWithActionKeyword(path, type, actionKeyword);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.AreEqual(result, expectedResult);
|
ClassicAssert.AreEqual(result, expectedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("somefolder", "c:\\somefolder\\", ResultType.Folder, "q", false, false, "q somefolder")]
|
[TestCase("somefolder", "c:\\somefolder\\", ResultType.Folder, "q", false, false, "q somefolder")]
|
||||||
|
|
@ -366,7 +342,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var result = ResultManager.GetAutoCompleteText(title, query, path, resultType);
|
var result = ResultManager.GetAutoCompleteText(title, query, path, resultType);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.AreEqual(result, expectedResult);
|
ClassicAssert.AreEqual(result, expectedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("somefile", "c:\\somefolder\\somefile", ResultType.File, "q", false, false, "q somefile")]
|
[TestCase("somefile", "c:\\somefolder\\somefile", ResultType.File, "q", false, false, "q somefile")]
|
||||||
|
|
@ -398,7 +374,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var result = ResultManager.GetAutoCompleteText(title, query, path, resultType);
|
var result = ResultManager.GetAutoCompleteText(title, query, path, resultType);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.AreEqual(result, expectedResult);
|
ClassicAssert.AreEqual(result, expectedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(@"c:\foo", @"c:\foo", true)]
|
[TestCase(@"c:\foo", @"c:\foo", true)]
|
||||||
|
|
@ -420,7 +396,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
};
|
};
|
||||||
|
|
||||||
// When, Then
|
// When, Then
|
||||||
Assert.AreEqual(expectedResult, comparator.Equals(result1, result2));
|
ClassicAssert.AreEqual(expectedResult, comparator.Equals(result1, result2));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(@"c:\foo\", @"c:\foo\")]
|
[TestCase(@"c:\foo\", @"c:\foo\")]
|
||||||
|
|
@ -444,7 +420,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var hash2 = comparator.GetHashCode(result2);
|
var hash2 = comparator.GetHashCode(result2);
|
||||||
|
|
||||||
// When, Then
|
// When, Then
|
||||||
Assert.IsTrue(hash1 == hash2);
|
ClassicAssert.IsTrue(hash1 == hash2);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(@"%appdata%", true)]
|
[TestCase(@"%appdata%", true)]
|
||||||
|
|
@ -461,7 +437,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var result = EnvironmentVariables.HasEnvironmentVar(path);
|
var result = EnvironmentVariables.HasEnvironmentVar(path);
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
Assert.AreEqual(result, expectedResult);
|
ClassicAssert.AreEqual(result, expectedResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Legacy;
|
||||||
using Flow.Launcher.Core.Plugin;
|
using Flow.Launcher.Core.Plugin;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Flow.Launcher.Test.Plugins
|
namespace Flow.Launcher.Test.Plugins
|
||||||
|
|
@ -40,13 +39,13 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
Search = resultText
|
Search = resultText
|
||||||
}, default);
|
}, default);
|
||||||
|
|
||||||
Assert.IsNotNull(results);
|
ClassicAssert.IsNotNull(results);
|
||||||
|
|
||||||
foreach (var result in results)
|
foreach (var result in results)
|
||||||
{
|
{
|
||||||
Assert.IsNotNull(result);
|
ClassicAssert.IsNotNull(result);
|
||||||
Assert.IsNotNull(result.AsyncAction);
|
ClassicAssert.IsNotNull(result.AsyncAction);
|
||||||
Assert.IsNotNull(result.Title);
|
ClassicAssert.IsNotNull(result.Title);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -56,12 +55,11 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
new JsonRPCQueryResponseModel(0, new List<JsonRPCResult>()),
|
new JsonRPCQueryResponseModel(0, new List<JsonRPCResult>()),
|
||||||
new JsonRPCQueryResponseModel(0, new List<JsonRPCResult>
|
new JsonRPCQueryResponseModel(0, new List<JsonRPCResult>
|
||||||
{
|
{
|
||||||
new JsonRPCResult
|
new()
|
||||||
{
|
{
|
||||||
Title = "Test1", SubTitle = "Test2"
|
Title = "Test1", SubTitle = "Test2"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Legacy;
|
||||||
using Flow.Launcher.Plugin.Url;
|
using Flow.Launcher.Plugin.Url;
|
||||||
|
|
||||||
namespace Flow.Launcher.Test
|
namespace Flow.Launcher.Test.Plugins
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class UrlPluginTest
|
public class UrlPluginTest
|
||||||
|
|
@ -10,23 +11,23 @@ namespace Flow.Launcher.Test
|
||||||
public void URLMatchTest()
|
public void URLMatchTest()
|
||||||
{
|
{
|
||||||
var plugin = new Main();
|
var plugin = new Main();
|
||||||
Assert.IsTrue(plugin.IsURL("http://www.google.com"));
|
ClassicAssert.IsTrue(plugin.IsURL("http://www.google.com"));
|
||||||
Assert.IsTrue(plugin.IsURL("https://www.google.com"));
|
ClassicAssert.IsTrue(plugin.IsURL("https://www.google.com"));
|
||||||
Assert.IsTrue(plugin.IsURL("http://google.com"));
|
ClassicAssert.IsTrue(plugin.IsURL("http://google.com"));
|
||||||
Assert.IsTrue(plugin.IsURL("www.google.com"));
|
ClassicAssert.IsTrue(plugin.IsURL("www.google.com"));
|
||||||
Assert.IsTrue(plugin.IsURL("google.com"));
|
ClassicAssert.IsTrue(plugin.IsURL("google.com"));
|
||||||
Assert.IsTrue(plugin.IsURL("http://localhost"));
|
ClassicAssert.IsTrue(plugin.IsURL("http://localhost"));
|
||||||
Assert.IsTrue(plugin.IsURL("https://localhost"));
|
ClassicAssert.IsTrue(plugin.IsURL("https://localhost"));
|
||||||
Assert.IsTrue(plugin.IsURL("http://localhost:80"));
|
ClassicAssert.IsTrue(plugin.IsURL("http://localhost:80"));
|
||||||
Assert.IsTrue(plugin.IsURL("https://localhost:80"));
|
ClassicAssert.IsTrue(plugin.IsURL("https://localhost:80"));
|
||||||
Assert.IsTrue(plugin.IsURL("http://110.10.10.10"));
|
ClassicAssert.IsTrue(plugin.IsURL("http://110.10.10.10"));
|
||||||
Assert.IsTrue(plugin.IsURL("110.10.10.10"));
|
ClassicAssert.IsTrue(plugin.IsURL("110.10.10.10"));
|
||||||
Assert.IsTrue(plugin.IsURL("ftp://110.10.10.10"));
|
ClassicAssert.IsTrue(plugin.IsURL("ftp://110.10.10.10"));
|
||||||
|
|
||||||
|
|
||||||
Assert.IsFalse(plugin.IsURL("wwww"));
|
ClassicAssert.IsFalse(plugin.IsURL("wwww"));
|
||||||
Assert.IsFalse(plugin.IsURL("wwww.c"));
|
ClassicAssert.IsFalse(plugin.IsURL("wwww.c"));
|
||||||
Assert.IsFalse(plugin.IsURL("wwww.c"));
|
ClassicAssert.IsFalse(plugin.IsURL("wwww.c"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Legacy;
|
||||||
using Flow.Launcher.Core.Plugin;
|
using Flow.Launcher.Core.Plugin;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
|
|
||||||
|
|
@ -17,17 +18,17 @@ namespace Flow.Launcher.Test
|
||||||
|
|
||||||
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", nonGlobalPlugins);
|
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", nonGlobalPlugins);
|
||||||
|
|
||||||
Assert.AreEqual("> ping google.com -n 20 -6", q.RawQuery);
|
ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.RawQuery);
|
||||||
Assert.AreEqual("ping google.com -n 20 -6", q.Search, "Search should not start with the ActionKeyword.");
|
ClassicAssert.AreEqual("ping google.com -n 20 -6", q.Search, "Search should not start with the ActionKeyword.");
|
||||||
Assert.AreEqual(">", q.ActionKeyword);
|
ClassicAssert.AreEqual(">", q.ActionKeyword);
|
||||||
|
|
||||||
Assert.AreEqual(5, q.SearchTerms.Length, "The length of SearchTerms should match.");
|
ClassicAssert.AreEqual(5, q.SearchTerms.Length, "The length of SearchTerms should match.");
|
||||||
|
|
||||||
Assert.AreEqual("ping", q.FirstSearch);
|
ClassicAssert.AreEqual("ping", q.FirstSearch);
|
||||||
Assert.AreEqual("google.com", q.SecondSearch);
|
ClassicAssert.AreEqual("google.com", q.SecondSearch);
|
||||||
Assert.AreEqual("-n", q.ThirdSearch);
|
ClassicAssert.AreEqual("-n", q.ThirdSearch);
|
||||||
|
|
||||||
Assert.AreEqual("google.com -n 20 -6", q.SecondToEndSearch, "SecondToEndSearch should be trimmed of multiple whitespace characters");
|
ClassicAssert.AreEqual("google.com -n 20 -6", q.SecondToEndSearch, "SecondToEndSearch should be trimmed of multiple whitespace characters");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
@ -40,11 +41,11 @@ namespace Flow.Launcher.Test
|
||||||
|
|
||||||
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", nonGlobalPlugins);
|
Query q = QueryBuilder.Build("> ping google.com -n 20 -6", nonGlobalPlugins);
|
||||||
|
|
||||||
Assert.AreEqual("> ping google.com -n 20 -6", q.Search);
|
ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.Search);
|
||||||
Assert.AreEqual(q.Search, q.RawQuery, "RawQuery should be equal to Search.");
|
ClassicAssert.AreEqual(q.Search, q.RawQuery, "RawQuery should be equal to Search.");
|
||||||
Assert.AreEqual(6, q.SearchTerms.Length, "The length of SearchTerms should match.");
|
ClassicAssert.AreEqual(6, q.SearchTerms.Length, "The length of SearchTerms should match.");
|
||||||
Assert.AreNotEqual(">", q.ActionKeyword, "ActionKeyword should not match that of a disabled plugin.");
|
ClassicAssert.AreNotEqual(">", q.ActionKeyword, "ActionKeyword should not match that of a disabled plugin.");
|
||||||
Assert.AreEqual("ping google.com -n 20 -6", q.SecondToEndSearch, "SecondToEndSearch should be trimmed of multiple whitespace characters");
|
ClassicAssert.AreEqual("ping google.com -n 20 -6", q.SecondToEndSearch, "SecondToEndSearch should be trimmed of multiple whitespace characters");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
@ -52,13 +53,13 @@ namespace Flow.Launcher.Test
|
||||||
{
|
{
|
||||||
Query q = QueryBuilder.Build("file.txt file2 file3", new Dictionary<string, PluginPair>());
|
Query q = QueryBuilder.Build("file.txt file2 file3", new Dictionary<string, PluginPair>());
|
||||||
|
|
||||||
Assert.AreEqual("file.txt file2 file3", q.Search);
|
ClassicAssert.AreEqual("file.txt file2 file3", q.Search);
|
||||||
Assert.AreEqual("", q.ActionKeyword);
|
ClassicAssert.AreEqual("", q.ActionKeyword);
|
||||||
|
|
||||||
Assert.AreEqual("file.txt", q.FirstSearch);
|
ClassicAssert.AreEqual("file.txt", q.FirstSearch);
|
||||||
Assert.AreEqual("file2", q.SecondSearch);
|
ClassicAssert.AreEqual("file2", q.SecondSearch);
|
||||||
Assert.AreEqual("file3", q.ThirdSearch);
|
ClassicAssert.AreEqual("file3", q.ThirdSearch);
|
||||||
Assert.AreEqual("file2 file3", q.SecondToEndSearch);
|
ClassicAssert.AreEqual("file2 file3", q.SecondToEndSearch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
private bool update;
|
private bool update;
|
||||||
private CustomPluginHotkey updateCustomHotkey;
|
private CustomPluginHotkey updateCustomHotkey;
|
||||||
public Settings Settings { get; }
|
|
||||||
|
|
||||||
public CustomQueryHotkeySetting(Settings settings)
|
public CustomQueryHotkeySetting(Settings settings)
|
||||||
{
|
{
|
||||||
|
|
@ -30,13 +29,13 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
if (!update)
|
if (!update)
|
||||||
{
|
{
|
||||||
Settings.CustomPluginHotkeys ??= new ObservableCollection<CustomPluginHotkey>();
|
_settings.CustomPluginHotkeys ??= new ObservableCollection<CustomPluginHotkey>();
|
||||||
|
|
||||||
var pluginHotkey = new CustomPluginHotkey
|
var pluginHotkey = new CustomPluginHotkey
|
||||||
{
|
{
|
||||||
Hotkey = HotkeyControl.CurrentHotkey.ToString(), ActionKeyword = tbAction.Text
|
Hotkey = HotkeyControl.CurrentHotkey.ToString(), ActionKeyword = tbAction.Text
|
||||||
};
|
};
|
||||||
Settings.CustomPluginHotkeys.Add(pluginHotkey);
|
_settings.CustomPluginHotkeys.Add(pluginHotkey);
|
||||||
|
|
||||||
HotKeyMapper.SetCustomQueryHotkey(pluginHotkey);
|
HotKeyMapper.SetCustomQueryHotkey(pluginHotkey);
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +55,7 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
public void UpdateItem(CustomPluginHotkey item)
|
public void UpdateItem(CustomPluginHotkey item)
|
||||||
{
|
{
|
||||||
updateCustomHotkey = Settings.CustomPluginHotkeys.FirstOrDefault(o =>
|
updateCustomHotkey = _settings.CustomPluginHotkeys.FirstOrDefault(o =>
|
||||||
o.ActionKeyword == item.ActionKeyword && o.Hotkey == item.Hotkey);
|
o.ActionKeyword == item.ActionKeyword && o.Hotkey == item.Hotkey);
|
||||||
if (updateCustomHotkey == null)
|
if (updateCustomHotkey == null)
|
||||||
{
|
{
|
||||||
|
|
@ -74,8 +73,7 @@ namespace Flow.Launcher
|
||||||
private void BtnTestActionKeyword_OnClick(object sender, RoutedEventArgs e)
|
private void BtnTestActionKeyword_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
App.API.ChangeQuery(tbAction.Text);
|
App.API.ChangeQuery(tbAction.Text);
|
||||||
Application.Current.MainWindow.Show();
|
App.API.ShowMainWindow();
|
||||||
Application.Current.MainWindow.Opacity = 1;
|
|
||||||
Application.Current.MainWindow.Focus();
|
Application.Current.MainWindow.Focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,7 @@ namespace Flow.Launcher
|
||||||
private void BtnTestShortcut_OnClick(object sender, RoutedEventArgs e)
|
private void BtnTestShortcut_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
App.API.ChangeQuery(tbExpand.Text);
|
App.API.ChangeQuery(tbExpand.Text);
|
||||||
Application.Current.MainWindow.Show();
|
App.API.ShowMainWindow();
|
||||||
Application.Current.MainWindow.Opacity = 1;
|
|
||||||
Application.Current.MainWindow.Focus();
|
Application.Current.MainWindow.Focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ChefKeys" Version="0.1.2" />
|
||||||
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
<PackageReference Include="Fody" Version="6.5.4">
|
<PackageReference Include="Fody" Version="6.5.4">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@ using NHotkey.Wpf;
|
||||||
using Flow.Launcher.Core.Resource;
|
using Flow.Launcher.Core.Resource;
|
||||||
using Flow.Launcher.ViewModel;
|
using Flow.Launcher.ViewModel;
|
||||||
using Flow.Launcher.Core;
|
using Flow.Launcher.Core;
|
||||||
|
using ChefKeys;
|
||||||
|
using System.Globalization;
|
||||||
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper;
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
|
|
@ -29,21 +32,57 @@ internal static class HotKeyMapper
|
||||||
_mainViewModel.ToggleFlowLauncher();
|
_mainViewModel.ToggleFlowLauncher();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void OnToggleHotkeyWithChefKeys()
|
||||||
|
{
|
||||||
|
if (!_mainViewModel.ShouldIgnoreHotkeys())
|
||||||
|
_mainViewModel.ToggleFlowLauncher();
|
||||||
|
}
|
||||||
|
|
||||||
private static void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action)
|
private static void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action)
|
||||||
{
|
{
|
||||||
var hotkey = new HotkeyModel(hotkeyStr);
|
var hotkey = new HotkeyModel(hotkeyStr);
|
||||||
SetHotkey(hotkey, action);
|
SetHotkey(hotkey, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void SetWithChefKeys(string hotkeyStr)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ChefKeysManager.RegisterHotkey(hotkeyStr, hotkeyStr, OnToggleHotkeyWithChefKeys);
|
||||||
|
ChefKeysManager.Start();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(
|
||||||
|
string.Format("|HotkeyMapper.SetWithChefKeys|Error registering hotkey: {0} \nStackTrace:{1}",
|
||||||
|
e.Message,
|
||||||
|
e.StackTrace));
|
||||||
|
string errorMsg = string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"), hotkeyStr);
|
||||||
|
string errorMsgTitle = InternationalizationManager.Instance.GetTranslation("MessageBoxTitle");
|
||||||
|
MessageBoxEx.Show(errorMsg, errorMsgTitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static void SetHotkey(HotkeyModel hotkey, EventHandler<HotkeyEventArgs> action)
|
internal static void SetHotkey(HotkeyModel hotkey, EventHandler<HotkeyEventArgs> action)
|
||||||
{
|
{
|
||||||
string hotkeyStr = hotkey.ToString();
|
string hotkeyStr = hotkey.ToString();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (hotkeyStr == "LWin" || hotkeyStr == "RWin")
|
||||||
|
{
|
||||||
|
SetWithChefKeys(hotkeyStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
HotkeyManager.Current.AddOrReplace(hotkeyStr, hotkey.CharKey, hotkey.ModifierKeys, action);
|
HotkeyManager.Current.AddOrReplace(hotkeyStr, hotkey.CharKey, hotkey.ModifierKeys, action);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
Log.Error(
|
||||||
|
string.Format("|HotkeyMapper.SetHotkey|Error registering hotkey {2}: {0} \nStackTrace:{1}",
|
||||||
|
e.Message,
|
||||||
|
e.StackTrace,
|
||||||
|
hotkeyStr));
|
||||||
string errorMsg = string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"), hotkeyStr);
|
string errorMsg = string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"), hotkeyStr);
|
||||||
string errorMsgTitle = InternationalizationManager.Instance.GetTranslation("MessageBoxTitle");
|
string errorMsgTitle = InternationalizationManager.Instance.GetTranslation("MessageBoxTitle");
|
||||||
App.API.ShowMsgBox(errorMsg, errorMsgTitle);
|
App.API.ShowMsgBox(errorMsg, errorMsgTitle);
|
||||||
|
|
@ -52,10 +91,33 @@ internal static class HotKeyMapper
|
||||||
|
|
||||||
internal static void RemoveHotkey(string hotkeyStr)
|
internal static void RemoveHotkey(string hotkeyStr)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(hotkeyStr))
|
try
|
||||||
{
|
{
|
||||||
HotkeyManager.Current.Remove(hotkeyStr);
|
if (hotkeyStr == "LWin" || hotkeyStr == "RWin")
|
||||||
|
{
|
||||||
|
RemoveWithChefKeys(hotkeyStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(hotkeyStr))
|
||||||
|
HotkeyManager.Current.Remove(hotkeyStr);
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(
|
||||||
|
string.Format("|HotkeyMapper.RemoveHotkey|Error removing hotkey: {0} \nStackTrace:{1}",
|
||||||
|
e.Message,
|
||||||
|
e.StackTrace));
|
||||||
|
string errorMsg = string.Format(InternationalizationManager.Instance.GetTranslation("unregisterHotkeyFailed"), hotkeyStr);
|
||||||
|
string errorMsgTitle = InternationalizationManager.Instance.GetTranslation("MessageBoxTitle");
|
||||||
|
MessageBoxEx.Show(errorMsg, errorMsgTitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RemoveWithChefKeys(string hotkeyStr)
|
||||||
|
{
|
||||||
|
ChefKeysManager.UnregisterHotkey(hotkeyStr);
|
||||||
|
ChefKeysManager.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void LoadCustomPluginHotkey()
|
internal static void LoadCustomPluginHotkey()
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,16 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
if (triggerValidate)
|
if (triggerValidate)
|
||||||
{
|
{
|
||||||
bool hotkeyAvailable = CheckHotkeyAvailability(keyModel, ValidateKeyGesture);
|
bool hotkeyAvailable = false;
|
||||||
|
// TODO: This is a temporary way to enforce changing only the open flow hotkey to Win, and will be removed by PR #3157
|
||||||
|
if (keyModel.ToString() == "LWin" || keyModel.ToString() == "RWin")
|
||||||
|
{
|
||||||
|
hotkeyAvailable = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hotkeyAvailable = CheckHotkeyAvailability(keyModel, ValidateKeyGesture);
|
||||||
|
}
|
||||||
|
|
||||||
if (!hotkeyAvailable)
|
if (!hotkeyAvailable)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using ChefKeys;
|
||||||
using Flow.Launcher.Core.Resource;
|
using Flow.Launcher.Core.Resource;
|
||||||
using Flow.Launcher.Helper;
|
using Flow.Launcher.Helper;
|
||||||
using Flow.Launcher.Infrastructure.Hotkey;
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
|
|
@ -33,6 +34,8 @@ public partial class HotkeyControlDialog : ContentDialog
|
||||||
public string ResultValue { get; private set; } = string.Empty;
|
public string ResultValue { get; private set; } = string.Empty;
|
||||||
public static string EmptyHotkey => InternationalizationManager.Instance.GetTranslation("none");
|
public static string EmptyHotkey => InternationalizationManager.Instance.GetTranslation("none");
|
||||||
|
|
||||||
|
private static bool isOpenFlowHotkey;
|
||||||
|
|
||||||
public HotkeyControlDialog(string hotkey, string defaultHotkey, IHotkeySettings hotkeySettings, string windowTitle = "")
|
public HotkeyControlDialog(string hotkey, string defaultHotkey, IHotkeySettings hotkeySettings, string windowTitle = "")
|
||||||
{
|
{
|
||||||
WindowTitle = windowTitle switch
|
WindowTitle = windowTitle switch
|
||||||
|
|
@ -46,6 +49,14 @@ public partial class HotkeyControlDialog : ContentDialog
|
||||||
SetKeysToDisplay(CurrentHotkey);
|
SetKeysToDisplay(CurrentHotkey);
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
// TODO: This is a temporary way to enforce changing only the open flow hotkey to Win, and will be removed by PR #3157
|
||||||
|
isOpenFlowHotkey = _hotkeySettings.RegisteredHotkeys
|
||||||
|
.Any(x => x.DescriptionResourceKey == "flowlauncherHotkey"
|
||||||
|
&& x.Hotkey.ToString() == hotkey);
|
||||||
|
|
||||||
|
ChefKeysManager.StartMenuEnableBlocking = true;
|
||||||
|
ChefKeysManager.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Reset(object sender, RoutedEventArgs routedEventArgs)
|
private void Reset(object sender, RoutedEventArgs routedEventArgs)
|
||||||
|
|
@ -61,12 +72,18 @@ public partial class HotkeyControlDialog : ContentDialog
|
||||||
|
|
||||||
private void Cancel(object sender, RoutedEventArgs routedEventArgs)
|
private void Cancel(object sender, RoutedEventArgs routedEventArgs)
|
||||||
{
|
{
|
||||||
|
ChefKeysManager.StartMenuEnableBlocking = false;
|
||||||
|
ChefKeysManager.Stop();
|
||||||
|
|
||||||
ResultType = EResultType.Cancel;
|
ResultType = EResultType.Cancel;
|
||||||
Hide();
|
Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Save(object sender, RoutedEventArgs routedEventArgs)
|
private void Save(object sender, RoutedEventArgs routedEventArgs)
|
||||||
{
|
{
|
||||||
|
ChefKeysManager.StartMenuEnableBlocking = false;
|
||||||
|
ChefKeysManager.Stop();
|
||||||
|
|
||||||
if (KeysToDisplay.Count == 1 && KeysToDisplay[0] == EmptyHotkey)
|
if (KeysToDisplay.Count == 1 && KeysToDisplay[0] == EmptyHotkey)
|
||||||
{
|
{
|
||||||
ResultType = EResultType.Delete;
|
ResultType = EResultType.Delete;
|
||||||
|
|
@ -85,6 +102,9 @@ public partial class HotkeyControlDialog : ContentDialog
|
||||||
//when alt is pressed, the real key should be e.SystemKey
|
//when alt is pressed, the real key should be e.SystemKey
|
||||||
Key key = e.Key == Key.System ? e.SystemKey : e.Key;
|
Key key = e.Key == Key.System ? e.SystemKey : e.Key;
|
||||||
|
|
||||||
|
if (ChefKeysManager.StartMenuBlocked && key.ToString() == ChefKeysManager.StartMenuSimulatedKey)
|
||||||
|
return;
|
||||||
|
|
||||||
SpecialKeyState specialKeyState = GlobalHotkey.CheckModifiers();
|
SpecialKeyState specialKeyState = GlobalHotkey.CheckModifiers();
|
||||||
|
|
||||||
var hotkeyModel = new HotkeyModel(
|
var hotkeyModel = new HotkeyModel(
|
||||||
|
|
@ -168,8 +188,13 @@ public partial class HotkeyControlDialog : ContentDialog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CheckHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture) =>
|
private static bool CheckHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture)
|
||||||
hotkey.Validate(validateKeyGesture) && HotKeyMapper.CheckAvailability(hotkey);
|
{
|
||||||
|
if (isOpenFlowHotkey && (hotkey.ToString() == "LWin" || hotkey.ToString() == "RWin"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return hotkey.Validate(validateKeyGesture) && HotKeyMapper.CheckAvailability(hotkey);
|
||||||
|
}
|
||||||
|
|
||||||
private void Overwrite(object sender, RoutedEventArgs e)
|
private void Overwrite(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
<!-- MainWindow -->
|
<!-- MainWindow -->
|
||||||
<system:String x:Key="registerHotkeyFailed">Failed to register hotkey "{0}". The hotkey may be in use by another program. Change to a different hotkey, or exit another program.</system:String>
|
<system:String x:Key="registerHotkeyFailed">Failed to register hotkey "{0}". The hotkey may be in use by another program. Change to a different hotkey, or exit another program.</system:String>
|
||||||
|
<system:String x:Key="unregisterHotkeyFailed">Failed to unregister hotkey "{0}". Please try again or see log for details</system:String>
|
||||||
<system:String x:Key="MessageBoxTitle">Flow Launcher</system:String>
|
<system:String x:Key="MessageBoxTitle">Flow Launcher</system:String>
|
||||||
<system:String x:Key="couldnotStartCmd">Could not start {0}</system:String>
|
<system:String x:Key="couldnotStartCmd">Could not start {0}</system:String>
|
||||||
<system:String x:Key="invalidFlowLauncherPluginFileFormat">Invalid Flow Launcher plugin file format</system:String>
|
<system:String x:Key="invalidFlowLauncherPluginFileFormat">Invalid Flow Launcher plugin file format</system:String>
|
||||||
|
|
@ -128,7 +129,8 @@
|
||||||
<system:String x:Key="plugin_query_version">Version</system:String>
|
<system:String x:Key="plugin_query_version">Version</system:String>
|
||||||
<system:String x:Key="plugin_query_web">Website</system:String>
|
<system:String x:Key="plugin_query_web">Website</system:String>
|
||||||
<system:String x:Key="plugin_uninstall">Uninstall</system:String>
|
<system:String x:Key="plugin_uninstall">Uninstall</system:String>
|
||||||
|
<system:String x:Key="failedToRemovePluginSettingsTitle">Fail to remove plugin settings</system:String>
|
||||||
|
<system:String x:Key="failedToRemovePluginSettingsMessage">Plugins: {0} - Fail to remove plugin settings files, please remove them manually</system:String>
|
||||||
|
|
||||||
<!-- Setting Plugin Store -->
|
<!-- Setting Plugin Store -->
|
||||||
<system:String x:Key="pluginStore">Plugin Store</system:String>
|
<system:String x:Key="pluginStore">Plugin Store</system:String>
|
||||||
|
|
@ -145,8 +147,6 @@
|
||||||
<system:String x:Key="LabelNewToolTip">This plugin has been updated within the last 7 days</system:String>
|
<system:String x:Key="LabelNewToolTip">This plugin has been updated within the last 7 days</system:String>
|
||||||
<system:String x:Key="LabelUpdateToolTip">New Update is Available</system:String>
|
<system:String x:Key="LabelUpdateToolTip">New Update is Available</system:String>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Setting Theme -->
|
<!-- Setting Theme -->
|
||||||
<system:String x:Key="theme">Theme</system:String>
|
<system:String x:Key="theme">Theme</system:String>
|
||||||
<system:String x:Key="appearance">Appearance</system:String>
|
<system:String x:Key="appearance">Appearance</system:String>
|
||||||
|
|
@ -196,7 +196,6 @@
|
||||||
<system:String x:Key="TypeIsDarkToolTip">This theme supports two(light/dark) modes.</system:String>
|
<system:String x:Key="TypeIsDarkToolTip">This theme supports two(light/dark) modes.</system:String>
|
||||||
<system:String x:Key="TypeHasBlurToolTip">This theme supports Blur Transparent Background.</system:String>
|
<system:String x:Key="TypeHasBlurToolTip">This theme supports Blur Transparent Background.</system:String>
|
||||||
|
|
||||||
|
|
||||||
<!-- Setting Hotkey -->
|
<!-- Setting Hotkey -->
|
||||||
<system:String x:Key="hotkey">Hotkey</system:String>
|
<system:String x:Key="hotkey">Hotkey</system:String>
|
||||||
<system:String x:Key="hotkeys">Hotkeys</system:String>
|
<system:String x:Key="hotkeys">Hotkeys</system:String>
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
Foreground="{DynamicResource PopupTextColor}"
|
Foreground="{DynamicResource PopupTextColor}"
|
||||||
ResizeMode="NoResize"
|
ResizeMode="NoResize"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
|
Topmost="True"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<WindowChrome.WindowChrome>
|
<WindowChrome.WindowChrome>
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,23 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<Type, object> _pluginJsonStorages = new();
|
private readonly ConcurrentDictionary<Type, object> _pluginJsonStorages = new();
|
||||||
|
|
||||||
|
public object RemovePluginSettings(string assemblyName)
|
||||||
|
{
|
||||||
|
foreach (var keyValuePair in _pluginJsonStorages)
|
||||||
|
{
|
||||||
|
var key = keyValuePair.Key;
|
||||||
|
var value = keyValuePair.Value;
|
||||||
|
var name = value.GetType().GetField("AssemblyName")?.GetValue(value)?.ToString();
|
||||||
|
if (name == assemblyName)
|
||||||
|
{
|
||||||
|
_pluginJsonStorages.Remove(key, out var pluginJsonStorage);
|
||||||
|
return pluginJsonStorage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Save plugin settings.
|
/// Save plugin settings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -232,8 +232,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
var token = e.Token == default ? _updateToken : e.Token;
|
var token = e.Token == default ? _updateToken : e.Token;
|
||||||
|
|
||||||
// make a copy of results to avoid plugin change the result when updating view model
|
// make a clone to avoid possible issue that plugin will also change the list and items when updating view model
|
||||||
var resultsCopy = e.Results.ToList();
|
var resultsCopy = DeepCloneResults(e.Results, token);
|
||||||
|
|
||||||
PluginManager.UpdatePluginMetadata(resultsCopy, pair.Metadata, e.Query);
|
PluginManager.UpdatePluginMetadata(resultsCopy, pair.Metadata, e.Query);
|
||||||
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, pair.Metadata, e.Query,
|
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, pair.Metadata, e.Query,
|
||||||
|
|
@ -280,10 +280,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
public void ReQuery(bool reselect)
|
public void ReQuery(bool reselect)
|
||||||
{
|
{
|
||||||
if (SelectedIsFromQueryResults())
|
BackToQueryResults();
|
||||||
{
|
QueryResults(isReQuery: true, reSelect: reselect);
|
||||||
QueryResults(isReQuery: true, reSelect: reselect);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
|
|
@ -415,6 +413,22 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IReadOnlyList<Result> DeepCloneResults(IReadOnlyList<Result> results, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
var resultsCopy = new List<Result>();
|
||||||
|
foreach (var result in results.ToList())
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultCopy = result.Clone();
|
||||||
|
resultsCopy.Add(resultCopy);
|
||||||
|
}
|
||||||
|
return resultsCopy;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region BasicCommands
|
#region BasicCommands
|
||||||
|
|
@ -611,6 +625,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
|
BackToQueryResults();
|
||||||
|
|
||||||
if (QueryText != queryText)
|
if (QueryText != queryText)
|
||||||
{
|
{
|
||||||
// re-query is done in QueryText's setter method
|
// re-query is done in QueryText's setter method
|
||||||
|
|
@ -1181,9 +1197,18 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
currentCancellationToken.ThrowIfCancellationRequested();
|
currentCancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
results ??= _emptyResult;
|
IReadOnlyList<Result> resultsCopy;
|
||||||
|
if (results == null)
|
||||||
|
{
|
||||||
|
resultsCopy = _emptyResult;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// make a copy of results to avoid possible issue that FL changes some properties of the records, like score, etc.
|
||||||
|
resultsCopy = DeepCloneResults(results);
|
||||||
|
}
|
||||||
|
|
||||||
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, plugin.Metadata, query,
|
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query,
|
||||||
currentCancellationToken, reSelect)))
|
currentCancellationToken, reSelect)))
|
||||||
{
|
{
|
||||||
Log.Error("MainViewModel", "Unable to add item to Result Update Queue");
|
Log.Error("MainViewModel", "Unable to add item to Result Update Queue");
|
||||||
|
|
@ -1267,7 +1292,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
_topMostRecord.Remove(result);
|
_topMostRecord.Remove(result);
|
||||||
App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success"));
|
App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success"));
|
||||||
App.API.BackToQueryResults();
|
|
||||||
App.API.ReQuery();
|
App.API.ReQuery();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1285,7 +1309,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
_topMostRecord.AddOrUpdate(result);
|
_topMostRecord.AddOrUpdate(result);
|
||||||
App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success"));
|
App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success"));
|
||||||
App.API.BackToQueryResults();
|
|
||||||
App.API.ReQuery();
|
App.API.ReQuery();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1472,12 +1495,31 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
result.Score = Result.MaxScore;
|
result.Score = Result.MaxScore;
|
||||||
}
|
}
|
||||||
else if (result.Score != Result.MaxScore)
|
else
|
||||||
{
|
{
|
||||||
var priorityScore = metaResults.Metadata.Priority * 150;
|
var priorityScore = metaResults.Metadata.Priority * 150;
|
||||||
result.Score += result.AddSelectedCount ?
|
if (result.AddSelectedCount)
|
||||||
_userSelectedRecord.GetSelectedCount(result) + priorityScore :
|
{
|
||||||
priorityScore;
|
if ((long)result.Score + _userSelectedRecord.GetSelectedCount(result) + priorityScore > Result.MaxScore)
|
||||||
|
{
|
||||||
|
result.Score = Result.MaxScore;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Score += _userSelectedRecord.GetSelectedCount(result) + priorityScore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((long)result.Score + priorityScore > Result.MaxScore)
|
||||||
|
{
|
||||||
|
result.Score = Result.MaxScore;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Score += priorityScore;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
private Control _bottomPart2;
|
private Control _bottomPart2;
|
||||||
public Control BottomPart2 => IsExpanded ? _bottomPart2 ??= new InstalledPluginDisplayBottomData() : null;
|
public Control BottomPart2 => IsExpanded ? _bottomPart2 ??= new InstalledPluginDisplayBottomData() : null;
|
||||||
|
|
||||||
public bool HasSettingControl => PluginPair.Plugin is ISettingProvider;
|
public bool HasSettingControl => PluginPair.Plugin is ISettingProvider settingProvider && settingProvider.CreateSettingPanel() != null;
|
||||||
public Control SettingControl
|
public Control SettingControl
|
||||||
=> IsExpanded
|
=> IsExpanded
|
||||||
? _settingControl
|
? _settingControl
|
||||||
|
|
@ -159,5 +159,4 @@ namespace Flow.Launcher.ViewModel
|
||||||
changeKeywordsWindow.ShowDialog();
|
changeKeywordsWindow.ShowDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
||||||
var link = pluginManifestInfo.UrlSourceCode.StartsWith("https://github.com")
|
var link = pluginManifestInfo.UrlSourceCode.StartsWith("https://github.com")
|
||||||
? Regex.Replace(pluginManifestInfo.UrlSourceCode, @"\/tree\/\w+$", "") + "/issues"
|
? Regex.Replace(pluginManifestInfo.UrlSourceCode, @"\/tree\/\w+$", "") + "/issues"
|
||||||
: pluginManifestInfo.UrlSourceCode;
|
: pluginManifestInfo.UrlSourceCode;
|
||||||
|
|
||||||
Context.API.OpenUrl(link);
|
Context.API.OpenUrl(link);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
<system:String x:Key="plugin_pluginsmanager_installing_plugin">Installing Plugin</system:String>
|
<system:String x:Key="plugin_pluginsmanager_installing_plugin">Installing Plugin</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_install_from_web">Download and install {0}</system:String>
|
<system:String x:Key="plugin_pluginsmanager_install_from_web">Download and install {0}</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_uninstall_title">Plugin Uninstall</system:String>
|
<system:String x:Key="plugin_pluginsmanager_uninstall_title">Plugin Uninstall</system:String>
|
||||||
|
<system:String x:Key="plugin_pluginsmanager_keep_plugin_settings_title">Keep plugin settings</system:String>
|
||||||
|
<system:String x:Key="plugin_pluginsmanager_keep_plugin_settings_subtitle">Do you want to keep the settings of the plugin for the next usage?</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_install_success_restart">Plugin {0} successfully installed. Restarting Flow, please wait...</system:String>
|
<system:String x:Key="plugin_pluginsmanager_install_success_restart">Plugin {0} successfully installed. Restarting Flow, please wait...</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_install_errormetadatafile">Unable to find the plugin.json metadata file from the extracted zip file.</system:String>
|
<system:String x:Key="plugin_pluginsmanager_install_errormetadatafile">Unable to find the plugin.json metadata file from the extracted zip file.</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_install_error_duplicate">Error: A plugin which has the same or greater version with {0} already exists.</system:String>
|
<system:String x:Key="plugin_pluginsmanager_install_error_duplicate">Error: A plugin which has the same or greater version with {0} already exists.</system:String>
|
||||||
|
|
@ -37,13 +39,13 @@
|
||||||
<system:String x:Key="plugin_pluginsmanager_update_success_restart">Plugin {0} successfully updated. Restarting Flow, please wait...</system:String>
|
<system:String x:Key="plugin_pluginsmanager_update_success_restart">Plugin {0} successfully updated. Restarting Flow, please wait...</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_install_unknown_source_warning_title">Installing from an unknown source</system:String>
|
<system:String x:Key="plugin_pluginsmanager_install_unknown_source_warning_title">Installing from an unknown source</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_install_unknown_source_warning">You are installing this plugin from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning via settings)</system:String>
|
<system:String x:Key="plugin_pluginsmanager_install_unknown_source_warning">You are installing this plugin from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning via settings)</system:String>
|
||||||
|
|
||||||
<system:String x:Key="plugin_pluginsmanager_install_success_no_restart">Plugin {0} successfully installed. Please restart Flow.</system:String>
|
<system:String x:Key="plugin_pluginsmanager_install_success_no_restart">Plugin {0} successfully installed. Please restart Flow.</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_uninstall_success_no_restart">Plugin {0} successfully uninstalled. Please restart Flow.</system:String>
|
<system:String x:Key="plugin_pluginsmanager_uninstall_success_no_restart">Plugin {0} successfully uninstalled. Please restart Flow.</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_update_success_no_restart">Plugin {0} successfully updated. Please restart Flow.</system:String>
|
<system:String x:Key="plugin_pluginsmanager_update_success_no_restart">Plugin {0} successfully updated. Please restart Flow.</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_update_all_success_no_restart">{0} plugins successfully updated. Please restart Flow.</system:String>
|
<system:String x:Key="plugin_pluginsmanager_update_all_success_no_restart">{0} plugins successfully updated. Please restart Flow.</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_plugin_modified_error">Plugin {0} has already been modified. Please restart Flow before making any further changes.</system:String>
|
<system:String x:Key="plugin_pluginsmanager_plugin_modified_error">Plugin {0} has already been modified. Please restart Flow before making any further changes.</system:String>
|
||||||
|
|
||||||
<!-- Plugin Infos -->
|
<!-- Plugin Infos -->
|
||||||
<system:String x:Key="plugin_pluginsmanager_plugin_name">Plugins Manager</system:String>
|
<system:String x:Key="plugin_pluginsmanager_plugin_name">Plugins Manager</system:String>
|
||||||
<system:String x:Key="plugin_pluginsmanager_plugin_description">Management of installing, uninstalling or updating Flow Launcher plugins</system:String>
|
<system:String x:Key="plugin_pluginsmanager_plugin_description">Management of installing, uninstalling or updating Flow Launcher plugins</system:String>
|
||||||
|
|
|
||||||
|
|
@ -733,7 +733,11 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PluginManager.UninstallPlugin(plugin, removeSettings: true);
|
var removePluginSettings = Context.API.ShowMsgBox(
|
||||||
|
Context.API.GetTranslation("plugin_pluginsmanager_keep_plugin_settings_subtitle"),
|
||||||
|
Context.API.GetTranslation("plugin_pluginsmanager_keep_plugin_settings_title"),
|
||||||
|
button: MessageBoxButton.YesNo) == MessageBoxResult.No;
|
||||||
|
PluginManager.UninstallPlugin(plugin, removePluginFromSettings: true, removePluginSettings: removePluginSettings);
|
||||||
}
|
}
|
||||||
catch (ArgumentException e)
|
catch (ArgumentException e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@
|
||||||
<system:String x:Key="flowlauncher_plugin_program_enable_hideuninstallers_tooltip">Hides programs with common uninstaller names, such as unins000.exe</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_enable_hideuninstallers_tooltip">Hides programs with common uninstaller names, such as unins000.exe</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_enable_description">Search in Program Description</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_enable_description">Search in Program Description</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_enable_description_tooltip">Flow will search program's description</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_enable_description_tooltip">Flow will search program's description</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_enable_hideduplicatedwindowsapp">Hide duplicated apps</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_enable_hideduplicatedwindowsapp_tooltip">Hide duplicated Win32 programs that are already in the UWP list</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_suffixes_header">Suffixes</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_header">Suffixes</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_max_depth_header">Max Depth</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_max_depth_header">Max Depth</system:String>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
private const string ExeUninstallerSuffix = ".exe";
|
private const string ExeUninstallerSuffix = ".exe";
|
||||||
private const string InkUninstallerSuffix = ".lnk";
|
private const string InkUninstallerSuffix = ".lnk";
|
||||||
|
|
||||||
|
private static readonly string WindowsAppPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WindowsApps");
|
||||||
|
|
||||||
static Main()
|
static Main()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -90,11 +92,20 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Collect all UWP Windows app directories
|
||||||
|
var uwpsDirectories = _settings.HideDuplicatedWindowsApp ? _uwps
|
||||||
|
.Where(uwp => !string.IsNullOrEmpty(uwp.Location)) // Exclude invalid paths
|
||||||
|
.Where(uwp => uwp.Location.StartsWith(WindowsAppPath, StringComparison.OrdinalIgnoreCase)) // Keep system apps
|
||||||
|
.Select(uwp => uwp.Location.TrimEnd('\\')) // Remove trailing slash
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToArray() : null;
|
||||||
|
|
||||||
return _win32s.Cast<IProgram>()
|
return _win32s.Cast<IProgram>()
|
||||||
.Concat(_uwps)
|
.Concat(_uwps)
|
||||||
.AsParallel()
|
.AsParallel()
|
||||||
.WithCancellation(token)
|
.WithCancellation(token)
|
||||||
.Where(HideUninstallersFilter)
|
.Where(HideUninstallersFilter)
|
||||||
|
.Where(p => HideDuplicatedWindowsAppFilter(p, uwpsDirectories))
|
||||||
.Where(p => p.Enabled)
|
.Where(p => p.Enabled)
|
||||||
.Select(p => p.Result(query.Search, Context.API))
|
.Select(p => p.Result(query.Search, Context.API))
|
||||||
.Where(r => r?.Score > 0)
|
.Where(r => r?.Score > 0)
|
||||||
|
|
@ -152,6 +163,23 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool HideDuplicatedWindowsAppFilter(IProgram program, string[] uwpsDirectories)
|
||||||
|
{
|
||||||
|
if (uwpsDirectories == null || uwpsDirectories.Length == 0) return true;
|
||||||
|
if (program is UWPApp) return true;
|
||||||
|
|
||||||
|
var location = program.Location.TrimEnd('\\'); // Ensure trailing slash
|
||||||
|
if (string.IsNullOrEmpty(location))
|
||||||
|
return true; // Keep if location is invalid
|
||||||
|
|
||||||
|
if (!location.StartsWith(WindowsAppPath, StringComparison.OrdinalIgnoreCase))
|
||||||
|
return true; // Keep if not a Windows app
|
||||||
|
|
||||||
|
// Check if the any Win32 executable directory contains UWP Windows app location matches
|
||||||
|
return !uwpsDirectories.Any(uwpDirectory =>
|
||||||
|
location.StartsWith(uwpDirectory, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task InitAsync(PluginInitContext context)
|
public async Task InitAsync(PluginInitContext context)
|
||||||
{
|
{
|
||||||
Context = context;
|
Context = context;
|
||||||
|
|
@ -264,7 +292,6 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
Context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success"),
|
Context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success"),
|
||||||
Context.API.GetTranslation(
|
Context.API.GetTranslation(
|
||||||
"flowlauncher_plugin_program_disable_dlgtitle_success_message"));
|
"flowlauncher_plugin_program_disable_dlgtitle_success_message"));
|
||||||
Context.API.BackToQueryResults();
|
|
||||||
Context.API.ReQuery();
|
Context.API.ReQuery();
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
public bool EnableRegistrySource { get; set; } = true;
|
public bool EnableRegistrySource { get; set; } = true;
|
||||||
public bool EnablePathSource { get; set; } = false;
|
public bool EnablePathSource { get; set; } = false;
|
||||||
public bool EnableUWP { get; set; } = true;
|
public bool EnableUWP { get; set; } = true;
|
||||||
|
public bool HideDuplicatedWindowsApp { get; set; } = false;
|
||||||
|
|
||||||
internal const char SuffixSeparator = ';';
|
internal const char SuffixSeparator = ';';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid Margin="0">
|
<Grid Margin="0">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
|
@ -18,40 +18,40 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<DockPanel
|
<DockPanel
|
||||||
Margin="70,10,0,8"
|
Margin="70 10 0 8"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
LastChildFill="True">
|
LastChildFill="True">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="0,5,10,0"
|
Margin="0 5 10 0"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_index_source}" />
|
Text="{DynamicResource flowlauncher_plugin_program_index_source}" />
|
||||||
<WrapPanel
|
<WrapPanel
|
||||||
Width="Auto"
|
Width="Auto"
|
||||||
Margin="0,0,14,0"
|
Margin="0 0 14 0"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Right">
|
DockPanel.Dock="Right">
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="UWPEnabled"
|
Name="UWPEnabled"
|
||||||
Margin="12,0,12,0"
|
Margin="12 0 12 0"
|
||||||
Visibility="{Binding ShowUWPCheckbox, Converter={StaticResource BooleanToVisibilityConverter}}"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_uwp}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_uwp}"
|
||||||
IsChecked="{Binding EnableUWP}"
|
IsChecked="{Binding EnableUWP}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_uwp_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_uwp_tooltip}"
|
||||||
|
Visibility="{Binding ShowUWPCheckbox, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="StartMenuEnabled"
|
Name="StartMenuEnabled"
|
||||||
Margin="12,0,12,0"
|
Margin="12 0 12 0"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
|
||||||
IsChecked="{Binding EnableStartMenuSource}"
|
IsChecked="{Binding EnableStartMenuSource}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="RegistryEnabled"
|
Name="RegistryEnabled"
|
||||||
Margin="12,0,12,0"
|
Margin="12 0 12 0"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
|
||||||
IsChecked="{Binding EnableRegistrySource}"
|
IsChecked="{Binding EnableRegistrySource}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="PATHEnabled"
|
Name="PATHEnabled"
|
||||||
Margin="12,0,12,0"
|
Margin="12 0 12 0"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_PATH}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_PATH}"
|
||||||
IsChecked="{Binding EnablePATHSource}"
|
IsChecked="{Binding EnablePATHSource}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_PATH_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_PATH_tooltip}" />
|
||||||
|
|
@ -67,21 +67,20 @@
|
||||||
BorderBrush="{DynamicResource Color03B}"
|
BorderBrush="{DynamicResource Color03B}"
|
||||||
BorderThickness="1" />
|
BorderThickness="1" />
|
||||||
<DockPanel
|
<DockPanel
|
||||||
Margin="70,10,0,8"
|
Margin="70 10 0 8"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
LastChildFill="True">
|
LastChildFill="True">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="0,5,10,0"
|
Margin="0 5 10 0"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_index_option}" />
|
Text="{DynamicResource flowlauncher_plugin_program_index_option}" />
|
||||||
<WrapPanel
|
<WrapPanel
|
||||||
Width="Auto"
|
Width="Auto"
|
||||||
Margin="0,0,14,0"
|
Margin="0 0 14 0"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Right">
|
DockPanel.Dock="Right">
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="HideLnkEnabled"
|
Margin="12 0 12 0"
|
||||||
Margin="12,0,12,0"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
|
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
|
||||||
IsChecked="{Binding HideAppsPath}"
|
IsChecked="{Binding HideAppsPath}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
|
||||||
|
|
@ -91,11 +90,15 @@
|
||||||
IsChecked="{Binding HideUninstallers}"
|
IsChecked="{Binding HideUninstallers}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideuninstallers_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideuninstallers_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="DescriptionEnabled"
|
Margin="12 0 12 0"
|
||||||
Margin="12,0,12,0"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
|
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
|
||||||
IsChecked="{Binding EnableDescription}"
|
IsChecked="{Binding EnableDescription}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
|
||||||
|
<CheckBox
|
||||||
|
Margin="12 0 12 0"
|
||||||
|
Content="{DynamicResource flowlauncher_plugin_program_enable_hideduplicatedwindowsapp}"
|
||||||
|
IsChecked="{Binding HideDuplicatedWindowsApp}"
|
||||||
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideduplicatedwindowsapp_tooltip}" />
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<Separator
|
<Separator
|
||||||
|
|
@ -103,28 +106,28 @@
|
||||||
BorderBrush="{DynamicResource Color03B}"
|
BorderBrush="{DynamicResource Color03B}"
|
||||||
BorderThickness="1" />
|
BorderThickness="1" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Margin="60,0,0,2"
|
Margin="60 0 0 2"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnLoadAllProgramSource"
|
x:Name="btnLoadAllProgramSource"
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="10,10,5,10"
|
Margin="10 10 5 10"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Click="btnLoadAllProgramSource_OnClick"
|
Click="btnLoadAllProgramSource_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_all_programs}" />
|
Content="{DynamicResource flowlauncher_plugin_program_all_programs}" />
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnProgramSuffixes"
|
x:Name="btnProgramSuffixes"
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="5,10,5,10"
|
Margin="5 10 5 10"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Click="BtnProgramSuffixes_OnClick"
|
Click="BtnProgramSuffixes_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_suffixes}" />
|
Content="{DynamicResource flowlauncher_plugin_program_suffixes}" />
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnReindex"
|
x:Name="btnReindex"
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="5,10,5,10"
|
Margin="5 10 5 10"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Click="btnReindex_Click"
|
Click="btnReindex_Click"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_reindex}" />
|
Content="{DynamicResource flowlauncher_plugin_program_reindex}" />
|
||||||
|
|
@ -142,7 +145,7 @@
|
||||||
Minimum="0" />
|
Minimum="0" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Height="20"
|
Height="20"
|
||||||
Margin="10,0,0,0"
|
Margin="10 0 0 0"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_indexing}" />
|
Text="{DynamicResource flowlauncher_plugin_program_indexing}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
@ -151,7 +154,7 @@
|
||||||
<ListView
|
<ListView
|
||||||
x:Name="programSourceView"
|
x:Name="programSourceView"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Margin="70,0,20,0"
|
Margin="70 0 20 0"
|
||||||
AllowDrop="True"
|
AllowDrop="True"
|
||||||
BorderBrush="DarkGray"
|
BorderBrush="DarkGray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
|
|
@ -203,7 +206,7 @@
|
||||||
<DockPanel
|
<DockPanel
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.RowSpan="1"
|
Grid.RowSpan="1"
|
||||||
Margin="0,0,20,0">
|
Margin="0 0 20 0">
|
||||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnProgramSourceStatus"
|
x:Name="btnProgramSourceStatus"
|
||||||
|
|
@ -220,7 +223,7 @@
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnAddProgramSource"
|
x:Name="btnAddProgramSource"
|
||||||
MinWidth="100"
|
MinWidth="100"
|
||||||
Margin="10,10,0,10"
|
Margin="10 10 0 10"
|
||||||
Click="btnAddProgramSource_OnClick"
|
Click="btnAddProgramSource_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_add}" />
|
Content="{DynamicResource flowlauncher_plugin_program_add}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,16 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HideDuplicatedWindowsApp
|
||||||
|
{
|
||||||
|
get => _settings.HideDuplicatedWindowsApp;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Main.ResetCache();
|
||||||
|
_settings.HideDuplicatedWindowsApp = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool EnableRegistrySource
|
public bool EnableRegistrySource
|
||||||
{
|
{
|
||||||
get => _settings.EnableRegistrySource;
|
get => _settings.EnableRegistrySource;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
|
||||||
using WindowsInput;
|
using WindowsInput;
|
||||||
using WindowsInput.Native;
|
using WindowsInput.Native;
|
||||||
using Flow.Launcher.Infrastructure.Hotkey;
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
|
|
@ -379,7 +378,7 @@ namespace Flow.Launcher.Plugin.Shell
|
||||||
private void OnWinRPressed()
|
private void OnWinRPressed()
|
||||||
{
|
{
|
||||||
// show the main window and set focus to the query box
|
// show the main window and set focus to the query box
|
||||||
Task.Run(() =>
|
_ = Task.Run(() =>
|
||||||
{
|
{
|
||||||
context.API.ShowMainWindow();
|
context.API.ShowMainWindow();
|
||||||
context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeywords[0]}{Plugin.Query.TermSeparator}");
|
context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeywords[0]}{Plugin.Query.TermSeparator}");
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
|
||||||
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Url
|
namespace Flow.Launcher.Plugin.Url
|
||||||
{
|
{
|
||||||
public class Main : ISettingProvider,IPlugin, IPluginI18n
|
public class Main : IPlugin, IPluginI18n
|
||||||
{
|
{
|
||||||
//based on https://gist.github.com/dperini/729294
|
//based on https://gist.github.com/dperini/729294
|
||||||
private const string urlPattern = "^" +
|
private const string urlPattern = "^" +
|
||||||
|
|
@ -43,7 +42,6 @@ namespace Flow.Launcher.Plugin.Url
|
||||||
Regex reg = new Regex(urlPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
Regex reg = new Regex(urlPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
private PluginInitContext context;
|
private PluginInitContext context;
|
||||||
private Settings _settings;
|
private Settings _settings;
|
||||||
|
|
||||||
|
|
||||||
public List<Result> Query(Query query)
|
public List<Result> Query(Query query)
|
||||||
{
|
{
|
||||||
|
|
@ -82,12 +80,6 @@ namespace Flow.Launcher.Plugin.Url
|
||||||
return new List<Result>(0);
|
return new List<Result>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Control CreateSettingPanel()
|
|
||||||
{
|
|
||||||
return new SettingsControl(context.API,_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsURL(string raw)
|
public bool IsURL(string raw)
|
||||||
{
|
{
|
||||||
raw = raw.ToLower();
|
raw = raw.ToLower();
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
<UserControl
|
|
||||||
x:Class="Flow.Launcher.Plugin.Url.SettingsControl"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
Height="0"
|
|
||||||
d:DesignHeight="300"
|
|
||||||
d:DesignWidth="500"
|
|
||||||
mc:Ignorable="d">
|
|
||||||
<Grid Margin="40,40,10,0">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="40" />
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Url
|
|
||||||
{
|
|
||||||
public partial class SettingsControl : UserControl
|
|
||||||
{
|
|
||||||
private Settings _settings;
|
|
||||||
private IPublicAPI _flowlauncherAPI;
|
|
||||||
|
|
||||||
public SettingsControl(IPublicAPI flowlauncherAPI,Settings settings)
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
_settings = settings;
|
|
||||||
_flowlauncherAPI = flowlauncherAPI;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue