mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Improve code quality
This commit is contained in:
parent
6044f87e80
commit
383c0aeffc
3 changed files with 213 additions and 219 deletions
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Core.ExternalPlugins;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
|
|
@ -24,6 +25,8 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
private static readonly string ClassName = nameof(PluginManager);
|
||||
|
||||
private static readonly Settings FlowSettings = Ioc.Default.GetRequiredService<Settings>();
|
||||
|
||||
private static IEnumerable<PluginPair> _contextMenuPlugins;
|
||||
private static IEnumerable<PluginPair> _homePlugins;
|
||||
|
||||
|
|
@ -547,6 +550,177 @@ namespace Flow.Launcher.Core.Plugin
|
|||
await UninstallPluginAsync(plugin, removePluginFromSettings, removePluginSettings, true);
|
||||
}
|
||||
|
||||
public static async Task InstallPluginAndCheckRestartAsync(UserPlugin newPlugin)
|
||||
{
|
||||
if (API.ShowMsgBox(
|
||||
string.Format(
|
||||
API.GetTranslation("InstallPromptSubtitle"),
|
||||
newPlugin.Name, newPlugin.Author, Environment.NewLine),
|
||||
API.GetTranslation("InstallPromptTitle"),
|
||||
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
|
||||
|
||||
try
|
||||
{
|
||||
// at minimum should provide a name, but handle plugin that is not downloaded from plugins manifest and is a url download
|
||||
var downloadFilename = string.IsNullOrEmpty(newPlugin.Version)
|
||||
? $"{newPlugin.Name}-{Guid.NewGuid()}.zip"
|
||||
: $"{newPlugin.Name}-{newPlugin.Version}.zip";
|
||||
|
||||
var filePath = Path.Combine(Path.GetTempPath(), downloadFilename);
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
|
||||
if (!newPlugin.IsFromLocalInstallPath)
|
||||
{
|
||||
await DownloadFileAsync(
|
||||
$"{API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}",
|
||||
newPlugin.UrlDownload, filePath, cts);
|
||||
}
|
||||
else
|
||||
{
|
||||
filePath = newPlugin.LocalInstallPath;
|
||||
}
|
||||
|
||||
// check if user cancelled download before installing plugin
|
||||
if (cts.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
throw new FileNotFoundException($"Plugin {newPlugin.ID} zip file not found at {filePath}", filePath);
|
||||
}
|
||||
|
||||
API.InstallPlugin(newPlugin, filePath);
|
||||
|
||||
if (!newPlugin.IsFromLocalInstallPath)
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Failed to install plugin", e);
|
||||
API.ShowMsgError(API.GetTranslation("ErrorInstallingPlugin"));
|
||||
return; // don’t restart on failure
|
||||
}
|
||||
|
||||
if (FlowSettings.AutoRestartAfterChanging)
|
||||
{
|
||||
API.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
API.ShowMsg(
|
||||
API.GetTranslation("installbtn"),
|
||||
string.Format(
|
||||
API.GetTranslation(
|
||||
"InstallSuccessNoRestart"),
|
||||
newPlugin.Name));
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task UninstallPluginAndCheckRestartAsync(PluginMetadata oldPlugin)
|
||||
{
|
||||
if (API.ShowMsgBox(
|
||||
string.Format(
|
||||
API.GetTranslation("UninstallPromptSubtitle"),
|
||||
oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
|
||||
API.GetTranslation("UninstallPromptTitle"),
|
||||
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
|
||||
|
||||
var removePluginSettings = API.ShowMsgBox(
|
||||
API.GetTranslation("KeepPluginSettingsSubtitle"),
|
||||
API.GetTranslation("KeepPluginSettingsTitle"),
|
||||
button: MessageBoxButton.YesNo) == MessageBoxResult.No;
|
||||
|
||||
try
|
||||
{
|
||||
await API.UninstallPluginAsync(oldPlugin, removePluginSettings);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Failed to uninstall plugin", e);
|
||||
API.ShowMsgError(API.GetTranslation("ErrorUninstallingPlugin"));
|
||||
return; // don’t restart on failure
|
||||
}
|
||||
|
||||
if (FlowSettings.AutoRestartAfterChanging)
|
||||
{
|
||||
API.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
API.ShowMsg(
|
||||
API.GetTranslation("uninstallbtn"),
|
||||
string.Format(
|
||||
API.GetTranslation(
|
||||
"UninstallSuccessNoRestart"),
|
||||
oldPlugin.Name));
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task UpdatePluginAndCheckRestartAsync(UserPlugin newPlugin, PluginMetadata oldPlugin)
|
||||
{
|
||||
if (API.ShowMsgBox(
|
||||
string.Format(
|
||||
API.GetTranslation("UpdatePromptSubtitle"),
|
||||
oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
|
||||
API.GetTranslation("UpdatePromptTitle"),
|
||||
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
|
||||
|
||||
try
|
||||
{
|
||||
var filePath = Path.Combine(Path.GetTempPath(), $"{newPlugin.Name}-{newPlugin.Version}.zip");
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
|
||||
if (!newPlugin.IsFromLocalInstallPath)
|
||||
{
|
||||
await DownloadFileAsync(
|
||||
$"{API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}",
|
||||
newPlugin.UrlDownload, filePath, cts);
|
||||
}
|
||||
else
|
||||
{
|
||||
filePath = newPlugin.LocalInstallPath;
|
||||
}
|
||||
|
||||
// check if user cancelled download before installing plugin
|
||||
if (cts.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await API.UpdatePluginAsync(oldPlugin, newPlugin, filePath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, "Failed to update plugin", e);
|
||||
API.ShowMsgError(API.GetTranslation("ErrorUpdatingPlugin"));
|
||||
return; // don’t restart on failure
|
||||
}
|
||||
|
||||
if (FlowSettings.AutoRestartAfterChanging)
|
||||
{
|
||||
API.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
API.ShowMsg(
|
||||
API.GetTranslation("updatebtn"),
|
||||
string.Format(
|
||||
API.GetTranslation(
|
||||
"UpdateSuccessNoRestart"),
|
||||
newPlugin.Name));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal functions
|
||||
|
|
@ -694,6 +868,41 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
}
|
||||
|
||||
internal static async Task DownloadFileAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true)
|
||||
{
|
||||
if (deleteFile && File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
|
||||
if (showProgress)
|
||||
{
|
||||
var exceptionHappened = false;
|
||||
await API.ShowProgressBoxAsync(prgBoxTitle,
|
||||
async (reportProgress) =>
|
||||
{
|
||||
if (reportProgress == null)
|
||||
{
|
||||
// when reportProgress is null, it means there is expcetion with the progress box
|
||||
// so we record it with exceptionHappened and return so that progress box will close instantly
|
||||
exceptionHappened = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
}, cts.Cancel);
|
||||
|
||||
// if exception happened while downloading and user does not cancel downloading,
|
||||
// we need to redownload the plugin
|
||||
if (exceptionHappened && (!cts.IsCancellationRequested))
|
||||
await API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Version = SemanticVersioning.Version;
|
||||
|
||||
|
|
@ -14,10 +9,6 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
public partial class PluginStoreItemViewModel : BaseModel
|
||||
{
|
||||
private static readonly string ClassName = nameof(PluginStoreItemViewModel);
|
||||
|
||||
private static readonly Settings Settings = Ioc.Default.GetRequiredService<Settings>();
|
||||
|
||||
private readonly UserPlugin _newPlugin;
|
||||
private readonly PluginPair _oldPluginPair;
|
||||
|
||||
|
|
@ -74,223 +65,17 @@ namespace Flow.Launcher.ViewModel
|
|||
switch (action)
|
||||
{
|
||||
case "install":
|
||||
await InstallPluginAsync(_newPlugin);
|
||||
await PluginManager.InstallPluginAndCheckRestartAsync(_newPlugin);
|
||||
break;
|
||||
case "uninstall":
|
||||
await UninstallPluginAsync(_oldPluginPair.Metadata);
|
||||
await PluginManager.UninstallPluginAndCheckRestartAsync(_oldPluginPair.Metadata);
|
||||
break;
|
||||
case "update":
|
||||
await UpdatePluginAsync(_newPlugin, _oldPluginPair.Metadata);
|
||||
await PluginManager.UpdatePluginAndCheckRestartAsync(_newPlugin, _oldPluginPair.Metadata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task InstallPluginAsync(UserPlugin newPlugin)
|
||||
{
|
||||
if (App.API.ShowMsgBox(
|
||||
string.Format(
|
||||
App.API.GetTranslation("InstallPromptSubtitle"),
|
||||
newPlugin.Name, newPlugin.Author, Environment.NewLine),
|
||||
App.API.GetTranslation("InstallPromptTitle"),
|
||||
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
|
||||
|
||||
try
|
||||
{
|
||||
// at minimum should provide a name, but handle plugin that is not downloaded from plugins manifest and is a url download
|
||||
var downloadFilename = string.IsNullOrEmpty(newPlugin.Version)
|
||||
? $"{newPlugin.Name}-{Guid.NewGuid()}.zip"
|
||||
: $"{newPlugin.Name}-{newPlugin.Version}.zip";
|
||||
|
||||
var filePath = Path.Combine(Path.GetTempPath(), downloadFilename);
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
|
||||
if (!newPlugin.IsFromLocalInstallPath)
|
||||
{
|
||||
await DownloadFileAsync(
|
||||
$"{App.API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}",
|
||||
newPlugin.UrlDownload, filePath, cts);
|
||||
}
|
||||
else
|
||||
{
|
||||
filePath = newPlugin.LocalInstallPath;
|
||||
}
|
||||
|
||||
// check if user cancelled download before installing plugin
|
||||
if (cts.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
throw new FileNotFoundException($"Plugin {newPlugin.ID} zip file not found at {filePath}", filePath);
|
||||
}
|
||||
|
||||
App.API.InstallPlugin(newPlugin, filePath);
|
||||
|
||||
if (!newPlugin.IsFromLocalInstallPath)
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
App.API.LogException(ClassName, "Failed to install plugin", e);
|
||||
App.API.ShowMsgError(App.API.GetTranslation("ErrorInstallingPlugin"));
|
||||
return; // don’t restart on failure
|
||||
}
|
||||
|
||||
if (Settings.AutoRestartAfterChanging)
|
||||
{
|
||||
App.API.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
App.API.ShowMsg(
|
||||
App.API.GetTranslation("installbtn"),
|
||||
string.Format(
|
||||
App.API.GetTranslation(
|
||||
"InstallSuccessNoRestart"),
|
||||
newPlugin.Name));
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task UninstallPluginAsync(PluginMetadata oldPlugin)
|
||||
{
|
||||
if (App.API.ShowMsgBox(
|
||||
string.Format(
|
||||
App.API.GetTranslation("UninstallPromptSubtitle"),
|
||||
oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
|
||||
App.API.GetTranslation("UninstallPromptTitle"),
|
||||
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
|
||||
|
||||
var removePluginSettings = App.API.ShowMsgBox(
|
||||
App.API.GetTranslation("KeepPluginSettingsSubtitle"),
|
||||
App.API.GetTranslation("KeepPluginSettingsTitle"),
|
||||
button: MessageBoxButton.YesNo) == MessageBoxResult.No;
|
||||
|
||||
try
|
||||
{
|
||||
await App.API.UninstallPluginAsync(oldPlugin, removePluginSettings);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
App.API.LogException(ClassName, "Failed to uninstall plugin", e);
|
||||
App.API.ShowMsgError(App.API.GetTranslation("ErrorUninstallingPlugin"));
|
||||
return; // don’t restart on failure
|
||||
}
|
||||
|
||||
if (Settings.AutoRestartAfterChanging)
|
||||
{
|
||||
App.API.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
App.API.ShowMsg(
|
||||
App.API.GetTranslation("uninstallbtn"),
|
||||
string.Format(
|
||||
App.API.GetTranslation(
|
||||
"UninstallSuccessNoRestart"),
|
||||
oldPlugin.Name));
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task UpdatePluginAsync(UserPlugin newPlugin, PluginMetadata oldPlugin)
|
||||
{
|
||||
if (App.API.ShowMsgBox(
|
||||
string.Format(
|
||||
App.API.GetTranslation("UpdatePromptSubtitle"),
|
||||
oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
|
||||
App.API.GetTranslation("UpdatePromptTitle"),
|
||||
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
|
||||
|
||||
try
|
||||
{
|
||||
var filePath = Path.Combine(Path.GetTempPath(), $"{newPlugin.Name}-{newPlugin.Version}.zip");
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
|
||||
if (!newPlugin.IsFromLocalInstallPath)
|
||||
{
|
||||
await DownloadFileAsync(
|
||||
$"{App.API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}",
|
||||
newPlugin.UrlDownload, filePath, cts);
|
||||
}
|
||||
else
|
||||
{
|
||||
filePath = newPlugin.LocalInstallPath;
|
||||
}
|
||||
|
||||
// check if user cancelled download before installing plugin
|
||||
if (cts.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await App.API.UpdatePluginAsync(oldPlugin, newPlugin, filePath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
App.API.LogException(ClassName, "Failed to update plugin", e);
|
||||
App.API.ShowMsgError(App.API.GetTranslation("ErrorUpdatingPlugin"));
|
||||
return; // don’t restart on failure
|
||||
}
|
||||
|
||||
if (Settings.AutoRestartAfterChanging)
|
||||
{
|
||||
App.API.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
App.API.ShowMsg(
|
||||
App.API.GetTranslation("updatebtn"),
|
||||
string.Format(
|
||||
App.API.GetTranslation(
|
||||
"UpdateSuccessNoRestart"),
|
||||
newPlugin.Name));
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task DownloadFileAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true)
|
||||
{
|
||||
if (deleteFile && File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
|
||||
if (showProgress)
|
||||
{
|
||||
var exceptionHappened = false;
|
||||
await App.API.ShowProgressBoxAsync(prgBoxTitle,
|
||||
async (reportProgress) =>
|
||||
{
|
||||
if (reportProgress == null)
|
||||
{
|
||||
// when reportProgress is null, it means there is expcetion with the progress box
|
||||
// so we record it with exceptionHappened and return so that progress box will close instantly
|
||||
exceptionHappened = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await App.API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
}, cts.Cancel);
|
||||
|
||||
// if exception happened while downloading and user does not cancel downloading,
|
||||
// we need to redownload the plugin
|
||||
if (exceptionHappened && (!cts.IsCancellationRequested))
|
||||
await App.API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await App.API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ namespace Flow.Launcher.ViewModel
|
|||
[RelayCommand]
|
||||
private async Task OpenDeletePluginWindowAsync()
|
||||
{
|
||||
await PluginStoreItemViewModel.UninstallPluginAsync(PluginPair.Metadata);
|
||||
await PluginManager.UninstallPluginAndCheckRestartAsync(PluginPair.Metadata);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
|
|
|
|||
Loading…
Reference in a new issue