Browse Source

Updated download service to use IProgress

pull/5/head
JT 1 year ago
parent
commit
4b96406af0
  1. 19
      StabilityMatrix/CheckpointBrowserPage.xaml
  2. 7
      StabilityMatrix/DesignData/MockCheckpointBrowserViewModel.cs
  3. 12
      StabilityMatrix/Helper/PrerequisiteHelper.cs
  4. 16
      StabilityMatrix/Models/Packages/BaseGitPackage.cs
  5. 21
      StabilityMatrix/Services/DownloadService.cs
  6. 5
      StabilityMatrix/Services/IDownloadService.cs
  7. 45
      StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs
  8. 2
      StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs
  9. 4
      StabilityMatrix/ViewModels/ProgressViewModel.cs

19
StabilityMatrix/CheckpointBrowserPage.xaml

@ -8,7 +8,6 @@
ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}" ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}" ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
x:Class="StabilityMatrix.CheckpointBrowserPage" x:Class="StabilityMatrix.CheckpointBrowserPage"
x:Name="CheckpointBrowserPg"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:api="clr-namespace:StabilityMatrix.Models.Api" xmlns:api="clr-namespace:StabilityMatrix.Models.Api"
xmlns:converters="clr-namespace:StabilityMatrix.Converters" xmlns:converters="clr-namespace:StabilityMatrix.Converters"
@ -41,18 +40,18 @@
FontSize="11" FontSize="11"
Foreground="{DynamicResource TextFillColorTertiaryBrush}" Foreground="{DynamicResource TextFillColorTertiaryBrush}"
Margin="0,2,0,0" Margin="0,2,0,0"
Text="{Binding ModelVersions[0].Name}" Text="{Binding CivitModel.ModelVersions[0].Name}"
VerticalAlignment="Center" /> VerticalAlignment="Center" />
<Grid> <Grid>
<Image <Image
Margin="0,8,0,8" Margin="0,8,0,8"
MaxHeight="300" MaxHeight="300"
Source="{Binding ModelVersions[0].Images[0].Url, Converter={StaticResource UriToBitmapConverter}}" Source="{Binding CivitModel.ModelVersions[0].Images[0].Url, Converter={StaticResource UriToBitmapConverter}}"
Stretch="UniformToFill" /> Stretch="UniformToFill" />
<ui:Button <ui:Button
Appearance="Info" Appearance="Info"
Command="{Binding OpenModelCommand}" Command="{Binding OpenModelCommand}"
CommandParameter="{Binding}" CommandParameter="{Binding CivitModel}"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Margin="0,16,8,0" Margin="0,16,8,0"
VerticalAlignment="Top"> VerticalAlignment="Top">
@ -64,21 +63,21 @@
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Margin="0,8,0,8" Margin="0,8,0,8"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
Visibility="{Binding DataContext.ImportCommand.IsRunning, Source={x:Reference CheckpointBrowserPg}, Converter={StaticResource BoolToVisibilityConverter}}" /> Visibility="{Binding ImportCommand.IsRunning, Converter={StaticResource BoolToVisibilityConverter}}" />
<StackPanel <StackPanel
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Orientation="Vertical" Orientation="Vertical"
VerticalAlignment="Center" VerticalAlignment="Center"
Visibility="{Binding DataContext.ImportCommand.IsRunning, Source={x:Reference CheckpointBrowserPg}, Converter={StaticResource BoolToVisibilityConverter}}"> Visibility="{Binding ImportCommand.IsRunning, Converter={StaticResource BoolToVisibilityConverter}}">
<ui:ProgressRing <ui:ProgressRing
HorizontalAlignment="Center" HorizontalAlignment="Center"
IsIndeterminate="False" IsIndeterminate="False"
Progress="{Binding DataContext.ImportProgress, Source={x:Reference CheckpointBrowserPg}}" Progress="{Binding Value}"
VerticalAlignment="Center" /> VerticalAlignment="Center" />
<TextBlock <TextBlock
HorizontalAlignment="Center" HorizontalAlignment="Center"
Margin="0,8,0,0" Margin="0,8,0,0"
Text="{Binding ImportStatus, FallbackValue=Importing...}" Text="{Binding Text, FallbackValue=Importing...}"
VerticalAlignment="Center" /> VerticalAlignment="Center" />
</StackPanel> </StackPanel>
</Grid> </Grid>
@ -88,8 +87,8 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<ui:Button <ui:Button
Appearance="Primary" Appearance="Primary"
Command="{Binding DataContext.ImportCommand, Source={x:Reference CheckpointBrowserPg}}" Command="{Binding ImportCommand}"
CommandParameter="{Binding}" CommandParameter="{Binding CivitModel}"
Content="Import" Content="Import"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Margin="0,8,0,0" /> Margin="0,8,0,0" />

