Skip to content

Commit 383c0ae

Browse files
committed
Improve code quality
1 parent 6044f87 commit 383c0ae

File tree

3 files changed

+213
-219
lines changed

3 files changed

+213
-219
lines changed

Flow.Launcher.Core/Plugin/PluginManager.cs

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Text.Json;
77
using System.Threading;
88
using System.Threading.Tasks;
9+
using System.Windows;
910
using CommunityToolkit.Mvvm.DependencyInjection;
1011
using Flow.Launcher.Core.ExternalPlugins;
1112
using Flow.Launcher.Infrastructure;
@@ -24,6 +25,8 @@ public static class PluginManager
2425
{
2526
private static readonly string ClassName = nameof(PluginManager);
2627

28+
private static readonly Settings FlowSettings = Ioc.Default.GetRequiredService<Settings>();
29+
2730
private static IEnumerable<PluginPair> _contextMenuPlugins;
2831
private static IEnumerable<PluginPair> _homePlugins;
2932

@@ -547,6 +550,177 @@ public static async Task UninstallPluginAsync(PluginMetadata plugin, bool remove
547550
await UninstallPluginAsync(plugin, removePluginFromSettings, removePluginSettings, true);
548551
}
549552

553+
public static async Task InstallPluginAndCheckRestartAsync(UserPlugin newPlugin)
554+
{
555+
if (API.ShowMsgBox(
556+
string.Format(
557+
API.GetTranslation("InstallPromptSubtitle"),
558+
newPlugin.Name, newPlugin.Author, Environment.NewLine),
559+
API.GetTranslation("InstallPromptTitle"),
560+
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
561+
562+
try
563+
{
564+
// at minimum should provide a name, but handle plugin that is not downloaded from plugins manifest and is a url download
565+
var downloadFilename = string.IsNullOrEmpty(newPlugin.Version)
566+
? $"{newPlugin.Name}-{Guid.NewGuid()}.zip"
567+
: $"{newPlugin.Name}-{newPlugin.Version}.zip";
568+
569+
var filePath = Path.Combine(Path.GetTempPath(), downloadFilename);
570+
571+
using var cts = new CancellationTokenSource();
572+
573+
if (!newPlugin.IsFromLocalInstallPath)
574+
{
575+
await DownloadFileAsync(
576+
$"{API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}",
577+
newPlugin.UrlDownload, filePath, cts);
578+
}
579+
else
580+
{
581+
filePath = newPlugin.LocalInstallPath;
582+
}
583+
584+
// check if user cancelled download before installing plugin
585+
if (cts.IsCancellationRequested)
586+
{
587+
return;
588+
}
589+
else
590+
{
591+
if (!File.Exists(filePath))
592+
{
593+
throw new FileNotFoundException($"Plugin {newPlugin.ID} zip file not found at {filePath}", filePath);
594+
}
595+
596+
API.InstallPlugin(newPlugin, filePath);
597+
598+
if (!newPlugin.IsFromLocalInstallPath)
599+
{
600+
File.Delete(filePath);
601+
}
602+
}
603+
}
604+
catch (Exception e)
605+
{
606+
API.LogException(ClassName, "Failed to install plugin", e);
607+
API.ShowMsgError(API.GetTranslation("ErrorInstallingPlugin"));
608+
return; // don’t restart on failure
609+
}
610+
611+
if (FlowSettings.AutoRestartAfterChanging)
612+
{
613+
API.RestartApp();
614+
}
615+
else
616+
{
617+
API.ShowMsg(
618+
API.GetTranslation("installbtn"),
619+
string.Format(
620+
API.GetTranslation(
621+
"InstallSuccessNoRestart"),
622+
newPlugin.Name));
623+
}
624+
}
625+
626+
public static async Task UninstallPluginAndCheckRestartAsync(PluginMetadata oldPlugin)
627+
{
628+
if (API.ShowMsgBox(
629+
string.Format(
630+
API.GetTranslation("UninstallPromptSubtitle"),
631+
oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
632+
API.GetTranslation("UninstallPromptTitle"),
633+
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
634+
635+
var removePluginSettings = API.ShowMsgBox(
636+
API.GetTranslation("KeepPluginSettingsSubtitle"),
637+
API.GetTranslation("KeepPluginSettingsTitle"),
638+
button: MessageBoxButton.YesNo) == MessageBoxResult.No;
639+
640+
try
641+
{
642+
await API.UninstallPluginAsync(oldPlugin, removePluginSettings);
643+
}
644+
catch (Exception e)
645+
{
646+
API.LogException(ClassName, "Failed to uninstall plugin", e);
647+
API.ShowMsgError(API.GetTranslation("ErrorUninstallingPlugin"));
648+
return; // don’t restart on failure
649+
}
650+
651+
if (FlowSettings.AutoRestartAfterChanging)
652+
{
653+
API.RestartApp();
654+
}
655+
else
656+
{
657+
API.ShowMsg(
658+
API.GetTranslation("uninstallbtn"),
659+
string.Format(
660+
API.GetTranslation(
661+
"UninstallSuccessNoRestart"),
662+
oldPlugin.Name));
663+
}
664+
}
665+
666+
public static async Task UpdatePluginAndCheckRestartAsync(UserPlugin newPlugin, PluginMetadata oldPlugin)
667+
{
668+
if (API.ShowMsgBox(
669+
string.Format(
670+
API.GetTranslation("UpdatePromptSubtitle"),
671+
oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
672+
API.GetTranslation("UpdatePromptTitle"),
673+
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
674+
675+
try
676+
{
677+
var filePath = Path.Combine(Path.GetTempPath(), $"{newPlugin.Name}-{newPlugin.Version}.zip");
678+
679+
using var cts = new CancellationTokenSource();
680+
681+
if (!newPlugin.IsFromLocalInstallPath)
682+
{
683+
await DownloadFileAsync(
684+
$"{API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}",
685+
newPlugin.UrlDownload, filePath, cts);
686+
}
687+
else
688+
{
689+
filePath = newPlugin.LocalInstallPath;
690+
}
691+
692+
// check if user cancelled download before installing plugin
693+
if (cts.IsCancellationRequested)
694+
{
695+
return;
696+
}
697+
else
698+
{
699+
await API.UpdatePluginAsync(oldPlugin, newPlugin, filePath);
700+
}
701+
}
702+
catch (Exception e)
703+
{
704+
API.LogException(ClassName, "Failed to update plugin", e);
705+
API.ShowMsgError(API.GetTranslation("ErrorUpdatingPlugin"));
706+
return; // don’t restart on failure
707+
}
708+
709+
if (FlowSettings.AutoRestartAfterChanging)
710+
{
711+
API.RestartApp();
712+
}
713+
else
714+
{
715+
API.ShowMsg(
716+
API.GetTranslation("updatebtn"),
717+
string.Format(
718+
API.GetTranslation(
719+
"UpdateSuccessNoRestart"),
720+
newPlugin.Name));
721+
}
722+
}
723+
550724
#endregion
551725

552726
#region Internal functions
@@ -694,6 +868,41 @@ internal static async Task UninstallPluginAsync(PluginMetadata plugin, bool remo
694868
}
695869
}
696870

871+
internal static async Task DownloadFileAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true)
872+
{
873+
if (deleteFile && File.Exists(filePath))
874+
File.Delete(filePath);
875+
876+
if (showProgress)
877+
{
878+
var exceptionHappened = false;
879+
await API.ShowProgressBoxAsync(prgBoxTitle,
880+
async (reportProgress) =>
881+
{
882+
if (reportProgress == null)
883+
{
884+
// when reportProgress is null, it means there is expcetion with the progress box
885+
// so we record it with exceptionHappened and return so that progress box will close instantly
886+
exceptionHappened = true;
887+
return;
888+
}
889+
else
890+
{
891+
await API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false);
892+
}
893+
}, cts.Cancel);
894+
895+
// if exception happened while downloading and user does not cancel downloading,
896+
// we need to redownload the plugin
897+
if (exceptionHappened && (!cts.IsCancellationRequested))
898+
await API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
899+
}
900+
else
901+
{
902+
await API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
903+
}
904+
}
905+
697906
#endregion
698907
}
699908
}

0 commit comments

Comments
 (0)