diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml
index 25a32534b18..8d24c145c45 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml
@@ -11,6 +11,13 @@
Plugin Install
Plugin Uninstall
Install failed: unable to find the plugin.json metadata file from the new plugin
+ No update available
+ All plugins are up to date
+ {0} by {1} {2}{3}Would you like to update this plugin? After the update Flow will automatically restart.
+ Plugin Update
+ This plugin has an update, would you like to see it?
+ This plugin is already installed
+
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs
index 58ec5005fb5..43f92e7b91f 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs
@@ -42,9 +42,13 @@ public List Query(Query query)
var pluginManager = new PluginsManager(Context, Settings);
if (!string.IsNullOrEmpty(search)
- && ($"{Settings.UninstallHotkey} ".StartsWith(search) || search.StartsWith($"{Settings.UninstallHotkey} ")))
+ && ($"{Settings.HotkeyUninstall} ".StartsWith(search) || search.StartsWith($"{Settings.HotkeyUninstall} ")))
return pluginManager.RequestUninstall(search);
-
+
+ if (!string.IsNullOrEmpty(search)
+ && ($"{Settings.HotkeyUpdate} ".StartsWith(search) || search.StartsWith($"{Settings.HotkeyUpdate} ")))
+ return pluginManager.RequestUpdate(search);
+
return pluginManager.RequestInstallOrUpdate(search);
}
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs
index 3bc44e0f6fe..c1af3014bf9 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
+
namespace Flow.Launcher.Plugin.PluginsManager.Models
{
public class UserPlugin
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs
index 23e038d4bd5..90f3277fb33 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs
@@ -19,6 +19,21 @@ internal class PluginsManager
private Settings Settings { get; set; }
+ private bool shouldHideWindow = true;
+ private bool ShouldHideWindow
+ {
+ set { shouldHideWindow = value; }
+ get
+ {
+ var setValue = shouldHideWindow;
+ // Default value for hide main window is true. Revert after get call.
+ // This ensures when set by another method to false, it is only used once.
+ shouldHideWindow = true;
+
+ return setValue;
+ }
+ }
+
private readonly string icoPath = "Images\\pluginsmanager.png";
internal PluginsManager(PluginInitContext context, Settings settings)
@@ -31,7 +46,22 @@ internal void InstallOrUpdate(UserPlugin plugin)
{
if (PluginExists(plugin.ID))
{
- Context.API.ShowMsg("Plugin already installed");
+ if (Context.API.GetAllPlugins().Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version != plugin.Version))
+ {
+ if (MessageBox.Show(Context.API.GetTranslation("plugin_pluginsmanager_update_exists"),
+ Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
+ MessageBoxButton.YesNo) == MessageBoxResult.Yes)
+ Context
+ .API
+ .ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.HotkeyUpdate} {plugin.Name}");
+
+ Application.Current.MainWindow.Show();
+ shouldHideWindow = false;
+
+ return;
+ }
+
+ Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_update_alreadyexists"));
return;
}
@@ -42,7 +72,7 @@ internal void InstallOrUpdate(UserPlugin plugin)
if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_install_title"), MessageBoxButton.YesNo) == MessageBoxResult.No)
return;
- var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}.zip");
+ var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}-{plugin.Version}.zip");
try
{
@@ -62,12 +92,81 @@ internal void InstallOrUpdate(UserPlugin plugin)
Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload");
}
- Application.Current.Dispatcher.Invoke(() => Install(plugin, filePath));
+ Application.Current.Dispatcher.Invoke(() => { Install(plugin, filePath); Context.API.RestartApp(); });
}
- internal void Update()
+ internal List RequestUpdate(string search)
{
- throw new NotImplementedException();
+ var autocompletedResults = AutoCompleteReturnAllResults(search,
+ Settings.HotkeyUpdate,
+ "Update",
+ "Select a plugin to update");
+
+ if (autocompletedResults.Any())
+ return autocompletedResults;
+
+ var uninstallSearch = search.Replace(Settings.HotkeyUpdate, string.Empty).TrimStart();
+
+
+ var resultsForUpdate =
+ from existingPlugin in Context.API.GetAllPlugins()
+ join pluginFromManifest in pluginsManifest.UserPlugins
+ on existingPlugin.Metadata.ID equals pluginFromManifest.ID
+ where existingPlugin.Metadata.Version != pluginFromManifest.Version
+ select
+ new
+ {
+ pluginFromManifest.Name,
+ pluginFromManifest.Author,
+ CurrentVersion = existingPlugin.Metadata.Version,
+ NewVersion = pluginFromManifest.Version,
+ existingPlugin.Metadata.IcoPath,
+ PluginExistingMetadata = existingPlugin.Metadata,
+ PluginNewUserPlugin = pluginFromManifest
+ };
+
+ if (!resultsForUpdate.Any())
+ return new List {
+ new Result
+ {
+ Title = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_title"),
+ SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_subtitle"),
+ IcoPath = icoPath
+ }};
+
+
+ var results = resultsForUpdate
+ .Select(x =>
+ new Result
+ {
+ Title = $"{x.Name} by {x.Author}",
+ SubTitle = $"Update from version {x.CurrentVersion} to {x.NewVersion}",
+ IcoPath = x.IcoPath,
+ Action = e =>
+ {
+ string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_update_prompt"),
+ x.Name, x.Author,
+ Environment.NewLine, Environment.NewLine);
+
+ if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
+ MessageBoxButton.YesNo) == MessageBoxResult.Yes)
+ {
+ Uninstall(x.PluginExistingMetadata);
+
+ var downloadToFilePath = Path.Combine(DataLocation.PluginsDirectory, $"{x.Name}-{x.NewVersion}.zip");
+ Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath);
+ Install(x.PluginNewUserPlugin, downloadToFilePath);
+
+ Context.API.RestartApp();
+
+ return true;
+ }
+
+ return false;
+ }
+ });
+
+ return Search(results, uninstallSearch);
}
internal bool PluginExists(string id)
@@ -75,16 +174,10 @@ internal bool PluginExists(string id)
return Context.API.GetAllPlugins().Any(x => x.Metadata.ID == id);
}
- internal void PluginsManifestSiteOpen()
- {
- //Open from context menu https://git.vcmq.workers.dev/Flow-Launcher/Flow.Launcher.PluginsManifest
- throw new NotImplementedException();
- }
-
- internal List Search(List results, string searchName)
+ internal List Search(IEnumerable results, string searchName)
{
if (string.IsNullOrEmpty(searchName))
- return results;
+ return results.ToList();
return results
.Where(x =>
@@ -114,11 +207,10 @@ internal List RequestInstallOrUpdate(string searchName)
Application.Current.MainWindow.Hide();
InstallOrUpdate(x);
- return true;
+ return ShouldHideWindow;
},
ContextData = x
- })
- .ToList();
+ });
return Search(results, searchName);
}
@@ -154,42 +246,24 @@ private void Install(UserPlugin plugin, string downloadedFilePath)
return;
}
- string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}");
+ string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}-{plugin.Version}");
Directory.Move(pluginFolderPath, newPluginPath);
-
- Context.API.RestartApp();
}
internal List RequestUninstall(string search)
{
- if (!string.IsNullOrEmpty(search)
- && Settings.UninstallHotkey.StartsWith(search)
- && (Settings.UninstallHotkey != search || !search.StartsWith(Settings.UninstallHotkey)))
- {
- return
- new List
- {
- new Result
- {
- Title = "Uninstall",
- IcoPath = icoPath,
- SubTitle = "Select a plugin to uninstall",
- Action = e =>
- {
- Context
- .API
- .ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.UninstallHotkey} ");
+ var autocompletedResults = AutoCompleteReturnAllResults(search,
+ Settings.HotkeyUninstall,
+ "Uninstall",
+ "Select a plugin to uninstall");
- return false;
- }
- }
- };
- }
+ if (autocompletedResults.Any())
+ return autocompletedResults;
- var uninstallSearch = search.Replace(Settings.UninstallHotkey, string.Empty).TrimStart();
+ var uninstallSearch = search.Replace(Settings.HotkeyUninstall, string.Empty).TrimStart();
- var results= Context.API
+ var results = Context.API
.GetAllPlugins()
.Select(x =>
new Result
@@ -199,30 +273,60 @@ internal List RequestUninstall(string search)
IcoPath = x.Metadata.IcoPath,
Action = e =>
{
- Application.Current.MainWindow.Hide();
- Uninstall(x.Metadata);
+ string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt"),
+ x.Metadata.Name, x.Metadata.Author,
+ Environment.NewLine, Environment.NewLine);
- return true;
+ if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"),
+ MessageBoxButton.YesNo) == MessageBoxResult.Yes)
+ {
+ Application.Current.MainWindow.Hide();
+ Uninstall(x.Metadata);
+ Context.API.RestartApp();
+
+ return true;
+ }
+
+ return false;
}
- })
- .ToList();
+ });
return Search(results, uninstallSearch);
}
private void Uninstall(PluginMetadata plugin)
{
- string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt"),
- plugin.Name, plugin.Author,
- Environment.NewLine, Environment.NewLine);
+ // Marked for deletion. Will be deleted on next start up
+ using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt"));
+ }
- if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"),
- MessageBoxButton.YesNo) == MessageBoxResult.Yes)
+ private List AutoCompleteReturnAllResults(string search, string hotkey, string title, string subtitle)
+ {
+ if (!string.IsNullOrEmpty(search)
+ && hotkey.StartsWith(search)
+ && (hotkey != search || !search.StartsWith(hotkey)))
{
- using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt"));
-
- Context.API.RestartApp();
+ return
+ new List
+ {
+ new Result
+ {
+ Title = title,
+ IcoPath = icoPath,
+ SubTitle = subtitle,
+ Action = e =>
+ {
+ Context
+ .API
+ .ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {hotkey} ");
+
+ return false;
+ }
+ }
+ };
}
+
+ return new List();
}
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs
index 0c647e6ae96..e2e8d22e59f 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs
@@ -6,6 +6,8 @@ namespace Flow.Launcher.Plugin.PluginsManager
{
internal class Settings
{
- internal string UninstallHotkey { get; set; } = "uninstall";
+ internal string HotkeyUninstall { get; set; } = "uninstall";
+
+ internal string HotkeyUpdate { get; set; } = "update";
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json
index 73e03d525b6..e970e5a8ecd 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json
@@ -6,7 +6,7 @@
"Name": "Plugins Manager",
"Description": "Management of installing, uninstalling or updating Flow Launcher plugins",
"Author": "Jeremy Wu",
- "Version": "1.2.0",
+ "Version": "1.3.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll",