mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Add progress box support for downloading plugin
This commit is contained in:
parent
37058f7651
commit
562b233c15
3 changed files with 239 additions and 2 deletions
106
Flow.Launcher.Core/ProgressBoxEx.xaml
Normal file
106
Flow.Launcher.Core/ProgressBoxEx.xaml
Normal 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>
|
||||||
76
Flow.Launcher.Core/ProgressBoxEx.xaml.cs
Normal file
76
Flow.Launcher.Core/ProgressBoxEx.xaml.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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.Core.Plugin;
|
||||||
using Flow.Launcher.Infrastructure;
|
using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Infrastructure.Http;
|
using Flow.Launcher.Infrastructure.Http;
|
||||||
|
|
@ -142,6 +143,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
||||||
|
|
||||||
var filePath = Path.Combine(Path.GetTempPath(), downloadFilename);
|
var filePath = Path.Combine(Path.GetTempPath(), downloadFilename);
|
||||||
|
|
||||||
|
ProgressBoxEx prgBox = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!plugin.IsFromLocalInstallPath)
|
if (!plugin.IsFromLocalInstallPath)
|
||||||
|
|
@ -149,7 +151,42 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
File.Delete(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
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -164,6 +201,15 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
||||||
string.Format(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), plugin.Name),
|
string.Format(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), plugin.Name),
|
||||||
Context.API.GetTranslation("plugin_pluginsmanager_download_error"));
|
Context.API.GetTranslation("plugin_pluginsmanager_download_error"));
|
||||||
Log.Exception("PluginsManager", "An error occurred while downloading plugin", e);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
@ -172,6 +218,15 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
||||||
string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"),
|
string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"),
|
||||||
plugin.Name));
|
plugin.Name));
|
||||||
Log.Exception("PluginsManager", "An error occurred while downloading plugin", e);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue