diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 17517832b..aa6c54a94 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -454,16 +454,11 @@ namespace Flow.Launcher.Core.Plugin #region Public functions - public static bool PluginModified(string uuid) + public static bool PluginModified(string id) { - return _modifiedPlugins.Contains(uuid); + return _modifiedPlugins.Contains(id); } - - /// - /// Update a plugin to new version, from a zip file. By default will remove the zip file if update is via url, - /// unless it's a local path installation - /// public static async Task UpdatePluginAsync(PluginMetadata existingVersion, UserPlugin newVersion, string zipFilePath) { InstallPlugin(newVersion, zipFilePath, checkModified:false); @@ -471,17 +466,11 @@ namespace Flow.Launcher.Core.Plugin _modifiedPlugins.Add(existingVersion.ID); } - /// - /// Install a plugin. By default will remove the zip file if installation is from url, unless it's a local path installation - /// public static void InstallPlugin(UserPlugin plugin, string zipFilePath) { InstallPlugin(plugin, zipFilePath, checkModified: true); } - /// - /// Uninstall a plugin. - /// public static async Task UninstallPluginAsync(PluginMetadata plugin, bool removePluginFromSettings = true, bool removePluginSettings = false) { await UninstallPluginAsync(plugin, removePluginFromSettings, removePluginSettings, true); @@ -525,20 +514,20 @@ namespace Flow.Launcher.Core.Plugin var folderName = string.IsNullOrEmpty(plugin.Version) ? $"{plugin.Name}-{Guid.NewGuid()}" : $"{plugin.Name}-{plugin.Version}"; var defaultPluginIDs = new List - { - "0ECADE17459B49F587BF81DC3A125110", // BrowserBookmark - "CEA0FDFC6D3B4085823D60DC76F28855", // Calculator - "572be03c74c642baae319fc283e561a8", // Explorer - "6A122269676E40EB86EB543B945932B9", // PluginIndicator - "9f8f9b14-2518-4907-b211-35ab6290dee7", // PluginsManager - "b64d0a79-329a-48b0-b53f-d658318a1bf6", // ProcessKiller - "791FC278BA414111B8D1886DFE447410", // Program - "D409510CD0D2481F853690A07E6DC426", // Shell - "CEA08895D2544B019B2E9C5009600DF4", // Sys - "0308FD86DE0A4DEE8D62B9B535370992", // URL - "565B73353DBF4806919830B9202EE3BF", // WebSearch - "5043CETYU6A748679OPA02D27D99677A" // WindowsSettings - }; + { + "0ECADE17459B49F587BF81DC3A125110", // BrowserBookmark + "CEA0FDFC6D3B4085823D60DC76F28855", // Calculator + "572be03c74c642baae319fc283e561a8", // Explorer + "6A122269676E40EB86EB543B945932B9", // PluginIndicator + "9f8f9b14-2518-4907-b211-35ab6290dee7", // PluginsManager + "b64d0a79-329a-48b0-b53f-d658318a1bf6", // ProcessKiller + "791FC278BA414111B8D1886DFE447410", // Program + "D409510CD0D2481F853690A07E6DC426", // Shell + "CEA08895D2544B019B2E9C5009600DF4", // Sys + "0308FD86DE0A4DEE8D62B9B535370992", // URL + "565B73353DBF4806919830B9202EE3BF", // WebSearch + "5043CETYU6A748679OPA02D27D99677A" // WindowsSettings + }; // Treat default plugin differently, it needs to be removable along with each flow release var installDirectory = !defaultPluginIDs.Any(x => x == plugin.ID) diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index 513c2da84..eeb3f5de3 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -352,15 +352,54 @@ namespace Flow.Launcher.Plugin /// FL has multiple urls to download the plugin manifest. Set this to true to only use the primary url. /// /// - /// - /// True if the manifest is updated successfully, false otherwise. - /// + /// True if the manifest is updated successfully, false otherwise public Task UpdatePluginManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default); /// /// Get the plugin manifest /// /// - public IReadOnlyList GetUserPlugins(); + public IReadOnlyList GetPluginManifest(); + + /// + /// Check if the plugin has been modified. + /// If this plugin is updated, installed or uninstalled and users do not restart the app, + /// it will be marked as modified + /// + /// Plugin id + /// + public bool PluginModified(string id); + + /// + /// Update a plugin to new version, from a zip file. By default will remove the zip file if update is via url, + /// unless it's a local path installation + /// + /// The metadata of the old plugin to update + /// The new plugin to update + /// + /// Path to the zip file containing the plugin. It will be unzipped to the temporary directory, removed and installed. + /// + /// + public Task UpdatePluginAsync(PluginMetadata pluginMetadata, UserPlugin plugin, string zipFilePath); + + /// + /// Install a plugin. By default will remove the zip file if installation is from url, + /// unless it's a local path installation + /// + /// The plugin to install + /// + /// Path to the zip file containing the plugin. It will be unzipped to the temporary directory, removed and installed. + /// + public void InstallPlugin(UserPlugin plugin, string zipFilePath); + + /// + /// Uninstall a plugin + /// + /// The metadata of the plugin to uninstall + /// + /// Plugin has their own settings. If this is set to true, the plugin settings will be removed. + /// + /// + public Task UninstallPluginAsync(PluginMetadata pluginMetadata, bool removePluginSettings = false); } } diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index a8ec46982..c40e40ebb 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -358,7 +358,18 @@ namespace Flow.Launcher public Task UpdatePluginManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default) => PluginsManifest.UpdateManifestAsync(usePrimaryUrlOnly, token); - public IReadOnlyList GetUserPlugins() => PluginsManifest.UserPlugins; + public IReadOnlyList GetPluginManifest() => PluginsManifest.UserPlugins; + + public bool PluginModified(string id) => PluginManager.PluginModified(id); + + public Task UpdatePluginAsync(PluginMetadata pluginMetadata, UserPlugin plugin, string zipFilePath) => + PluginManager.UpdatePluginAsync(pluginMetadata, plugin, zipFilePath); + + public void InstallPlugin(UserPlugin plugin, string zipFilePath) => + PluginManager.InstallPlugin(plugin, zipFilePath); + + public Task UninstallPluginAsync(PluginMetadata pluginMetadata, bool removePluginSettings = false) => + PluginManager.UninstallPluginAsync(pluginMetadata, removePluginSettings); #endregion diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs index 23a316304..84d8a2ff9 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs @@ -13,7 +13,7 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel public string FilterText { get; set; } = string.Empty; public IList ExternalPlugins => - App.API.GetUserPlugins()?.Select(p => new PluginStoreItemViewModel(p)) + App.API.GetPluginManifest()?.Select(p => new PluginStoreItemViewModel(p)) .OrderByDescending(p => p.Category == PluginStoreItemViewModel.NewRelease) .ThenByDescending(p => p.Category == PluginStoreItemViewModel.RecentlyUpdated) .ThenByDescending(p => p.Category == PluginStoreItemViewModel.None) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index c742e457c..a16778ff4 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -1,6 +1,4 @@ -using Flow.Launcher.Core.Plugin; -using Flow.Launcher.Plugin.SharedCommands; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -8,6 +6,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using System.Windows; +using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Plugin.PluginsManager { @@ -49,7 +48,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { return new List() { - new Result() + new() { Title = Settings.InstallCommand, IcoPath = icoPath, @@ -61,7 +60,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return false; } }, - new Result() + new() { Title = Settings.UninstallCommand, IcoPath = icoPath, @@ -73,7 +72,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return false; } }, - new Result() + new() { Title = Settings.UpdateCommand, IcoPath = icoPath, @@ -248,7 +247,7 @@ namespace Flow.Launcher.Plugin.PluginsManager } var updateSource = !updateFromLocalPath - ? Context.API.GetUserPlugins() + ? Context.API.GetPluginManifest() : new List { pluginFromLocalPath }; var resultsForUpdate = ( @@ -258,7 +257,7 @@ namespace Flow.Launcher.Plugin.PluginsManager 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) - && !PluginManager.PluginModified(existingPlugin.Metadata.ID) + && !Context.API.PluginModified(existingPlugin.Metadata.ID) select new { @@ -274,7 +273,7 @@ namespace Flow.Launcher.Plugin.PluginsManager if (!resultsForUpdate.Any()) return new List { - new Result + new() { Title = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_title"), SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_subtitle"), @@ -339,7 +338,7 @@ namespace Flow.Launcher.Plugin.PluginsManager } else { - await PluginManager.UpdatePluginAsync(x.PluginExistingMetadata, x.PluginNewUserPlugin, + await Context.API.UpdatePluginAsync(x.PluginExistingMetadata, x.PluginNewUserPlugin, downloadToFilePath); if (Settings.AutoRestartAfterChanging) @@ -431,7 +430,7 @@ namespace Flow.Launcher.Plugin.PluginsManager if (cts.IsCancellationRequested) return; else - await PluginManager.UpdatePluginAsync(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin, + await Context.API.UpdatePluginAsync(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin, downloadToFilePath); } catch (Exception ex) @@ -550,7 +549,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return new List { - new Result + new() { Title = $"{plugin.Name} by {plugin.Author}", SubTitle = plugin.Description, @@ -610,8 +609,8 @@ namespace Flow.Launcher.Plugin.PluginsManager return InstallFromLocalPath(search); var results = - Context.API.GetUserPlugins() - .Where(x => !PluginExists(x.ID) && !PluginManager.PluginModified(x.ID)) + Context.API.GetPluginManifest() + .Where(x => !PluginExists(x.ID) && !Context.API.PluginModified(x.ID)) .Select(x => new Result { @@ -644,7 +643,7 @@ namespace Flow.Launcher.Plugin.PluginsManager try { - PluginManager.InstallPlugin(plugin, downloadedFilePath); + Context.API.InstallPlugin(plugin, downloadedFilePath); if (!plugin.IsFromLocalInstallPath) File.Delete(downloadedFilePath); @@ -737,7 +736,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.GetTranslation("plugin_pluginsmanager_keep_plugin_settings_subtitle"), Context.API.GetTranslation("plugin_pluginsmanager_keep_plugin_settings_title"), button: MessageBoxButton.YesNo) == MessageBoxResult.No; - await PluginManager.UninstallPluginAsync(plugin, removePluginFromSettings: true, removePluginSettings: removePluginSettings); + await Context.API.UninstallPluginAsync(plugin, removePluginSettings); } catch (ArgumentException e) {