Skip to content

Commit ba0d412

Browse files
authored
Merge branch 'dev' into multiple_keywords
2 parents 9ec8681 + 57f20ae commit ba0d412

File tree

81 files changed

+1269
-599
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1269
-599
lines changed

Flow.Launcher.Core/Configuration/Portable.cs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@
99
using Flow.Launcher.Infrastructure.UserSettings;
1010
using Flow.Launcher.Plugin.SharedCommands;
1111
using System.Linq;
12+
using CommunityToolkit.Mvvm.DependencyInjection;
13+
using Flow.Launcher.Plugin;
1214

1315
namespace Flow.Launcher.Core.Configuration
1416
{
1517
public class Portable : IPortable
1618
{
19+
private readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();
20+
1721
/// <summary>
1822
/// As at Squirrel.Windows version 1.5.2, UpdateManager needs to be disposed after finish
1923
/// </summary>
@@ -40,7 +44,7 @@ public void DisablePortableMode()
4044
#endif
4145
IndicateDeletion(DataLocation.PortableDataPath);
4246

43-
MessageBoxEx.Show("Flow Launcher needs to restart to finish disabling portable mode, " +
47+
API.ShowMsgBox("Flow Launcher needs to restart to finish disabling portable mode, " +
4448
"after the restart your portable data profile will be deleted and roaming data profile kept");
4549

4650
UpdateManager.RestartApp(Constant.ApplicationFileName);
@@ -64,7 +68,7 @@ public void EnablePortableMode()
6468
#endif
6569
IndicateDeletion(DataLocation.RoamingDataPath);
6670

67-
MessageBoxEx.Show("Flow Launcher needs to restart to finish enabling portable mode, " +
71+
API.ShowMsgBox("Flow Launcher needs to restart to finish enabling portable mode, " +
6872
"after the restart your roaming data profile will be deleted and portable data profile kept");
6973

7074
UpdateManager.RestartApp(Constant.ApplicationFileName);
@@ -95,13 +99,13 @@ public void RemoveUninstallerEntry()
9599

96100
public void MoveUserDataFolder(string fromLocation, string toLocation)
97101
{
98-
FilesFolders.CopyAll(fromLocation, toLocation, MessageBoxEx.Show);
102+
FilesFolders.CopyAll(fromLocation, toLocation, (s) => API.ShowMsgBox(s));
99103
VerifyUserDataAfterMove(fromLocation, toLocation);
100104
}
101105

102106
public void VerifyUserDataAfterMove(string fromLocation, string toLocation)
103107
{
104-
FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, MessageBoxEx.Show);
108+
FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => API.ShowMsgBox(s));
105109
}
106110

107111
public void CreateShortcuts()
@@ -157,13 +161,13 @@ public void PreStartCleanUpAfterPortabilityUpdate()
157161
// delete it and prompt the user to pick the portable data location
158162
if (File.Exists(roamingDataDeleteFilePath))
159163
{
160-
FilesFolders.RemoveFolderIfExists(roamingDataDir, MessageBoxEx.Show);
164+
FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => API.ShowMsgBox(s));
161165

162-
if (MessageBoxEx.Show("Flow Launcher has detected you enabled portable mode, " +
166+
if (API.ShowMsgBox("Flow Launcher has detected you enabled portable mode, " +
163167
"would you like to move it to a different location?", string.Empty,
164168
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
165169
{
166-
FilesFolders.OpenPath(Constant.RootDirectory, MessageBoxEx.Show);
170+
FilesFolders.OpenPath(Constant.RootDirectory, (s) => API.ShowMsgBox(s));
167171

168172
Environment.Exit(0);
169173
}
@@ -172,9 +176,9 @@ public void PreStartCleanUpAfterPortabilityUpdate()
172176
// delete it and notify the user about it.
173177
else if (File.Exists(portableDataDeleteFilePath))
174178
{
175-
FilesFolders.RemoveFolderIfExists(portableDataDir, MessageBoxEx.Show);
179+
FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => API.ShowMsgBox(s));
176180

177-
MessageBoxEx.Show("Flow Launcher has detected you disabled portable mode, " +
181+
API.ShowMsgBox("Flow Launcher has detected you disabled portable mode, " +
178182
"the relevant shortcuts and uninstaller entry have been created");
179183
}
180184
}
@@ -186,7 +190,7 @@ public bool CanUpdatePortability()
186190

187191
if (roamingLocationExists && portableLocationExists)
188192
{
189-
MessageBoxEx.Show(string.Format("Flow Launcher detected your user data exists both in {0} and " +
193+
API.ShowMsgBox(string.Format("Flow Launcher detected your user data exists both in {0} and " +
190194
"{1}. {2}{2}Please delete {1} in order to proceed. No changes have occurred.",
191195
DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
192196

Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
using System.Windows;
99
using System.Windows.Forms;
1010
using Flow.Launcher.Core.Resource;
11+
using CommunityToolkit.Mvvm.DependencyInjection;
1112

1213
namespace Flow.Launcher.Core.ExternalPlugins.Environments
1314
{
1415
public abstract class AbstractPluginEnvironment
1516
{
17+
protected readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();
18+
1619
internal abstract string Language { get; }
1720

1821
internal abstract string EnvName { get; }
@@ -25,7 +28,7 @@ public abstract class AbstractPluginEnvironment
2528

2629
internal virtual string FileDialogFilter => string.Empty;
2730

28-
internal abstract string PluginsSettingsFilePath { get; set; }
31+
internal abstract string PluginsSettingsFilePath { get; set; }
2932

3033
internal List<PluginMetadata> PluginMetadataList;
3134

@@ -57,7 +60,7 @@ internal IEnumerable<PluginPair> Setup()
5760
EnvName,
5861
Environment.NewLine
5962
);
60-
if (MessageBoxEx.Show(noRuntimeMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
63+
if (API.ShowMsgBox(noRuntimeMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
6164
{
6265
var msg = string.Format(InternationalizationManager.Instance.GetTranslation("runtimePluginChooseRuntimeExecutable"), EnvName);
6366
string selectedFile;
@@ -82,7 +85,7 @@ internal IEnumerable<PluginPair> Setup()
8285
}
8386
else
8487
{
85-
MessageBoxEx.Show(string.Format(InternationalizationManager.Instance.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language));
88+
API.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language));
8689
Log.Error("PluginsLoader",
8790
$"Not able to successfully set {EnvName} path, setting's plugin executable path variable is still an empty string.",
8891
$"{Language}Environment");
@@ -98,7 +101,7 @@ private void EnsureLatestInstalled(string expectedPath, string currentPath, stri
98101
if (expectedPath == currentPath)
99102
return;
100103

101-
FilesFolders.RemoveFolderIfExists(installedDirPath, MessageBoxEx.Show);
104+
FilesFolders.RemoveFolderIfExists(installedDirPath, (s) => API.ShowMsgBox(s));
102105

103106
InstallEnvironment();
104107

Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ internal PythonEnvironment(List<PluginMetadata> pluginMetadataList, PluginsSetti
2828

2929
internal override void InstallEnvironment()
3030
{
31-
FilesFolders.RemoveFolderIfExists(InstallPath, MessageBoxEx.Show);
31+
FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));
3232

3333
// Python 3.11.4 is no longer Windows 7 compatible. If user is on Win 7 and
3434
// uses Python plugin they need to custom install and use v3.8.9

Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ internal TypeScriptEnvironment(List<PluginMetadata> pluginMetadataList, PluginsS
2525

2626
internal override void InstallEnvironment()
2727
{
28-
FilesFolders.RemoveFolderIfExists(InstallPath, MessageBoxEx.Show);
28+
FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));
2929

3030
DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath).Wait();
3131

Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ internal TypeScriptV2Environment(List<PluginMetadata> pluginMetadataList, Plugin
2525

2626
internal override void InstallEnvironment()
2727
{
28-
FilesFolders.RemoveFolderIfExists(InstallPath, MessageBoxEx.Show);
28+
FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));
2929

3030
DroplexPackage.Drop(App.nodejs_16_18_0, InstallPath).Wait();
3131

Flow.Launcher.Core/Plugin/JsonRPCPluginBase.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ internal abstract class JsonRPCPluginBase : IAsyncPlugin, IContextMenu, ISetting
4444
private string SettingConfigurationPath =>
4545
Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "SettingsTemplate.yaml");
4646

47-
private string SettingPath => Path.Combine(DataLocation.PluginSettingsDirectory,
48-
Context.CurrentPluginMetadata.Name, "Settings.json");
47+
private string SettingDirectory => Path.Combine(DataLocation.PluginSettingsDirectory,
48+
Context.CurrentPluginMetadata.Name);
49+
50+
private string SettingPath => Path.Combine(SettingDirectory, "Settings.json");
4951

5052
public abstract List<Result> LoadContextMenus(Result selectedResult);
5153

@@ -159,5 +161,13 @@ public Control CreateSettingPanel()
159161
{
160162
return Settings.CreateSettingPanel();
161163
}
164+
165+
public void DeletePluginSettingsDirectory()
166+
{
167+
if (Directory.Exists(SettingDirectory))
168+
{
169+
Directory.Delete(SettingDirectory, true);
170+
}
171+
}
162172
}
163173
}

Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,15 @@ private void SetupJsonRPC()
112112
RPC.StartListening();
113113
}
114114

115-
public virtual Task ReloadDataAsync()
115+
public virtual async Task ReloadDataAsync()
116116
{
117-
SetupJsonRPC();
118-
return Task.CompletedTask;
117+
try
118+
{
119+
await RPC.InvokeAsync("reload_data", Context);
120+
}
121+
catch (RemoteMethodNotFoundException e)
122+
{
123+
}
119124
}
120125

121126
public virtual async ValueTask DisposeAsync()

Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,5 +175,15 @@ public void BackToQueryResults()
175175
{
176176
_api.BackToQueryResults();
177177
}
178+
179+
public void StartLoadingBar()
180+
{
181+
_api.StartLoadingBar();
182+
}
183+
184+
public void StopLoadingBar()
185+
{
186+
_api.StopLoadingBar();
187+
}
178188
}
179189
}

Flow.Launcher.Core/Plugin/PluginManager.cs

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Flow.Launcher.Plugin.SharedCommands;
1515
using System.Text.Json;
1616
using Flow.Launcher.Core.Resource;
17+
using CommunityToolkit.Mvvm.DependencyInjection;
1718

1819
namespace Flow.Launcher.Core.Plugin
1920
{
@@ -28,7 +29,9 @@ public static class PluginManager
2829
public static readonly HashSet<PluginPair> GlobalPlugins = new();
2930
public static readonly Dictionary<string, PluginPair> NonGlobalPlugins = new();
3031

31-
public static IPublicAPI API { private set; get; }
32+
// We should not initialize API in static constructor because it will create another API instance
33+
private static IPublicAPI api = null;
34+
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
3235

3336
private static PluginsSettings Settings;
3437
private static List<PluginMetadata> _metadatas;
@@ -158,9 +161,8 @@ public static void LoadPlugins(PluginsSettings settings)
158161
/// Call initialize for all plugins
159162
/// </summary>
160163
/// <returns>return the list of failed to init plugins or null for none</returns>
161-
public static async Task InitializePluginsAsync(IPublicAPI api)
164+
public static async Task InitializePluginsAsync()
162165
{
163-
API = api;
164166
var failedPlugins = new ConcurrentQueue<PluginPair>();
165167

166168
var InitTasks = AllPlugins.Select(pair => Task.Run(async delegate
@@ -204,15 +206,15 @@ public static async Task InitializePluginsAsync(IPublicAPI api)
204206
}
205207

206208
InternationalizationManager.Instance.AddPluginLanguageDirectories(GetPluginsForInterface<IPluginI18n>());
207-
InternationalizationManager.Instance.ChangeLanguage(InternationalizationManager.Instance.Settings.Language);
209+
InternationalizationManager.Instance.ChangeLanguage(Ioc.Default.GetRequiredService<Settings>().Language);
208210

209211
if (failedPlugins.Any())
210212
{
211213
var failed = string.Join(",", failedPlugins.Select(x => x.Metadata.Name));
212214
API.ShowMsg(
213-
InternationalizationManager.Instance.GetTranslation("failedToInitializePluginsTitle"),
215+
API.GetTranslation("failedToInitializePluginsTitle"),
214216
string.Format(
215-
InternationalizationManager.Instance.GetTranslation("failedToInitializePluginsMessage"),
217+
API.GetTranslation("failedToInitializePluginsMessage"),
216218
failed
217219
),
218220
"",
@@ -280,7 +282,7 @@ public static async Task<List<Result>> QueryForPluginAsync(PluginPair pair, Quer
280282
return results;
281283
}
282284

283-
public static void UpdatePluginMetadata(List<Result> results, PluginMetadata metadata, Query query)
285+
public static void UpdatePluginMetadata(IReadOnlyList<Result> results, PluginMetadata metadata, Query query)
284286
{
285287
foreach (var r in results)
286288
{
@@ -446,7 +448,7 @@ public static bool PluginModified(string uuid)
446448
public static void UpdatePlugin(PluginMetadata existingVersion, UserPlugin newVersion, string zipFilePath)
447449
{
448450
InstallPlugin(newVersion, zipFilePath, checkModified:false);
449-
UninstallPlugin(existingVersion, removeSettings:false, checkModified:false);
451+
UninstallPlugin(existingVersion, removePluginFromSettings:false, removePluginSettings:false, checkModified: false);
450452
_modifiedPlugins.Add(existingVersion.ID);
451453
}
452454

@@ -461,9 +463,9 @@ public static void InstallPlugin(UserPlugin plugin, string zipFilePath)
461463
/// <summary>
462464
/// Uninstall a plugin.
463465
/// </summary>
464-
public static void UninstallPlugin(PluginMetadata plugin, bool removeSettings = true)
466+
public static void UninstallPlugin(PluginMetadata plugin, bool removePluginFromSettings = true, bool removePluginSettings = false)
465467
{
466-
UninstallPlugin(plugin, removeSettings, true);
468+
UninstallPlugin(plugin, removePluginFromSettings, removePluginSettings, true);
467469
}
468470

469471
#endregion
@@ -526,24 +528,80 @@ internal static void InstallPlugin(UserPlugin plugin, string zipFilePath, bool c
526528

527529
var newPluginPath = Path.Combine(installDirectory, folderName);
528530

529-
FilesFolders.CopyAll(pluginFolderPath, newPluginPath, MessageBoxEx.Show);
531+
FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => API.ShowMsgBox(s));
530532

531-
Directory.Delete(tempFolderPluginPath, true);
533+
try
534+
{
535+
if (Directory.Exists(tempFolderPluginPath))
536+
Directory.Delete(tempFolderPluginPath, true);
537+
}
538+
catch (Exception e)
539+
{
540+
Log.Exception($"|PluginManager.InstallPlugin|Failed to delete temp folder {tempFolderPluginPath}", e);
541+
}
532542

533543
if (checkModified)
534544
{
535545
_modifiedPlugins.Add(plugin.ID);
536546
}
537547
}
538548

539-
internal static void UninstallPlugin(PluginMetadata plugin, bool removeSettings, bool checkModified)
549+
internal static void UninstallPlugin(PluginMetadata plugin, bool removePluginFromSettings, bool removePluginSettings, bool checkModified)
540550
{
541551
if (checkModified && PluginModified(plugin.ID))
542552
{
543553
throw new ArgumentException($"Plugin {plugin.Name} has been modified");
544554
}
545555

546-
if (removeSettings)
556+
if (removePluginSettings)
557+
{
558+
if (AllowedLanguage.IsDotNet(plugin.Language)) // for the plugin in .NET, we can use assembly loader
559+
{
560+
var assemblyLoader = new PluginAssemblyLoader(plugin.ExecuteFilePath);
561+
var assembly = assemblyLoader.LoadAssemblyAndDependencies();
562+
var assemblyName = assembly.GetName().Name;
563+
564+
// if user want to remove the plugin settings, we cannot call save method for the plugin json storage instance of this plugin
565+
// so we need to remove it from the api instance
566+
var method = API.GetType().GetMethod("RemovePluginSettings");
567+
var pluginJsonStorage = method?.Invoke(API, new object[] { assemblyName });
568+
569+
// if there exists a json storage for current plugin, we need to delete the directory path
570+
if (pluginJsonStorage != null)
571+
{
572+
var deleteMethod = pluginJsonStorage.GetType().GetMethod("DeleteDirectory");
573+
try
574+
{
575+
deleteMethod?.Invoke(pluginJsonStorage, null);
576+
}
577+
catch (Exception e)
578+
{
579+
Log.Exception($"|PluginManager.UninstallPlugin|Failed to delete plugin json folder for {plugin.Name}", e);
580+
API.ShowMsg(API.GetTranslation("failedToRemovePluginSettingsTitle"),
581+
string.Format(API.GetTranslation("failedToRemovePluginSettingsMessage"), plugin.Name));
582+
}
583+
}
584+
}
585+
else // the plugin with json prc interface
586+
{
587+
var pluginPair = AllPlugins.FirstOrDefault(p => p.Metadata.ID == plugin.ID);
588+
if (pluginPair != null && pluginPair.Plugin is JsonRPCPlugin jsonRpcPlugin)
589+
{
590+
try
591+
{
592+
jsonRpcPlugin.DeletePluginSettingsDirectory();
593+
}
594+
catch (Exception e)
595+
{
596+
Log.Exception($"|PluginManager.UninstallPlugin|Failed to delete plugin json folder for {plugin.Name}", e);
597+
API.ShowMsg(API.GetTranslation("failedToRemovePluginSettingsTitle"),
598+
string.Format(API.GetTranslation("failedToRemovePluginSettingsMessage"), plugin.Name));
599+
}
600+
}
601+
}
602+
}
603+
604+
if (removePluginFromSettings)
547605
{
548606
Settings.Plugins.Remove(plugin.ID);
549607
AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID);

0 commit comments

Comments
 (0)