7
StabilityMatrix/DesignData/MockCheckpointBrowserViewModel.cs

@ -10,9 +10,11 @@ public class MockCheckpointBrowserViewModel : CheckpointBrowserViewModel
{ {
public MockCheckpointBrowserViewModel() : base(null!, null!) public MockCheckpointBrowserViewModel() : base(null!, null!)
{ {
CivitModels = new ObservableCollection<CivitModel> ModelCards = new ObservableCollection<CheckpointBrowserCardViewModel>
{ {
new() new (null!, null!)
{
CivitModel = new()
{ {
Name = "bb95 Furry Mix", Name = "bb95 Furry Mix",
ModelVersions = new[] ModelVersions = new[]
@ -31,6 +33,7 @@ public class MockCheckpointBrowserViewModel : CheckpointBrowserViewModel
} }
} }
} }
}
}; };
} }
} }

12
StabilityMatrix/Helper/PrerequisiteHelper.cs

@ -59,13 +59,13 @@ public class PrerequisiteHelper : IPrerequisiteHelper
if (!File.Exists(PortableGitDownloadPath)) if (!File.Exists(PortableGitDownloadPath))
{ {
downloadService.DownloadProgressChanged += OnDownloadProgressChanged; var progress = new Progress<ProgressReport>(progress =>
downloadService.DownloadComplete += OnDownloadComplete; {
OnDownloadProgressChanged(this, progress);
await downloadService.DownloadToFileAsync(portableGitUrl, PortableGitDownloadPath); });
downloadService.DownloadProgressChanged -= OnDownloadProgressChanged; await downloadService.DownloadToFileAsync(portableGitUrl, PortableGitDownloadPath, progress: progress);
downloadService.DownloadComplete -= OnDownloadComplete; OnDownloadComplete(this, new ProgressReport(progress: 1f));
} }
await UnzipGit(); await UnzipGit();

16
StabilityMatrix/Models/Packages/BaseGitPackage.cs

@ -108,19 +108,13 @@ public abstract class BaseGitPackage : BasePackage
Directory.CreateDirectory(DownloadLocation.Replace($"{Name}.zip", "")); Directory.CreateDirectory(DownloadLocation.Replace($"{Name}.zip", ""));
} }
void DownloadProgressHandler(object? _, ProgressReport progress) => var progress = new Progress<ProgressReport>(progress =>
{
DownloadServiceOnDownloadProgressChanged(progress, isUpdate); DownloadServiceOnDownloadProgressChanged(progress, isUpdate);
});
void DownloadFinishedHandler(object? _, ProgressReport downloadLocation) => await DownloadService.DownloadToFileAsync(downloadUrl, DownloadLocation, progress: progress);
DownloadServiceOnDownloadFinished(downloadLocation, isUpdate); DownloadServiceOnDownloadFinished(new ProgressReport(100, "Download Complete"), isUpdate);
DownloadService.DownloadProgressChanged += DownloadProgressHandler;
DownloadService.DownloadComplete += DownloadFinishedHandler;
await DownloadService.DownloadToFileAsync(downloadUrl, DownloadLocation);
DownloadService.DownloadProgressChanged -= DownloadProgressHandler;
DownloadService.DownloadComplete -= DownloadFinishedHandler;
return version; return version;
} }

