diff --git a/StabilityMatrix/CheckpointBrowserPage.xaml b/StabilityMatrix/CheckpointBrowserPage.xaml index 6f2c8da9..19ba9b4a 100644 --- a/StabilityMatrix/CheckpointBrowserPage.xaml +++ b/StabilityMatrix/CheckpointBrowserPage.xaml @@ -8,7 +8,6 @@ ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}" ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}" x:Class="StabilityMatrix.CheckpointBrowserPage" - x:Name="CheckpointBrowserPg" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:api="clr-namespace:StabilityMatrix.Models.Api" xmlns:converters="clr-namespace:StabilityMatrix.Converters" @@ -41,18 +40,18 @@ FontSize="11" Foreground="{DynamicResource TextFillColorTertiaryBrush}" Margin="0,2,0,0" - Text="{Binding ModelVersions[0].Name}" + Text="{Binding CivitModel.ModelVersions[0].Name}" VerticalAlignment="Center" /> @@ -64,21 +63,21 @@ HorizontalAlignment="Stretch" Margin="0,8,0,8" VerticalAlignment="Stretch" - Visibility="{Binding DataContext.ImportCommand.IsRunning, Source={x:Reference CheckpointBrowserPg}, Converter={StaticResource BoolToVisibilityConverter}}" /> + Visibility="{Binding ImportCommand.IsRunning, Converter={StaticResource BoolToVisibilityConverter}}" /> + Visibility="{Binding ImportCommand.IsRunning, Converter={StaticResource BoolToVisibilityConverter}}"> @@ -88,8 +87,8 @@ diff --git a/StabilityMatrix/DesignData/MockCheckpointBrowserViewModel.cs b/StabilityMatrix/DesignData/MockCheckpointBrowserViewModel.cs index 787e78c8..fdaccfed 100644 --- a/StabilityMatrix/DesignData/MockCheckpointBrowserViewModel.cs +++ b/StabilityMatrix/DesignData/MockCheckpointBrowserViewModel.cs @@ -10,22 +10,25 @@ public class MockCheckpointBrowserViewModel : CheckpointBrowserViewModel { public MockCheckpointBrowserViewModel() : base(null!, null!) { - CivitModels = new ObservableCollection + ModelCards = new ObservableCollection { - new() + new (null!, null!) { - Name = "bb95 Furry Mix", - ModelVersions = new[] + CivitModel = new() { - new CivitModelVersion + Name = "bb95 Furry Mix", + ModelVersions = new[] { - Name = "v7.0", - Images = new[] + new CivitModelVersion { - new CivitImage + Name = "v7.0", + Images = new[] { - Url = - "https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/1547f350-461a-4cd0-a753-0544aa81e4fc/width=450/00000-4137473915.jpeg" + new CivitImage + { + Url = + "https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/1547f350-461a-4cd0-a753-0544aa81e4fc/width=450/00000-4137473915.jpeg" + } } } } diff --git a/StabilityMatrix/Helper/PrerequisiteHelper.cs b/StabilityMatrix/Helper/PrerequisiteHelper.cs index b104091c..4f903eb2 100644 --- a/StabilityMatrix/Helper/PrerequisiteHelper.cs +++ b/StabilityMatrix/Helper/PrerequisiteHelper.cs @@ -59,13 +59,13 @@ public class PrerequisiteHelper : IPrerequisiteHelper if (!File.Exists(PortableGitDownloadPath)) { - downloadService.DownloadProgressChanged += OnDownloadProgressChanged; - downloadService.DownloadComplete += OnDownloadComplete; + var progress = new Progress(progress => + { + OnDownloadProgressChanged(this, progress); + }); - await downloadService.DownloadToFileAsync(portableGitUrl, PortableGitDownloadPath); - - downloadService.DownloadProgressChanged -= OnDownloadProgressChanged; - downloadService.DownloadComplete -= OnDownloadComplete; + await downloadService.DownloadToFileAsync(portableGitUrl, PortableGitDownloadPath, progress: progress); + OnDownloadComplete(this, new ProgressReport(progress: 1f)); } await UnzipGit(); diff --git a/StabilityMatrix/Models/Packages/BaseGitPackage.cs b/StabilityMatrix/Models/Packages/BaseGitPackage.cs index 601b7aac..fe3e21b1 100644 --- a/StabilityMatrix/Models/Packages/BaseGitPackage.cs +++ b/StabilityMatrix/Models/Packages/BaseGitPackage.cs @@ -108,19 +108,13 @@ public abstract class BaseGitPackage : BasePackage Directory.CreateDirectory(DownloadLocation.Replace($"{Name}.zip", "")); } - void DownloadProgressHandler(object? _, ProgressReport progress) => + var progress = new Progress(progress => + { DownloadServiceOnDownloadProgressChanged(progress, isUpdate); - - void DownloadFinishedHandler(object? _, ProgressReport downloadLocation) => - DownloadServiceOnDownloadFinished(downloadLocation, isUpdate); - - DownloadService.DownloadProgressChanged += DownloadProgressHandler; - DownloadService.DownloadComplete += DownloadFinishedHandler; - - await DownloadService.DownloadToFileAsync(downloadUrl, DownloadLocation); + }); - DownloadService.DownloadProgressChanged -= DownloadProgressHandler; - DownloadService.DownloadComplete -= DownloadFinishedHandler; + await DownloadService.DownloadToFileAsync(downloadUrl, DownloadLocation, progress: progress); + DownloadServiceOnDownloadFinished(new ProgressReport(100, "Download Complete"), isUpdate); return version; } diff --git a/StabilityMatrix/Services/DownloadService.cs b/StabilityMatrix/Services/DownloadService.cs index 5dd998d3..6669de51 100644 --- a/StabilityMatrix/Services/DownloadService.cs +++ b/StabilityMatrix/Services/DownloadService.cs @@ -19,11 +19,9 @@ public class DownloadService : IDownloadService this.logger = logger; this.httpClientFactory = httpClientFactory; } - - public event EventHandler? DownloadProgressChanged; - public event EventHandler? DownloadComplete; - - public async Task DownloadToFileAsync(string downloadUrl, string downloadLocation, int bufferSize = ushort.MaxValue) + + public async Task DownloadToFileAsync(string downloadUrl, string downloadLocation, int bufferSize = ushort.MaxValue, + IProgress? progress = null) { using var client = httpClientFactory.CreateClient(); client.Timeout = TimeSpan.FromMinutes(5); @@ -47,7 +45,7 @@ public class DownloadService : IDownloadService var isIndeterminate = contentLength == 0; await using var stream = await response.Content.ReadAsStreamAsync(); - var totalBytesRead = 0; + var totalBytesRead = 0L; while (true) { var buffer = new byte[bufferSize]; @@ -59,22 +57,15 @@ public class DownloadService : IDownloadService if (isIndeterminate) { - OnDownloadProgressChanged(-1); + progress?.Report(new ProgressReport(-1, isIndeterminate: true)); } else { - var progress = totalBytesRead / (double) contentLength; - OnDownloadProgressChanged(progress); + progress?.Report(new ProgressReport(current: Convert.ToUInt64(totalBytesRead), + total: Convert.ToUInt64(contentLength))); } } 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)); } diff --git a/StabilityMatrix/Services/IDownloadService.cs b/StabilityMatrix/Services/IDownloadService.cs index 889dc09c..a1e529bf 100644 --- a/StabilityMatrix/Services/IDownloadService.cs +++ b/StabilityMatrix/Services/IDownloadService.cs @@ -6,7 +6,6 @@ namespace StabilityMatrix.Services; public interface IDownloadService { - event EventHandler? DownloadProgressChanged; - event EventHandler? DownloadComplete; - Task DownloadToFileAsync(string downloadUrl, string downloadLocation, int bufferSize = ushort.MaxValue); + Task DownloadToFileAsync(string downloadUrl, string downloadLocation, int bufferSize = ushort.MaxValue, + IProgress? progress = null); } diff --git a/StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs b/StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs index b0134e87..c14cd63e 100644 --- a/StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs +++ b/StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs @@ -1,34 +1,28 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.IO; +using System.Net.Mime; using System.Threading.Tasks; -using CommunityToolkit.Mvvm.ComponentModel; +using System.Windows; using CommunityToolkit.Mvvm.Input; using StabilityMatrix.Models; using StabilityMatrix.Models.Api; +using StabilityMatrix.Services; namespace StabilityMatrix.ViewModels; -public partial class CheckpointBrowserCardViewModel : ObservableObject +public partial class CheckpointBrowserCardViewModel : ProgressViewModel { + private readonly IDownloadService downloadService; public CivitModel CivitModel { get; init; } - - [ObservableProperty] private int importProgress; - [ObservableProperty] private string importStatus; - - public CheckpointBrowserCardViewModel(CivitModel civitModel) - { - CivitModel = civitModel; - } - private void DownloadServiceOnDownloadComplete(object? sender, ProgressReport e) - { - ImportStatus = "Import complete!"; - ImportProgress = 100; - } - private void DownloadServiceOnDownloadProgressChanged(object? sender, ProgressReport e) + public override Visibility ProgressVisibility => Value > 0 ? Visibility.Visible : Visibility.Collapsed; + public override Visibility TextVisibility => Value > 0 ? Visibility.Visible : Visibility.Collapsed; + + public CheckpointBrowserCardViewModel(CivitModel civitModel, IDownloadService downloadService) { - ImportProgress = (int)e.Percentage; - ImportStatus = $"Importing... {e.Percentage}%"; + this.downloadService = downloadService; + CivitModel = civitModel; } [RelayCommand] @@ -44,20 +38,21 @@ public partial class CheckpointBrowserCardViewModel : ObservableObject [RelayCommand] private async Task Import(CivitModel model) { - IsIndeterminate = false; - ImportStatus = "Downloading..."; + Text = "Downloading..."; var latestModelFile = model.ModelVersions[0].Files[0]; var downloadPath = Path.Combine(SharedFolders.SharedFoldersPath, SharedFolders.SharedFolderTypeToName(model.Type.ToSharedFolderType()), latestModelFile.Name); - downloadService.DownloadProgressChanged += DownloadServiceOnDownloadProgressChanged; - downloadService.DownloadComplete += DownloadServiceOnDownloadComplete; - - await downloadService.DownloadToFileAsync(latestModelFile.DownloadUrl, downloadPath); + var progress = new Progress(progress => + { + Value = progress.Percentage; + Text = $"Importing... {progress.Percentage}%"; + }); + await downloadService.DownloadToFileAsync(latestModelFile.DownloadUrl, downloadPath, progress: progress); - downloadService.DownloadProgressChanged -= DownloadServiceOnDownloadProgressChanged; - downloadService.DownloadComplete -= DownloadServiceOnDownloadComplete; + Text = "Import complete!"; + Value = 100; } } diff --git a/StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs b/StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs index c6a9d697..91487f11 100644 --- a/StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs +++ b/StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs @@ -76,7 +76,7 @@ public partial class CheckpointBrowserViewModel : ObservableObject CanGoToPreviousPage = CurrentPageNumber > 1; CanGoToNextPage = CurrentPageNumber < TotalPages; ModelCards = new ObservableCollection(models.Items.Select( - m => new CheckpointBrowserCardViewModel { CivitModel = m })); + m => new CheckpointBrowserCardViewModel(m, downloadService))); ShowMainLoadingSpinner = false; Logger.Debug($"Found {models.Items.Length} models"); diff --git a/StabilityMatrix/ViewModels/ProgressViewModel.cs b/StabilityMatrix/ViewModels/ProgressViewModel.cs index d78c85f8..ee6374ae 100644 --- a/StabilityMatrix/ViewModels/ProgressViewModel.cs +++ b/StabilityMatrix/ViewModels/ProgressViewModel.cs @@ -22,7 +22,7 @@ public partial class ProgressViewModel : ObservableObject [NotifyPropertyChangedFor(nameof(ProgressVisibility))] 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; }