mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge branch 'dev' into squirrel_upgrade
This commit is contained in:
commit
b34851bd12
79 changed files with 803 additions and 745 deletions
|
|
@ -3,10 +3,8 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using Microsoft.Win32;
|
||||
using Squirrel;
|
||||
|
|
@ -17,8 +15,6 @@ namespace Flow.Launcher.Core.Configuration
|
|||
{
|
||||
private static readonly string ClassName = nameof(Portable);
|
||||
|
||||
private readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
/// <summary>
|
||||
/// As at Squirrel.Windows version 1.5.2, UpdateManager needs to be disposed after finish
|
||||
/// </summary>
|
||||
|
|
@ -45,13 +41,13 @@ namespace Flow.Launcher.Core.Configuration
|
|||
#endif
|
||||
IndicateDeletion(DataLocation.PortableDataPath);
|
||||
|
||||
API.ShowMsgBox(API.GetTranslation("restartToDisablePortableMode"));
|
||||
PublicApi.Instance.ShowMsgBox(Localize.restartToDisablePortableMode());
|
||||
|
||||
UpdateManager.RestartApp(Constant.ApplicationFileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Error occurred while disabling portable mode", e);
|
||||
PublicApi.Instance.LogException(ClassName, "Error occurred while disabling portable mode", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,13 +64,13 @@ namespace Flow.Launcher.Core.Configuration
|
|||
#endif
|
||||
IndicateDeletion(DataLocation.RoamingDataPath);
|
||||
|
||||
API.ShowMsgBox(API.GetTranslation("restartToEnablePortableMode"));
|
||||
PublicApi.Instance.ShowMsgBox(Localize.restartToEnablePortableMode());
|
||||
|
||||
UpdateManager.RestartApp(Constant.ApplicationFileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Error occurred while enabling portable mode", e);
|
||||
PublicApi.Instance.LogException(ClassName, "Error occurred while enabling portable mode", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,13 +90,13 @@ namespace Flow.Launcher.Core.Configuration
|
|||
|
||||
public void MoveUserDataFolder(string fromLocation, string toLocation)
|
||||
{
|
||||
FilesFolders.CopyAll(fromLocation, toLocation, (s) => API.ShowMsgBox(s));
|
||||
FilesFolders.CopyAll(fromLocation, toLocation, (s) => PublicApi.Instance.ShowMsgBox(s));
|
||||
VerifyUserDataAfterMove(fromLocation, toLocation);
|
||||
}
|
||||
|
||||
public void VerifyUserDataAfterMove(string fromLocation, string toLocation)
|
||||
{
|
||||
FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => API.ShowMsgBox(s));
|
||||
FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => PublicApi.Instance.ShowMsgBox(s));
|
||||
}
|
||||
|
||||
public void CreateShortcuts()
|
||||
|
|
@ -150,12 +146,12 @@ namespace Flow.Launcher.Core.Configuration
|
|||
// delete it and prompt the user to pick the portable data location
|
||||
if (File.Exists(roamingDataDeleteFilePath))
|
||||
{
|
||||
FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => API.ShowMsgBox(s));
|
||||
FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => PublicApi.Instance.ShowMsgBox(s));
|
||||
|
||||
if (API.ShowMsgBox(API.GetTranslation("moveToDifferentLocation"),
|
||||
if (PublicApi.Instance.ShowMsgBox(Localize.moveToDifferentLocation(),
|
||||
string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
FilesFolders.OpenPath(Constant.RootDirectory, (s) => API.ShowMsgBox(s));
|
||||
FilesFolders.OpenPath(Constant.RootDirectory, (s) => PublicApi.Instance.ShowMsgBox(s));
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
|
@ -164,9 +160,9 @@ namespace Flow.Launcher.Core.Configuration
|
|||
// delete it and notify the user about it.
|
||||
else if (File.Exists(portableDataDeleteFilePath))
|
||||
{
|
||||
FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => API.ShowMsgBox(s));
|
||||
FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => PublicApi.Instance.ShowMsgBox(s));
|
||||
|
||||
API.ShowMsgBox(API.GetTranslation("shortcutsUninstallerCreated"));
|
||||
PublicApi.Instance.ShowMsgBox(Localize.shortcutsUninstallerCreated());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,8 +173,7 @@ namespace Flow.Launcher.Core.Configuration
|
|||
|
||||
if (roamingLocationExists && portableLocationExists)
|
||||
{
|
||||
API.ShowMsgBox(string.Format(API.GetTranslation("userDataDuplicated"),
|
||||
DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
|
||||
PublicApi.Instance.ShowMsgBox(Localize.userDataDuplicated(DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ using System.Text.Json;
|
|||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Infrastructure.Http;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
|
|
@ -18,13 +17,9 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
{
|
||||
private static readonly string ClassName = nameof(CommunityPluginSource);
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
private string latestEtag = "";
|
||||
|
||||
private List<UserPlugin> plugins = new();
|
||||
private List<UserPlugin> plugins = [];
|
||||
|
||||
private static readonly JsonSerializerOptions PluginStoreItemSerializationOption = new()
|
||||
{
|
||||
|
|
@ -41,7 +36,7 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
/// </remarks>
|
||||
public async Task<List<UserPlugin>> FetchAsync(CancellationToken token)
|
||||
{
|
||||
API.LogInfo(ClassName, $"Loading plugins from {ManifestFileUrl}");
|
||||
PublicApi.Instance.LogInfo(ClassName, $"Loading plugins from {ManifestFileUrl}");
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, ManifestFileUrl);
|
||||
|
||||
|
|
@ -59,40 +54,40 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
.ConfigureAwait(false);
|
||||
latestEtag = response.Headers.ETag?.Tag;
|
||||
|
||||
API.LogInfo(ClassName, $"Loaded {plugins.Count} plugins from {ManifestFileUrl}");
|
||||
PublicApi.Instance.LogInfo(ClassName, $"Loaded {plugins.Count} plugins from {ManifestFileUrl}");
|
||||
return plugins;
|
||||
}
|
||||
else if (response.StatusCode == HttpStatusCode.NotModified)
|
||||
{
|
||||
API.LogInfo(ClassName, $"Resource {ManifestFileUrl} has not been modified.");
|
||||
PublicApi.Instance.LogInfo(ClassName, $"Resource {ManifestFileUrl} has not been modified.");
|
||||
return plugins;
|
||||
}
|
||||
else
|
||||
{
|
||||
API.LogWarn(ClassName, $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
|
||||
PublicApi.Instance.LogWarn(ClassName, $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||
{
|
||||
API.LogDebug(ClassName, $"Fetching from {ManifestFileUrl} was cancelled by caller.");
|
||||
PublicApi.Instance.LogDebug(ClassName, $"Fetching from {ManifestFileUrl} was cancelled by caller.");
|
||||
return null;
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// Likely an HttpClient timeout or external cancellation not requested by our token
|
||||
API.LogWarn(ClassName, $"Fetching from {ManifestFileUrl} timed out.");
|
||||
PublicApi.Instance.LogWarn(ClassName, $"Fetching from {ManifestFileUrl} timed out.");
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is HttpRequestException or WebException or SocketException || e.InnerException is TimeoutException)
|
||||
{
|
||||
API.LogException(ClassName, $"Check your connection and proxy settings to {ManifestFileUrl}.", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Check your connection and proxy settings to {ManifestFileUrl}.", e);
|
||||
}
|
||||
else
|
||||
{
|
||||
API.LogException(ClassName, "Error Occurred", e);
|
||||
PublicApi.Instance.LogException(ClassName, "Error Occurred", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
|
|
@ -15,7 +14,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
{
|
||||
private static readonly string ClassName = nameof(AbstractPluginEnvironment);
|
||||
|
||||
protected readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
protected readonly IPublicAPI API = PublicApi.Instance;
|
||||
|
||||
internal abstract string Language { get; }
|
||||
|
||||
|
|
@ -58,15 +57,10 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
|
||||
}
|
||||
|
||||
var noRuntimeMessage = string.Format(
|
||||
API.GetTranslation("runtimePluginInstalledChooseRuntimePrompt"),
|
||||
Language,
|
||||
EnvName,
|
||||
Environment.NewLine
|
||||
);
|
||||
var noRuntimeMessage = Localize.runtimePluginInstalledChooseRuntimePrompt(Language, EnvName, Environment.NewLine);
|
||||
if (API.ShowMsgBox(noRuntimeMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
|
||||
{
|
||||
var msg = string.Format(API.GetTranslation("runtimePluginChooseRuntimeExecutable"), EnvName);
|
||||
var msg = Localize.runtimePluginChooseRuntimeExecutable(EnvName);
|
||||
|
||||
var selectedFile = GetFileFromDialog(msg, FileDialogFilter);
|
||||
|
||||
|
|
@ -77,12 +71,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
// Nothing selected because user pressed cancel from the file dialog window
|
||||
else
|
||||
{
|
||||
var forceDownloadMessage = string.Format(
|
||||
API.GetTranslation("runtimeExecutableInvalidChooseDownload"),
|
||||
Language,
|
||||
EnvName,
|
||||
Environment.NewLine
|
||||
);
|
||||
var forceDownloadMessage = Localize.runtimeExecutableInvalidChooseDownload(Language, EnvName, Environment.NewLine);
|
||||
|
||||
// Let users select valid path or choose to download
|
||||
while (string.IsNullOrEmpty(selectedFile))
|
||||
|
|
@ -120,7 +109,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
}
|
||||
else
|
||||
{
|
||||
API.ShowMsgBox(string.Format(API.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language));
|
||||
API.ShowMsgBox(Localize.runtimePluginUnableToSetExecutablePath(Language));
|
||||
API.LogError(ClassName,
|
||||
$"Not able to successfully set {EnvName} path, setting's plugin executable path variable is still an empty string.",
|
||||
$"{Language}Environment");
|
||||
|
|
@ -248,7 +237,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
private static string GetUpdatedEnvironmentPath(string filePath)
|
||||
{
|
||||
var index = filePath.IndexOf(DataLocation.PluginEnvironments);
|
||||
|
||||
|
||||
// get the substring after "Environments" because we can not determine it dynamically
|
||||
var executablePathSubstring = filePath[(index + DataLocation.PluginEnvironments.Length)..];
|
||||
return $"{DataLocation.PluginEnvironmentsPath}{executablePathSubstring}";
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
API.ShowMsgError(API.GetTranslation("failToInstallPythonEnv"));
|
||||
API.ShowMsgError(Localize.failToInstallPythonEnv());
|
||||
API.LogException(ClassName, "Failed to install Python environment", e);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
API.ShowMsgError(API.GetTranslation("failToInstallTypeScriptEnv"));
|
||||
API.ShowMsgError(Localize.failToInstallTypeScriptEnv());
|
||||
API.LogException(ClassName, "Failed to install TypeScript environment", e);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
API.ShowMsgError(API.GetTranslation("failToInstallTypeScriptEnv"));
|
||||
API.ShowMsgError(Localize.failToInstallTypeScriptEnv());
|
||||
API.LogException(ClassName, "Failed to install TypeScript environment", e);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
|
||||
|
|
@ -23,10 +22,6 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
private static DateTime lastFetchedAt = DateTime.MinValue;
|
||||
private static readonly TimeSpan fetchTimeout = TimeSpan.FromMinutes(2);
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
public static List<UserPlugin> UserPlugins { get; private set; }
|
||||
|
||||
public static async Task<bool> UpdateManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default)
|
||||
|
|
@ -61,7 +56,7 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Http request failed", e);
|
||||
PublicApi.Instance.LogException(ClassName, "Http request failed", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -83,12 +78,12 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. "
|
||||
PublicApi.Instance.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. "
|
||||
+ "Plugin excluded from manifest", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
API.LogInfo(ClassName, $"Plugin {plugin.Name} requires minimum Flow Launcher version {plugin.MinimumAppVersion}, "
|
||||
PublicApi.Instance.LogInfo(ClassName, $"Plugin {plugin.Name} requires minimum Flow Launcher version {plugin.MinimumAppVersion}, "
|
||||
+ $"but current version is {Constant.Version}. Plugin excluded from manifest.");
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<NoWarn>$(NoWarn);FLSG0007</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -55,6 +56,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Droplex" Version="1.7.0" />
|
||||
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
|
||||
<PackageReference Include="FSharp.Core" Version="9.0.303" />
|
||||
<PackageReference Include="Meziantou.Framework.Win32.Jobs" Version="3.4.5" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
|
|
@ -63,6 +65,17 @@
|
|||
<PackageReference Include="squirrel.windows" Version="1.9.0" NoWarn="NU1701" />
|
||||
<PackageReference Include="StreamJsonRpc" Version="2.22.11" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<FLLUseDependencyInjection>true</FLLUseDependencyInjection>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Remove="Languages\en.xaml" />
|
||||
<AdditionalFiles Include="..\Flow.Launcher\Languages\en.xaml">
|
||||
<Link>Languages\en.xaml</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
HorizontalAlignment = HorizontalAlignment.Left,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = SettingPanelItemLeftMargin,
|
||||
Content = API.GetTranslation("select")
|
||||
Content = Localize.select()
|
||||
};
|
||||
|
||||
Btn.Click += (_, _) =>
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ using System.IO;
|
|||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Plugin;
|
||||
using System.Text.Json;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
|
|
@ -14,10 +12,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
private static readonly string ClassName = nameof(PluginConfig);
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
/// <summary>
|
||||
/// Parse plugin metadata in the given directories
|
||||
/// </summary>
|
||||
|
|
@ -39,7 +33,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Can't delete <{directory}>", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Can't delete <{directory}>", e);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -56,7 +50,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
duplicateList
|
||||
.ForEach(
|
||||
x => API.LogWarn(ClassName,
|
||||
x => PublicApi.Instance.LogWarn(ClassName,
|
||||
string.Format("Duplicate plugin name: {0}, id: {1}, version: {2} " +
|
||||
"not loaded due to version not the highest of the duplicates",
|
||||
x.Name, x.ID, x.Version),
|
||||
|
|
@ -108,7 +102,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
string configPath = Path.Combine(pluginDirectory, Constant.PluginMetadataFileName);
|
||||
if (!File.Exists(configPath))
|
||||
{
|
||||
API.LogError(ClassName, $"Didn't find config file <{configPath}>");
|
||||
PublicApi.Instance.LogError(ClassName, $"Didn't find config file <{configPath}>");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -124,19 +118,19 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Invalid json for config <{configPath}>", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Invalid json for config <{configPath}>", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!AllowedLanguage.IsAllowed(metadata.Language))
|
||||
{
|
||||
API.LogError(ClassName, $"Invalid language <{metadata.Language}> for config <{configPath}>");
|
||||
PublicApi.Instance.LogError(ClassName, $"Invalid language <{metadata.Language}> for config <{configPath}>");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!File.Exists(metadata.ExecuteFilePath))
|
||||
{
|
||||
API.LogError(ClassName, $"Execute file path didn't exist <{metadata.ExecuteFilePath}> for conifg <{configPath}");
|
||||
PublicApi.Instance.LogError(ClassName, $"Execute file path didn't exist <{metadata.ExecuteFilePath}> for conifg <{configPath}");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
|
@ -22,10 +22,6 @@ public static class PluginInstaller
|
|||
|
||||
private static readonly Settings Settings = Ioc.Default.GetRequiredService<Settings>();
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
/// <summary>
|
||||
/// Installs a plugin and restarts the application if required by settings. Prompts user for confirmation and handles download if needed.
|
||||
/// </summary>
|
||||
|
|
@ -33,18 +29,16 @@ public static class PluginInstaller
|
|||
/// <returns>A Task representing the asynchronous install operation.</returns>
|
||||
public static async Task InstallPluginAndCheckRestartAsync(UserPlugin newPlugin)
|
||||
{
|
||||
if (API.PluginModified(newPlugin.ID))
|
||||
if (PublicApi.Instance.PluginModified(newPlugin.ID))
|
||||
{
|
||||
API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), newPlugin.Name),
|
||||
API.GetTranslation("pluginModifiedAlreadyMessage"));
|
||||
PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(newPlugin.Name),
|
||||
Localize.pluginModifiedAlreadyMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (API.ShowMsgBox(
|
||||
string.Format(
|
||||
API.GetTranslation("InstallPromptSubtitle"),
|
||||
newPlugin.Name, newPlugin.Author, Environment.NewLine),
|
||||
API.GetTranslation("InstallPromptTitle"),
|
||||
if (PublicApi.Instance.ShowMsgBox(
|
||||
Localize.InstallPromptSubtitle(newPlugin.Name, newPlugin.Author, Environment.NewLine),
|
||||
Localize.InstallPromptTitle(),
|
||||
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
|
||||
|
||||
try
|
||||
|
|
@ -61,7 +55,7 @@ public static class PluginInstaller
|
|||
if (!newPlugin.IsFromLocalInstallPath)
|
||||
{
|
||||
await DownloadFileAsync(
|
||||
$"{API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}",
|
||||
$"{Localize.DownloadingPlugin()} {newPlugin.Name}",
|
||||
newPlugin.UrlDownload, filePath, cts);
|
||||
}
|
||||
else
|
||||
|
|
@ -80,7 +74,7 @@ public static class PluginInstaller
|
|||
throw new FileNotFoundException($"Plugin {newPlugin.ID} zip file not found at {filePath}", filePath);
|
||||
}
|
||||
|
||||
if (!API.InstallPlugin(newPlugin, filePath))
|
||||
if (!PublicApi.Instance.InstallPlugin(newPlugin, filePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -92,23 +86,20 @@ public static class PluginInstaller
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Failed to install plugin", e);
|
||||
API.ShowMsgError(API.GetTranslation("ErrorInstallingPlugin"));
|
||||
PublicApi.Instance.LogException(ClassName, "Failed to install plugin", e);
|
||||
PublicApi.Instance.ShowMsgError(Localize.ErrorInstallingPlugin());
|
||||
return; // do not restart on failure
|
||||
}
|
||||
|
||||
if (Settings.AutoRestartAfterChanging)
|
||||
{
|
||||
API.RestartApp();
|
||||
PublicApi.Instance.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
API.ShowMsg(
|
||||
API.GetTranslation("installbtn"),
|
||||
string.Format(
|
||||
API.GetTranslation(
|
||||
"InstallSuccessNoRestart"),
|
||||
newPlugin.Name));
|
||||
PublicApi.Instance.ShowMsg(
|
||||
Localize.installbtn(),
|
||||
Localize.InstallSuccessNoRestart(newPlugin.Name));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,24 +124,23 @@ public static class PluginInstaller
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Failed to validate zip file", e);
|
||||
API.ShowMsgError(API.GetTranslation("ZipFileNotHavePluginJson"));
|
||||
PublicApi.Instance.LogException(ClassName, "Failed to validate zip file", e);
|
||||
PublicApi.Instance.ShowMsgError(Localize.ZipFileNotHavePluginJson());
|
||||
return;
|
||||
}
|
||||
|
||||
if (API.PluginModified(plugin.ID))
|
||||
if (PublicApi.Instance.PluginModified(plugin.ID))
|
||||
{
|
||||
API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), plugin.Name),
|
||||
API.GetTranslation("pluginModifiedAlreadyMessage"));
|
||||
PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(plugin.Name),
|
||||
Localize.pluginModifiedAlreadyMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (Settings.ShowUnknownSourceWarning)
|
||||
{
|
||||
if (!InstallSourceKnown(plugin.Website)
|
||||
&& API.ShowMsgBox(string.Format(
|
||||
API.GetTranslation("InstallFromUnknownSourceSubtitle"), Environment.NewLine),
|
||||
API.GetTranslation("InstallFromUnknownSourceTitle"),
|
||||
&& PublicApi.Instance.ShowMsgBox(Localize.InstallFromUnknownSourceSubtitle(Environment.NewLine),
|
||||
Localize.InstallFromUnknownSourceTitle(),
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.No)
|
||||
return;
|
||||
}
|
||||
|
|
@ -165,51 +155,46 @@ public static class PluginInstaller
|
|||
/// <returns>A Task representing the asynchronous uninstall operation.</returns>
|
||||
public static async Task UninstallPluginAndCheckRestartAsync(PluginMetadata oldPlugin)
|
||||
{
|
||||
if (API.PluginModified(oldPlugin.ID))
|
||||
if (PublicApi.Instance.PluginModified(oldPlugin.ID))
|
||||
{
|
||||
API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), oldPlugin.Name),
|
||||
API.GetTranslation("pluginModifiedAlreadyMessage"));
|
||||
PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(oldPlugin.Name),
|
||||
Localize.pluginModifiedAlreadyMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (API.ShowMsgBox(
|
||||
string.Format(
|
||||
API.GetTranslation("UninstallPromptSubtitle"),
|
||||
oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
|
||||
API.GetTranslation("UninstallPromptTitle"),
|
||||
if (PublicApi.Instance.ShowMsgBox(
|
||||
Localize.UninstallPromptSubtitle(oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
|
||||
Localize.UninstallPromptTitle(),
|
||||
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
|
||||
|
||||
var removePluginSettings = API.ShowMsgBox(
|
||||
API.GetTranslation("KeepPluginSettingsSubtitle"),
|
||||
API.GetTranslation("KeepPluginSettingsTitle"),
|
||||
var removePluginSettings = PublicApi.Instance.ShowMsgBox(
|
||||
Localize.KeepPluginSettingsSubtitle(),
|
||||
Localize.KeepPluginSettingsTitle(),
|
||||
button: MessageBoxButton.YesNo) == MessageBoxResult.No;
|
||||
|
||||
try
|
||||
{
|
||||
if (!await API.UninstallPluginAsync(oldPlugin, removePluginSettings))
|
||||
if (!await PublicApi.Instance.UninstallPluginAsync(oldPlugin, removePluginSettings))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Failed to uninstall plugin", e);
|
||||
API.ShowMsgError(API.GetTranslation("ErrorUninstallingPlugin"));
|
||||
PublicApi.Instance.LogException(ClassName, "Failed to uninstall plugin", e);
|
||||
PublicApi.Instance.ShowMsgError(Localize.ErrorUninstallingPlugin());
|
||||
return; // don not restart on failure
|
||||
}
|
||||
|
||||
if (Settings.AutoRestartAfterChanging)
|
||||
{
|
||||
API.RestartApp();
|
||||
PublicApi.Instance.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
API.ShowMsg(
|
||||
API.GetTranslation("uninstallbtn"),
|
||||
string.Format(
|
||||
API.GetTranslation(
|
||||
"UninstallSuccessNoRestart"),
|
||||
oldPlugin.Name));
|
||||
PublicApi.Instance.ShowMsg(
|
||||
Localize.uninstallbtn(),
|
||||
Localize.UninstallSuccessNoRestart(oldPlugin.Name));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,11 +206,9 @@ public static class PluginInstaller
|
|||
/// <returns>A Task representing the asynchronous update operation.</returns>
|
||||
public static async Task UpdatePluginAndCheckRestartAsync(UserPlugin newPlugin, PluginMetadata oldPlugin)
|
||||
{
|
||||
if (API.ShowMsgBox(
|
||||
string.Format(
|
||||
API.GetTranslation("UpdatePromptSubtitle"),
|
||||
oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
|
||||
API.GetTranslation("UpdatePromptTitle"),
|
||||
if (PublicApi.Instance.ShowMsgBox(
|
||||
Localize.UpdatePromptSubtitle(oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
|
||||
Localize.UpdatePromptTitle(),
|
||||
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
|
||||
|
||||
try
|
||||
|
|
@ -237,7 +220,7 @@ public static class PluginInstaller
|
|||
if (!newPlugin.IsFromLocalInstallPath)
|
||||
{
|
||||
await DownloadFileAsync(
|
||||
$"{API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}",
|
||||
$"{Localize.DownloadingPlugin()} {newPlugin.Name}",
|
||||
newPlugin.UrlDownload, filePath, cts);
|
||||
}
|
||||
else
|
||||
|
|
@ -251,30 +234,27 @@ public static class PluginInstaller
|
|||
return;
|
||||
}
|
||||
|
||||
if (!await API.UpdatePluginAsync(oldPlugin, newPlugin, filePath))
|
||||
if (!await PublicApi.Instance.UpdatePluginAsync(oldPlugin, newPlugin, filePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Failed to update plugin", e);
|
||||
API.ShowMsgError(API.GetTranslation("ErrorUpdatingPlugin"));
|
||||
PublicApi.Instance.LogException(ClassName, "Failed to update plugin", e);
|
||||
PublicApi.Instance.ShowMsgError(Localize.ErrorUpdatingPlugin());
|
||||
return; // do not restart on failure
|
||||
}
|
||||
|
||||
if (Settings.AutoRestartAfterChanging)
|
||||
{
|
||||
API.RestartApp();
|
||||
PublicApi.Instance.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
API.ShowMsg(
|
||||
API.GetTranslation("updatebtn"),
|
||||
string.Format(
|
||||
API.GetTranslation(
|
||||
"UpdateSuccessNoRestart"),
|
||||
newPlugin.Name));
|
||||
PublicApi.Instance.ShowMsg(
|
||||
Localize.updatebtn(),
|
||||
Localize.UpdateSuccessNoRestart(newPlugin.Name));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,17 +269,17 @@ public static class PluginInstaller
|
|||
public static async Task CheckForPluginUpdatesAsync(Action<List<PluginUpdateInfo>> updateAllPlugins, bool silentUpdate = true, bool usePrimaryUrlOnly = false, CancellationToken token = default)
|
||||
{
|
||||
// Update the plugin manifest
|
||||
await API.UpdatePluginManifestAsync(usePrimaryUrlOnly, token);
|
||||
await PublicApi.Instance.UpdatePluginManifestAsync(usePrimaryUrlOnly, token);
|
||||
|
||||
// Get all plugins that can be updated
|
||||
var resultsForUpdate = (
|
||||
from existingPlugin in API.GetAllPlugins()
|
||||
join pluginUpdateSource in API.GetPluginManifest()
|
||||
from existingPlugin in PublicApi.Instance.GetAllPlugins()
|
||||
join pluginUpdateSource in PublicApi.Instance.GetPluginManifest()
|
||||
on existingPlugin.Metadata.ID equals pluginUpdateSource.ID
|
||||
where string.Compare(existingPlugin.Metadata.Version, pluginUpdateSource.Version,
|
||||
StringComparison.InvariantCulture) <
|
||||
0 // if current version precedes version of the plugin from update source (e.g. PluginsManifest)
|
||||
&& !API.PluginModified(existingPlugin.Metadata.ID)
|
||||
&& !PublicApi.Instance.PluginModified(existingPlugin.Metadata.ID)
|
||||
select
|
||||
new PluginUpdateInfo()
|
||||
{
|
||||
|
|
@ -314,25 +294,25 @@ public static class PluginInstaller
|
|||
}).ToList();
|
||||
|
||||
// No updates
|
||||
if (!resultsForUpdate.Any())
|
||||
if (resultsForUpdate.Count == 0)
|
||||
{
|
||||
if (!silentUpdate)
|
||||
{
|
||||
API.ShowMsg(API.GetTranslation("updateNoResultTitle"), API.GetTranslation("updateNoResultSubtitle"));
|
||||
PublicApi.Instance.ShowMsg(Localize.updateNoResultTitle(), Localize.updateNoResultSubtitle());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If all plugins are modified, just return
|
||||
if (resultsForUpdate.All(x => API.PluginModified(x.ID)))
|
||||
if (resultsForUpdate.All(x => PublicApi.Instance.PluginModified(x.ID)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Show message box with button to update all plugins
|
||||
API.ShowMsgWithButton(
|
||||
API.GetTranslation("updateAllPluginsTitle"),
|
||||
API.GetTranslation("updateAllPluginsButtonContent"),
|
||||
PublicApi.Instance.ShowMsgWithButton(
|
||||
Localize.updateAllPluginsTitle(),
|
||||
Localize.updateAllPluginsButtonContent(),
|
||||
() =>
|
||||
{
|
||||
updateAllPlugins(resultsForUpdate);
|
||||
|
|
@ -357,7 +337,7 @@ public static class PluginInstaller
|
|||
using var cts = new CancellationTokenSource();
|
||||
|
||||
await DownloadFileAsync(
|
||||
$"{API.GetTranslation("DownloadingPlugin")} {plugin.PluginNewUserPlugin.Name}",
|
||||
$"{Localize.DownloadingPlugin()} {plugin.PluginNewUserPlugin.Name}",
|
||||
plugin.PluginNewUserPlugin.UrlDownload, downloadToFilePath, cts);
|
||||
|
||||
// check if user cancelled download before installing plugin
|
||||
|
|
@ -366,7 +346,7 @@ public static class PluginInstaller
|
|||
return;
|
||||
}
|
||||
|
||||
if (!await API.UpdatePluginAsync(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin, downloadToFilePath))
|
||||
if (!await PublicApi.Instance.UpdatePluginAsync(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin, downloadToFilePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -375,8 +355,8 @@ public static class PluginInstaller
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Failed to update plugin", e);
|
||||
API.ShowMsgError(API.GetTranslation("ErrorUpdatingPlugin"));
|
||||
PublicApi.Instance.LogException(ClassName, "Failed to update plugin", e);
|
||||
PublicApi.Instance.ShowMsgError(Localize.ErrorUpdatingPlugin());
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
@ -384,13 +364,13 @@ public static class PluginInstaller
|
|||
|
||||
if (restart)
|
||||
{
|
||||
API.RestartApp();
|
||||
PublicApi.Instance.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
API.ShowMsg(
|
||||
API.GetTranslation("updatebtn"),
|
||||
API.GetTranslation("PluginsUpdateSuccessNoRestart"));
|
||||
PublicApi.Instance.ShowMsg(
|
||||
Localize.updatebtn(),
|
||||
Localize.PluginsUpdateSuccessNoRestart());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -412,7 +392,7 @@ public static class PluginInstaller
|
|||
if (showProgress)
|
||||
{
|
||||
var exceptionHappened = false;
|
||||
await API.ShowProgressBoxAsync(progressBoxTitle,
|
||||
await PublicApi.Instance.ShowProgressBoxAsync(progressBoxTitle,
|
||||
async (reportProgress) =>
|
||||
{
|
||||
if (reportProgress == null)
|
||||
|
|
@ -424,18 +404,18 @@ public static class PluginInstaller
|
|||
}
|
||||
else
|
||||
{
|
||||
await API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false);
|
||||
await PublicApi.Instance.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
}, cts.Cancel);
|
||||
|
||||
// if exception happened while downloading and user does not cancel downloading,
|
||||
// we need to redownload the plugin
|
||||
if (exceptionHappened && (!cts.IsCancellationRequested))
|
||||
await API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
|
||||
await PublicApi.Instance.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
|
||||
await PublicApi.Instance.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -462,7 +442,7 @@ public static class PluginInstaller
|
|||
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri) || uri.Host != acceptedHost)
|
||||
return false;
|
||||
|
||||
return API.GetAllPlugins().Any(x =>
|
||||
return PublicApi.Instance.GetAllPlugins().Any(x =>
|
||||
!string.IsNullOrEmpty(x.Metadata.Website) &&
|
||||
x.Metadata.Website.StartsWith(constructedUrlPart)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using System.Linq;
|
|||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Core.ExternalPlugins;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.DialogJump;
|
||||
|
|
@ -29,10 +28,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
public static readonly HashSet<PluginPair> GlobalPlugins = new();
|
||||
public static readonly Dictionary<string, PluginPair> NonGlobalPlugins = new();
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
private static PluginsSettings Settings;
|
||||
private static readonly ConcurrentBag<string> ModifiedPlugins = new();
|
||||
|
||||
|
|
@ -75,12 +70,12 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to save plugin {pluginPair.Metadata.Name}", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Failed to save plugin {pluginPair.Metadata.Name}", e);
|
||||
}
|
||||
}
|
||||
|
||||
API.SavePluginSettings();
|
||||
API.SavePluginCaches();
|
||||
PublicApi.Instance.SavePluginSettings();
|
||||
PublicApi.Instance.SavePluginCaches();
|
||||
}
|
||||
|
||||
public static async ValueTask DisposePluginsAsync()
|
||||
|
|
@ -107,7 +102,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to dispose plugin {pluginPair.Metadata.Name}", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Failed to dispose plugin {pluginPair.Metadata.Name}", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -218,7 +213,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
if (string.IsNullOrEmpty(metadata.AssemblyName))
|
||||
{
|
||||
API.LogWarn(ClassName, $"AssemblyName is empty for plugin with metadata: {metadata.Name}");
|
||||
PublicApi.Instance.LogWarn(ClassName, $"AssemblyName is empty for plugin with metadata: {metadata.Name}");
|
||||
continue; // Skip if AssemblyName is not set, which can happen for erroneous plugins
|
||||
}
|
||||
metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.AssemblyName);
|
||||
|
|
@ -228,7 +223,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
if (string.IsNullOrEmpty(metadata.Name))
|
||||
{
|
||||
API.LogWarn(ClassName, $"Name is empty for plugin with metadata: {metadata.Name}");
|
||||
PublicApi.Instance.LogWarn(ClassName, $"Name is empty for plugin with metadata: {metadata.Name}");
|
||||
continue; // Skip if Name is not set, which can happen for erroneous plugins
|
||||
}
|
||||
metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.Name);
|
||||
|
|
@ -249,28 +244,28 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
try
|
||||
{
|
||||
var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Init method time cost for <{pair.Metadata.Name}>",
|
||||
() => pair.Plugin.InitAsync(new PluginInitContext(pair.Metadata, API)));
|
||||
var milliseconds = await PublicApi.Instance.StopwatchLogDebugAsync(ClassName, $"Init method time cost for <{pair.Metadata.Name}>",
|
||||
() => pair.Plugin.InitAsync(new PluginInitContext(pair.Metadata, PublicApi.Instance)));
|
||||
|
||||
pair.Metadata.InitTime += milliseconds;
|
||||
API.LogInfo(ClassName,
|
||||
PublicApi.Instance.LogInfo(ClassName,
|
||||
$"Total init cost for <{pair.Metadata.Name}> is <{pair.Metadata.InitTime}ms>");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Fail to Init plugin: {pair.Metadata.Name}", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Fail to Init plugin: {pair.Metadata.Name}", e);
|
||||
if (pair.Metadata.Disabled && pair.Metadata.HomeDisabled)
|
||||
{
|
||||
// If this plugin is already disabled, do not show error message again
|
||||
// Or else it will be shown every time
|
||||
API.LogDebug(ClassName, $"Skipped init for <{pair.Metadata.Name}> due to error");
|
||||
PublicApi.Instance.LogDebug(ClassName, $"Skipped init for <{pair.Metadata.Name}> due to error");
|
||||
}
|
||||
else
|
||||
{
|
||||
pair.Metadata.Disabled = true;
|
||||
pair.Metadata.HomeDisabled = true;
|
||||
failedPlugins.Enqueue(pair);
|
||||
API.LogDebug(ClassName, $"Disable plugin <{pair.Metadata.Name}> because init failed");
|
||||
PublicApi.Instance.LogDebug(ClassName, $"Disable plugin <{pair.Metadata.Name}> because init failed");
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
|
@ -295,15 +290,12 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
}
|
||||
|
||||
if (failedPlugins.Any())
|
||||
if (!failedPlugins.IsEmpty)
|
||||
{
|
||||
var failed = string.Join(",", failedPlugins.Select(x => x.Metadata.Name));
|
||||
API.ShowMsg(
|
||||
API.GetTranslation("failedToInitializePluginsTitle"),
|
||||
string.Format(
|
||||
API.GetTranslation("failedToInitializePluginsMessage"),
|
||||
failed
|
||||
),
|
||||
PublicApi.Instance.ShowMsg(
|
||||
Localize.failedToInitializePluginsTitle(),
|
||||
Localize.failedToInitializePluginsMessage(failed),
|
||||
"",
|
||||
false
|
||||
);
|
||||
|
|
@ -326,7 +318,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
if (dialogJump && plugin.Plugin is not IAsyncDialogJump)
|
||||
return Array.Empty<PluginPair>();
|
||||
|
||||
if (API.PluginModified(plugin.Metadata.ID))
|
||||
if (PublicApi.Instance.PluginModified(plugin.Metadata.ID))
|
||||
return Array.Empty<PluginPair>();
|
||||
|
||||
return new List<PluginPair>
|
||||
|
|
@ -347,7 +339,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
try
|
||||
{
|
||||
var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
|
||||
var milliseconds = await PublicApi.Instance.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
|
||||
async () => results = await pair.Plugin.QueryAsync(query, token).ConfigureAwait(false));
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
|
@ -391,7 +383,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
try
|
||||
{
|
||||
var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
|
||||
var milliseconds = await PublicApi.Instance.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
|
||||
async () => results = await ((IAsyncHomeQuery)pair.Plugin).HomeQueryAsync(token).ConfigureAwait(false));
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
|
@ -408,7 +400,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to query home for plugin: {metadata.Name}", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Failed to query home for plugin: {metadata.Name}", e);
|
||||
return null;
|
||||
}
|
||||
return results;
|
||||
|
|
@ -421,7 +413,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
try
|
||||
{
|
||||
var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
|
||||
var milliseconds = await PublicApi.Instance.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
|
||||
async () => results = await ((IAsyncDialogJump)pair.Plugin).QueryDialogJumpAsync(query, token).ConfigureAwait(false));
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
|
@ -438,7 +430,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to query Dialog Jump for plugin: {metadata.Name}", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Failed to query Dialog Jump for plugin: {metadata.Name}", e);
|
||||
return null;
|
||||
}
|
||||
return results;
|
||||
|
|
@ -505,7 +497,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName,
|
||||
PublicApi.Instance.LogException(ClassName,
|
||||
$"Can't load context menus for plugin <{pluginPair.Metadata.Name}>",
|
||||
e);
|
||||
}
|
||||
|
|
@ -636,8 +628,8 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
if (PluginModified(existingVersion.ID))
|
||||
{
|
||||
API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), existingVersion.Name),
|
||||
API.GetTranslation("pluginModifiedAlreadyMessage"));
|
||||
PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(existingVersion.Name),
|
||||
Localize.pluginModifiedAlreadyMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -669,8 +661,8 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
if (checkModified && PluginModified(plugin.ID))
|
||||
{
|
||||
API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), plugin.Name),
|
||||
API.GetTranslation("pluginModifiedAlreadyMessage"));
|
||||
PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(plugin.Name),
|
||||
Localize.pluginModifiedAlreadyMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -689,15 +681,15 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
if (string.IsNullOrEmpty(metadataJsonFilePath) || string.IsNullOrEmpty(pluginFolderPath))
|
||||
{
|
||||
API.ShowMsgError(string.Format(API.GetTranslation("failedToInstallPluginTitle"), plugin.Name),
|
||||
string.Format(API.GetTranslation("fileNotFoundMessage"), pluginFolderPath));
|
||||
PublicApi.Instance.ShowMsgError(Localize.failedToInstallPluginTitle(plugin.Name),
|
||||
Localize.fileNotFoundMessage(pluginFolderPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SameOrLesserPluginVersionExists(metadataJsonFilePath))
|
||||
{
|
||||
API.ShowMsgError(string.Format(API.GetTranslation("failedToInstallPluginTitle"), plugin.Name),
|
||||
API.GetTranslation("pluginExistAlreadyMessage"));
|
||||
PublicApi.Instance.ShowMsgError(Localize.failedToInstallPluginTitle(plugin.Name),
|
||||
Localize.pluginExistAlreadyMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -726,7 +718,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
var newPluginPath = Path.Combine(installDirectory, folderName);
|
||||
|
||||
FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => API.ShowMsgBox(s));
|
||||
FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => PublicApi.Instance.ShowMsgBox(s));
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -735,7 +727,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to delete temp folder {tempFolderPluginPath}", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Failed to delete temp folder {tempFolderPluginPath}", e);
|
||||
}
|
||||
|
||||
if (checkModified)
|
||||
|
|
@ -750,8 +742,8 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
if (checkModified && PluginModified(plugin.ID))
|
||||
{
|
||||
API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), plugin.Name),
|
||||
API.GetTranslation("pluginModifiedAlreadyMessage"));
|
||||
PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(plugin.Name),
|
||||
Localize.pluginModifiedAlreadyMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -770,7 +762,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
if (removePluginSettings)
|
||||
{
|
||||
// For dotnet plugins, we need to remove their PluginJsonStorage and PluginBinaryStorage instances
|
||||
if (AllowedLanguage.IsDotNet(plugin.Language) && API is IRemovable removable)
|
||||
if (AllowedLanguage.IsDotNet(plugin.Language) && PublicApi.Instance is IRemovable removable)
|
||||
{
|
||||
removable.RemovePluginSettings(plugin.AssemblyName);
|
||||
removable.RemovePluginCaches(plugin.PluginCacheDirectoryPath);
|
||||
|
|
@ -784,9 +776,9 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to delete plugin settings folder for {plugin.Name}", e);
|
||||
API.ShowMsgError(API.GetTranslation("failedToRemovePluginSettingsTitle"),
|
||||
string.Format(API.GetTranslation("failedToRemovePluginSettingsMessage"), plugin.Name));
|
||||
PublicApi.Instance.LogException(ClassName, $"Failed to delete plugin settings folder for {plugin.Name}", e);
|
||||
PublicApi.Instance.ShowMsgError(Localize.failedToRemovePluginSettingsTitle(),
|
||||
Localize.failedToRemovePluginSettingsMessage(plugin.Name));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -800,9 +792,9 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to delete plugin cache folder for {plugin.Name}", e);
|
||||
API.ShowMsgError(API.GetTranslation("failedToRemovePluginCacheTitle"),
|
||||
string.Format(API.GetTranslation("failedToRemovePluginCacheMessage"), plugin.Name));
|
||||
PublicApi.Instance.LogException(ClassName, $"Failed to delete plugin cache folder for {plugin.Name}", e);
|
||||
PublicApi.Instance.ShowMsgError(Localize.failedToRemovePluginCacheTitle(),
|
||||
Localize.failedToRemovePluginCacheMessage(plugin.Name));
|
||||
}
|
||||
Settings.RemovePluginSettings(plugin.ID);
|
||||
AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID);
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Core.ExternalPlugins.Environments;
|
||||
#pragma warning disable IDE0005
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
|
|
@ -18,10 +15,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
private static readonly string ClassName = nameof(PluginsLoader);
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
public static List<PluginPair> Plugins(List<PluginMetadata> metadatas, PluginsSettings settings)
|
||||
{
|
||||
var dotnetPlugins = DotNetPlugins(metadatas);
|
||||
|
|
@ -64,7 +57,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
foreach (var metadata in metadatas)
|
||||
{
|
||||
var milliseconds = API.StopwatchLogDebug(ClassName, $"Constructor init cost for {metadata.Name}", () =>
|
||||
var milliseconds = PublicApi.Instance.StopwatchLogDebug(ClassName, $"Constructor init cost for {metadata.Name}", () =>
|
||||
{
|
||||
Assembly assembly = null;
|
||||
IAsyncPlugin plugin = null;
|
||||
|
|
@ -89,19 +82,19 @@ namespace Flow.Launcher.Core.Plugin
|
|||
#else
|
||||
catch (Exception e) when (assembly == null)
|
||||
{
|
||||
Log.Exception(ClassName, $"Couldn't load assembly for the plugin: {metadata.Name}", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Couldn't load assembly for the plugin: {metadata.Name}", e);
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
Log.Exception(ClassName, $"Can't find the required IPlugin interface for the plugin: <{metadata.Name}>", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Can't find the required IPlugin interface for the plugin: <{metadata.Name}>", e);
|
||||
}
|
||||
catch (ReflectionTypeLoadException e)
|
||||
{
|
||||
Log.Exception(ClassName, $"The GetTypes method was unable to load assembly types for the plugin: <{metadata.Name}>", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"The GetTypes method was unable to load assembly types for the plugin: <{metadata.Name}>", e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception(ClassName, $"The following plugin has errored and can not be loaded: <{metadata.Name}>", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"The following plugin has errored and can not be loaded: <{metadata.Name}>", e);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -121,12 +114,12 @@ namespace Flow.Launcher.Core.Plugin
|
|||
var errorPluginString = string.Join(Environment.NewLine, erroredPlugins);
|
||||
|
||||
var errorMessage = erroredPlugins.Count > 1 ?
|
||||
API.GetTranslation("pluginsHaveErrored") :
|
||||
API.GetTranslation("pluginHasErrored");
|
||||
Localize.pluginsHaveErrored():
|
||||
Localize.pluginHasErrored();
|
||||
|
||||
API.ShowMsgError($"{errorMessage}{Environment.NewLine}{Environment.NewLine}" +
|
||||
PublicApi.Instance.ShowMsgError($"{errorMessage}{Environment.NewLine}{Environment.NewLine}" +
|
||||
$"{errorPluginString}{Environment.NewLine}{Environment.NewLine}" +
|
||||
API.GetTranslation("referToLogs"));
|
||||
Localize.referToLogs());
|
||||
}
|
||||
|
||||
return plugins;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
|
|
@ -18,10 +17,6 @@ namespace Flow.Launcher.Core.Resource
|
|||
{
|
||||
private static readonly string ClassName = nameof(Internationalization);
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
private const string Folder = "Languages";
|
||||
private const string DefaultLanguageCode = "en";
|
||||
private const string DefaultFile = "en.xaml";
|
||||
|
|
@ -104,7 +99,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
var directory = Path.Combine(Constant.ProgramDirectory, Folder);
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
API.LogError(ClassName, $"Flow Launcher language directory can't be found <{directory}>");
|
||||
PublicApi.Instance.LogError(ClassName, $"Flow Launcher language directory can't be found <{directory}>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +170,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
FirstOrDefault(o => o.LanguageCode.Equals(languageCode, StringComparison.OrdinalIgnoreCase));
|
||||
if (language == null)
|
||||
{
|
||||
API.LogError(ClassName, $"Language code can't be found <{languageCode}>");
|
||||
PublicApi.Instance.LogError(ClassName, $"Language code can't be found <{languageCode}>");
|
||||
return AvailableLanguages.English;
|
||||
}
|
||||
else
|
||||
|
|
@ -208,7 +203,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to change language to <{language.LanguageCode}>", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Failed to change language to <{language.LanguageCode}>", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -254,7 +249,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
// "Do you want to search with pinyin?"
|
||||
string text = languageToSet == AvailableLanguages.Chinese ? "是否启用拼音搜索?" : "是否啓用拼音搜索?";
|
||||
|
||||
if (API.ShowMsgBox(text, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
|
||||
if (PublicApi.Instance.ShowMsgBox(text, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
@ -311,7 +306,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
}
|
||||
else
|
||||
{
|
||||
API.LogError(ClassName, $"Language path can't be found <{path}>");
|
||||
PublicApi.Instance.LogError(ClassName, $"Language path can't be found <{path}>");
|
||||
var english = Path.Combine(folder, DefaultFile);
|
||||
if (File.Exists(english))
|
||||
{
|
||||
|
|
@ -319,7 +314,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
}
|
||||
else
|
||||
{
|
||||
API.LogError(ClassName, $"Default English Language path can't be found <{path}>");
|
||||
PublicApi.Instance.LogError(ClassName, $"Default English Language path can't be found <{path}>");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
@ -354,7 +349,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
}
|
||||
else
|
||||
{
|
||||
API.LogError(ClassName, $"No Translation for key {key}");
|
||||
PublicApi.Instance.LogError(ClassName, $"No Translation for key {key}");
|
||||
return $"No Translation for key {key}";
|
||||
}
|
||||
}
|
||||
|
|
@ -377,7 +372,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed for <{p.Metadata.Name}>", e);
|
||||
PublicApi.Instance.LogException(ClassName, $"Failed for <{p.Metadata.Name}>", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
using System.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.Core.Resource
|
||||
{
|
||||
public class LocalizedDescriptionAttribute : DescriptionAttribute
|
||||
{
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
private readonly string _resourceKey;
|
||||
|
||||
public LocalizedDescriptionAttribute(string resourceKey)
|
||||
|
|
@ -21,7 +15,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
{
|
||||
get
|
||||
{
|
||||
string description = API.GetTranslation(_resourceKey);
|
||||
string description = PublicApi.Instance.GetTranslation(_resourceKey);
|
||||
return string.IsNullOrWhiteSpace(description) ?
|
||||
string.Format("[[{0}]]", _resourceKey) : description;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -444,7 +444,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
_api.LogError(ClassName, $"Theme <{theme}> path can't be found");
|
||||
if (theme != Constant.DefaultTheme)
|
||||
{
|
||||
_api.ShowMsgBox(string.Format(_api.GetTranslation("theme_load_failure_path_not_exists"), theme));
|
||||
_api.ShowMsgBox(Localize.theme_load_failure_path_not_exists(theme));
|
||||
ChangeTheme(Constant.DefaultTheme);
|
||||
}
|
||||
return false;
|
||||
|
|
@ -454,7 +454,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
_api.LogError(ClassName, $"Theme <{theme}> fail to parse");
|
||||
if (theme != Constant.DefaultTheme)
|
||||
{
|
||||
_api.ShowMsgBox(string.Format(_api.GetTranslation("theme_load_failure_parse_error"), theme));
|
||||
_api.ShowMsgBox(Localize.theme_load_failure_parse_error(theme));
|
||||
ChangeTheme(Constant.DefaultTheme);
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ namespace Flow.Launcher.Core
|
|||
try
|
||||
{
|
||||
if (!silentUpdate)
|
||||
_api.ShowMsg(_api.GetTranslation("pleaseWait"),
|
||||
_api.GetTranslation("update_flowlauncher_update_check"));
|
||||
_api.ShowMsg(Localize.pleaseWait(),
|
||||
Localize.update_flowlauncher_update_check());
|
||||
|
||||
using var updateManager = await GitHubUpdateManagerAsync(GitHubRepository).ConfigureAwait(false);
|
||||
|
||||
|
|
@ -58,13 +58,13 @@ namespace Flow.Launcher.Core
|
|||
if (newReleaseVersion <= currentVersion)
|
||||
{
|
||||
if (!silentUpdate)
|
||||
_api.ShowMsgBox(_api.GetTranslation("update_flowlauncher_already_on_latest"));
|
||||
_api.ShowMsgBox(Localize.update_flowlauncher_already_on_latest());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!silentUpdate)
|
||||
_api.ShowMsg(_api.GetTranslation("update_flowlauncher_update_found"),
|
||||
_api.GetTranslation("update_flowlauncher_updating"));
|
||||
_api.ShowMsg(Localize.update_flowlauncher_update_found(),
|
||||
Localize.update_flowlauncher_updating());
|
||||
|
||||
await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply).ConfigureAwait(false);
|
||||
|
||||
|
|
@ -77,10 +77,7 @@ namespace Flow.Launcher.Core
|
|||
FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination, (s) => _api.ShowMsgBox(s));
|
||||
if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination,
|
||||
(s) => _api.ShowMsgBox(s)))
|
||||
_api.ShowMsgBox(string.Format(
|
||||
_api.GetTranslation("update_flowlauncher_fail_moving_portable_user_profile_data"),
|
||||
DataLocation.PortableDataPath,
|
||||
targetDestination));
|
||||
_api.ShowMsgBox(Localize.update_flowlauncher_fail_moving_portable_user_profile_data(DataLocation.PortableDataPath, targetDestination));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -91,7 +88,7 @@ namespace Flow.Launcher.Core
|
|||
|
||||
_api.LogInfo(ClassName, $"Update success:{newVersionTips}");
|
||||
|
||||
if (_api.ShowMsgBox(newVersionTips, _api.GetTranslation("update_flowlauncher_new_update"),
|
||||
if (_api.ShowMsgBox(newVersionTips, Localize.update_flowlauncher_new_update(),
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
UpdateManager.RestartApp(Constant.ApplicationFileName);
|
||||
|
|
@ -111,8 +108,8 @@ namespace Flow.Launcher.Core
|
|||
}
|
||||
|
||||
if (!silentUpdate)
|
||||
_api.ShowMsgError(_api.GetTranslation("update_flowlauncher_fail"),
|
||||
_api.GetTranslation("update_flowlauncher_check_connection"));
|
||||
_api.ShowMsgError(Localize.update_flowlauncher_fail(),
|
||||
Localize.update_flowlauncher_check_connection());
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -150,9 +147,9 @@ namespace Flow.Launcher.Core
|
|||
return manager;
|
||||
}
|
||||
|
||||
private string NewVersionTips(string version)
|
||||
private static string NewVersionTips(string version)
|
||||
{
|
||||
var tips = string.Format(_api.GetTranslation("newVersionTips"), version);
|
||||
var tips = Localize.newVersionTips(version);
|
||||
|
||||
return tips;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@
|
|||
"YamlDotNet": "9.1.0"
|
||||
}
|
||||
},
|
||||
"Flow.Launcher.Localization": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.0.6, )",
|
||||
"resolved": "0.0.6",
|
||||
"contentHash": "WNI/TLGPDr3XdOW8gaALN0Uyz9h+bzqOaNZev2nHEuA3HW9o7XuqaM6C0PqNi96mNgxiypwWpVazBNzaylJ2Aw=="
|
||||
},
|
||||
"FSharp.Core": {
|
||||
"type": "Direct",
|
||||
"requested": "[9.0.303, )",
|
||||
|
|
@ -84,6 +90,11 @@
|
|||
"resolved": "1.1.0",
|
||||
"contentHash": "j/zGAQ9hLbl7JDpeO40DaXvyyNxwQNDwnJEN7eCexn5F9Kid+VKya/Er0rfIv5Zod/32XarkqFP/V6WFHS/UpQ=="
|
||||
},
|
||||
"ini-parser": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.5.2",
|
||||
"contentHash": "hp3gKmC/14+6eKLgv7Jd1Z7OV86lO+tNfOXr/stQbwmRhdQuXVSvrRAuAe7G5+lwhkov0XkqZ8/bn1PYWMx6eg=="
|
||||
},
|
||||
"InputSimulator": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.4",
|
||||
|
|
@ -1161,6 +1172,7 @@
|
|||
"Ben.Demystifier": "[0.4.1, )",
|
||||
"BitFaster.Caching": "[2.5.4, )",
|
||||
"CommunityToolkit.Mvvm": "[8.4.0, )",
|
||||
"Flow.Launcher.Localization": "[0.0.6, )",
|
||||
"Flow.Launcher.Plugin": "[5.0.0, )",
|
||||
"InputSimulator": "[1.0.4, )",
|
||||
"MemoryPack": "[1.21.4, )",
|
||||
|
|
@ -1170,7 +1182,8 @@
|
|||
"NLog.OutputDebugString": "[6.0.4, )",
|
||||
"SharpVectors.Wpf": "[1.8.5, )",
|
||||
"System.Drawing.Common": "[7.0.0, )",
|
||||
"ToolGood.Words.Pinyin": "[3.1.0.3, )"
|
||||
"ToolGood.Words.Pinyin": "[3.1.0.3, )",
|
||||
"ini-parser": "[2.5.2, )"
|
||||
}
|
||||
},
|
||||
"flow.launcher.plugin": {
|
||||
|
|
|
|||
|
|
@ -58,21 +58,17 @@ namespace Flow.Launcher.Infrastructure.DialogJump
|
|||
|
||||
private static readonly Settings _settings = Ioc.Default.GetRequiredService<Settings>();
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
private static HWND _mainWindowHandle = HWND.Null;
|
||||
|
||||
private static readonly Dictionary<DialogJumpExplorerPair, IDialogJumpExplorerWindow> _dialogJumpExplorers = new();
|
||||
|
||||
private static DialogJumpExplorerPair _lastExplorer = null;
|
||||
private static readonly object _lastExplorerLock = new();
|
||||
private static readonly Lock _lastExplorerLock = new();
|
||||
|
||||
private static readonly Dictionary<DialogJumpDialogPair, IDialogJumpDialogWindow> _dialogJumpDialogs = new();
|
||||
|
||||
private static IDialogJumpDialogWindow _dialogWindow = null;
|
||||
private static readonly object _dialogWindowLock = new();
|
||||
private static readonly Lock _dialogWindowLock = new();
|
||||
|
||||
private static HWINEVENTHOOK _foregroundChangeHook = HWINEVENTHOOK.Null;
|
||||
private static HWINEVENTHOOK _locationChangeHook = HWINEVENTHOOK.Null;
|
||||
|
|
@ -89,8 +85,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
|
|||
private static DispatcherTimer _dragMoveTimer = null;
|
||||
|
||||
// A list of all file dialog windows that are auto switched already
|
||||
private static readonly List<HWND> _autoSwitchedDialogs = new();
|
||||
private static readonly object _autoSwitchedDialogsLock = new();
|
||||
private static readonly List<HWND> _autoSwitchedDialogs = [];
|
||||
private static readonly Lock _autoSwitchedDialogsLock = new();
|
||||
|
||||
private static HWINEVENTHOOK _moveSizeHook = HWINEVENTHOOK.Null;
|
||||
private static readonly WINEVENTPROC _moveProc = MoveSizeCallBack;
|
||||
|
|
@ -315,7 +311,7 @@ namespace Flow.Launcher.Infrastructure.DialogJump
|
|||
{
|
||||
foreach (var explorer in _dialogJumpExplorers.Keys)
|
||||
{
|
||||
if (API.PluginModified(explorer.Metadata.ID) || // Plugin is modified
|
||||
if (PublicApi.Instance.PluginModified(explorer.Metadata.ID) || // Plugin is modified
|
||||
explorer.Metadata.Disabled) continue; // Plugin is disabled
|
||||
|
||||
var explorerWindow = explorer.Plugin.CheckExplorerWindow(hWnd);
|
||||
|
|
@ -493,7 +489,7 @@ namespace Flow.Launcher.Infrastructure.DialogJump
|
|||
var dialogWindowChanged = false;
|
||||
foreach (var dialog in _dialogJumpDialogs.Keys)
|
||||
{
|
||||
if (API.PluginModified(dialog.Metadata.ID) || // Plugin is modified
|
||||
if (PublicApi.Instance.PluginModified(dialog.Metadata.ID) || // Plugin is modified
|
||||
dialog.Metadata.Disabled) continue; // Plugin is disabled
|
||||
|
||||
IDialogJumpDialogWindow dialogWindow;
|
||||
|
|
@ -596,7 +592,7 @@ namespace Flow.Launcher.Infrastructure.DialogJump
|
|||
{
|
||||
foreach (var explorer in _dialogJumpExplorers.Keys)
|
||||
{
|
||||
if (API.PluginModified(explorer.Metadata.ID) || // Plugin is modified
|
||||
if (PublicApi.Instance.PluginModified(explorer.Metadata.ID) || // Plugin is modified
|
||||
explorer.Metadata.Disabled) continue; // Plugin is disabled
|
||||
|
||||
var explorerWindow = explorer.Plugin.CheckExplorerWindow(hwnd);
|
||||
|
|
@ -871,7 +867,7 @@ namespace Flow.Launcher.Infrastructure.DialogJump
|
|||
// Then check all dialog windows
|
||||
foreach (var dialog in _dialogJumpDialogs.Keys)
|
||||
{
|
||||
if (API.PluginModified(dialog.Metadata.ID) || // Plugin is modified
|
||||
if (PublicApi.Instance.PluginModified(dialog.Metadata.ID) || // Plugin is modified
|
||||
dialog.Metadata.Disabled) continue; // Plugin is disabled
|
||||
|
||||
var dialogWindow = _dialogJumpDialogs[dialog];
|
||||
|
|
@ -884,7 +880,7 @@ namespace Flow.Launcher.Infrastructure.DialogJump
|
|||
// Finally search for the dialog window again
|
||||
foreach (var dialog in _dialogJumpDialogs.Keys)
|
||||
{
|
||||
if (API.PluginModified(dialog.Metadata.ID) || // Plugin is modified
|
||||
if (PublicApi.Instance.PluginModified(dialog.Metadata.ID) || // Plugin is modified
|
||||
dialog.Metadata.Disabled) continue; // Plugin is disabled
|
||||
|
||||
IDialogJumpDialogWindow dialogWindow;
|
||||
|
|
@ -1067,11 +1063,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
|
|||
_navigationLock.Dispose();
|
||||
|
||||
// Stop drag move timer
|
||||
if (_dragMoveTimer != null)
|
||||
{
|
||||
_dragMoveTimer.Stop();
|
||||
_dragMoveTimer = null;
|
||||
}
|
||||
_dragMoveTimer?.Stop();
|
||||
_dragMoveTimer = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<NoWarn>$(NoWarn);FLSG0007</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -56,10 +57,12 @@
|
|||
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
||||
<PackageReference Include="BitFaster.Caching" Version="2.5.4" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
|
||||
<PackageReference Include="Fody" Version="6.9.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ini-parser" Version="2.5.2" />
|
||||
<PackageReference Include="InputSimulator" Version="1.0.4" />
|
||||
<PackageReference Include="MemoryPack" Version="1.21.4" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.14.15" />
|
||||
|
|
@ -80,4 +83,15 @@
|
|||
<PackageReference Include="ToolGood.Words.Pinyin" Version="3.1.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<FLLUseDependencyInjection>true</FLLUseDependencyInjection>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Remove="Languages\en.xaml" />
|
||||
<AdditionalFiles Include="..\Flow.Launcher\Languages\en.xaml">
|
||||
<Link>Languages\en.xaml</Link>
|
||||
</AdditionalFiles>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -4,10 +4,8 @@ using System.Net;
|
|||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.Http
|
||||
|
|
@ -20,10 +18,6 @@ namespace Flow.Launcher.Infrastructure.Http
|
|||
|
||||
private static readonly HttpClient client = new();
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
static Http()
|
||||
{
|
||||
// need to be added so it would work on a win10 machine
|
||||
|
|
@ -82,7 +76,7 @@ namespace Flow.Launcher.Infrastructure.Http
|
|||
}
|
||||
catch (UriFormatException e)
|
||||
{
|
||||
API.ShowMsgError(API.GetTranslation("pleaseTryAgain"), API.GetTranslation("parseProxyFailed"));
|
||||
PublicApi.Instance.ShowMsgError(Localize.pleaseTryAgain(), Localize.parseProxyFailed());
|
||||
Log.Exception(ClassName, "Unable to parse Uri", e);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media.Imaging;
|
||||
using IniParser;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.Graphics.Gdi;
|
||||
using Windows.Win32.UI.Shell;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.Image
|
||||
{
|
||||
|
|
@ -35,9 +36,32 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
|
||||
private static readonly HRESULT S_PATHNOTFOUND = (HRESULT)0x8004B205;
|
||||
|
||||
private const string UrlExtension = ".url";
|
||||
|
||||
/// <summary>
|
||||
/// Obtains a BitmapSource thumbnail for the specified file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the file is a Windows URL shortcut (".url"), the method attempts to resolve the shortcut's icon and use that for the thumbnail; otherwise it requests a thumbnail for the file path. The native HBITMAP used to create the BitmapSource is always released to avoid native memory leaks.
|
||||
/// </remarks>
|
||||
/// <param name="fileName">Path to the file (can be a regular file or a ".url" shortcut).</param>
|
||||
/// <param name="width">Requested thumbnail width in pixels.</param>
|
||||
/// <param name="height">Requested thumbnail height in pixels.</param>
|
||||
/// <param name="options">Thumbnail extraction options (flags) controlling fallback and caching behavior.</param>
|
||||
/// <returns>A BitmapSource representing the requested thumbnail.</returns>
|
||||
public static BitmapSource GetThumbnail(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
HBITMAP hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
|
||||
HBITMAP hBitmap;
|
||||
|
||||
var extension = Path.GetExtension(fileName);
|
||||
if (string.Equals(extension, UrlExtension, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
hBitmap = GetHBitmapForUrlFile(fileName, width, height, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -50,6 +74,21 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains a native HBITMAP for the specified file at the requested size using the Windows Shell image factory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If <paramref name="options"/> is <see cref="ThumbnailOptions.ThumbnailOnly"/> and thumbnail extraction fails
|
||||
/// due to extraction errors or a missing path, the method falls back to requesting an icon (<see cref="ThumbnailOptions.IconOnly"/>).
|
||||
/// The returned HBITMAP is a raw GDI handle; the caller is responsible for releasing it (e.g., via DeleteObject) to avoid native memory leaks.
|
||||
/// </remarks>
|
||||
/// <param name="fileName">Path to the file to thumbnail.</param>
|
||||
/// <param name="width">Requested thumbnail width in pixels.</param>
|
||||
/// <param name="height">Requested thumbnail height in pixels.</param>
|
||||
/// <param name="options">Thumbnail request flags that control behavior (e.g., ThumbnailOnly, IconOnly).</param>
|
||||
/// <returns>An HBITMAP handle containing the image. Caller must free the handle when finished.</returns>
|
||||
/// <exception cref="COMException">If creating the shell item fails (HRESULT returned by SHCreateItemFromParsingName).</exception>
|
||||
/// <exception cref="InvalidOperationException">If the shell item does not expose IShellItemImageFactory or if an unexpected error occurs while obtaining the image.</exception>
|
||||
private static unsafe HBITMAP GetHBitmap(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
var retCode = PInvoke.SHCreateItemFromParsingName(
|
||||
|
|
@ -108,5 +147,44 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains an HBITMAP for a Windows .url shortcut by resolving its IconFile entry and delegating to GetHBitmap.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The method parses the .url file as an INI, looks in the "InternetShortcut" section for the "IconFile" entry,
|
||||
/// and requests a bitmap for that icon path. If no IconFile is present or any error occurs while reading or
|
||||
/// resolving the icon, it falls back to requesting a thumbnail for the .url file itself.
|
||||
/// </remarks>
|
||||
/// <param name="fileName">Path to the .url shortcut file.</param>
|
||||
/// <param name="width">Requested thumbnail width (pixels).</param>
|
||||
/// <param name="height">Requested thumbnail height (pixels).</param>
|
||||
/// <param name="options">ThumbnailOptions flags controlling extraction behavior.</param>
|
||||
/// <returns>An HBITMAP containing the requested image; callers are responsible for freeing the native handle.</returns>
|
||||
private static unsafe HBITMAP GetHBitmapForUrlFile(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
HBITMAP hBitmap;
|
||||
|
||||
try
|
||||
{
|
||||
var parser = new FileIniDataParser();
|
||||
var data = parser.ReadFile(fileName);
|
||||
var urlSection = data["InternetShortcut"];
|
||||
|
||||
var iconPath = urlSection?["IconFile"];
|
||||
if (!File.Exists(iconPath))
|
||||
{
|
||||
// If the IconFile is missing, throw exception to fallback to the default icon
|
||||
throw new FileNotFoundException("Icon file not specified in Internet shortcut (.url) file.");
|
||||
}
|
||||
hBitmap = GetHBitmap(Path.GetFullPath(iconPath), width, height, options);
|
||||
}
|
||||
catch
|
||||
{
|
||||
hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
|
||||
}
|
||||
|
||||
return hBitmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,13 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.UserSettings
|
||||
{
|
||||
public class CustomBrowserViewModel : BaseModel
|
||||
{
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
public string Name { get; set; }
|
||||
[JsonIgnore]
|
||||
public string DisplayName => Name == "Default" ? API.GetTranslation("defaultBrowser_default") : Name;
|
||||
public string DisplayName => Name == "Default" ? Localize.defaultBrowser_default() : Name;
|
||||
public string Path { get; set; }
|
||||
public string PrivateArg { get; set; }
|
||||
public bool EnablePrivate { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,18 +1,13 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.UserSettings
|
||||
{
|
||||
public class CustomExplorerViewModel : BaseModel
|
||||
{
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
public string Name { get; set; }
|
||||
[JsonIgnore]
|
||||
public string DisplayName => Name == "Explorer" ? API.GetTranslation("fileManagerExplorer") : Name;
|
||||
public string DisplayName => Name == "Explorer" ? Localize.fileManagerExplorer() : Name;
|
||||
public string Path { get; set; }
|
||||
public string FileArgument { get; set; } = "\"%d\"";
|
||||
public string DirectoryArgument { get; set; } = "\"%d\"";
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.UserSettings
|
||||
{
|
||||
|
|
@ -55,11 +53,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
{
|
||||
public string Description { get; set; }
|
||||
|
||||
public string LocalizedDescription => API.GetTranslation(Description);
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
public string LocalizedDescription => PublicApi.Instance.GetTranslation(Description);
|
||||
|
||||
public BaseBuiltinShortcutModel(string key, string description)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,12 +23,24 @@
|
|||
"resolved": "8.4.0",
|
||||
"contentHash": "tqVU8yc/ADO9oiTRyTnwhFN68hCwvkliMierptWOudIAvWY1mWCh5VFh+guwHJmpMwfg0J0rY+yyd5Oy7ty9Uw=="
|
||||
},
|
||||
"Flow.Launcher.Localization": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.0.6, )",
|
||||
"resolved": "0.0.6",
|
||||
"contentHash": "WNI/TLGPDr3XdOW8gaALN0Uyz9h+bzqOaNZev2nHEuA3HW9o7XuqaM6C0PqNi96mNgxiypwWpVazBNzaylJ2Aw=="
|
||||
},
|
||||
"Fody": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.9.3, )",
|
||||
"resolved": "6.9.3",
|
||||
"contentHash": "1CUGgFdyECDKgi5HaUBhdv6k+VG9Iy4OCforGfHyar3xQXAJypZkzymgKtWj/4SPd6nSG0Qi7NH71qHrDSZLaA=="
|
||||
},
|
||||
"ini-parser": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.5.2, )",
|
||||
"resolved": "2.5.2",
|
||||
"contentHash": "hp3gKmC/14+6eKLgv7Jd1Z7OV86lO+tNfOXr/stQbwmRhdQuXVSvrRAuAe7G5+lwhkov0XkqZ8/bn1PYWMx6eg=="
|
||||
},
|
||||
"InputSimulator": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.0.4, )",
|
||||
|
|
|
|||
|
|
@ -150,6 +150,16 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
return File.Exists(filePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a file or directory exists
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static bool FileOrLocationExists(this string path)
|
||||
{
|
||||
return LocationExists(path) || FileExists(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open a directory window (using the OS's default handler, usually explorer)
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ namespace Flow.Launcher
|
|||
|
||||
if (addedActionKeywords.Any(App.API.ActionKeywordAssigned))
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("newActionKeywordsHasBeenAssigned"));
|
||||
App.API.ShowMsgBox(Localize.newActionKeywordsHasBeenAssigned());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ namespace Flow.Launcher
|
|||
if (sortedOldActionKeywords.SequenceEqual(sortedNewActionKeywords))
|
||||
{
|
||||
// User just changes the sequence of action keywords
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("newActionKeywordsSameAsOld"));
|
||||
App.API.ShowMsgBox(Localize.newActionKeywordsSameAsOld());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ namespace Flow.Launcher
|
|||
// but if it fails (permissions, etc) then don't keep retrying
|
||||
// this also gives the user a visual indication in the Settings widget
|
||||
_settings.StartFlowLauncherOnSystemStartup = false;
|
||||
API.ShowMsgError(API.GetTranslation("setAutoStartFailed"), e.Message);
|
||||
API.ShowMsgError(Localize.setAutoStartFailed(), e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace Flow.Launcher
|
|||
|
||||
if (string.IsNullOrEmpty(Hotkey) && string.IsNullOrEmpty(ActionKeyword))
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("emptyPluginHotkey"));
|
||||
App.API.ShowMsgBox(Localize.emptyPluginHotkey());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,14 +40,14 @@ namespace Flow.Launcher
|
|||
{
|
||||
if (string.IsNullOrEmpty(Key) || string.IsNullOrEmpty(Value))
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("emptyShortcut"));
|
||||
App.API.ShowMsgBox(Localize.emptyShortcut());
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if key is modified or adding a new one
|
||||
if (((update && originalKey != Key) || !update) && _hotkeyVm.DoesShortcutExist(Key))
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("duplicateShortcut"));
|
||||
App.API.ShowMsgBox(Localize.duplicateShortcut());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,14 +37,53 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<NoWarn>$(NoWarn);FLSG0007</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="RemoveUnnecessaryRuntimesAfterBuild" AfterTargets="Build">
|
||||
<RemoveDir Directories="$(OutputPath)runtimes\browser-wasm;
 $(OutputPath)runtimes\linux-arm;
 $(OutputPath)runtimes\linux-arm64;
 $(OutputPath)runtimes\linux-armel;
 $(OutputPath)runtimes\linux-mips64;
 $(OutputPath)runtimes\linux-musl-arm;
 $(OutputPath)runtimes\linux-musl-arm64;
 $(OutputPath)runtimes\linux-musl-x64;
 $(OutputPath)runtimes\linux-musl-s390x;
 $(OutputPath)runtimes\linux-ppc64le;
 $(OutputPath)runtimes\linux-s390x;
 $(OutputPath)runtimes\linux-x64;
 $(OutputPath)runtimes\linux-x86;
 $(OutputPath)runtimes\maccatalyst-arm64;
 $(OutputPath)runtimes\maccatalyst-x64;
 $(OutputPath)runtimes\osx;
 $(OutputPath)runtimes\osx-arm64;
 $(OutputPath)runtimes\osx-x64;
 $(OutputPath)runtimes\win-arm;
 $(OutputPath)runtimes\win-arm64;" />
|
||||
<RemoveDir Directories="$(OutputPath)runtimes\browser-wasm;
|
||||
$(OutputPath)runtimes\linux-arm;
|
||||
$(OutputPath)runtimes\linux-arm64;
|
||||
$(OutputPath)runtimes\linux-armel;
|
||||
$(OutputPath)runtimes\linux-mips64;
|
||||
$(OutputPath)runtimes\linux-musl-arm;
|
||||
$(OutputPath)runtimes\linux-musl-arm64;
|
||||
$(OutputPath)runtimes\linux-musl-x64;
|
||||
$(OutputPath)runtimes\linux-musl-s390x;
|
||||
$(OutputPath)runtimes\linux-ppc64le;
|
||||
$(OutputPath)runtimes\linux-s390x;
|
||||
$(OutputPath)runtimes\linux-x64;
|
||||
$(OutputPath)runtimes\linux-x86;
|
||||
$(OutputPath)runtimes\maccatalyst-arm64;
|
||||
$(OutputPath)runtimes\maccatalyst-x64;
|
||||
$(OutputPath)runtimes\osx;
|
||||
$(OutputPath)runtimes\osx-arm64;
|
||||
$(OutputPath)runtimes\osx-x64;
|
||||
$(OutputPath)runtimes\win-arm;
|
||||
$(OutputPath)runtimes\win-arm64;"/>
|
||||
</Target>
|
||||
|
||||
<Target Name="RemoveUnnecessaryRuntimesAfterPublish" AfterTargets="Publish">
|
||||
<RemoveDir Directories="$(PublishDir)runtimes\browser-wasm;
 $(PublishDir)runtimes\linux-arm;
 $(PublishDir)runtimes\linux-arm64;
 $(PublishDir)runtimes\linux-armel;
 $(PublishDir)runtimes\linux-mips64;
 $(PublishDir)runtimes\linux-musl-arm;
 $(PublishDir)runtimes\linux-musl-arm64;
 $(PublishDir)runtimes\linux-musl-x64;
 $(PublishDir)runtimes\linux-musl-s390x;
 $(PublishDir)runtimes\linux-ppc64le;
 $(PublishDir)runtimes\linux-s390x;
 $(PublishDir)runtimes\linux-x64;
 $(PublishDir)runtimes\linux-x86;
 $(PublishDir)runtimes\maccatalyst-arm64;
 $(PublishDir)runtimes\maccatalyst-x64;
 $(PublishDir)runtimes\osx;
 $(PublishDir)runtimes\osx-arm64;
 $(PublishDir)runtimes\osx-x64;
 $(PublishDir)runtimes\win-arm;
 $(PublishDir)runtimes\win-arm64;" />
|
||||
<RemoveDir Directories="$(PublishDir)runtimes\browser-wasm;
|
||||
$(PublishDir)runtimes\linux-arm;
|
||||
$(PublishDir)runtimes\linux-arm64;
|
||||
$(PublishDir)runtimes\linux-armel;
|
||||
$(PublishDir)runtimes\linux-mips64;
|
||||
$(PublishDir)runtimes\linux-musl-arm;
|
||||
$(PublishDir)runtimes\linux-musl-arm64;
|
||||
$(PublishDir)runtimes\linux-musl-x64;
|
||||
$(PublishDir)runtimes\linux-musl-s390x;
|
||||
$(PublishDir)runtimes\linux-ppc64le;
|
||||
$(PublishDir)runtimes\linux-s390x;
|
||||
$(PublishDir)runtimes\linux-x64;
|
||||
$(PublishDir)runtimes\linux-x86;
|
||||
$(PublishDir)runtimes\maccatalyst-arm64;
|
||||
$(PublishDir)runtimes\maccatalyst-x64;
|
||||
$(PublishDir)runtimes\osx;
|
||||
$(PublishDir)runtimes\osx-arm64;
|
||||
$(PublishDir)runtimes\osx-x64;
|
||||
$(PublishDir)runtimes\win-arm;
|
||||
$(PublishDir)runtimes\win-arm64;"/>
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -94,6 +133,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="ChefKeys" Version="0.1.2" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
|
||||
<PackageReference Include="Fody" Version="6.9.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
|
@ -123,6 +163,10 @@
|
|||
<ProjectReference Include="..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<FLLUseDependencyInjection>true</FLLUseDependencyInjection>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Resources\open.wav">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ internal static class HotKeyMapper
|
|||
string.Format("|HotkeyMapper.SetWithChefKeys|Error registering hotkey: {0} \nStackTrace:{1}",
|
||||
e.Message,
|
||||
e.StackTrace));
|
||||
string errorMsg = string.Format(App.API.GetTranslation("registerHotkeyFailed"), hotkeyStr);
|
||||
string errorMsgTitle = App.API.GetTranslation("MessageBoxTitle");
|
||||
string errorMsg = Localize.registerHotkeyFailed(hotkeyStr);
|
||||
string errorMsgTitle = Localize.MessageBoxTitle();
|
||||
App.API.ShowMsgBox(errorMsg, errorMsgTitle);
|
||||
}
|
||||
}
|
||||
|
|
@ -87,8 +87,8 @@ internal static class HotKeyMapper
|
|||
e.Message,
|
||||
e.StackTrace,
|
||||
hotkeyStr));
|
||||
string errorMsg = string.Format(App.API.GetTranslation("registerHotkeyFailed"), hotkeyStr);
|
||||
string errorMsgTitle = App.API.GetTranslation("MessageBoxTitle");
|
||||
string errorMsg = Localize.registerHotkeyFailed(hotkeyStr);
|
||||
string errorMsgTitle = Localize.MessageBoxTitle();
|
||||
App.API.ShowMsgBox(errorMsg, errorMsgTitle);
|
||||
}
|
||||
}
|
||||
|
|
@ -112,8 +112,8 @@ internal static class HotKeyMapper
|
|||
string.Format("|HotkeyMapper.RemoveHotkey|Error removing hotkey: {0} \nStackTrace:{1}",
|
||||
e.Message,
|
||||
e.StackTrace));
|
||||
string errorMsg = string.Format(App.API.GetTranslation("unregisterHotkeyFailed"), hotkeyStr);
|
||||
string errorMsgTitle = App.API.GetTranslation("MessageBoxTitle");
|
||||
string errorMsg = Localize.unregisterHotkeyFailed(hotkeyStr);
|
||||
string errorMsgTitle = Localize.MessageBoxTitle();
|
||||
App.API.ShowMsgBox(errorMsg, errorMsgTitle);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.ObjectModel;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
|
@ -234,7 +234,7 @@ namespace Flow.Launcher
|
|||
private static bool CheckHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture) =>
|
||||
hotkey.Validate(validateKeyGesture) && HotKeyMapper.CheckAvailability(hotkey);
|
||||
|
||||
public string EmptyHotkey => App.API.GetTranslation("none");
|
||||
public string EmptyHotkey => Localize.none();
|
||||
|
||||
public ObservableCollection<string> KeysToDisplay { get; set; } = new();
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public partial class HotkeyControlDialog : ContentDialog
|
|||
|
||||
public EResultType ResultType { get; private set; } = EResultType.Cancel;
|
||||
public string ResultValue { get; private set; } = string.Empty;
|
||||
public static string EmptyHotkey => App.API.GetTranslation("none");
|
||||
public static string EmptyHotkey => Localize.none();
|
||||
|
||||
private static bool isOpenFlowHotkey;
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ public partial class HotkeyControlDialog : ContentDialog
|
|||
{
|
||||
WindowTitle = windowTitle switch
|
||||
{
|
||||
"" or null => App.API.GetTranslation("hotkeyRegTitle"),
|
||||
"" or null => Localize.hotkeyRegTitle(),
|
||||
_ => windowTitle
|
||||
};
|
||||
DefaultHotkey = defaultHotkey;
|
||||
|
|
@ -146,10 +146,7 @@ public partial class HotkeyControlDialog : ContentDialog
|
|||
Alert.Visibility = Visibility.Visible;
|
||||
if (registeredHotkeyData.RemoveHotkey is not null)
|
||||
{
|
||||
tbMsg.Text = string.Format(
|
||||
App.API.GetTranslation("hotkeyUnavailableEditable"),
|
||||
description
|
||||
);
|
||||
tbMsg.Text = Localize.hotkeyUnavailableEditable(description);
|
||||
SaveBtn.IsEnabled = false;
|
||||
SaveBtn.Visibility = Visibility.Collapsed;
|
||||
OverwriteBtn.IsEnabled = true;
|
||||
|
|
@ -158,10 +155,7 @@ public partial class HotkeyControlDialog : ContentDialog
|
|||
}
|
||||
else
|
||||
{
|
||||
tbMsg.Text = string.Format(
|
||||
App.API.GetTranslation("hotkeyUnavailableUneditable"),
|
||||
description
|
||||
);
|
||||
tbMsg.Text = Localize.hotkeyUnavailableUneditable(description);
|
||||
SaveBtn.IsEnabled = false;
|
||||
SaveBtn.Visibility = Visibility.Visible;
|
||||
OverwriteBtn.IsEnabled = false;
|
||||
|
|
@ -175,7 +169,7 @@ public partial class HotkeyControlDialog : ContentDialog
|
|||
|
||||
if (!CheckHotkeyAvailability(hotkey.Value, true))
|
||||
{
|
||||
tbMsg.Text = App.API.GetTranslation("hotkeyUnavailable");
|
||||
tbMsg.Text = Localize.hotkeyUnavailable();
|
||||
Alert.Visibility = Visibility.Visible;
|
||||
SaveBtn.IsEnabled = false;
|
||||
SaveBtn.Visibility = Visibility.Visible;
|
||||
|
|
|
|||
|
|
@ -209,6 +209,8 @@
|
|||
<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_uninstall">Uninstall</system:String>
|
||||
<system:String x:Key="plugin_default_search_delay_time">Search delay time: default</system:String>
|
||||
<system:String x:Key="plugin_search_delay_time">Search delay time: {0}ms</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>
|
||||
<system:String x:Key="failedToRemovePluginCacheTitle">Fail to remove plugin cache</system:String>
|
||||
|
|
@ -588,8 +590,9 @@
|
|||
The specified file manager could not be found. Please check the Custom File Manager setting under Settings > General.
|
||||
</system:String>
|
||||
<system:String x:Key="errorTitle">Error</system:String>
|
||||
<system:String x:Key="folderOpenError">An error occurred while opening the folder. {0}</system:String>
|
||||
<system:String x:Key="folderOpenError">An error occurred while opening the folder.</system:String>
|
||||
<system:String x:Key="browserOpenError">An error occurred while opening the URL in the browser. Please check your Default Web Browser configuration in the General section of the settings window</system:String>
|
||||
<system:String x:Key="fileNotFoundError">File or directory not found: {0}</system:String>
|
||||
|
||||
<!-- General Notice -->
|
||||
<system:String x:Key="pleaseWait">Please wait...</system:String>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Media;
|
||||
|
|
@ -145,8 +145,8 @@ namespace Flow.Launcher
|
|||
_settings.ReleaseNotesVersion = Constant.Version;
|
||||
// Show release note popup with button
|
||||
App.API.ShowMsgWithButton(
|
||||
string.Format(App.API.GetTranslation("appUpdateTitle"), Constant.Version),
|
||||
App.API.GetTranslation("appUpdateButtonContent"),
|
||||
Localize.appUpdateTitle(Constant.Version),
|
||||
Localize.appUpdateButtonContent(),
|
||||
() =>
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
|
|
@ -753,12 +753,12 @@ namespace Flow.Launcher
|
|||
private void UpdateNotifyIconText()
|
||||
{
|
||||
var menu = _contextMenu;
|
||||
((MenuItem)menu.Items[0]).Header = App.API.GetTranslation("iconTrayOpen") +
|
||||
((MenuItem)menu.Items[0]).Header = Localize.iconTrayOpen() +
|
||||
" (" + _settings.Hotkey + ")";
|
||||
((MenuItem)menu.Items[1]).Header = App.API.GetTranslation("GameMode");
|
||||
((MenuItem)menu.Items[2]).Header = App.API.GetTranslation("PositionReset");
|
||||
((MenuItem)menu.Items[3]).Header = App.API.GetTranslation("iconTraySettings");
|
||||
((MenuItem)menu.Items[4]).Header = App.API.GetTranslation("iconTrayExit");
|
||||
((MenuItem)menu.Items[1]).Header = Localize.GameMode();
|
||||
((MenuItem)menu.Items[2]).Header = Localize.PositionReset();
|
||||
((MenuItem)menu.Items[3]).Header = Localize.iconTraySettings();
|
||||
((MenuItem)menu.Items[4]).Header = Localize.iconTrayExit();
|
||||
}
|
||||
|
||||
private void InitializeContextMenu()
|
||||
|
|
@ -768,31 +768,31 @@ namespace Flow.Launcher
|
|||
var openIcon = new FontIcon { Glyph = "\ue71e" };
|
||||
var open = new MenuItem
|
||||
{
|
||||
Header = App.API.GetTranslation("iconTrayOpen") + " (" + _settings.Hotkey + ")",
|
||||
Header = Localize.iconTrayOpen() + " (" + _settings.Hotkey + ")",
|
||||
Icon = openIcon
|
||||
};
|
||||
var gamemodeIcon = new FontIcon { Glyph = "\ue7fc" };
|
||||
var gamemode = new MenuItem
|
||||
{
|
||||
Header = App.API.GetTranslation("GameMode"),
|
||||
Header = Localize.GameMode(),
|
||||
Icon = gamemodeIcon
|
||||
};
|
||||
var positionresetIcon = new FontIcon { Glyph = "\ue73f" };
|
||||
var positionreset = new MenuItem
|
||||
{
|
||||
Header = App.API.GetTranslation("PositionReset"),
|
||||
Header = Localize.PositionReset(),
|
||||
Icon = positionresetIcon
|
||||
};
|
||||
var settingsIcon = new FontIcon { Glyph = "\ue713" };
|
||||
var settings = new MenuItem
|
||||
{
|
||||
Header = App.API.GetTranslation("iconTraySettings"),
|
||||
Header = Localize.iconTraySettings(),
|
||||
Icon = settingsIcon
|
||||
};
|
||||
var exitIcon = new FontIcon { Glyph = "\ue7e8" };
|
||||
var exit = new MenuItem
|
||||
{
|
||||
Header = App.API.GetTranslation("iconTrayExit"),
|
||||
Header = Localize.iconTrayExit(),
|
||||
Icon = exitIcon
|
||||
};
|
||||
|
||||
|
|
@ -802,8 +802,8 @@ namespace Flow.Launcher
|
|||
settings.Click += (o, e) => App.API.OpenSettingDialog();
|
||||
exit.Click += (o, e) => Close();
|
||||
|
||||
gamemode.ToolTip = App.API.GetTranslation("GameModeToolTip");
|
||||
positionreset.ToolTip = App.API.GetTranslation("PositionResetToolTip");
|
||||
gamemode.ToolTip = Localize.GameModeToolTip();
|
||||
positionreset.ToolTip = Localize.PositionResetToolTip();
|
||||
|
||||
_contextMenu.Items.Add(open);
|
||||
_contextMenu.Items.Add(gamemode);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Flow.Launcher
|
|||
{
|
||||
var checkBox = new CheckBox
|
||||
{
|
||||
Content = string.Format(App.API.GetTranslation("updatePluginCheckboxContent"), plugin.Name, plugin.CurrentVersion, plugin.NewVersion),
|
||||
Content = Localize.updatePluginCheckboxContent(plugin.Name, plugin.CurrentVersion, plugin.NewVersion),
|
||||
IsChecked = true,
|
||||
Margin = new Thickness(0, 5, 0, 5),
|
||||
Tag = plugin,
|
||||
|
|
@ -50,10 +50,7 @@ namespace Flow.Launcher
|
|||
{
|
||||
if (sender is not CheckBox cb) return;
|
||||
if (cb.Tag is not PluginUpdateInfo plugin) return;
|
||||
if (Plugins.Contains(plugin))
|
||||
{
|
||||
Plugins.Remove(plugin);
|
||||
}
|
||||
Plugins.Remove(plugin);
|
||||
}
|
||||
|
||||
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
|
||||
|
|
@ -66,7 +63,7 @@ namespace Flow.Launcher
|
|||
{
|
||||
if (Plugins.Count == 0)
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("updatePluginNoSelected"));
|
||||
App.API.ShowMsgBox(Localize.updatePluginNoSelected());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
|
|
@ -74,7 +74,6 @@ namespace Flow.Launcher
|
|||
_mainVM.ChangeQueryText(query, requery);
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "<Pending>")]
|
||||
public void RestartApp()
|
||||
{
|
||||
_mainVM.Hide();
|
||||
|
|
@ -179,20 +178,20 @@ namespace Flow.Launcher
|
|||
|
||||
Clipboard.SetFileDropList(paths);
|
||||
});
|
||||
|
||||
|
||||
if (exception == null)
|
||||
{
|
||||
if (showDefaultNotification)
|
||||
{
|
||||
ShowMsg(
|
||||
$"{GetTranslation("copy")} {(isFile ? GetTranslation("fileTitle") : GetTranslation("folderTitle"))}",
|
||||
GetTranslation("completedSuccessfully"));
|
||||
$"{Localize.copy()} {(isFile ? Localize.fileTitle(): Localize.folderTitle())}",
|
||||
Localize.completedSuccessfully());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogException(nameof(PublicAPIInstance), "Failed to copy file/folder to clipboard", exception);
|
||||
ShowMsgError(GetTranslation("failedToCopy"));
|
||||
ShowMsgError(Localize.failedToCopy());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -210,15 +209,15 @@ namespace Flow.Launcher
|
|||
if (showDefaultNotification)
|
||||
{
|
||||
ShowMsg(
|
||||
$"{GetTranslation("copy")} {GetTranslation("textTitle")}",
|
||||
GetTranslation("completedSuccessfully"));
|
||||
$"{Localize.copy()} {Localize.textTitle()}",
|
||||
Localize.completedSuccessfully());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogException(nameof(PublicAPIInstance), "Failed to copy text to clipboard", exception);
|
||||
ShowMsgError(GetTranslation("failedToCopy"));
|
||||
}
|
||||
ShowMsgError(Localize.failedToCopy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +326,7 @@ namespace Flow.Launcher
|
|||
|
||||
((PluginJsonStorage<T>)_pluginJsonStorages[type]).Save();
|
||||
}
|
||||
|
||||
|
||||
public void OpenDirectory(string directoryPath, string fileNameOrFilePath = null)
|
||||
{
|
||||
try
|
||||
|
|
@ -394,24 +393,30 @@ namespace Flow.Launcher
|
|||
}
|
||||
catch (Win32Exception ex) when (ex.NativeErrorCode == 2)
|
||||
{
|
||||
LogError(ClassName, "File Manager not found");
|
||||
LogException(ClassName, "File Manager not found", ex);
|
||||
ShowMsgError(
|
||||
GetTranslation("fileManagerNotFoundTitle"),
|
||||
string.Format(GetTranslation("fileManagerNotFound"), ex.Message)
|
||||
Localize.fileManagerNotFoundTitle(),
|
||||
Localize.fileManagerNotFound()
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogException(ClassName, "Failed to open folder", ex);
|
||||
ShowMsgError(
|
||||
GetTranslation("errorTitle"),
|
||||
string.Format(GetTranslation("folderOpenError"), ex.Message)
|
||||
Localize.errorTitle(),
|
||||
Localize.folderOpenError()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenUri(Uri uri, bool? inPrivate = null, bool forceBrowser = false)
|
||||
{
|
||||
if (uri.IsFile && !FilesFolders.FileOrLocationExists(uri.LocalPath))
|
||||
{
|
||||
ShowMsgError(Localize.errorTitle(), Localize.fileNotFoundError(uri.LocalPath));
|
||||
return;
|
||||
}
|
||||
|
||||
if (forceBrowser || uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)
|
||||
{
|
||||
var browserInfo = _settings.CustomBrowser;
|
||||
|
|
@ -434,20 +439,26 @@ namespace Flow.Launcher
|
|||
var tabOrWindow = browserInfo.OpenInTab ? "tab" : "window";
|
||||
LogException(ClassName, $"Failed to open URL in browser {tabOrWindow}: {path}, {inPrivate ?? browserInfo.EnablePrivate}, {browserInfo.PrivateArg}", e);
|
||||
ShowMsgError(
|
||||
GetTranslation("errorTitle"),
|
||||
GetTranslation("browserOpenError")
|
||||
Localize.errorTitle(),
|
||||
Localize.browserOpenError()
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Process.Start(new ProcessStartInfo()
|
||||
try
|
||||
{
|
||||
FileName = uri.AbsoluteUri,
|
||||
UseShellExecute = true
|
||||
})?.Dispose();
|
||||
|
||||
return;
|
||||
Process.Start(new ProcessStartInfo()
|
||||
{
|
||||
FileName = uri.AbsoluteUri,
|
||||
UseShellExecute = true
|
||||
})?.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogException(ClassName, $"Failed to open: {uri.AbsoluteUri}", e);
|
||||
ShowMsgError(Localize.errorTitle(), e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -481,7 +492,7 @@ namespace Flow.Launcher
|
|||
OpenUri(appUri);
|
||||
}
|
||||
|
||||
public void ToggleGameMode()
|
||||
public void ToggleGameMode()
|
||||
{
|
||||
_mainVM.ToggleGameMode();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,8 +132,8 @@ namespace Flow.Launcher
|
|||
RefreshButton.Visibility = Visibility.Visible;
|
||||
MarkdownViewer.Visibility = Visibility.Collapsed;
|
||||
App.API.ShowMsgError(
|
||||
App.API.GetTranslation("checkNetworkConnectionTitle"),
|
||||
App.API.GetTranslation("checkNetworkConnectionSubTitle"));
|
||||
Localize.checkNetworkConnectionTitle(),
|
||||
Localize.checkNetworkConnectionSubTitle());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -48,10 +48,10 @@ namespace Flow.Launcher
|
|||
_ => Constant.IssuesUrl
|
||||
};
|
||||
|
||||
var paragraph = Hyperlink(App.API.GetTranslation("reportWindow_please_open_issue"), websiteUrl);
|
||||
paragraph.Inlines.Add(string.Format(App.API.GetTranslation("reportWindow_upload_log"), log.FullName));
|
||||
var paragraph = Hyperlink(Localize.reportWindow_please_open_issue(), websiteUrl);
|
||||
paragraph.Inlines.Add(Localize.reportWindow_upload_log(log.FullName));
|
||||
paragraph.Inlines.Add("\n");
|
||||
paragraph.Inlines.Add(App.API.GetTranslation("reportWindow_copy_below"));
|
||||
paragraph.Inlines.Add(Localize.reportWindow_copy_below());
|
||||
ErrorTextbox.Document.Blocks.Add(paragraph);
|
||||
|
||||
StringBuilder content = new StringBuilder();
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ namespace Flow.Launcher.Resources.Pages
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
App.API.ShowMsgError(App.API.GetTranslation("setAutoStartFailed"), e.Message);
|
||||
App.API.ShowMsgError(Localize.setAutoStartFailed(), e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel
|
|||
get
|
||||
{
|
||||
var size = GetLogFiles().Sum(file => file.Length);
|
||||
return $"{App.API.GetTranslation("clearlogfolder")} ({BytesToReadableString(size)})";
|
||||
return $"{Localize.clearlogfolder()} ({BytesToReadableString(size)})";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel
|
|||
get
|
||||
{
|
||||
var size = GetCacheFiles().Sum(file => file.Length);
|
||||
return $"{App.API.GetTranslation("clearcachefolder")} ({BytesToReadableString(size)})";
|
||||
return $"{Localize.clearcachefolder()} ({BytesToReadableString(size)})";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,10 +51,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel
|
|||
_ => Constant.Version
|
||||
};
|
||||
|
||||
public string ActivatedTimes => string.Format(
|
||||
App.API.GetTranslation("about_activate_times"),
|
||||
_settings.ActivateTimes
|
||||
);
|
||||
public string ActivatedTimes => Localize.about_activate_times(_settings.ActivateTimes);
|
||||
|
||||
public class LogLevelData : DropdownDataGeneric<LOGLEVEL> { }
|
||||
|
||||
|
|
@ -98,8 +95,8 @@ public partial class SettingsPaneAboutViewModel : BaseModel
|
|||
private void AskClearLogFolderConfirmation()
|
||||
{
|
||||
var confirmResult = App.API.ShowMsgBox(
|
||||
App.API.GetTranslation("clearlogfolderMessage"),
|
||||
App.API.GetTranslation("clearlogfolder"),
|
||||
Localize.clearlogfolderMessage(),
|
||||
Localize.clearlogfolder(),
|
||||
MessageBoxButton.YesNo
|
||||
);
|
||||
|
||||
|
|
@ -107,7 +104,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel
|
|||
{
|
||||
if (!ClearLogFolder())
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("clearfolderfailMessage"));
|
||||
App.API.ShowMsgBox(Localize.clearfolderfailMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -116,8 +113,8 @@ public partial class SettingsPaneAboutViewModel : BaseModel
|
|||
private void AskClearCacheFolderConfirmation()
|
||||
{
|
||||
var confirmResult = App.API.ShowMsgBox(
|
||||
App.API.GetTranslation("clearcachefolderMessage"),
|
||||
App.API.GetTranslation("clearcachefolder"),
|
||||
Localize.clearcachefolderMessage(),
|
||||
Localize.clearcachefolder(),
|
||||
MessageBoxButton.YesNo
|
||||
);
|
||||
|
||||
|
|
@ -125,7 +122,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel
|
|||
{
|
||||
if (!ClearCacheFolder())
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("clearfolderfailMessage"));
|
||||
App.API.ShowMsgBox(Localize.clearfolderfailMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
App.API.ShowMsgError(App.API.GetTranslation("setAutoStartFailed"), e.Message);
|
||||
App.API.ShowMsgError(Localize.setAutoStartFailed(), e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +92,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
App.API.ShowMsgError(App.API.GetTranslation("setAutoStartFailed"), e.Message);
|
||||
App.API.ShowMsgError(Localize.setAutoStartFailed(), e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -257,7 +257,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
|||
else
|
||||
{
|
||||
// Since this is rarely seen text, language support is not provided.
|
||||
App.API.ShowMsgError(App.API.GetTranslation("KoreanImeSettingChangeFailTitle"), App.API.GetTranslation("KoreanImeSettingChangeFailSubTitle"));
|
||||
App.API.ShowMsgError(Localize.KoreanImeSettingChangeFailTitle(), Localize.KoreanImeSettingChangeFailSubTitle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -325,10 +325,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
|||
|
||||
public List<Language> Languages => _translater.LoadAvailableLanguages();
|
||||
|
||||
public string AlwaysPreviewToolTip => string.Format(
|
||||
App.API.GetTranslation("AlwaysPreviewToolTip"),
|
||||
Settings.PreviewHotkey
|
||||
);
|
||||
public string AlwaysPreviewToolTip => Localize.AlwaysPreviewToolTip(Settings.PreviewHotkey);
|
||||
|
||||
private static string GetFileFromDialog(string title, string filter = "")
|
||||
{
|
||||
|
|
@ -372,7 +369,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
|||
private void SelectPython()
|
||||
{
|
||||
var selectedFile = GetFileFromDialog(
|
||||
App.API.GetTranslation("selectPythonExecutable"),
|
||||
Localize.selectPythonExecutable(),
|
||||
"Python|pythonw.exe"
|
||||
);
|
||||
|
||||
|
|
@ -384,7 +381,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
|||
private void SelectNode()
|
||||
{
|
||||
var selectedFile = GetFileFromDialog(
|
||||
App.API.GetTranslation("selectNodeExecutable"),
|
||||
Localize.selectNodeExecutable(),
|
||||
"node|*.exe"
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,15 +50,13 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
|
|||
var item = SelectedCustomPluginHotkey;
|
||||
if (item is null)
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("pleaseSelectAnItem"));
|
||||
App.API.ShowMsgBox(Localize.pleaseSelectAnItem());
|
||||
return;
|
||||
}
|
||||
|
||||
var result = App.API.ShowMsgBox(
|
||||
string.Format(
|
||||
App.API.GetTranslation("deleteCustomHotkeyWarning"), item.Hotkey
|
||||
),
|
||||
App.API.GetTranslation("delete"),
|
||||
Localize.deleteCustomHotkeyWarning(item.Hotkey),
|
||||
Localize.delete(),
|
||||
MessageBoxButton.YesNo
|
||||
);
|
||||
|
||||
|
|
@ -75,7 +73,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
|
|||
var item = SelectedCustomPluginHotkey;
|
||||
if (item is null)
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("pleaseSelectAnItem"));
|
||||
App.API.ShowMsgBox(Localize.pleaseSelectAnItem());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +81,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
|
|||
o.ActionKeyword == item.ActionKeyword && o.Hotkey == item.Hotkey);
|
||||
if (settingItem == null)
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("invalidPluginHotkey"));
|
||||
App.API.ShowMsgBox(Localize.invalidPluginHotkey());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -114,15 +112,13 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
|
|||
var item = SelectedCustomShortcut;
|
||||
if (item is null)
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("pleaseSelectAnItem"));
|
||||
App.API.ShowMsgBox(Localize.pleaseSelectAnItem());
|
||||
return;
|
||||
}
|
||||
|
||||
var result = App.API.ShowMsgBox(
|
||||
string.Format(
|
||||
App.API.GetTranslation("deleteCustomShortcutWarning"), item.Key, item.Value
|
||||
),
|
||||
App.API.GetTranslation("delete"),
|
||||
Localize.deleteCustomShortcutWarning(item.Key, item.Value),
|
||||
Localize.delete(),
|
||||
MessageBoxButton.YesNo
|
||||
);
|
||||
|
||||
|
|
@ -138,7 +134,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
|
|||
var item = SelectedCustomShortcut;
|
||||
if (item is null)
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("pleaseSelectAnItem"));
|
||||
App.API.ShowMsgBox(Localize.pleaseSelectAnItem());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +142,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
|
|||
o.Key == item.Key && o.Value == item.Value);
|
||||
if (settingItem == null)
|
||||
{
|
||||
App.API.ShowMsgBox(App.API.GetTranslation("invalidShortcut"));
|
||||
App.API.ShowMsgBox(Localize.invalidShortcut());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -103,8 +103,8 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel
|
|||
private async Task InstallPluginAsync()
|
||||
{
|
||||
var file = GetFileFromDialog(
|
||||
App.API.GetTranslation("SelectZipFile"),
|
||||
$"{App.API.GetTranslation("ZipFiles")} (*.zip)|*.zip");
|
||||
Localize.SelectZipFile(),
|
||||
$"{Localize.ZipFiles()} (*.zip)|*.zip");
|
||||
|
||||
if (!string.IsNullOrEmpty(file))
|
||||
await PluginInstaller.InstallPluginAndCheckRestartAsync(file);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
|||
private readonly Theme _theme;
|
||||
|
||||
private readonly string DefaultFont = Win32Helper.GetSystemDefaultFont();
|
||||
public string BackdropSubText => !Win32Helper.IsBackdropSupported() ? App.API.GetTranslation("BackdropTypeDisabledToolTip") : "";
|
||||
public string BackdropSubText => !Win32Helper.IsBackdropSupported() ? Localize.BackdropTypeDisabledToolTip(): "";
|
||||
|
||||
public static string LinkHowToCreateTheme => @"https://www.flowlauncher.com/theme-builder/";
|
||||
public static string LinkThemeGallery => "https://github.com/Flow-Launcher/Flow.Launcher/discussions/1438";
|
||||
|
|
@ -272,7 +272,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
|||
|
||||
public string PlaceholderTextTip
|
||||
{
|
||||
get => string.Format(App.API.GetTranslation("PlaceholderTextTip"), App.API.GetTranslation("queryTextBoxPlaceholder"));
|
||||
get => Localize.PlaceholderTextTip(Localize.queryTextBoxPlaceholder());
|
||||
}
|
||||
|
||||
public string PlaceholderText
|
||||
|
|
@ -447,8 +447,8 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
|||
{
|
||||
new()
|
||||
{
|
||||
Title = App.API.GetTranslation("SampleTitleExplorer"),
|
||||
SubTitle = App.API.GetTranslation("SampleSubTitleExplorer"),
|
||||
Title = Localize.SampleTitleExplorer(),
|
||||
SubTitle = Localize.SampleSubTitleExplorer(),
|
||||
IcoPath = Path.Combine(
|
||||
Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png"
|
||||
|
|
@ -456,8 +456,8 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
|||
},
|
||||
new()
|
||||
{
|
||||
Title = App.API.GetTranslation("SampleTitleWebSearch"),
|
||||
SubTitle = App.API.GetTranslation("SampleSubTitleWebSearch"),
|
||||
Title = Localize.SampleTitleWebSearch(),
|
||||
SubTitle = Localize.SampleSubTitleWebSearch(),
|
||||
IcoPath = Path.Combine(
|
||||
Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png"
|
||||
|
|
@ -465,8 +465,8 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
|||
},
|
||||
new()
|
||||
{
|
||||
Title = App.API.GetTranslation("SampleTitleProgram"),
|
||||
SubTitle = App.API.GetTranslation("SampleSubTitleProgram"),
|
||||
Title = Localize.SampleTitleProgram(),
|
||||
SubTitle = Localize.SampleSubTitleProgram(),
|
||||
IcoPath = Path.Combine(
|
||||
Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.Program\Images\program.png"
|
||||
|
|
@ -474,8 +474,8 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
|||
},
|
||||
new()
|
||||
{
|
||||
Title = App.API.GetTranslation("SampleTitleProcessKiller"),
|
||||
SubTitle = App.API.GetTranslation("SampleSubTitleProcessKiller"),
|
||||
Title = Localize.SampleTitleProcessKiller(),
|
||||
SubTitle = Localize.SampleSubTitleProcessKiller(),
|
||||
IcoPath = Path.Combine(
|
||||
Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png"
|
||||
|
|
|
|||
|
|
@ -342,8 +342,8 @@ namespace Flow.Launcher.ViewModel
|
|||
Hide();
|
||||
|
||||
await PluginManager.ReloadDataAsync().ConfigureAwait(false);
|
||||
App.API.ShowMsg(App.API.GetTranslation("success"),
|
||||
App.API.GetTranslation("completedSuccessfully"));
|
||||
App.API.ShowMsg(Localize.success(),
|
||||
Localize.completedSuccessfully());
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
|
|
@ -908,7 +908,7 @@ namespace Flow.Launcher.ViewModel
|
|||
private string _placeholderText;
|
||||
public string PlaceholderText
|
||||
{
|
||||
get => string.IsNullOrEmpty(_placeholderText) ? App.API.GetTranslation("queryTextBoxPlaceholder") : _placeholderText;
|
||||
get => string.IsNullOrEmpty(_placeholderText) ? Localize.queryTextBoxPlaceholder(): _placeholderText;
|
||||
set
|
||||
{
|
||||
_placeholderText = value;
|
||||
|
|
@ -1312,12 +1312,10 @@ namespace Flow.Launcher.ViewModel
|
|||
var results = new List<Result>();
|
||||
foreach (var h in historyItems)
|
||||
{
|
||||
var title = App.API.GetTranslation("executeQuery");
|
||||
var time = App.API.GetTranslation("lastExecuteTime");
|
||||
var result = new Result
|
||||
{
|
||||
Title = string.Format(title, h.Query),
|
||||
SubTitle = string.Format(time, h.ExecutedDateTime),
|
||||
Title = Localize.executeQuery(h.Query),
|
||||
SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime),
|
||||
IcoPath = Constant.HistoryIcon,
|
||||
OriginQuery = new Query { RawQuery = h.Query },
|
||||
Action = _ =>
|
||||
|
|
@ -1714,13 +1712,13 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
menu = new Result
|
||||
{
|
||||
Title = App.API.GetTranslation("cancelTopMostInThisQuery"),
|
||||
Title = Localize.cancelTopMostInThisQuery(),
|
||||
IcoPath = "Images\\down.png",
|
||||
PluginDirectory = Constant.ProgramDirectory,
|
||||
Action = _ =>
|
||||
{
|
||||
_topMostRecord.Remove(result);
|
||||
App.API.ShowMsg(App.API.GetTranslation("success"));
|
||||
App.API.ShowMsg(Localize.success());
|
||||
App.API.ReQuery();
|
||||
return false;
|
||||
},
|
||||
|
|
@ -1732,13 +1730,13 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
menu = new Result
|
||||
{
|
||||
Title = App.API.GetTranslation("setAsTopMostInThisQuery"),
|
||||
Title = Localize.setAsTopMostInThisQuery(),
|
||||
IcoPath = "Images\\up.png",
|
||||
PluginDirectory = Constant.ProgramDirectory,
|
||||
Action = _ =>
|
||||
{
|
||||
_topMostRecord.AddOrUpdate(result);
|
||||
App.API.ShowMsg(App.API.GetTranslation("success"));
|
||||
App.API.ShowMsg(Localize.success());
|
||||
App.API.ReQuery();
|
||||
return false;
|
||||
},
|
||||
|
|
@ -1756,10 +1754,10 @@ namespace Flow.Launcher.ViewModel
|
|||
var metadata = PluginManager.GetPluginForId(id).Metadata;
|
||||
var translator = App.API;
|
||||
|
||||
var author = translator.GetTranslation("author");
|
||||
var website = translator.GetTranslation("website");
|
||||
var version = translator.GetTranslation("version");
|
||||
var plugin = translator.GetTranslation("plugin");
|
||||
var author = Localize.author();
|
||||
var website = Localize.website();
|
||||
var version = Localize.version();
|
||||
var plugin = Localize.plugin();
|
||||
var title = $"{plugin}: {metadata.Name}";
|
||||
var icon = metadata.IcoPath;
|
||||
var subtitle = $"{author} {metadata.Author}";
|
||||
|
|
|
|||
|
|
@ -155,8 +155,7 @@ namespace Flow.Launcher.ViewModel
|
|||
App.API.LogException(ClassName, $"Failed to create setting panel for {pair.Metadata.Name}", e);
|
||||
|
||||
// Show error message in UI
|
||||
var errorMsg = string.Format(App.API.GetTranslation("errorCreatingSettingPanel"),
|
||||
pair.Metadata.Name, Environment.NewLine, e.Message);
|
||||
var errorMsg = Localize.errorCreatingSettingPanel(pair.Metadata.Name, Environment.NewLine, e.Message);
|
||||
return CreateErrorSettingPanel(errorMsg);
|
||||
}
|
||||
}
|
||||
|
|
@ -165,16 +164,16 @@ namespace Flow.Launcher.ViewModel
|
|||
Visibility.Collapsed : Visibility.Visible;
|
||||
public string InitializeTime => PluginPair.Metadata.InitTime + "ms";
|
||||
public string QueryTime => PluginPair.Metadata.AvgQueryTime + "ms";
|
||||
public string Version => App.API.GetTranslation("plugin_query_version") + " " + PluginPair.Metadata.Version;
|
||||
public string Version => Localize.plugin_query_version() + " " + PluginPair.Metadata.Version;
|
||||
public string InitAndQueryTime =>
|
||||
App.API.GetTranslation("plugin_init_time") + " " +
|
||||
Localize.plugin_init_time() + " " +
|
||||
PluginPair.Metadata.InitTime + "ms, " +
|
||||
App.API.GetTranslation("plugin_query_time") + " " +
|
||||
Localize.plugin_query_time() + " " +
|
||||
PluginPair.Metadata.AvgQueryTime + "ms";
|
||||
public string ActionKeywordsText => string.Join(Query.ActionKeywordSeparator, PluginPair.Metadata.ActionKeywords);
|
||||
public string SearchDelayTimeText => PluginPair.Metadata.SearchDelayTime == null ?
|
||||
App.API.GetTranslation("default") :
|
||||
App.API.GetTranslation($"SearchDelayTime{PluginPair.Metadata.SearchDelayTime}");
|
||||
Localize.plugin_default_search_delay_time() :
|
||||
Localize.plugin_search_delay_time(PluginPair.Metadata.SearchDelayTime);
|
||||
public Infrastructure.UserSettings.Plugin PluginSettingsObject{ get; init; }
|
||||
public bool SearchDelayEnabled => Settings.SearchQueryResultsWithDelay;
|
||||
public string DefaultSearchDelay => Settings.SearchDelayTime.ToString();
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public partial class SelectBrowserViewModel : BaseModel
|
|||
{
|
||||
CustomBrowsers.Add(new()
|
||||
{
|
||||
Name = App.API.GetTranslation("defaultBrowser_new_profile")
|
||||
Name = Localize.defaultBrowser_new_profile()
|
||||
});
|
||||
SelectedCustomBrowserIndex = CustomBrowsers.Count - 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,9 +48,8 @@ public partial class SelectFileManagerViewModel : BaseModel
|
|||
if (!IsFileManagerValid(CustomExplorer.Path))
|
||||
{
|
||||
var result = App.API.ShowMsgBox(
|
||||
string.Format(App.API.GetTranslation("fileManagerPathNotFound"),
|
||||
CustomExplorer.Name, CustomExplorer.Path),
|
||||
App.API.GetTranslation("fileManagerPathError"),
|
||||
Localize.fileManagerPathNotFound(CustomExplorer.Name, CustomExplorer.Path),
|
||||
Localize.fileManagerPathError(),
|
||||
MessageBoxButton.YesNo,
|
||||
MessageBoxImage.Warning);
|
||||
|
||||
|
|
@ -105,7 +104,7 @@ public partial class SelectFileManagerViewModel : BaseModel
|
|||
{
|
||||
CustomExplorers.Add(new()
|
||||
{
|
||||
Name = App.API.GetTranslation("defaultBrowser_new_profile")
|
||||
Name = Localize.defaultBrowser_new_profile()
|
||||
});
|
||||
SelectedCustomExplorerIndex = CustomExplorers.Count - 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,12 @@
|
|||
"resolved": "8.4.0",
|
||||
"contentHash": "tqVU8yc/ADO9oiTRyTnwhFN68hCwvkliMierptWOudIAvWY1mWCh5VFh+guwHJmpMwfg0J0rY+yyd5Oy7ty9Uw=="
|
||||
},
|
||||
"Flow.Launcher.Localization": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.0.6, )",
|
||||
"resolved": "0.0.6",
|
||||
"contentHash": "WNI/TLGPDr3XdOW8gaALN0Uyz9h+bzqOaNZev2nHEuA3HW9o7XuqaM6C0PqNi96mNgxiypwWpVazBNzaylJ2Aw=="
|
||||
},
|
||||
"Fody": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.9.3, )",
|
||||
|
|
@ -204,6 +210,11 @@
|
|||
"resolved": "1.11.42",
|
||||
"contentHash": "LDc1bEfF14EY2DZzak4xvzWvbpNXK3vi1u0KQbBpLUN4+cx/VrvXhgCAMSJhSU5vz0oMfW9JZIR20vj/PkDHPA=="
|
||||
},
|
||||
"ini-parser": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.5.2",
|
||||
"contentHash": "hp3gKmC/14+6eKLgv7Jd1Z7OV86lO+tNfOXr/stQbwmRhdQuXVSvrRAuAe7G5+lwhkov0XkqZ8/bn1PYWMx6eg=="
|
||||
},
|
||||
"InputSimulator": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.4",
|
||||
|
|
@ -1599,6 +1610,7 @@
|
|||
"Droplex": "[1.7.0, )",
|
||||
"FSharp.Core": "[9.0.303, )",
|
||||
"Flow.Launcher.Infrastructure": "[1.0.0, )",
|
||||
"Flow.Launcher.Localization": "[0.0.6, )",
|
||||
"Flow.Launcher.Plugin": "[5.0.0, )",
|
||||
"Meziantou.Framework.Win32.Jobs": "[3.4.5, )",
|
||||
"Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )",
|
||||
|
|
@ -1613,6 +1625,7 @@
|
|||
"Ben.Demystifier": "[0.4.1, )",
|
||||
"BitFaster.Caching": "[2.5.4, )",
|
||||
"CommunityToolkit.Mvvm": "[8.4.0, )",
|
||||
"Flow.Launcher.Localization": "[0.0.6, )",
|
||||
"Flow.Launcher.Plugin": "[5.0.0, )",
|
||||
"InputSimulator": "[1.0.4, )",
|
||||
"MemoryPack": "[1.21.4, )",
|
||||
|
|
@ -1622,7 +1635,8 @@
|
|||
"NLog.OutputDebugString": "[6.0.4, )",
|
||||
"SharpVectors.Wpf": "[1.8.5, )",
|
||||
"System.Drawing.Common": "[7.0.0, )",
|
||||
"ToolGood.Words.Pinyin": "[3.1.0.3, )"
|
||||
"ToolGood.Words.Pinyin": "[3.1.0.3, )",
|
||||
"ini-parser": "[2.5.2, )"
|
||||
}
|
||||
},
|
||||
"flow.launcher.plugin": {
|
||||
|
|
|
|||
|
|
@ -106,8 +106,8 @@
|
|||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.9" />
|
||||
<PackageReference Include="Svg.Skia" Version="3.0.6" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.119.0" />
|
||||
<PackageReference Include="Svg.Skia" Version="3.2.1" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.119.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ namespace Flow.Launcher.Plugin.Calculator
|
|||
{
|
||||
[EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_calculator_decimal_separator_use_system_locale))]
|
||||
UseSystemLocale,
|
||||
|
||||
|
||||
[EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_calculator_decimal_separator_dot))]
|
||||
Dot,
|
||||
|
||||
Dot,
|
||||
|
||||
[EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_calculator_decimal_separator_comma))]
|
||||
Comma
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ using System.Linq;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Controls;
|
||||
using Mages.Core;
|
||||
using Flow.Launcher.Plugin.Calculator.Views;
|
||||
using Flow.Launcher.Plugin.Calculator.ViewModels;
|
||||
using Flow.Launcher.Plugin.Calculator.Views;
|
||||
using Mages.Core;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Calculator
|
||||
{
|
||||
|
|
@ -26,7 +26,7 @@ namespace Flow.Launcher.Plugin.Calculator
|
|||
private const string IcoPath = "Images/calculator.png";
|
||||
private static readonly List<Result> EmptyResults = [];
|
||||
|
||||
internal static PluginInitContext Context { get; set; } = null!;
|
||||
internal static PluginInitContext Context { get; private set; } = null!;
|
||||
|
||||
private Settings _settings;
|
||||
private SettingsViewModel _viewModel;
|
||||
|
|
@ -57,10 +57,10 @@ namespace Flow.Launcher.Plugin.Calculator
|
|||
{
|
||||
var search = query.Search;
|
||||
bool isFunctionPresent = FunctionRegex.IsMatch(search);
|
||||
|
||||
|
||||
// Mages is case sensitive, so we need to convert all function names to lower case.
|
||||
search = FunctionRegex.Replace(search, m => m.Value.ToLowerInvariant());
|
||||
|
||||
|
||||
var decimalSep = GetDecimalSeparator();
|
||||
var groupSep = GetGroupSeparator(decimalSep);
|
||||
var expression = NumberRegex.Replace(search, m => NormalizeNumber(m.Value, isFunctionPresent, decimalSep, groupSep));
|
||||
|
|
@ -292,7 +292,7 @@ namespace Flow.Launcher.Plugin.Calculator
|
|||
{
|
||||
processedStr = processedStr.Replace(decimalSep, ".");
|
||||
}
|
||||
|
||||
|
||||
return processedStr;
|
||||
}
|
||||
else
|
||||
|
|
@ -310,7 +310,7 @@ namespace Flow.Launcher.Plugin.Calculator
|
|||
return processedStr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static bool IsValidGrouping(string[] parts, int[] groupSizes)
|
||||
{
|
||||
if (parts.Length <= 1) return true;
|
||||
|
|
@ -326,7 +326,7 @@ namespace Flow.Launcher.Plugin.Calculator
|
|||
|
||||
var lastGroupSize = groupSizes.Last();
|
||||
var canRepeatLastGroup = lastGroupSize != 0;
|
||||
|
||||
|
||||
int groupIndex = 0;
|
||||
for (int i = parts.Length - 1; i > 0; i--)
|
||||
{
|
||||
|
|
@ -335,7 +335,7 @@ namespace Flow.Launcher.Plugin.Calculator
|
|||
{
|
||||
expectedSize = groupSizes[groupIndex];
|
||||
}
|
||||
else if(canRepeatLastGroup)
|
||||
else if (canRepeatLastGroup)
|
||||
{
|
||||
expectedSize = lastGroupSize;
|
||||
}
|
||||
|
|
@ -345,7 +345,7 @@ namespace Flow.Launcher.Plugin.Calculator
|
|||
}
|
||||
|
||||
if (parts[i].Length != expectedSize) return false;
|
||||
|
||||
|
||||
groupIndex++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
namespace Flow.Launcher.Plugin.Calculator;
|
||||
namespace Flow.Launcher.Plugin.Calculator;
|
||||
|
||||
public class Settings
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<NoWarn>$(NoWarn);FLSG0007</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -54,5 +55,9 @@
|
|||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -5,19 +5,19 @@ namespace Flow.Launcher.Plugin.PluginIndicator
|
|||
{
|
||||
public class Main : IPlugin, IPluginI18n, IHomeQuery
|
||||
{
|
||||
internal PluginInitContext Context { get; private set; }
|
||||
internal static PluginInitContext Context { get; private set; }
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
Context = context;
|
||||
}
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
return QueryResults(query);
|
||||
}
|
||||
|
||||
public List<Result> HomeQuery()
|
||||
{
|
||||
return QueryResults();
|
||||
}
|
||||
|
||||
private List<Result> QueryResults(Query query = null)
|
||||
private static List<Result> QueryResults(Query query = null)
|
||||
{
|
||||
var nonGlobalPlugins = GetNonGlobalPlugins();
|
||||
var querySearch = query?.Search ?? string.Empty;
|
||||
|
|
@ -34,7 +34,7 @@ namespace Flow.Launcher.Plugin.PluginIndicator
|
|||
select new Result
|
||||
{
|
||||
Title = keyword,
|
||||
SubTitle = string.Format(Context.API.GetTranslation("flowlauncher_plugin_pluginindicator_result_subtitle"), plugin.Name),
|
||||
SubTitle = Localize.flowlauncher_plugin_pluginindicator_result_subtitle(plugin.Name),
|
||||
Score = score,
|
||||
IcoPath = plugin.IcoPath,
|
||||
AutoCompleteText = $"{keyword}{Plugin.Query.TermSeparator}",
|
||||
|
|
@ -44,10 +44,10 @@ namespace Flow.Launcher.Plugin.PluginIndicator
|
|||
return false;
|
||||
}
|
||||
};
|
||||
return results.ToList();
|
||||
return [.. results];
|
||||
}
|
||||
|
||||
private Dictionary<string, PluginPair> GetNonGlobalPlugins()
|
||||
private static Dictionary<string, PluginPair> GetNonGlobalPlugins()
|
||||
{
|
||||
var nonGlobalPlugins = new Dictionary<string, PluginPair>();
|
||||
foreach (var plugin in Context.API.GetAllPlugins())
|
||||
|
|
@ -66,19 +66,19 @@ namespace Flow.Launcher.Plugin.PluginIndicator
|
|||
return nonGlobalPlugins;
|
||||
}
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
Context = context;
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return Context.API.GetTranslation("flowlauncher_plugin_pluginindicator_plugin_name");
|
||||
return Localize.flowlauncher_plugin_pluginindicator_plugin_name();
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return Context.API.GetTranslation("flowlauncher_plugin_pluginindicator_plugin_description");
|
||||
return Localize.flowlauncher_plugin_pluginindicator_plugin_description();
|
||||
}
|
||||
|
||||
public List<Result> HomeQuery()
|
||||
{
|
||||
return QueryResults();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<NoWarn>$(NoWarn);FLSG0007</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -52,6 +53,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.205">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
|
|
|||
|
|
@ -9,19 +9,19 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
{
|
||||
public class Main : IPlugin, IPluginI18n, IContextMenu, ISettingProvider
|
||||
{
|
||||
internal static PluginInitContext Context { get; private set; }
|
||||
|
||||
private Settings _settings;
|
||||
|
||||
private readonly ProcessHelper processHelper = new();
|
||||
|
||||
private static PluginInitContext _context;
|
||||
|
||||
internal Settings Settings;
|
||||
|
||||
private SettingsViewModel _viewModel;
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
_context = context;
|
||||
Settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||
_viewModel = new SettingsViewModel(Settings);
|
||||
Context = context;
|
||||
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||
_viewModel = new SettingsViewModel(_settings);
|
||||
}
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
|
|
@ -31,12 +31,12 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return _context.API.GetTranslation("flowlauncher_plugin_processkiller_plugin_name");
|
||||
return Localize.flowlauncher_plugin_processkiller_plugin_name();
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return _context.API.GetTranslation("flowlauncher_plugin_processkiller_plugin_description");
|
||||
return Localize.flowlauncher_plugin_processkiller_plugin_description();
|
||||
}
|
||||
|
||||
public List<Result> LoadContextMenus(Result result)
|
||||
|
|
@ -51,13 +51,13 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
{
|
||||
menuOptions.Add(new Result
|
||||
{
|
||||
Title = _context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_instances"),
|
||||
Title = Localize.flowlauncher_plugin_processkiller_kill_instances(),
|
||||
SubTitle = processPath,
|
||||
Action = _ =>
|
||||
{
|
||||
foreach (var p in similarProcesses)
|
||||
{
|
||||
processHelper.TryKill(_context, p);
|
||||
ProcessHelper.TryKill(p);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -72,8 +72,8 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
private List<Result> CreateResultsFromQuery(Query query)
|
||||
{
|
||||
// Get all non-system processes
|
||||
var allPocessList = processHelper.GetMatchingProcesses();
|
||||
if (!allPocessList.Any())
|
||||
var allProcessList = processHelper.GetMatchingProcesses();
|
||||
if (allProcessList.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
@ -82,12 +82,12 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
var searchTerm = query.Search;
|
||||
var processlist = new List<ProcessResult>();
|
||||
var processWindowTitle =
|
||||
Settings.ShowWindowTitle || Settings.PutVisibleWindowProcessesTop ?
|
||||
_settings.ShowWindowTitle || _settings.PutVisibleWindowProcessesTop ?
|
||||
ProcessHelper.GetProcessesWithNonEmptyWindowTitle() :
|
||||
new Dictionary<int, string>();
|
||||
[];
|
||||
if (string.IsNullOrWhiteSpace(searchTerm))
|
||||
{
|
||||
foreach (var p in allPocessList)
|
||||
foreach (var p in allProcessList)
|
||||
{
|
||||
var progressNameIdTitle = ProcessHelper.GetProcessNameIdTitle(p);
|
||||
|
||||
|
|
@ -97,8 +97,8 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
// Use window title for those processes if enabled
|
||||
processlist.Add(new ProcessResult(
|
||||
p,
|
||||
Settings.PutVisibleWindowProcessesTop ? 200 : 0,
|
||||
Settings.ShowWindowTitle ? windowTitle : progressNameIdTitle,
|
||||
_settings.PutVisibleWindowProcessesTop ? 200 : 0,
|
||||
_settings.ShowWindowTitle ? windowTitle : progressNameIdTitle,
|
||||
null,
|
||||
progressNameIdTitle));
|
||||
}
|
||||
|
|
@ -115,35 +115,35 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
}
|
||||
else
|
||||
{
|
||||
foreach (var p in allPocessList)
|
||||
foreach (var p in allProcessList)
|
||||
{
|
||||
var progressNameIdTitle = ProcessHelper.GetProcessNameIdTitle(p);
|
||||
|
||||
if (processWindowTitle.TryGetValue(p.Id, out var windowTitle))
|
||||
{
|
||||
// Get max score from searching process name, window title and process id
|
||||
var windowTitleMatch = _context.API.FuzzySearch(searchTerm, windowTitle);
|
||||
var processNameIdMatch = _context.API.FuzzySearch(searchTerm, progressNameIdTitle);
|
||||
var windowTitleMatch = Context.API.FuzzySearch(searchTerm, windowTitle);
|
||||
var processNameIdMatch = Context.API.FuzzySearch(searchTerm, progressNameIdTitle);
|
||||
var score = Math.Max(windowTitleMatch.Score, processNameIdMatch.Score);
|
||||
if (score > 0)
|
||||
{
|
||||
// Add score to prioritize processes with visible windows
|
||||
// Use window title for those processes
|
||||
if (Settings.PutVisibleWindowProcessesTop)
|
||||
if (_settings.PutVisibleWindowProcessesTop)
|
||||
{
|
||||
score += 200;
|
||||
}
|
||||
processlist.Add(new ProcessResult(
|
||||
p,
|
||||
score,
|
||||
Settings.ShowWindowTitle ? windowTitle : progressNameIdTitle,
|
||||
_settings.ShowWindowTitle ? windowTitle : progressNameIdTitle,
|
||||
score == windowTitleMatch.Score ? windowTitleMatch : null,
|
||||
progressNameIdTitle));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var processNameIdMatch = _context.API.FuzzySearch(searchTerm, progressNameIdTitle);
|
||||
var processNameIdMatch = Context.API.FuzzySearch(searchTerm, progressNameIdTitle);
|
||||
var score = processNameIdMatch.Score;
|
||||
if (score > 0)
|
||||
{
|
||||
|
|
@ -162,7 +162,7 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
foreach (var pr in processlist)
|
||||
{
|
||||
var p = pr.Process;
|
||||
var path = processHelper.TryGetProcessFilename(p);
|
||||
var path = ProcessHelper.TryGetProcessFilename(p);
|
||||
results.Add(new Result()
|
||||
{
|
||||
IcoPath = path,
|
||||
|
|
@ -172,12 +172,12 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
TitleHighlightData = pr.TitleMatch?.MatchData,
|
||||
Score = pr.Score,
|
||||
ContextData = p.ProcessName,
|
||||
AutoCompleteText = $"{_context.CurrentPluginMetadata.ActionKeyword}{Plugin.Query.TermSeparator}{p.ProcessName}",
|
||||
AutoCompleteText = $"{Context.CurrentPluginMetadata.ActionKeyword}{Plugin.Query.TermSeparator}{p.ProcessName}",
|
||||
Action = (c) =>
|
||||
{
|
||||
processHelper.TryKill(_context, p);
|
||||
ProcessHelper.TryKill(p);
|
||||
// Re-query to refresh process list
|
||||
_context.API.ReQuery();
|
||||
Context.API.ReQuery();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
|
@ -194,17 +194,17 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
sortedResults.Insert(1, new Result()
|
||||
{
|
||||
IcoPath = firstResult?.IcoPath,
|
||||
Title = string.Format(_context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_all"), firstResult?.ContextData),
|
||||
SubTitle = string.Format(_context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_all_count"), processlist.Count),
|
||||
Title = Localize.flowlauncher_plugin_processkiller_kill_all(firstResult?.ContextData),
|
||||
SubTitle = Localize.flowlauncher_plugin_processkiller_kill_all_count(processlist.Count),
|
||||
Score = 200,
|
||||
Action = (c) =>
|
||||
{
|
||||
foreach (var p in processlist)
|
||||
{
|
||||
processHelper.TryKill(_context, p.Process);
|
||||
ProcessHelper.TryKill(p.Process);
|
||||
}
|
||||
// Re-query to refresh process list
|
||||
_context.API.ReQuery();
|
||||
Context.API.ReQuery();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
{
|
||||
private static readonly string ClassName = nameof(ProcessHelper);
|
||||
|
||||
private readonly HashSet<string> _systemProcessList = new()
|
||||
{
|
||||
private readonly HashSet<string> _systemProcessList =
|
||||
[
|
||||
"conhost",
|
||||
"svchost",
|
||||
"idle",
|
||||
|
|
@ -31,12 +31,12 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
"winlogon",
|
||||
"services",
|
||||
"spoolsv",
|
||||
"explorer"
|
||||
};
|
||||
"explorer"
|
||||
];
|
||||
|
||||
private const string FlowLauncherProcessName = "Flow.Launcher";
|
||||
|
||||
private bool IsSystemProcessOrFlowLauncher(Process p) =>
|
||||
private bool IsSystemProcessOrFlowLauncher(Process p) =>
|
||||
_systemProcessList.Contains(p.ProcessName.ToLower()) ||
|
||||
string.Equals(p.ProcessName, FlowLauncherProcessName, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
return Process.GetProcesses().Where(p => !IsSystemProcessOrFlowLauncher(p) && TryGetProcessFilename(p) == processPath);
|
||||
}
|
||||
|
||||
public void TryKill(PluginInitContext context, Process p)
|
||||
public static void TryKill(Process p)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -154,11 +154,11 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.API.LogException(ClassName, $"Failed to kill process {p.ProcessName}", e);
|
||||
Main.Context.API.LogException(ClassName, $"Failed to kill process {p.ProcessName}", e);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe string TryGetProcessFilename(Process p)
|
||||
public static unsafe string TryGetProcessFilename(Process p)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,25 +3,16 @@ using Flow.Launcher.Plugin.SharedModels;
|
|||
|
||||
namespace Flow.Launcher.Plugin.ProcessKiller
|
||||
{
|
||||
internal class ProcessResult
|
||||
internal class ProcessResult(Process process, int score, string title, MatchResult match, string tooltip)
|
||||
{
|
||||
public ProcessResult(Process process, int score, string title, MatchResult match, string tooltip)
|
||||
{
|
||||
Process = process;
|
||||
Score = score;
|
||||
Title = title;
|
||||
TitleMatch = match;
|
||||
Tooltip = tooltip;
|
||||
}
|
||||
public Process Process { get; } = process;
|
||||
|
||||
public Process Process { get; }
|
||||
public int Score { get; } = score;
|
||||
|
||||
public int Score { get; }
|
||||
public string Title { get; } = title;
|
||||
|
||||
public string Title { get; }
|
||||
public MatchResult TitleMatch { get; } = match;
|
||||
|
||||
public MatchResult TitleMatch { get; }
|
||||
|
||||
public string Tooltip { get; }
|
||||
public string Tooltip { get; } = tooltip;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,7 @@
|
|||
namespace Flow.Launcher.Plugin.ProcessKiller.ViewModels
|
||||
{
|
||||
public class SettingsViewModel
|
||||
public class SettingsViewModel(Settings settings)
|
||||
{
|
||||
public Settings Settings { get; set; }
|
||||
|
||||
public SettingsViewModel(Settings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
public bool ShowWindowTitle
|
||||
{
|
||||
get => Settings.ShowWindowTitle;
|
||||
set => Settings.ShowWindowTitle = value;
|
||||
}
|
||||
|
||||
public bool PutVisibleWindowProcessesTop
|
||||
{
|
||||
get => Settings.PutVisibleWindowProcessesTop;
|
||||
set => Settings.PutVisibleWindowProcessesTop = value;
|
||||
}
|
||||
public Settings Settings { get; set; } = settings;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
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"
|
||||
xmlns:vm="clr-namespace:Flow.Launcher.Plugin.ProcessKiller.ViewModels"
|
||||
d:DataContext="{d:DesignInstance Type=vm:SettingsViewModel}"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="500"
|
||||
mc:Ignorable="d">
|
||||
|
|
@ -18,11 +20,11 @@
|
|||
Grid.Row="0"
|
||||
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||
Content="{DynamicResource flowlauncher_plugin_processkiller_show_window_title}"
|
||||
IsChecked="{Binding ShowWindowTitle}" />
|
||||
IsChecked="{Binding Settings.ShowWindowTitle}" />
|
||||
<CheckBox
|
||||
Grid.Row="1"
|
||||
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||
Content="{DynamicResource flowlauncher_plugin_processkiller_put_visible_window_process_top}"
|
||||
IsChecked="{Binding PutVisibleWindowProcessesTop}" />
|
||||
IsChecked="{Binding Settings.PutVisibleWindowProcessesTop}" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
@ -5,9 +5,6 @@ namespace Flow.Launcher.Plugin.ProcessKiller.Views;
|
|||
|
||||
public partial class SettingsControl : UserControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SettingsControl.xaml
|
||||
/// </summary>
|
||||
public SettingsControl(SettingsViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<NoWarn>$(NoWarn);FLSG0007</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -58,6 +59,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
|
||||
<PackageReference Include="InputSimulator" Version="1.0.4" NoWarn="NU1701" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using WindowsInput;
|
||||
using WindowsInput.Native;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using Control = System.Windows.Controls.Control;
|
||||
using Keys = System.Windows.Forms.Keys;
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
{
|
||||
private static readonly string ClassName = nameof(Main);
|
||||
|
||||
internal PluginInitContext Context { get; private set; }
|
||||
internal static PluginInitContext Context { get; private set; }
|
||||
|
||||
private const string Image = "Images/shell.png";
|
||||
private bool _winRStroked;
|
||||
|
|
@ -27,7 +27,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
List<Result> results = new List<Result>();
|
||||
List<Result> results = [];
|
||||
string cmd = query.Search;
|
||||
if (string.IsNullOrEmpty(cmd))
|
||||
{
|
||||
|
|
@ -45,7 +45,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
string basedir = null;
|
||||
string dir = null;
|
||||
string excmd = Environment.ExpandEnvironmentVariables(cmd);
|
||||
if (Directory.Exists(excmd) && (cmd.EndsWith("/") || cmd.EndsWith(@"\")))
|
||||
if (Directory.Exists(excmd) && (cmd.EndsWith('/') || cmd.EndsWith('\\')))
|
||||
{
|
||||
basedir = excmd;
|
||||
dir = cmd;
|
||||
|
|
@ -54,7 +54,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
{
|
||||
basedir = Path.GetDirectoryName(excmd);
|
||||
var dirName = Path.GetDirectoryName(cmd);
|
||||
dir = (dirName.EndsWith("/") || dirName.EndsWith(@"\")) ? dirName : cmd[..(dirName.Length + 1)];
|
||||
dir = (dirName.EndsWith('/') || dirName.EndsWith('\\')) ? dirName : cmd[..(dirName.Length + 1)];
|
||||
}
|
||||
|
||||
if (basedir != null)
|
||||
|
|
@ -103,14 +103,14 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
{
|
||||
if (m.Key == cmd)
|
||||
{
|
||||
result.SubTitle = string.Format(Context.API.GetTranslation("flowlauncher_plugin_cmd_cmd_has_been_executed_times"), m.Value);
|
||||
result.SubTitle = Localize.flowlauncher_plugin_cmd_cmd_has_been_executed_times(m.Value);
|
||||
return null;
|
||||
}
|
||||
|
||||
var ret = new Result
|
||||
{
|
||||
Title = m.Key,
|
||||
SubTitle = string.Format(Context.API.GetTranslation("flowlauncher_plugin_cmd_cmd_has_been_executed_times"), m.Value),
|
||||
SubTitle = Localize.flowlauncher_plugin_cmd_cmd_has_been_executed_times(m.Value),
|
||||
IcoPath = Image,
|
||||
Action = c =>
|
||||
{
|
||||
|
|
@ -129,9 +129,9 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
}).Where(o => o != null);
|
||||
|
||||
if (_settings.ShowOnlyMostUsedCMDs)
|
||||
return history.Take(_settings.ShowOnlyMostUsedCMDsNumber).ToList();
|
||||
return [.. history.Take(_settings.ShowOnlyMostUsedCMDsNumber)];
|
||||
|
||||
return history.ToList();
|
||||
return [.. history];
|
||||
}
|
||||
|
||||
private Result GetCurrentCmd(string cmd)
|
||||
|
|
@ -140,7 +140,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
{
|
||||
Title = cmd,
|
||||
Score = 5000,
|
||||
SubTitle = Context.API.GetTranslation("flowlauncher_plugin_cmd_execute_through_shell"),
|
||||
SubTitle = Localize.flowlauncher_plugin_cmd_execute_through_shell(),
|
||||
IcoPath = Image,
|
||||
Action = c =>
|
||||
{
|
||||
|
|
@ -165,7 +165,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
.Select(m => new Result
|
||||
{
|
||||
Title = m.Key,
|
||||
SubTitle = string.Format(Context.API.GetTranslation("flowlauncher_plugin_cmd_cmd_has_been_executed_times"), m.Value),
|
||||
SubTitle = Localize.flowlauncher_plugin_cmd_cmd_has_been_executed_times(m.Value),
|
||||
IcoPath = Image,
|
||||
Action = c =>
|
||||
{
|
||||
|
|
@ -182,9 +182,9 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
});
|
||||
|
||||
if (_settings.ShowOnlyMostUsedCMDs)
|
||||
return history.Take(_settings.ShowOnlyMostUsedCMDsNumber).ToList();
|
||||
return [.. history.Take(_settings.ShowOnlyMostUsedCMDsNumber)];
|
||||
|
||||
return history.ToList();
|
||||
return [.. history];
|
||||
}
|
||||
|
||||
private ProcessStartInfo PrepareProcessStartInfo(string command, bool runAsAdministrator = false)
|
||||
|
|
@ -199,7 +199,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
Verb = runAsAdministratorArg,
|
||||
WorkingDirectory = workingDirectory,
|
||||
};
|
||||
var notifyStr = Context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close");
|
||||
var notifyStr = Localize.flowlauncher_plugin_cmd_press_any_key_to_close();
|
||||
var addedCharacter = _settings.UseWindowsTerminal ? "\\" : "";
|
||||
switch (_settings.Shell)
|
||||
{
|
||||
|
|
@ -288,10 +288,10 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
|
||||
case Shell.RunCommand:
|
||||
{
|
||||
var parts = command.Split(new[]
|
||||
{
|
||||
var parts = command.Split(
|
||||
[
|
||||
' '
|
||||
}, 2);
|
||||
], 2);
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
var filename = parts[0];
|
||||
|
|
@ -336,12 +336,12 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
catch (FileNotFoundException e)
|
||||
{
|
||||
Context.API.ShowMsgError(GetTranslatedPluginTitle(),
|
||||
string.Format(Context.API.GetTranslation("flowlauncher_plugin_cmd_command_not_found"), e.Message));
|
||||
Localize.flowlauncher_plugin_cmd_command_not_found(e.Message));
|
||||
}
|
||||
catch (Win32Exception e)
|
||||
{
|
||||
Context.API.ShowMsgError(GetTranslatedPluginTitle(),
|
||||
string.Format(Context.API.GetTranslation("flowlauncher_plugin_cmd_error_running_command"), e.Message));
|
||||
Localize.flowlauncher_plugin_cmd_error_running_command(e.Message));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
@ -405,7 +405,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
return true;
|
||||
}
|
||||
|
||||
private void OnWinRPressed()
|
||||
private static void OnWinRPressed()
|
||||
{
|
||||
Context.API.ShowMainWindow();
|
||||
// show the main window and set focus to the query box
|
||||
|
|
@ -428,12 +428,12 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return Context.API.GetTranslation("flowlauncher_plugin_cmd_plugin_name");
|
||||
return Localize.flowlauncher_plugin_cmd_plugin_name();
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return Context.API.GetTranslation("flowlauncher_plugin_cmd_plugin_description");
|
||||
return Localize.flowlauncher_plugin_cmd_plugin_description();
|
||||
}
|
||||
|
||||
public List<Result> LoadContextMenus(Result selectedResult)
|
||||
|
|
@ -442,7 +442,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
{
|
||||
new()
|
||||
{
|
||||
Title = Context.API.GetTranslation("flowlauncher_plugin_cmd_run_as_different_user"),
|
||||
Title = Localize.flowlauncher_plugin_cmd_run_as_different_user(),
|
||||
Action = c =>
|
||||
{
|
||||
Execute(ShellCommand.RunAsDifferentUser, PrepareProcessStartInfo(selectedResult.Title));
|
||||
|
|
@ -453,7 +453,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
},
|
||||
new()
|
||||
{
|
||||
Title = Context.API.GetTranslation("flowlauncher_plugin_cmd_run_as_administrator"),
|
||||
Title = Localize.flowlauncher_plugin_cmd_run_as_administrator(),
|
||||
Action = c =>
|
||||
{
|
||||
Execute(Process.Start, PrepareProcessStartInfo(selectedResult.Title, true));
|
||||
|
|
@ -464,7 +464,7 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
},
|
||||
new()
|
||||
{
|
||||
Title = Context.API.GetTranslation("flowlauncher_plugin_cmd_copy"),
|
||||
Title = Localize.flowlauncher_plugin_cmd_copy(),
|
||||
Action = c =>
|
||||
{
|
||||
Context.API.CopyToClipboard(selectedResult.Title);
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
public class Settings
|
||||
{
|
||||
public Shell Shell { get; set; } = Shell.Cmd;
|
||||
|
||||
|
||||
public bool ReplaceWinR { get; set; } = false;
|
||||
|
||||
public bool CloseShellAfterPress { get; set; } = false;
|
||||
|
||||
|
||||
public bool LeaveShellOpen { get; set; }
|
||||
|
||||
public bool RunAsAdministrator { get; set; } = true;
|
||||
|
|
@ -20,18 +20,14 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
|
||||
public int ShowOnlyMostUsedCMDsNumber { get; set; }
|
||||
|
||||
public Dictionary<string, int> CommandHistory { get; set; } = new Dictionary<string, int>();
|
||||
public Dictionary<string, int> CommandHistory { get; set; } = [];
|
||||
|
||||
public void AddCmdHistory(string cmdName)
|
||||
{
|
||||
if (CommandHistory.ContainsKey(cmdName))
|
||||
if (!CommandHistory.TryAdd(cmdName, 1))
|
||||
{
|
||||
CommandHistory[cmdName] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandHistory.Add(cmdName, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,18 +19,18 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
ReplaceWinR.IsChecked = _settings.ReplaceWinR;
|
||||
|
||||
CloseShellAfterPress.IsChecked = _settings.CloseShellAfterPress;
|
||||
|
||||
|
||||
LeaveShellOpen.IsChecked = _settings.LeaveShellOpen;
|
||||
|
||||
|
||||
AlwaysRunAsAdministrator.IsChecked = _settings.RunAsAdministrator;
|
||||
|
||||
UseWindowsTerminal.IsChecked = _settings.UseWindowsTerminal;
|
||||
|
||||
|
||||
LeaveShellOpen.IsEnabled = _settings.Shell != Shell.RunCommand;
|
||||
|
||||
|
||||
ShowOnlyMostUsedCMDs.IsChecked = _settings.ShowOnlyMostUsedCMDs;
|
||||
|
||||
if ((bool)!ShowOnlyMostUsedCMDs.IsChecked)
|
||||
|
||||
if (ShowOnlyMostUsedCMDs.IsChecked != true)
|
||||
ShowOnlyMostUsedCMDsNumber.IsEnabled = false;
|
||||
|
||||
ShowOnlyMostUsedCMDsNumber.ItemsSource = new List<int>() { 5, 10, 20 };
|
||||
|
|
@ -137,7 +137,6 @@ namespace Flow.Launcher.Plugin.Shell
|
|||
{
|
||||
_settings.ShowOnlyMostUsedCMDsNumber = (int)ShowOnlyMostUsedCMDsNumber.SelectedItem;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,13 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
public partial class CommandKeywordSettingWindow
|
||||
{
|
||||
private readonly Command _oldSearchSource;
|
||||
private readonly PluginInitContext _context;
|
||||
|
||||
public CommandKeywordSettingWindow(PluginInitContext context, Command old)
|
||||
public CommandKeywordSettingWindow(Command old)
|
||||
{
|
||||
_context = context;
|
||||
_oldSearchSource = old;
|
||||
InitializeComponent();
|
||||
CommandKeyword.Text = old.Keyword;
|
||||
CommandKeywordTips.Text = string.Format(_context.API.GetTranslation("flowlauncher_plugin_sys_custom_command_keyword_tip"), old.Name);
|
||||
CommandKeywordTips.Text = Localize.flowlauncher_plugin_sys_custom_command_keyword_tip(old.Name);
|
||||
}
|
||||
|
||||
private void OnCancelButtonClick(object sender, RoutedEventArgs e)
|
||||
|
|
@ -26,8 +24,8 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
var keyword = CommandKeyword.Text;
|
||||
if (string.IsNullOrEmpty(keyword))
|
||||
{
|
||||
var warning = _context.API.GetTranslation("flowlauncher_plugin_sys_input_command_keyword");
|
||||
_context.API.ShowMsgBox(warning);
|
||||
var warning = Localize.flowlauncher_plugin_sys_input_command_keyword();
|
||||
Main.Context.API.ShowMsgBox(warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<NoWarn>$(NoWarn);FLSG0007</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -58,6 +59,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.205">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
|
|
|||
|
|
@ -78,4 +78,9 @@
|
|||
<system:String x:Key="flowlauncher_plugin_sys_plugin_name">System Commands</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_plugin_description">Provides System related commands. e.g. shutdown, lock, settings etc.</system:String>
|
||||
|
||||
<!-- Theme Selector -->
|
||||
<system:String x:Key="flowlauncher_plugin_sys_type_isdark_hasblur">This theme supports two (light/dark) modes and Blur Transparent Background</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_type_isdark">This theme supports two (light/dark) modes</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_sys_type_hasblur">This theme supports Blur Transparent Background</system:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using System.Diagnostics;
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
|
|
@ -42,7 +43,7 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
{"Toggle Game Mode", "flowlauncher_plugin_sys_toggle_game_mode_cmd"},
|
||||
{"Set Flow Launcher Theme", "flowlauncher_plugin_sys_theme_selector_cmd"}
|
||||
};
|
||||
private readonly Dictionary<string, string> KeywordDescriptionMappings = new();
|
||||
private readonly Dictionary<string, string> KeywordDescriptionMappings = [];
|
||||
|
||||
// SHTDN_REASON_MAJOR_OTHER indicates a generic shutdown reason that isn't categorized under hardware failure,
|
||||
// software updates, or other predefined reasons.
|
||||
|
|
@ -52,22 +53,21 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
|
||||
private const string Documentation = "https://flowlauncher.com/docs/#/usage-tips";
|
||||
|
||||
private PluginInitContext _context;
|
||||
internal static PluginInitContext Context { get; private set; }
|
||||
private Settings _settings;
|
||||
private ThemeSelector _themeSelector;
|
||||
private SettingsViewModel _viewModel;
|
||||
|
||||
public Control CreateSettingPanel()
|
||||
{
|
||||
UpdateLocalizedNameDescription(false);
|
||||
return new SysSettings(_context, _viewModel);
|
||||
return new SysSettings(_viewModel);
|
||||
}
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
if(query.Search.StartsWith(ThemeSelector.Keyword))
|
||||
if (query.Search.StartsWith(ThemeSelector.Keyword))
|
||||
{
|
||||
return _themeSelector.Query(query);
|
||||
return ThemeSelector.Query(query);
|
||||
}
|
||||
|
||||
var commands = Commands(query);
|
||||
|
|
@ -85,9 +85,9 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
}
|
||||
|
||||
// Match from localized title & localized subtitle & keyword
|
||||
var titleMatch = _context.API.FuzzySearch(query.Search, c.Title);
|
||||
var subTitleMatch = _context.API.FuzzySearch(query.Search, c.SubTitle);
|
||||
var keywordMatch = _context.API.FuzzySearch(query.Search, command.Keyword);
|
||||
var titleMatch = Context.API.FuzzySearch(query.Search, c.Title);
|
||||
var subTitleMatch = Context.API.FuzzySearch(query.Search, c.SubTitle);
|
||||
var keywordMatch = Context.API.FuzzySearch(query.Search, command.Keyword);
|
||||
|
||||
// Get the largest score from them
|
||||
var score = Math.Max(titleMatch.Score, subTitleMatch.Score);
|
||||
|
|
@ -113,30 +113,29 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
{
|
||||
if (!KeywordTitleMappings.TryGetValue(key, out var translationKey))
|
||||
{
|
||||
_context.API.LogError(ClassName, $"Title not found for: {key}");
|
||||
Context.API.LogError(ClassName, $"Title not found for: {key}");
|
||||
return "Title Not Found";
|
||||
}
|
||||
|
||||
return _context.API.GetTranslation(translationKey);
|
||||
return Context.API.GetTranslation(translationKey);
|
||||
}
|
||||
|
||||
private string GetDescription(string key)
|
||||
{
|
||||
if (!KeywordDescriptionMappings.TryGetValue(key, out var translationKey))
|
||||
{
|
||||
_context.API.LogError(ClassName, $"Description not found for: {key}");
|
||||
Context.API.LogError(ClassName, $"Description not found for: {key}");
|
||||
return "Description Not Found";
|
||||
}
|
||||
|
||||
return _context.API.GetTranslation(translationKey);
|
||||
return Context.API.GetTranslation(translationKey);
|
||||
}
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
_context = context;
|
||||
Context = context;
|
||||
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||
_viewModel = new SettingsViewModel(_settings);
|
||||
_themeSelector = new ThemeSelector(context);
|
||||
foreach (string key in KeywordTitleMappings.Keys)
|
||||
{
|
||||
// Remove _cmd in the last of the strings
|
||||
|
|
@ -194,12 +193,12 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
}
|
||||
}
|
||||
|
||||
private List<Result> Commands(Query query)
|
||||
private static List<Result> Commands(Query query)
|
||||
{
|
||||
var results = new List<Result>();
|
||||
var recycleBinFolder = "shell:RecycleBinFolder";
|
||||
results.AddRange(new[]
|
||||
{
|
||||
results.AddRange(
|
||||
[
|
||||
new Result
|
||||
{
|
||||
Title = "Shutdown",
|
||||
|
|
@ -207,9 +206,9 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
IcoPath = "Images\\shutdown.png",
|
||||
Action = c =>
|
||||
{
|
||||
var result = _context.API.ShowMsgBox(
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_shutdown_computer"),
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_shutdown_computer"),
|
||||
var result = Context.API.ShowMsgBox(
|
||||
Localize.flowlauncher_plugin_sys_dlgtext_shutdown_computer(),
|
||||
Localize.flowlauncher_plugin_sys_shutdown_computer(),
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
|
|
@ -228,9 +227,9 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
IcoPath = "Images\\restart.png",
|
||||
Action = c =>
|
||||
{
|
||||
var result = _context.API.ShowMsgBox(
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_restart_computer"),
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_restart_computer"),
|
||||
var result = Context.API.ShowMsgBox(
|
||||
Localize.flowlauncher_plugin_sys_dlgtext_restart_computer(),
|
||||
Localize.flowlauncher_plugin_sys_restart_computer(),
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
|
|
@ -249,9 +248,9 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
IcoPath = "Images\\restart_advanced.png",
|
||||
Action = c =>
|
||||
{
|
||||
var result = _context.API.ShowMsgBox(
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_restart_computer_advanced"),
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_restart_computer"),
|
||||
var result = Context.API.ShowMsgBox(
|
||||
Localize.flowlauncher_plugin_sys_dlgtext_restart_computer_advanced(),
|
||||
Localize.flowlauncher_plugin_sys_restart_computer(),
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
|
|
@ -270,9 +269,9 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
IcoPath = "Images\\logoff.png",
|
||||
Action = c =>
|
||||
{
|
||||
var result = _context.API.ShowMsgBox(
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_logoff_computer"),
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_log_off"),
|
||||
var result = Context.API.ShowMsgBox(
|
||||
Localize.flowlauncher_plugin_sys_dlgtext_logoff_computer(),
|
||||
Localize.flowlauncher_plugin_sys_log_off(),
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
|
|
@ -338,9 +337,9 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
var result = PInvoke.SHEmptyRecycleBin(new(), string.Empty, 0);
|
||||
if (result != HRESULT.S_OK && result != HRESULT.E_UNEXPECTED)
|
||||
{
|
||||
_context.API.ShowMsgBox(
|
||||
string.Format(_context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_empty_recycle_bin_failed"), Environment.NewLine),
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_dlgtitle_error"),
|
||||
Context.API.ShowMsgBox(
|
||||
Localize.flowlauncher_plugin_sys_dlgtext_empty_recycle_bin_failed(Environment.NewLine),
|
||||
Localize.flowlauncher_plugin_sys_dlgtitle_error(),
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
|
||||
|
|
@ -366,7 +365,7 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\xe89f"),
|
||||
Action = c =>
|
||||
{
|
||||
_context.API.HideMainWindow();
|
||||
Context.API.HideMainWindow();
|
||||
Application.Current.MainWindow.Close();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -378,9 +377,9 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
IcoPath = "Images\\app.png",
|
||||
Action = c =>
|
||||
{
|
||||
_context.API.SaveAppAllSettings();
|
||||
_context.API.ShowMsg(_context.API.GetTranslation("flowlauncher_plugin_sys_dlgtitle_success"),
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_all_settings_saved"));
|
||||
Context.API.SaveAppAllSettings();
|
||||
Context.API.ShowMsg(Localize.flowlauncher_plugin_sys_dlgtitle_success(),
|
||||
Localize.flowlauncher_plugin_sys_dlgtext_all_settings_saved());
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
|
@ -391,7 +390,7 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
IcoPath = "Images\\app.png",
|
||||
Action = c =>
|
||||
{
|
||||
_context.API.RestartApp();
|
||||
Context.API.RestartApp();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
|
@ -403,8 +402,8 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
Action = c =>
|
||||
{
|
||||
// Hide the window first then open setting dialog because main window can be topmost window which will still display on top of the setting dialog for a while
|
||||
_context.API.HideMainWindow();
|
||||
_context.API.OpenSettingDialog();
|
||||
Context.API.HideMainWindow();
|
||||
Context.API.OpenSettingDialog();
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
|
@ -416,14 +415,13 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
Action = c =>
|
||||
{
|
||||
// Hide the window first then show msg after done because sometimes the reload could take a while, so not to make user think it's frozen.
|
||||
_context.API.HideMainWindow();
|
||||
Context.API.HideMainWindow();
|
||||
|
||||
_ = _context.API.ReloadAllPluginData().ContinueWith(_ =>
|
||||
_context.API.ShowMsg(
|
||||
_context.API.GetTranslation("flowlauncher_plugin_sys_dlgtitle_success"),
|
||||
_context.API.GetTranslation(
|
||||
"flowlauncher_plugin_sys_dlgtext_all_applicableplugins_reloaded")),
|
||||
System.Threading.Tasks.TaskScheduler.Current);
|
||||
_ = Context.API.ReloadAllPluginData().ContinueWith(_ =>
|
||||
Context.API.ShowMsg(
|
||||
Localize.flowlauncher_plugin_sys_dlgtitle_success(),
|
||||
Localize.flowlauncher_plugin_sys_dlgtext_all_applicableplugins_reloaded()),
|
||||
TaskScheduler.Current);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -435,8 +433,8 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
IcoPath = "Images\\checkupdate.png",
|
||||
Action = c =>
|
||||
{
|
||||
_context.API.HideMainWindow();
|
||||
_context.API.CheckForNewUpdate();
|
||||
Context.API.HideMainWindow();
|
||||
Context.API.CheckForNewUpdate();
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
|
@ -445,11 +443,11 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\xf12b"),
|
||||
Title = "Open Log Location",
|
||||
IcoPath = "Images\\app.png",
|
||||
CopyText = _context.API.GetLogDirectory(),
|
||||
AutoCompleteText = _context.API.GetLogDirectory(),
|
||||
CopyText = Context.API.GetLogDirectory(),
|
||||
AutoCompleteText = Context.API.GetLogDirectory(),
|
||||
Action = c =>
|
||||
{
|
||||
_context.API.OpenDirectory(_context.API.GetLogDirectory());
|
||||
Context.API.OpenDirectory(Context.API.GetLogDirectory());
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
|
@ -462,7 +460,7 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
AutoCompleteText = Documentation,
|
||||
Action = c =>
|
||||
{
|
||||
_context.API.OpenUrl(Documentation);
|
||||
Context.API.OpenUrl(Documentation);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
|
@ -471,11 +469,11 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
Title = "Flow Launcher UserData Folder",
|
||||
Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\xf12b"),
|
||||
IcoPath = "Images\\app.png",
|
||||
CopyText = _context.API.GetDataDirectory(),
|
||||
AutoCompleteText = _context.API.GetDataDirectory(),
|
||||
CopyText = Context.API.GetDataDirectory(),
|
||||
AutoCompleteText = Context.API.GetDataDirectory(),
|
||||
Action = c =>
|
||||
{
|
||||
_context.API.OpenDirectory(_context.API.GetDataDirectory());
|
||||
Context.API.OpenDirectory(Context.API.GetDataDirectory());
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
|
@ -486,7 +484,7 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\ue7fc"),
|
||||
Action = c =>
|
||||
{
|
||||
_context.API.ToggleGameMode();
|
||||
Context.API.ToggleGameMode();
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
|
@ -499,29 +497,29 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
{
|
||||
if (string.IsNullOrEmpty(query.ActionKeyword))
|
||||
{
|
||||
_context.API.ChangeQuery($"{ThemeSelector.Keyword}{Plugin.Query.ActionKeywordSeparator}");
|
||||
Context.API.ChangeQuery($"{ThemeSelector.Keyword}{Plugin.Query.ActionKeywordSeparator}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.API.ChangeQuery($"{query.ActionKeyword}{Plugin.Query.ActionKeywordSeparator}{ThemeSelector.Keyword}{Plugin.Query.ActionKeywordSeparator}");
|
||||
Context.API.ChangeQuery($"{query.ActionKeyword}{Plugin.Query.ActionKeywordSeparator}{ThemeSelector.Keyword}{Plugin.Query.ActionKeywordSeparator}");
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
]);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return _context.API.GetTranslation("flowlauncher_plugin_sys_plugin_name");
|
||||
return Localize.flowlauncher_plugin_sys_plugin_name();
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return _context.API.GetTranslation("flowlauncher_plugin_sys_plugin_description");
|
||||
return Localize.flowlauncher_plugin_sys_plugin_description();
|
||||
}
|
||||
|
||||
public void OnCultureInfoChanged(CultureInfo _)
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ public class Settings : BaseModel
|
|||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<Command> Commands { get; set; } = new ObservableCollection<Command>
|
||||
{
|
||||
public ObservableCollection<Command> Commands { get; set; } =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Key = "Shutdown",
|
||||
|
|
@ -120,7 +120,7 @@ public class Settings : BaseModel
|
|||
Key = "Set Flow Launcher Theme",
|
||||
Keyword = "Set Flow Launcher Theme"
|
||||
}
|
||||
};
|
||||
];
|
||||
|
||||
[JsonIgnore]
|
||||
public Command SelectedCommand { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
namespace Flow.Launcher.Plugin.Sys
|
||||
{
|
||||
public class SettingsViewModel
|
||||
public class SettingsViewModel(Settings settings)
|
||||
{
|
||||
public SettingsViewModel(Settings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
public Settings Settings { get; }
|
||||
public Settings Settings { get; } = settings;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Sys
|
||||
{
|
||||
public partial class SysSettings : UserControl
|
||||
{
|
||||
private readonly PluginInitContext _context;
|
||||
private readonly Settings _settings;
|
||||
|
||||
public SysSettings(PluginInitContext context, SettingsViewModel viewModel)
|
||||
public SysSettings(SettingsViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
_context = context;
|
||||
_settings = viewModel.Settings;
|
||||
DataContext = viewModel;
|
||||
}
|
||||
|
|
@ -37,15 +36,15 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
|
||||
public void OnEditCommandKeywordClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var commandKeyword = new CommandKeywordSettingWindow(_context, _settings.SelectedCommand);
|
||||
var commandKeyword = new CommandKeywordSettingWindow(_settings.SelectedCommand);
|
||||
commandKeyword.ShowDialog();
|
||||
}
|
||||
|
||||
private void MouseDoubleClickItem(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
private void MouseDoubleClickItem(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (((FrameworkElement)e.OriginalSource).DataContext is Command && _settings.SelectedCommand != null)
|
||||
{
|
||||
var commandKeyword = new CommandKeywordSettingWindow(_context, _settings.SelectedCommand);
|
||||
var commandKeyword = new CommandKeywordSettingWindow(_settings.SelectedCommand);
|
||||
commandKeyword.ShowDialog();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,40 +4,30 @@ using Flow.Launcher.Plugin.SharedModels;
|
|||
|
||||
namespace Flow.Launcher.Plugin.Sys
|
||||
{
|
||||
public class ThemeSelector
|
||||
public static class ThemeSelector
|
||||
{
|
||||
public const string Keyword = "fltheme";
|
||||
|
||||
private readonly PluginInitContext _context;
|
||||
|
||||
public ThemeSelector(PluginInitContext context)
|
||||
public static List<Result> Query(Query query)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
var themes = _context.API.GetAvailableThemes();
|
||||
var selectedTheme = _context.API.GetCurrentTheme();
|
||||
var themes = Main.Context.API.GetAvailableThemes();
|
||||
var selectedTheme = Main.Context.API.GetCurrentTheme();
|
||||
|
||||
var search = query.SecondToEndSearch;
|
||||
if (string.IsNullOrWhiteSpace(search))
|
||||
{
|
||||
return themes.Select(x => CreateThemeResult(x, selectedTheme))
|
||||
.OrderBy(x => x.Title)
|
||||
.ToList();
|
||||
return [.. themes.Select(x => CreateThemeResult(x, selectedTheme)).OrderBy(x => x.Title)];
|
||||
}
|
||||
|
||||
return themes.Select(theme => (theme, matchResult: _context.API.FuzzySearch(search, theme.Name)))
|
||||
.Where(x => x.matchResult.IsSearchPrecisionScoreMet())
|
||||
.Select(x => CreateThemeResult(x.theme, selectedTheme, x.matchResult.Score, x.matchResult.MatchData))
|
||||
.OrderBy(x => x.Title)
|
||||
.ToList();
|
||||
return [.. themes.Select(theme => (theme, matchResult: Main.Context.API.FuzzySearch(search, theme.Name)))
|
||||
.Where(x => x.matchResult.IsSearchPrecisionScoreMet())
|
||||
.Select(x => CreateThemeResult(x.theme, selectedTheme, x.matchResult.Score, x.matchResult.MatchData))
|
||||
.OrderBy(x => x.Title)];
|
||||
}
|
||||
|
||||
private Result CreateThemeResult(ThemeData theme, ThemeData selectedTheme) => CreateThemeResult(theme, selectedTheme, 0, null);
|
||||
private static Result CreateThemeResult(ThemeData theme, ThemeData selectedTheme) => CreateThemeResult(theme, selectedTheme, 0, null);
|
||||
|
||||
private Result CreateThemeResult(ThemeData theme, ThemeData selectedTheme, int score, IList<int> highlightData)
|
||||
private static Result CreateThemeResult(ThemeData theme, ThemeData selectedTheme, int score, IList<int> highlightData)
|
||||
{
|
||||
string title;
|
||||
if (theme == selectedTheme)
|
||||
|
|
@ -53,17 +43,28 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
score = 1000;
|
||||
}
|
||||
|
||||
string description = string.Empty;
|
||||
string description;
|
||||
if (theme.IsDark == true)
|
||||
{
|
||||
description += _context.API.GetTranslation("TypeIsDarkToolTip");
|
||||
if (theme.HasBlur == true)
|
||||
{
|
||||
description = Localize.flowlauncher_plugin_sys_type_isdark_hasblur();
|
||||
}
|
||||
else
|
||||
{
|
||||
description = Localize.flowlauncher_plugin_sys_type_isdark();
|
||||
}
|
||||
}
|
||||
|
||||
if (theme.HasBlur == true)
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
description += " ";
|
||||
description += _context.API.GetTranslation("TypeHasBlurToolTip");
|
||||
if (theme.HasBlur == true)
|
||||
{
|
||||
description = Localize.flowlauncher_plugin_sys_type_hasblur();
|
||||
}
|
||||
else
|
||||
{
|
||||
description = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
return new Result
|
||||
|
|
@ -76,9 +77,9 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
Score = score,
|
||||
Action = c =>
|
||||
{
|
||||
if (_context.API.SetCurrentTheme(theme))
|
||||
if (Main.Context.API.SetCurrentTheme(theme))
|
||||
{
|
||||
_context.API.ReQuery();
|
||||
Main.Context.API.ReQuery();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<NoWarn>$(NoWarn);FLSG0007</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -56,4 +57,8 @@
|
|||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace Flow.Launcher.Plugin.Url
|
|||
"(?:/\\S*)?" +
|
||||
"$";
|
||||
Regex reg = new Regex(urlPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private PluginInitContext context;
|
||||
internal static PluginInitContext Context { get; private set; }
|
||||
private Settings _settings;
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
|
|
@ -53,7 +53,7 @@ namespace Flow.Launcher.Plugin.Url
|
|||
new Result
|
||||
{
|
||||
Title = raw,
|
||||
SubTitle = string.Format(context.API.GetTranslation("flowlauncher_plugin_url_open_url"),raw),
|
||||
SubTitle = Localize.flowlauncher_plugin_url_open_url(raw),
|
||||
IcoPath = "Images/url.png",
|
||||
Score = 8,
|
||||
Action = _ =>
|
||||
|
|
@ -64,13 +64,13 @@ namespace Flow.Launcher.Plugin.Url
|
|||
}
|
||||
try
|
||||
{
|
||||
context.API.OpenUrl(raw);
|
||||
Context.API.OpenUrl(raw);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
context.API.ShowMsgError(string.Format(context.API.GetTranslation("flowlauncher_plugin_url_cannot_open_url"), raw));
|
||||
Context.API.ShowMsgError(Localize.flowlauncher_plugin_url_cannot_open_url(raw));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -99,19 +99,19 @@ namespace Flow.Launcher.Plugin.Url
|
|||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
this.context = context;
|
||||
Context = context;
|
||||
|
||||
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return context.API.GetTranslation("flowlauncher_plugin_url_plugin_name");
|
||||
return Localize.flowlauncher_plugin_url_plugin_name();
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return context.API.GetTranslation("flowlauncher_plugin_url_plugin_description");
|
||||
return Localize.flowlauncher_plugin_url_plugin_description();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue