Add progress box support for downloading plugin

This commit is contained in:
Jack251970 2025-01-04 23:11:13 +08:00
parent 37058f7651
commit 562b233c15
3 changed files with 239 additions and 2 deletions

View file

@ -0,0 +1,106 @@
<Window
x:Class="Flow.Launcher.Core.ProgressBoxEx"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Flow.Launcher.Core"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="MessageBoxWindow"
Width="420"
Height="Auto"
Background="{DynamicResource PopuBGColor}"
Foreground="{DynamicResource PopupTextColor}"
ResizeMode="NoResize"
SizeToContent="Height"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
</WindowChrome.WindowChrome>
<Window.InputBindings>
<KeyBinding Key="Escape" Command="Close" />
</Window.InputBindings>
<Window.CommandBindings>
<CommandBinding Command="Close" Executed="KeyEsc_OnPress" />
</Window.CommandBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition MinHeight="68" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="1"
Click="Button_Cancel"
Style="{StaticResource TitleBarCloseButtonStyle}">
<Path
Width="46"
Height="32"
Data="M 18,11 27,20 M 18,20 27,11"
Stroke="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
StrokeThickness="1">
<Path.Style>
<Style TargetType="Path">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsActive, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="False">
<Setter Property="Opacity" Value="0.5" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Button>
</Grid>
</StackPanel>
</StackPanel>
<Grid Grid.Row="1" Margin="30 0 30 24">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
x:Name="TitleTextBlock"
Grid.Row="0"
MaxWidth="400"
Margin="0 0 26 12"
VerticalAlignment="Center"
FontFamily="Segoe UI"
FontSize="20"
FontWeight="SemiBold"
TextAlignment="Left"
TextWrapping="Wrap" />
<ProgressBar
x:Name="ProgressBar"
Grid.Row="1"
Margin="0 0 26 0"
Maximum="100"
Minimum="0"
Value="0" />
</Grid>
<Border
Grid.Row="2"
Margin="0 0 0 0"
Background="{DynamicResource PopupButtonAreaBGColor}"
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
BorderThickness="0 1 0 0">
<WrapPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<Button
x:Name="btnCancel"
MinWidth="120"
Margin="5 0 5 0"
Click="Button_Click"
Content="{DynamicResource commonCancel}" />
</WrapPanel>
</Border>
</Grid>
</Window>

View file

@ -0,0 +1,76 @@
using System;
using System.Windows;
using System.Windows.Input;
using Flow.Launcher.Infrastructure.Logger;
namespace Flow.Launcher.Core
{
public partial class ProgressBoxEx : Window
{
private ProgressBoxEx()
{
InitializeComponent();
}
public static ProgressBoxEx Show(string caption)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
return Application.Current.Dispatcher.Invoke(() => Show(caption));
}
try
{
var prgBox = new ProgressBoxEx
{
Title = caption
};
prgBox.TitleTextBlock.Text = caption;
prgBox.Show();
return prgBox;
}
catch (Exception e)
{
Log.Error($"|ProgressBoxEx.Show|An error occurred: {e.Message}");
return null;
}
}
public void ReportProgress(double progress)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.Invoke(() => ReportProgress(progress));
return;
}
if (progress < 0)
{
ProgressBar.Value = 0;
}
else if (progress >= 100)
{
ProgressBar.Value = 100;
}
else
{
ProgressBar.Value = progress;
}
}
private void KeyEsc_OnPress(object sender, ExecutedRoutedEventArgs e)
{
Close();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void Button_Cancel(object sender, RoutedEventArgs e)
{
Close();
}
}
}

View file

@ -1,4 +1,5 @@
using Flow.Launcher.Core.ExternalPlugins;
using Flow.Launcher.Core;
using Flow.Launcher.Core.ExternalPlugins;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Http;
@ -142,6 +143,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
var filePath = Path.Combine(Path.GetTempPath(), downloadFilename);
ProgressBoxEx prgBox = null;
try
{
if (!plugin.IsFromLocalInstallPath)
@ -149,7 +151,42 @@ namespace Flow.Launcher.Plugin.PluginsManager
if (File.Exists(filePath))
File.Delete(filePath);
await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false);
using var httpClient = new HttpClient();
using var response = await httpClient.GetAsync(plugin.UrlDownload, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var totalBytes = response.Content.Headers.ContentLength ?? -1L;
var canReportProgress = totalBytes != -1;
if (canReportProgress && (prgBox = ProgressBoxEx.Show("Download plugin...")) != null)
{
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;
while ((read = await contentStream.ReadAsync(buffer).ConfigureAwait(false)) > 0)
{
await fileStream.WriteAsync(buffer.AsMemory(0, read)).ConfigureAwait(false);
totalRead += read;
var progressValue = totalRead * 100 / totalBytes;
prgBox.ReportProgress(progressValue);
}
Application.Current.Dispatcher.Invoke(() =>
{
prgBox.Close();
prgBox = null;
});
}
else
{
await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false);
}
}
else
{
@ -164,6 +201,15 @@ namespace Flow.Launcher.Plugin.PluginsManager
string.Format(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), plugin.Name),
Context.API.GetTranslation("plugin_pluginsmanager_download_error"));
Log.Exception("PluginsManager", "An error occurred while downloading plugin", e);
// force close progress box
Application.Current.Dispatcher.Invoke(() =>
{
if (prgBox != null)
{
prgBox.Close();
prgBox = null;
}
});
return;
}
catch (Exception e)
@ -172,6 +218,15 @@ namespace Flow.Launcher.Plugin.PluginsManager
string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"),
plugin.Name));
Log.Exception("PluginsManager", "An error occurred while downloading plugin", e);
// force close progress box
Application.Current.Dispatcher.Invoke(() =>
{
if (prgBox != null)
{
prgBox.Close();
prgBox = null;
}
});
return;
}