Skip to content

Commit

Permalink
Add a download progress window to give feedback and allow cancelling …
Browse files Browse the repository at this point in the history
…downloads
  • Loading branch information
Legi428 committed Oct 5, 2024
1 parent 3349e90 commit 4678cbf
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 22 deletions.
14 changes: 14 additions & 0 deletions UnityLauncherPro/Data/DownloadProgress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace UnityLauncherPro
{
public readonly struct DownloadProgress
{
public long TotalRead { get; }
public long TotalBytes { get; }

public DownloadProgress(long totalRead, long totalBytes)
{
TotalRead = totalRead;
TotalBytes = totalBytes;
}
}
}
22 changes: 22 additions & 0 deletions UnityLauncherPro/DownloadProgressWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Window x:Class="UnityLauncherPro.DownloadProgressWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Download Progress" Height="70" Width="500"
ResizeMode="NoResize"
WindowStyle="None"
PreviewLostKeyboardFocus="Window_PreviewLostKeyboardFocus"
Background="{DynamicResource ThemeDarkestBackground}">
<Grid>
<Grid>
<Label Content="{Binding Title, RelativeSource={RelativeSource AncestorType=Window}, FallbackValue=Title}" IsHitTestVisible="False" Margin="5,0,0,-5" Foreground="{DynamicResource ThemeMainTitle}" FontSize="12" HorizontalAlignment="Left" />
<Button BorderThickness="0" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" HorizontalAlignment="Right" VerticalAlignment="Top" Height="23" Width="23" Background="Transparent" Click="CancelDownloadClick" Padding="0,2" IsTabStop="False">
<TextBlock Text="" FontSize="10" Foreground="{DynamicResource ThemeWindowMinClose}" Padding="5,3,4,4" HorizontalAlignment="Center" />
</Button>
</Grid>
<Grid VerticalAlignment="Bottom" Background="{DynamicResource ThemeMainBackgroundColor}">
<ProgressBar x:Name="ProgressBar" Height="23" VerticalAlignment="Center" Margin="10, 10, 70, 10"/>
<TextBlock x:Name="ProgressText" Text="0%" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10, 10, 70, 10"/>
<Button Style="{StaticResource CustomButton}" Content="Cancel" Width="50" Height="23" HorizontalAlignment="Right" Margin="10" Click="CancelDownloadClick"/>
</Grid>
</Grid>
</Window>
56 changes: 56 additions & 0 deletions UnityLauncherPro/DownloadProgressWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Windows;
using System.Windows.Input;

namespace UnityLauncherPro
{
public partial class DownloadProgressWindow
{
private readonly Action _cancelAction;
private readonly string _subjectName;
private static MainWindow MainWindow => Tools.mainWindow;

public DownloadProgressWindow(string subjectName, Action cancelAction = null)
{
InitializeComponent();
_subjectName = subjectName;
Title = subjectName;
_cancelAction = cancelAction;
Topmost = true;
Owner = MainWindow;
WindowStartupLocation = WindowStartupLocation.CenterOwner;
MainWindow.IsEnabled = false;
}

public void UpdateProgress(DownloadProgress downloadProgress)
{
Title = $"Downloading {_subjectName} ({downloadProgress.TotalRead / 1024d / 1024d:F1} MB / {downloadProgress.TotalBytes / 1024d / 1024d:F1} MB)";
var progress = downloadProgress.TotalBytes == 0 ? 0 : downloadProgress.TotalRead * 100d / downloadProgress.TotalBytes;
ProgressBar.Value = progress;
ProgressText.Text = $"{progress / 100:P1}";
}

private void CancelDownloadClick(object sender, RoutedEventArgs e)
{
CancelDownload();
}

private void CancelDownload()
{
_cancelAction?.Invoke();
}

private void Window_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var window = (Window)sender;
window.Topmost = true;
}

protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_cancelAction?.Invoke();
MainWindow.IsEnabled = true;
}
}
}
76 changes: 54 additions & 22 deletions UnityLauncherPro/Tools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
Expand Down Expand Up @@ -697,7 +699,7 @@ public static async void DownloadAndInstall(string version)
if (File.Exists(tempFile) == true) File.Delete(tempFile);

