mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge branch 'dev' into 250331-NewPluginsPage
This commit is contained in:
commit
378e98f0bb
9 changed files with 124 additions and 93 deletions
|
|
@ -1,15 +1,14 @@
|
|||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
|
||||
namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
||||
{
|
||||
|
|
@ -43,8 +42,11 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
|
||||
internal IEnumerable<PluginPair> Setup()
|
||||
{
|
||||
// If no plugin is using the language, return empty list
|
||||
if (!PluginMetadataList.Any(o => o.Language.Equals(Language, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return new List<PluginPair>();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(PluginsSettingsFilePath) && FilesFolders.FileExists(PluginsSettingsFilePath))
|
||||
{
|
||||
|
|
@ -56,24 +58,55 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
}
|
||||
|
||||
var noRuntimeMessage = string.Format(
|
||||
InternationalizationManager.Instance.GetTranslation("runtimePluginInstalledChooseRuntimePrompt"),
|
||||
API.GetTranslation("runtimePluginInstalledChooseRuntimePrompt"),
|
||||
Language,
|
||||
EnvName,
|
||||
Environment.NewLine
|
||||
);
|
||||
if (API.ShowMsgBox(noRuntimeMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
|
||||
{
|
||||
var msg = string.Format(InternationalizationManager.Instance.GetTranslation("runtimePluginChooseRuntimeExecutable"), EnvName);
|
||||
string selectedFile;
|
||||
var msg = string.Format(API.GetTranslation("runtimePluginChooseRuntimeExecutable"), EnvName);
|
||||
|
||||
selectedFile = GetFileFromDialog(msg, FileDialogFilter);
|
||||
var selectedFile = GetFileFromDialog(msg, FileDialogFilter);
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
{
|
||||
PluginsSettingsFilePath = selectedFile;
|
||||
|
||||
}
|
||||
// Nothing selected because user pressed cancel from the file dialog window
|
||||
if (string.IsNullOrEmpty(selectedFile))
|
||||
InstallEnvironment();
|
||||
else
|
||||
{
|
||||
var forceDownloadMessage = string.Format(
|
||||
API.GetTranslation("runtimeExecutableInvalidChooseDownload"),
|
||||
Language,
|
||||
EnvName,
|
||||
Environment.NewLine
|
||||
);
|
||||
|
||||
// Let users select valid path or choose to download
|
||||
while (string.IsNullOrEmpty(selectedFile))
|
||||
{
|
||||
if (API.ShowMsgBox(forceDownloadMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
// Continue select file
|
||||
selectedFile = GetFileFromDialog(msg, FileDialogFilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
// User selected no, break the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
{
|
||||
PluginsSettingsFilePath = selectedFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
InstallEnvironment();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -86,7 +119,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
}
|
||||
else
|
||||
{
|
||||
API.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language));
|
||||
API.ShowMsgBox(string.Format(API.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language));
|
||||
Log.Error("PluginsLoader",
|
||||
$"Not able to successfully set {EnvName} path, setting's plugin executable path variable is still an empty string.",
|
||||
$"{Language}Environment");
|
||||
|
|
@ -99,13 +132,11 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
|
||||
private void EnsureLatestInstalled(string expectedPath, string currentPath, string installedDirPath)
|
||||
{
|
||||
if (expectedPath == currentPath)
|
||||
return;
|
||||
if (expectedPath == currentPath) return;
|
||||
|
||||
FilesFolders.RemoveFolderIfExists(installedDirPath, (s) => API.ShowMsgBox(s));
|
||||
|
||||
InstallEnvironment();
|
||||
|
||||
}
|
||||
|
||||
internal abstract PluginPair CreatePluginPair(string filePath, PluginMetadata metadata);
|
||||
|
|
@ -126,7 +157,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
return pluginPairs;
|
||||
}
|
||||
|
||||
private string GetFileFromDialog(string title, string filter = "")
|
||||
private static string GetFileFromDialog(string title, string filter = "")
|
||||
{
|
||||
var dlg = new OpenFileDialog
|
||||
{
|
||||
|
|
@ -140,7 +171,6 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
|
||||
var result = dlg.ShowDialog();
|
||||
return result == DialogResult.OK ? dlg.FileName : string.Empty;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -183,31 +213,33 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
else
|
||||
{
|
||||
if (IsUsingPortablePath(settings.PluginSettings.PythonExecutablePath, DataLocation.PythonEnvironmentName))
|
||||
{
|
||||
settings.PluginSettings.PythonExecutablePath
|
||||
= GetUpdatedEnvironmentPath(settings.PluginSettings.PythonExecutablePath);
|
||||
}
|
||||
|
||||
if (IsUsingPortablePath(settings.PluginSettings.NodeExecutablePath, DataLocation.NodeEnvironmentName))
|
||||
{
|
||||
settings.PluginSettings.NodeExecutablePath
|
||||
= GetUpdatedEnvironmentPath(settings.PluginSettings.NodeExecutablePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsUsingPortablePath(string filePath, string pluginEnvironmentName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
return false;
|
||||
if (string.IsNullOrEmpty(filePath)) return false;
|
||||
|
||||
// DataLocation.PortableDataPath returns the current portable path, this determines if an out
|
||||
// of date path is also a portable path.
|
||||
var portableAppEnvLocation = $"UserData\\{DataLocation.PluginEnvironments}\\{pluginEnvironmentName}";
|
||||
var portableAppEnvLocation = Path.Combine("UserData", DataLocation.PluginEnvironments, pluginEnvironmentName);
|
||||
|
||||
return filePath.Contains(portableAppEnvLocation);
|
||||
}
|
||||
|
||||
private static bool IsUsingRoamingPath(string filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
return false;
|
||||
if (string.IsNullOrEmpty(filePath)) return false;
|
||||
|
||||
return filePath.StartsWith(DataLocation.RoamingDataPath);
|
||||
}
|
||||
|
|
@ -217,8 +249,8 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
var index = filePath.IndexOf(DataLocation.PluginEnvironments);
|
||||
|
||||
// get the substring after "Environments" because we can not determine it dynamically
|
||||
var ExecutablePathSubstring = filePath.Substring(index + DataLocation.PluginEnvironments.Count());
|
||||
return $"{DataLocation.PluginEnvironmentsPath}{ExecutablePathSubstring}";
|
||||
var executablePathSubstring = filePath[(index + DataLocation.PluginEnvironments.Length)..];
|
||||
return $"{DataLocation.PluginEnvironmentsPath}{executablePathSubstring}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using Droplex;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Droplex;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
||||
{
|
||||
|
|
@ -22,7 +22,11 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
|
||||
internal override string FileDialogFilter => "Python|pythonw.exe";
|
||||
|
||||
internal override string PluginsSettingsFilePath { get => PluginSettings.PythonExecutablePath; set => PluginSettings.PythonExecutablePath = value; }
|
||||
internal override string PluginsSettingsFilePath
|
||||
{
|
||||
get => PluginSettings.PythonExecutablePath;
|
||||
set => PluginSettings.PythonExecutablePath = value;
|
||||
}
|
||||
|
||||
internal PythonEnvironment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using Droplex;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using Flow.Launcher.Plugin;
|
||||
using System.IO;
|
||||
using Droplex;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
|
||||
namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
||||
{
|
||||
|
|
@ -19,7 +19,11 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
internal override string InstallPath => Path.Combine(EnvPath, "Node-v16.18.0");
|
||||
internal override string ExecutablePath => Path.Combine(InstallPath, "node-v16.18.0-win-x64\\node.exe");
|
||||
|
||||
internal override string PluginsSettingsFilePath { get => PluginSettings.NodeExecutablePath; set => PluginSettings.NodeExecutablePath = value; }
|
||||
internal override string PluginsSettingsFilePath
|
||||
{
|
||||
get => PluginSettings.NodeExecutablePath;
|
||||
set => PluginSettings.NodeExecutablePath = value;
|
||||
}
|
||||
|
||||
internal TypeScriptEnvironment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using Droplex;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using Flow.Launcher.Plugin;
|
||||
using System.IO;
|
||||
using Droplex;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
|
||||
namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
||||
{
|
||||
|
|
@ -19,7 +19,11 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
|
|||
internal override string InstallPath => Path.Combine(EnvPath, "Node-v16.18.0");
|
||||
internal override string ExecutablePath => Path.Combine(InstallPath, "node-v16.18.0-win-x64\\node.exe");
|
||||
|
||||
internal override string PluginsSettingsFilePath { get => PluginSettings.NodeExecutablePath; set => PluginSettings.NodeExecutablePath = value; }
|
||||
internal override string PluginsSettingsFilePath
|
||||
{
|
||||
get => PluginSettings.NodeExecutablePath;
|
||||
set => PluginSettings.NodeExecutablePath = value;
|
||||
}
|
||||
|
||||
internal TypeScriptV2Environment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
using Flow.Launcher.Core.ExternalPlugins;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
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.Logger;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using ISavable = Flow.Launcher.Plugin.ISavable;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using System.Text.Json;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using ISavable = Flow.Launcher.Plugin.ISavable;
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
|
|
|
|||
|
|
@ -138,6 +138,11 @@ namespace Flow.Launcher
|
|||
{
|
||||
await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
|
||||
{
|
||||
// Because new message box api uses MessageBoxEx window,
|
||||
// if it is created and closed before main window is created, it will cause the application to exit.
|
||||
// So set to OnExplicitShutdown to prevent the application from shutting down before main window is created
|
||||
Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
|
||||
|
||||
Log.SetLogLevel(_settings.LogLevel);
|
||||
|
||||
Ioc.Default.GetRequiredService<Portable>().PreStartCleanUpAfterPortabilityUpdate();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@
|
|||
Click no if it's already installed, and you will be prompted to select the folder that contains the {1} executable
|
||||
</system:String>
|
||||
<system:String x:Key="runtimePluginChooseRuntimeExecutable">Please select the {0} executable</system:String>
|
||||
<system:String x:Key="runtimeExecutableInvalidChooseDownload">
|
||||
Your selected {0} executable is invalid.
|
||||
{2}{2}
|
||||
Click yes if you would like select the {0} executable agian. Click no if you would like to download {1}
|
||||
</system:String>
|
||||
<system:String x:Key="runtimePluginUnableToSetExecutablePath">Unable to set {0} executable path, please try from Flow's settings (scroll down to the bottom).</system:String>
|
||||
<system:String x:Key="failedToInitializePluginsTitle">Fail to Init Plugins</system:String>
|
||||
<system:String x:Key="failedToInitializePluginsMessage">Plugins: {0} - fail to load and would be disabled, please contact plugin creator for help</system:String>
|
||||
|
|
|
|||
|
|
@ -28,16 +28,16 @@
|
|||
Style="{StaticResource PageTitle}"
|
||||
Text="{DynamicResource general}"
|
||||
TextAlignment="left" />
|
||||
|
||||
<cc:CardGroup Margin="0 10 0 0">
|
||||
|
||||
<cc:Card Title="{DynamicResource startFlowLauncherOnSystemStartup}" Icon="">
|
||||
<cc:ExCard
|
||||
Title="{DynamicResource startFlowLauncherOnSystemStartup}"
|
||||
Margin="0 8 0 0"
|
||||
Icon="">
|
||||
<cc:ExCard.SideContent>
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding StartFlowLauncherOnSystemStartup}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
|
||||
</cc:ExCard.SideContent>
|
||||
<cc:Card
|
||||
Title="{DynamicResource useLogonTaskForStartup}"
|
||||
Sub="{DynamicResource useLogonTaskForStartupTooltip}"
|
||||
|
|
@ -47,17 +47,16 @@
|
|||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource hideOnStartup}"
|
||||
Sub="{DynamicResource hideOnStartupToolTip}"
|
||||
Type="InsideFit">
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding Settings.HideOnStartup}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
</cc:ExCard>
|
||||
<cc:Card
|
||||
Title="{DynamicResource hideOnStartup}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource hideOnStartupToolTip}">
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding Settings.HideOnStartup}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource hideFlowLauncherWhenLoseFocus}" Margin="0 14 0 0">
|
||||
<ui:ToggleSwitch
|
||||
|
|
@ -178,30 +177,6 @@
|
|||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:CardGroup Margin="0 14 0 0">
|
||||
<cc:Card
|
||||
Title="{DynamicResource searchDelay}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource searchDelayToolTip}">
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding Settings.SearchQueryResultsWithDelay}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource searchDelayTime}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource searchDelayTimeToolTip}">
|
||||
<ComboBox
|
||||
MaxWidth="200"
|
||||
DisplayMemberPath="Display"
|
||||
ItemsSource="{Binding SearchDelayTimes}"
|
||||
SelectedItem="{Binding SearchDelayTime}"
|
||||
SelectedValuePath="Value" />
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
|
||||
<cc:CardGroup Margin="0 14 0 0">
|
||||
<cc:Card Title="{DynamicResource querySearchPrecision}" Sub="{DynamicResource querySearchPrecisionToolTip}">
|
||||
<ComboBox
|
||||
|
|
|
|||
|
|
@ -9,9 +9,13 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
{
|
||||
public const string Keyword = "fltheme";
|
||||
|
||||
private readonly Theme _theme;
|
||||
private readonly PluginInitContext _context;
|
||||
|
||||
// Do not initialize it in the constructor, because it will cause null reference in
|
||||
// var dicts = Application.Current.Resources.MergedDictionaries; line of Theme
|
||||
private Theme theme = null;
|
||||
private Theme Theme => theme ??= Ioc.Default.GetRequiredService<Theme>();
|
||||
|
||||
#region Theme Selection
|
||||
|
||||
// Theme select codes simplified from SettingsPaneThemeViewModel.cs
|
||||
|
|
@ -19,24 +23,23 @@ namespace Flow.Launcher.Plugin.Sys
|
|||
private Theme.ThemeData _selectedTheme;
|
||||
public Theme.ThemeData SelectedTheme
|
||||
{
|
||||
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == _theme.GetCurrentTheme());
|
||||
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == Theme.GetCurrentTheme());
|
||||
set
|
||||
{
|
||||
_selectedTheme = value;
|
||||
_theme.ChangeTheme(value.FileNameWithoutExtension);
|
||||
Theme.ChangeTheme(value.FileNameWithoutExtension);
|
||||
|
||||
_ = _theme.RefreshFrameAsync();
|
||||
_ = Theme.RefreshFrameAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Theme.ThemeData> Themes => _theme.LoadAvailableThemes();
|
||||
private List<Theme.ThemeData> Themes => Theme.LoadAvailableThemes();
|
||||
|
||||
#endregion
|
||||
|
||||
public ThemeSelector(PluginInitContext context)
|
||||
{
|
||||
_context = context;
|
||||
_theme = Ioc.Default.GetRequiredService<Theme>();
|
||||
}
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
|
|
|
|||
Loading…
Reference in a new issue