21
StabilityMatrix/Services/DownloadService.cs

@ -20,10 +20,8 @@ public class DownloadService : IDownloadService
this.httpClientFactory = httpClientFactory; this.httpClientFactory = httpClientFactory;
} }
public event EventHandler<ProgressReport>? DownloadProgressChanged; public async Task DownloadToFileAsync(string downloadUrl, string downloadLocation, int bufferSize = ushort.MaxValue,
public event EventHandler<ProgressReport>? DownloadComplete; IProgress<ProgressReport>? progress = null)
public async Task DownloadToFileAsync(string downloadUrl, string downloadLocation, int bufferSize = ushort.MaxValue)
{ {
using var client = httpClientFactory.CreateClient(); using var client = httpClientFactory.CreateClient();
client.Timeout = TimeSpan.FromMinutes(5); client.Timeout = TimeSpan.FromMinutes(5);
@ -47,7 +45,7 @@ public class DownloadService : IDownloadService
var isIndeterminate = contentLength == 0; var isIndeterminate = contentLength == 0;
await using var stream = await response.Content.ReadAsStreamAsync(); await using var stream = await response.Content.ReadAsStreamAsync();
var totalBytesRead = 0; var totalBytesRead = 0L;
while (true) while (true)
{ {
var buffer = new byte[bufferSize]; var buffer = new byte[bufferSize];
@ -59,22 +57,15 @@ public class DownloadService : IDownloadService
if (isIndeterminate) if (isIndeterminate)
{ {
OnDownloadProgressChanged(-1); progress?.Report(new ProgressReport(-1, isIndeterminate: true));
} }
else else
{ {
var progress = totalBytesRead / (double) contentLength; progress?.Report(new ProgressReport(current: Convert.ToUInt64(totalBytesRead),
OnDownloadProgressChanged(progress); total: Convert.ToUInt64(contentLength)));
} }
} }
await file.FlushAsync(); await file.FlushAsync();
OnDownloadComplete(downloadLocation);
} }
private void OnDownloadProgressChanged(double progress) =>
DownloadProgressChanged?.Invoke(this, new ProgressReport(progress));
private void OnDownloadComplete(string path) =>
DownloadComplete?.Invoke(this, new ProgressReport(progress: 100f, message: path));
} }

5
StabilityMatrix/Services/IDownloadService.cs

@ -6,7 +6,6 @@ namespace StabilityMatrix.Services;
public interface IDownloadService public interface IDownloadService
{ {
event EventHandler<ProgressReport>? DownloadProgressChanged; Task DownloadToFileAsync(string downloadUrl, string downloadLocation, int bufferSize = ushort.MaxValue,
event EventHandler<ProgressReport>? DownloadComplete; IProgress<ProgressReport>? progress = null);
Task DownloadToFileAsync(string downloadUrl, string downloadLocation, int bufferSize = ushort.MaxValue);
} }

45
StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs

@ -1,35 +1,29 @@
using System.Diagnostics; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Net.Mime;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel; using System.Windows;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using StabilityMatrix.Models; using StabilityMatrix.Models;
using StabilityMatrix.Models.Api; using StabilityMatrix.Models.Api;
using StabilityMatrix.Services;
namespace StabilityMatrix.ViewModels; namespace StabilityMatrix.ViewModels;
public partial class CheckpointBrowserCardViewModel : ObservableObject public partial class CheckpointBrowserCardViewModel : ProgressViewModel
{ {
private readonly IDownloadService downloadService;
public CivitModel CivitModel { get; init; } public CivitModel CivitModel { get; init; }
[ObservableProperty] private int importProgress; public override Visibility ProgressVisibility => Value > 0 ? Visibility.Visible : Visibility.Collapsed;
[ObservableProperty] private string importStatus; public override Visibility TextVisibility => Value > 0 ? Visibility.Visible : Visibility.Collapsed;
public CheckpointBrowserCardViewModel(CivitModel civitModel) public CheckpointBrowserCardViewModel(CivitModel civitModel, IDownloadService downloadService)
{ {
this.downloadService = downloadService;
CivitModel = civitModel; CivitModel = civitModel;
} }
private void DownloadServiceOnDownloadComplete(object? sender, ProgressReport e)
{
ImportStatus = "Import complete!";
ImportProgress = 100;
}
private void DownloadServiceOnDownloadProgressChanged(object? sender, ProgressReport e)
{
ImportProgress = (int)e.Percentage;
ImportStatus = $"Importing... {e.Percentage}%";
}
[RelayCommand] [RelayCommand]
private void OpenModel() private void OpenModel()
@ -44,20 +38,21 @@ public partial class CheckpointBrowserCardViewModel : ObservableObject
[RelayCommand] [RelayCommand]
private async Task Import(CivitModel model) private async Task Import(CivitModel model)
{ {
IsIndeterminate = false; Text = "Downloading...";
ImportStatus = "Downloading...";
var latestModelFile = model.ModelVersions[0].Files[0]; var latestModelFile = model.ModelVersions[0].Files[0];
var downloadPath = Path.Combine(SharedFolders.SharedFoldersPath, var downloadPath = Path.Combine(SharedFolders.SharedFoldersPath,
SharedFolders.SharedFolderTypeToName(model.Type.ToSharedFolderType()), latestModelFile.Name); SharedFolders.SharedFolderTypeToName(model.Type.ToSharedFolderType()), latestModelFile.Name);
downloadService.DownloadProgressChanged += DownloadServiceOnDownloadProgressChanged; var progress = new Progress<ProgressReport>(progress =>
downloadService.DownloadComplete += DownloadServiceOnDownloadComplete; {
Value = progress.Percentage;
await downloadService.DownloadToFileAsync(latestModelFile.DownloadUrl, downloadPath); Text = $"Importing... {progress.Percentage}%";
});
await downloadService.DownloadToFileAsync(latestModelFile.DownloadUrl, downloadPath, progress: progress);
downloadService.DownloadProgressChanged -= DownloadServiceOnDownloadProgressChanged; Text = "Import complete!";
downloadService.DownloadComplete -= DownloadServiceOnDownloadComplete; Value = 100;
} }
} }

2
StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs

@ -76,7 +76,7 @@ public partial class CheckpointBrowserViewModel : ObservableObject
CanGoToPreviousPage = CurrentPageNumber > 1; CanGoToPreviousPage = CurrentPageNumber > 1;
CanGoToNextPage = CurrentPageNumber < TotalPages; CanGoToNextPage = CurrentPageNumber < TotalPages;
ModelCards = new ObservableCollection<CheckpointBrowserCardViewModel>(models.Items.Select( ModelCards = new ObservableCollection<CheckpointBrowserCardViewModel>(models.Items.Select(
m => new CheckpointBrowserCardViewModel { CivitModel = m })); m => new CheckpointBrowserCardViewModel(m, downloadService)));
ShowMainLoadingSpinner = false; ShowMainLoadingSpinner = false;
Logger.Debug($"Found {models.Items.Length} models"); Logger.Debug($"Found {models.Items.Length} models");

4
StabilityMatrix/ViewModels/ProgressViewModel.cs

@ -22,7 +22,7 @@ public partial class ProgressViewModel : ObservableObject
[NotifyPropertyChangedFor(nameof(ProgressVisibility))] [NotifyPropertyChangedFor(nameof(ProgressVisibility))]
private bool isProgressVisible; private bool isProgressVisible;
public Visibility ProgressVisibility => IsProgressVisible? Visibility.Visible : Visibility.Collapsed; public virtual Visibility ProgressVisibility => IsProgressVisible ? Visibility.Visible : Visibility.Collapsed;
public Visibility TextVisibility => string.IsNullOrEmpty(Text) ? Visibility.Collapsed : Visibility.Visible; public virtual Visibility TextVisibility => string.IsNullOrEmpty(Text) ? Visibility.Collapsed : Visibility.Visible;
} }

Loading…
Cancel
Save