// TODO make async
if (DownloadFile(exeURL, tempFile) == true)
if (await DownloadFileAsync(exeURL, tempFile))
{
// get base version, to use for install path
// FIXME check if have any paths?
Expand Down Expand Up @@ -737,7 +739,7 @@ public static async void DownloadAndInstall(string version)

static readonly string initFileDefaultURL = "https://raw.githubusercontent.com/unitycoder/UnityInitializeProject/main/Assets/Editor/InitializeProject.cs";

public static void DownloadInitScript(string currentInitScriptFullPath, string currentInitScriptLocationOrURL)
public static async Task DownloadInitScript(string currentInitScriptFullPath, string currentInitScriptLocationOrURL)
{
string currentInitScriptFolder = Path.GetDirectoryName(currentInitScriptFullPath);
string currentInitScriptFile = Path.GetFileName(currentInitScriptFullPath);
Expand All @@ -750,7 +752,7 @@ public static void DownloadInitScript(string currentInitScriptFullPath, string c
if (currentInitScriptLocationOrURL.ToLower().StartsWith("http") == true)
{
// download into temp first
if (DownloadFile(currentInitScriptLocationOrURL, tempFile) == false) return;
if (await DownloadFileAsync(currentInitScriptLocationOrURL, tempFile) == false) return;
}
else // file is in local folders/drives/projects
{
Expand Down Expand Up @@ -819,25 +821,6 @@ static void DeleteTempFile(string path)
}
}

static bool DownloadFile(string url, string tempFile)
{
bool result = false;
try
{
using (WebClient client = new WebClient())
{
client.DownloadFile(url, tempFile);
// TODO check if actually exists
result = true;
}
}
catch (Exception e)
{
Console.WriteLine("Error> DownloadFile: " + e);
}
return result;
}

public static string DownloadHTML(string url)
{
if (string.IsNullOrEmpty(url) == true) return null;
Expand Down Expand Up @@ -2228,6 +2211,55 @@ internal static void OpenCustomAssetPath()
}
}
}

private static async Task<bool> DownloadFileAsync(string fileUrl, string destinationPath)
{
var cancellationTokenSource = new CancellationTokenSource();
var fileName = Path.GetFileName(fileUrl);
var progressWindow = new DownloadProgressWindow(fileName, () => cancellationTokenSource.Cancel());
progressWindow.Show();
var result = false;
try
{
using (var client = new HttpClient())
using (var response = await client.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead, cancellationTokenSource.Token))
{
response.EnsureSuccessStatusCode();

var totalBytes = response.Content.Headers.ContentLength ?? 1;
var buffer = new byte[8192];
var totalRead = 0;

using (var contentStream = await response.Content.ReadAsStreamAsync())
using (var fileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write,
FileShare.None, buffer.Length, true))
{
int bytesRead;
while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length, cancellationTokenSource.Token)) > 0)
{
await fileStream.WriteAsync(buffer, 0, bytesRead, cancellationTokenSource.Token);
totalRead += bytesRead;
progressWindow.UpdateProgress(new DownloadProgress(totalRead, totalBytes));
}
result = true;
}
}
}
catch (TaskCanceledException)
{
Console.WriteLine("Download cancelled");
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
DeleteTempFile(destinationPath);
progressWindow.Close();
}
return result;
}
} // class

} // namespace
5 changes: 5 additions & 0 deletions UnityLauncherPro/UnityLauncherPro.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,16 @@
<Compile Include="Converters\LastModifiedConverter.cs" />
<Compile Include="Data\BuildReport.cs" />
<Compile Include="Data\BuildReportItem.cs" />
<Compile Include="Data\DownloadProgress.cs" />
<Compile Include="Data\Platform.cs" />
<Compile Include="Data\Tabs.cs" />
<Compile Include="Data\ThemeColor.cs" />
<Compile Include="Data\UnityVersion.cs" />
<Compile Include="Data\UnityVersionResponse.cs" />
<Compile Include="Data\UnityVersionStream.cs" />
<Compile Include="DownloadProgressWindow.xaml.cs">
<DependentUpon>DownloadProgressWindow.xaml</DependentUpon>
</Compile>
<Compile Include="GetProjects.cs" />
<Compile Include="GetUnityInstallations.cs" />
<Compile Include="GetUnityUpdates.cs" />
Expand All @@ -141,6 +145,7 @@
<DependentUpon>UpgradeWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Version.cs" />
<Page Include="DownloadProgressWindow.xaml" />
<Page Include="NewProject.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
Expand Down

0 comments on commit 4678cbf

Please sign in to comment.