diff --git a/Flow.Launcher.Plugin/IProgressBoxEx.cs b/Flow.Launcher.Plugin/IProgressBoxEx.cs deleted file mode 100644 index 50ee6eb5536..00000000000 --- a/Flow.Launcher.Plugin/IProgressBoxEx.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Threading.Tasks; - -namespace Flow.Launcher.Plugin; - -/// -/// Interface for progress box -/// -public interface IProgressBoxEx -{ - /// - /// Show progress box. - /// - /// - /// Progress value. Should be between 0 and 100. When progress is 100, the progress box will be closed. - /// - public void ReportProgress(double progress); - - /// - /// Close progress box. - /// - public Task CloseAsync(); -} diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index 9cd45a1d313..c4bfd7033fb 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -322,8 +322,13 @@ public interface IPublicAPI /// If there is issue when showing the message box, it will return null. /// /// The caption of the message box. + /// + /// Time-consuming task function, whose input is the action to report progress. + /// The input of the action is the progress value which is a double value between 0 and 100. + /// If there are any exceptions, this action will be null. + /// /// When user closes the progress box manually by button or esc key, this action will be called. /// A progress box interface. - public IProgressBoxEx ShowProgressBox(string caption, Action forceClosed = null); + public Task ShowProgressBoxAsync(string caption, Func, Task> reportProgressAsync, Action forceClosed = null); } } diff --git a/Flow.Launcher/ProgressBoxEx.xaml.cs b/Flow.Launcher/ProgressBoxEx.xaml.cs index 507710e90c9..37ee2b0cb29 100644 --- a/Flow.Launcher/ProgressBoxEx.xaml.cs +++ b/Flow.Launcher/ProgressBoxEx.xaml.cs @@ -3,11 +3,10 @@ using System.Windows; using System.Windows.Input; using Flow.Launcher.Infrastructure.Logger; -using Flow.Launcher.Plugin; namespace Flow.Launcher { - public partial class ProgressBoxEx : Window, IProgressBoxEx + public partial class ProgressBoxEx : Window { private readonly Action _forceClosed; @@ -17,31 +16,48 @@ private ProgressBoxEx(Action forceClosed) InitializeComponent(); } - public static IProgressBoxEx Show(string caption, Action forceClosed = null) + public static async Task ShowAsync(string caption, Func, Task> reportProgressAsync, Action forceClosed = null) { - if (!Application.Current.Dispatcher.CheckAccess()) - { - return Application.Current.Dispatcher.Invoke(() => Show(caption, forceClosed)); - } - + ProgressBoxEx prgBox = null; try { - var prgBox = new ProgressBoxEx(forceClosed) + if (!Application.Current.Dispatcher.CheckAccess()) { - Title = caption - }; - prgBox.TitleTextBlock.Text = caption; - prgBox.Show(); - return prgBox; + await Application.Current.Dispatcher.InvokeAsync(() => + { + prgBox = new ProgressBoxEx(forceClosed) + { + Title = caption + }; + prgBox.TitleTextBlock.Text = caption; + prgBox.Show(); + }); + } + + await reportProgressAsync(prgBox.ReportProgress).ConfigureAwait(false); } catch (Exception e) { Log.Error($"|ProgressBoxEx.Show|An error occurred: {e.Message}"); - return null; + + await reportProgressAsync(null).ConfigureAwait(false); + } + finally + { + if (!Application.Current.Dispatcher.CheckAccess()) + { + await Application.Current.Dispatcher.InvokeAsync(async () => + { + if (prgBox != null) + { + await prgBox.CloseAsync(); + } + }); + } } } - public void ReportProgress(double progress) + private void ReportProgress(double progress) { if (!Application.Current.Dispatcher.CheckAccess()) { @@ -64,7 +80,7 @@ public void ReportProgress(double progress) } } - public async Task CloseAsync() + private async Task CloseAsync() { if (!Application.Current.Dispatcher.CheckAccess()) { diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index b403d604662..95d371fb09f 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -324,7 +324,7 @@ public bool IsGameModeOn() public MessageBoxResult ShowMsgBox(string messageBoxText, string caption = "", MessageBoxButton button = MessageBoxButton.OK, MessageBoxImage icon = MessageBoxImage.None, MessageBoxResult defaultResult = MessageBoxResult.OK) => MessageBoxEx.Show(messageBoxText, caption, button, icon, defaultResult); - public IProgressBoxEx ShowProgressBox(string caption, Action forceClosed = null) => ProgressBoxEx.Show(caption, forceClosed); + public Task ShowProgressBoxAsync(string caption, Func, Task> reportProgressAsync, Action forceClosed = null) => ProgressBoxEx.ShowAsync(caption, reportProgressAsync, forceClosed); #endregion diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 081f8d489e6..c3ed04a4da2 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -144,7 +144,6 @@ internal async Task InstallOrUpdateAsync(UserPlugin plugin) var filePath = Path.Combine(Path.GetTempPath(), downloadFilename); - IProgressBoxEx prgBox = null; var downloadCancelled = false; try { @@ -162,42 +161,45 @@ internal async Task InstallOrUpdateAsync(UserPlugin plugin) var canReportProgress = totalBytes != -1; var prgBoxTitle = $"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {plugin.Name}"; - if (canReportProgress && - (prgBox = Context.API.ShowProgressBox(prgBoxTitle, () => - { - if (prgBox != null) - { - cts.Cancel(); - downloadCancelled = true; - } - })) != null) + if (canReportProgress) { - await using var contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - await using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true); - - var buffer = new byte[8192]; - long totalRead = 0; - int read; + await Context.API.ShowProgressBoxAsync(prgBoxTitle, + async (reportProgress) => + { + if (reportProgress == null) + { + // cannot use progress box + await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false); + } + else + { + await using var contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true); - while ((read = await contentStream.ReadAsync(buffer).ConfigureAwait(false)) > 0) - { - await fileStream.WriteAsync(buffer.AsMemory(0, read)).ConfigureAwait(false); - totalRead += read; + var buffer = new byte[8192]; + long totalRead = 0; + int read; - var progressValue = totalRead * 100 / totalBytes; + while ((read = await contentStream.ReadAsync(buffer).ConfigureAwait(false)) > 0) + { + await fileStream.WriteAsync(buffer.AsMemory(0, read)).ConfigureAwait(false); + totalRead += read; - // check if user cancelled download before reporting progress - if (downloadCancelled) - return; - else - prgBox.ReportProgress(progressValue); - } + var progressValue = totalRead * 100 / totalBytes; - // check if user cancelled download before closing progress box - if (downloadCancelled) - return; - else - await prgBox?.CloseAsync(); + // check if user cancelled download before reporting progress + if (downloadCancelled) + return; + else + reportProgress(progressValue); + } + } + }, + () => + { + cts.Cancel(); + downloadCancelled = true; + }); } else { @@ -217,9 +219,6 @@ internal async Task InstallOrUpdateAsync(UserPlugin plugin) } catch (HttpRequestException e) { - // force close progress box - await prgBox?.CloseAsync(); - // show error message Context.API.ShowMsgError( string.Format(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), plugin.Name), @@ -230,9 +229,6 @@ internal async Task InstallOrUpdateAsync(UserPlugin plugin) } catch (Exception e) { - // force close progress box - await prgBox?.CloseAsync(); - // show error message Context.API.ShowMsgError(Context.API.GetTranslation("plugin_pluginsmanager_install_error_title"), string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"),