Skip to content
Merged
29 changes: 24 additions & 5 deletions Flow.Launcher.Core/Plugin/PluginManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ public static bool PluginModified(string uuid)
public static void UpdatePlugin(PluginMetadata existingVersion, UserPlugin newVersion, string zipFilePath)
{
InstallPlugin(newVersion, zipFilePath, checkModified:false);
UninstallPlugin(existingVersion, removeSettings:false, checkModified:false);
UninstallPlugin(existingVersion, removePluginFromSettings:false, removePluginSettings:false, checkModified: false);
_modifiedPlugins.Add(existingVersion.ID);
}

Expand All @@ -454,9 +454,9 @@ public static void InstallPlugin(UserPlugin plugin, string zipFilePath)
/// <summary>
/// Uninstall a plugin.
/// </summary>
public static void UninstallPlugin(PluginMetadata plugin, bool removeSettings = true)
public static void UninstallPlugin(PluginMetadata plugin, bool removePluginFromSettings = true, bool removePluginSettings = false)
{
UninstallPlugin(plugin, removeSettings, true);
UninstallPlugin(plugin, removePluginFromSettings, removePluginSettings, true);
}

#endregion
Expand Down Expand Up @@ -529,19 +529,38 @@ internal static void InstallPlugin(UserPlugin plugin, string zipFilePath, bool c
}
}

internal static void UninstallPlugin(PluginMetadata plugin, bool removeSettings, bool checkModified)
internal static void UninstallPlugin(PluginMetadata plugin, bool removePluginFromSettings, bool removePluginSettings, bool checkModified)
{
if (checkModified && PluginModified(plugin.ID))
{
throw new ArgumentException($"Plugin {plugin.Name} has been modified");
}

if (removeSettings)
if (removePluginFromSettings)
{
Settings.Plugins.Remove(plugin.ID);
AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID);
}

if (removePluginSettings)
{
var assemblyLoader = new PluginAssemblyLoader(plugin.ExecuteFilePath);
var assembly = assemblyLoader.LoadAssemblyAndDependencies();
var assemblyName = assembly.GetName().Name;

// if user want to remove the plugin settings, we cannot call save method for the plugin json storage instance of this plugin
// so we need to remove it from the api instance
var method = API.GetType().GetMethod("RemovePluginSettings");
var pluginJsonStorage = method?.Invoke(API, new object[] { assemblyName });

// if there exists a json storage for current plugin, we need to delete the directory path
if (pluginJsonStorage != null)
{
var deleteMethod = pluginJsonStorage.GetType().GetMethod("DeleteDirectory");
deleteMethod?.Invoke(pluginJsonStorage, null);
}
}

// Marked for deletion. Will be deleted on next start up
using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt"));

Expand Down
18 changes: 14 additions & 4 deletions Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@

namespace Flow.Launcher.Infrastructure.Storage
{
public class PluginJsonStorage<T> :JsonStorage<T> where T : new()
public class PluginJsonStorage<T> : JsonStorage<T> where T : new()
{
// Use assembly name to check which plugin is using this storage
public readonly string AssemblyName;

public PluginJsonStorage()
{
// C# related, add python related below
var dataType = typeof(T);
var assemblyName = dataType.Assembly.GetName().Name;
DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Plugins, assemblyName);
AssemblyName = dataType.Assembly.GetName().Name;
DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Plugins, AssemblyName);
Helper.ValidateDirectory(DirectoryPath);

FilePath = Path.Combine(DirectoryPath, $"{dataType.Name}{FileSuffix}");
Expand All @@ -20,6 +23,13 @@ public PluginJsonStorage(T data) : this()
{
Data = data;
}

public void DeleteDirectory()
{
if (Directory.Exists(DirectoryPath))
{
Directory.Delete(DirectoryPath, true);
}
}
}
}

17 changes: 17 additions & 0 deletions Flow.Launcher/PublicAPIInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,23 @@ public void LogException(string className, string message, Exception e,

private readonly ConcurrentDictionary<Type, object> _pluginJsonStorages = new();

public object RemovePluginSettings(string assemblyName)
{
foreach (var keyValuePair in _pluginJsonStorages)
{
var key = keyValuePair.Key;
var value = keyValuePair.Value;
var name = value.GetType().GetField("AssemblyName")?.GetValue(value)?.ToString();
if (name == assemblyName)
{
_pluginJsonStorages.Remove(key, out var pluginJsonStorage);
return pluginJsonStorage;
}
}

return null;
}

/// <summary>
/// Save plugin settings.
/// </summary>
Expand Down
6 changes: 4 additions & 2 deletions Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<system:String x:Key="plugin_pluginsmanager_installing_plugin">Installing Plugin</system:String>
<system:String x:Key="plugin_pluginsmanager_install_from_web">Download and install {0}</system:String>
<system:String x:Key="plugin_pluginsmanager_uninstall_title">Plugin Uninstall</system:String>
<system:String x:Key="plugin_pluginsmanager_keep_plugin_settings_title">Keep plugin settings</system:String>
<system:String x:Key="plugin_pluginsmanager_keep_plugin_settings_subtitle">Do you want to keep the settings of the plugin for the next usage?</system:String>
<system:String x:Key="plugin_pluginsmanager_install_success_restart">Plugin {0} successfully installed. Restarting Flow, please wait...</system:String>
<system:String x:Key="plugin_pluginsmanager_install_errormetadatafile">Unable to find the plugin.json metadata file from the extracted zip file.</system:String>
<system:String x:Key="plugin_pluginsmanager_install_error_duplicate">Error: A plugin which has the same or greater version with {0} already exists.</system:String>
Expand All @@ -37,13 +39,13 @@
<system:String x:Key="plugin_pluginsmanager_update_success_restart">Plugin {0} successfully updated. Restarting Flow, please wait...</system:String>
<system:String x:Key="plugin_pluginsmanager_install_unknown_source_warning_title">Installing from an unknown source</system:String>
<system:String x:Key="plugin_pluginsmanager_install_unknown_source_warning">You are installing this plugin from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning via settings)</system:String>

<system:String x:Key="plugin_pluginsmanager_install_success_no_restart">Plugin {0} successfully installed. Please restart Flow.</system:String>
<system:String x:Key="plugin_pluginsmanager_uninstall_success_no_restart">Plugin {0} successfully uninstalled. Please restart Flow.</system:String>
<system:String x:Key="plugin_pluginsmanager_update_success_no_restart">Plugin {0} successfully updated. Please restart Flow.</system:String>
<system:String x:Key="plugin_pluginsmanager_update_all_success_no_restart">{0} plugins successfully updated. Please restart Flow.</system:String>
<system:String x:Key="plugin_pluginsmanager_plugin_modified_error">Plugin {0} has already been modified. Please restart Flow before making any further changes.</system:String>

<!-- Plugin Infos -->
<system:String x:Key="plugin_pluginsmanager_plugin_name">Plugins Manager</system:String>
<system:String x:Key="plugin_pluginsmanager_plugin_description">Management of installing, uninstalling or updating Flow Launcher plugins</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,11 @@ private void Uninstall(PluginMetadata plugin)
{
try
{
PluginManager.UninstallPlugin(plugin, removeSettings: true);
var removePluginSettings = Context.API.ShowMsgBox(
Context.API.GetTranslation("plugin_pluginsmanager_keep_plugin_settings_subtitle"),
Context.API.GetTranslation("plugin_pluginsmanager_keep_plugin_settings_title"),
button: MessageBoxButton.YesNo) == MessageBoxResult.No;
PluginManager.UninstallPlugin(plugin, removePluginFromSettings: true, removePluginSettings: removePluginSettings);
}
catch (ArgumentException e)
{
Expand Down
Loading