Browse Source

many change

- Added more metadata to the image dialog info flyout
- Added Restart button to console page
- Model download location selector now searches all subfolders
- Fixed Civitai model browser not showing images when "Show NSFW" is disabled
- Fixed crash when Installed Workflows page is opened with no Workflows folder
- Fixed progress bars not displaying properly during package installs & updates
pull/629/head
JT 8 months ago
parent
commit
04db64fcfb
  1. 13
      CHANGELOG.md
  2. 14
      StabilityMatrix.Avalonia/Assets/sitecustomize.py
  3. 2
      StabilityMatrix.Avalonia/DesignData/DesignData.cs
  4. 21
      StabilityMatrix.Avalonia/Models/PackageSteps/UnpackSiteCustomizeStep.cs
  5. 2
      StabilityMatrix.Avalonia/Services/INavigationService.cs
  6. 2
      StabilityMatrix.Avalonia/Services/NavigationService.cs
  7. 5
      StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs
  8. 19
      StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs
  9. 6
      StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs
  10. 5
      StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs
  11. 3
      StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs
  12. 15
      StabilityMatrix.Avalonia/ViewModels/Progress/PackageInstallProgressItemViewModel.cs
  13. 10
      StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs
  14. 10
      StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml
  15. 23
      StabilityMatrix.Avalonia/Views/Dialogs/ImageViewerDialog.axaml
  16. 11
      StabilityMatrix.Core/Extensions/ProgressExtensions.cs
  17. 14
      StabilityMatrix.Core/Models/Api/CivitImage.cs
  18. 2
      StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs
  19. 9
      StabilityMatrix.Core/Models/PackageModification/UpdatePackageStep.cs
  20. 66
      StabilityMatrix.Core/Models/Progress/ProgressReport.cs

13
CHANGELOG.md

@ -5,7 +5,18 @@ All notable changes to Stability Matrix will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html).
## v2.10.0-preview.1 ## v2.10.0-pre.2
### Added
- Added more metadata to the image dialog info flyout
- Added Restart button to console page
### Changed
- Model download location selector now searches all subfolders
### Fixed
- Fixed Civitai model browser not showing images when "Show NSFW" is disabled
- Fixed crash when Installed Workflows page is opened with no Workflows folder
- Fixed progress bars not displaying properly during package installs & updates
## v2.10.0-pre.1
### Added ### Added
- Added OpenArt.AI workflow browser for ComfyUI workflows - Added OpenArt.AI workflow browser for ComfyUI workflows
- Added Output Sharing toggle in Advanced Options during install flow - Added Output Sharing toggle in Advanced Options during install flow

14
StabilityMatrix.Avalonia/Assets/sitecustomize.py

@ -68,6 +68,20 @@ def _patch_rich_console():
pass pass
except Exception as e: except Exception as e:
print("[sitecustomize error]:", e) print("[sitecustomize error]:", e)
try:
from pip._vendor.rich import console
class _Console(console.Console):
@property
def is_terminal(self) -> bool:
return True
console.Console = _Console
except ImportError:
pass
except Exception as e:
print("[sitecustomize error]:", e)
_patch_rich_console() _patch_rich_console()

2
StabilityMatrix.Avalonia/DesignData/DesignData.cs

@ -360,7 +360,7 @@ public static class DesignData
{ {
new() new()
{ {
Nsfw = "None", NsfwLevel = 1,
Url = Url =
"https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/" "https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/"
+ "78fd2a0a-42b6-42b0-9815-81cb11bb3d05/00009-2423234823.jpeg" + "78fd2a0a-42b6-42b0-9815-81cb11bb3d05/00009-2423234823.jpeg"

21
StabilityMatrix.Avalonia/Models/PackageSteps/UnpackSiteCustomizeStep.cs

@ -0,0 +1,21 @@
using System;
using System.Threading.Tasks;
using StabilityMatrix.Core.Models.FileInterfaces;
using StabilityMatrix.Core.Models.PackageModification;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Python;
namespace StabilityMatrix.Avalonia.Models.PackageSteps;
public class UnpackSiteCustomizeStep(DirectoryPath venvPath) : IPackageStep
{
public async Task ExecuteAsync(IProgress<ProgressReport>? progress = null)
{
var sitePackages = venvPath.JoinDir(PyVenvRunner.RelativeSitePackagesPath);
var file = sitePackages.JoinFile("sitecustomize.py");
file.Directory?.Create();
await Assets.PyScriptSiteCustomize.ExtractTo(file);
}
public string ProgressTitle => "Unpacking prerequisites...";
}

2
StabilityMatrix.Avalonia/Services/INavigationService.cs

@ -37,4 +37,6 @@ public interface INavigationService<[SuppressMessage("ReSharper", "UnusedTypePar
void NavigateTo(ViewModelBase viewModel, NavigationTransitionInfo? transitionInfo = null); void NavigateTo(ViewModelBase viewModel, NavigationTransitionInfo? transitionInfo = null);
bool GoBack(); bool GoBack();
bool CanGoBack { get; }
} }

2
StabilityMatrix.Avalonia/Services/NavigationService.cs

@ -188,4 +188,6 @@ public class NavigationService<T> : INavigationService<T>
_frame.GoBack(); _frame.GoBack();
return true; return true;
} }
public bool CanGoBack => _frame?.CanGoBack ?? false;
} }

5
StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CheckpointBrowserCardViewModel.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.ComponentModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -159,7 +160,7 @@ public partial class CheckpointBrowserCardViewModel : Base.ProgressViewModel
// Try to find a valid image // Try to find a valid image
var image = images var image = images
?.Where(img => LocalModelFile.SupportedImageExtensions.Any(img.Url.Contains)) ?.Where(img => LocalModelFile.SupportedImageExtensions.Any(img.Url.Contains))
.FirstOrDefault(image => nsfwEnabled || image.Nsfw == "None"); .FirstOrDefault(image => nsfwEnabled || image.NsfwLevel <= 1);
if (image != null) if (image != null)
{ {
CardImage = new Uri(image.Url); CardImage = new Uri(image.Url);
@ -256,7 +257,7 @@ public partial class CheckpointBrowserCardViewModel : Base.ProgressViewModel
{ {
var subFolder = var subFolder =
viewModel?.SelectedInstallLocation viewModel?.SelectedInstallLocation
?? Path.Combine("Models", model.Type.ConvertTo<SharedFolderType>().GetStringValue()); ?? Path.Combine(@"Models", model.Type.ConvertTo<SharedFolderType>().GetStringValue());
downloadPath = Path.Combine(settingsManager.LibraryDir, subFolder); downloadPath = Path.Combine(settingsManager.LibraryDir, subFolder);
} }

19
StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs

@ -12,6 +12,7 @@ using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using StabilityMatrix.Avalonia.Extensions; using StabilityMatrix.Avalonia.Extensions;
using StabilityMatrix.Avalonia.Models.PackageSteps;
using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Attributes;
@ -107,18 +108,19 @@ public partial class NewOneClickInstallViewModel : ContentDialogViewModelBase
{ {
Task.Run(async () => Task.Run(async () =>
{ {
var installLocation = Path.Combine(
settingsManager.LibraryDir,
"Packages",
selectedPackage.Name
);
var steps = new List<IPackageStep> var steps = new List<IPackageStep>
{ {
new SetPackageInstallingStep(settingsManager, selectedPackage.Name), new SetPackageInstallingStep(settingsManager, selectedPackage.Name),
new SetupPrerequisitesStep(prerequisiteHelper, pyRunner, selectedPackage) new SetupPrerequisitesStep(prerequisiteHelper, pyRunner, selectedPackage),
}; };
// get latest version & download & install // get latest version & download & install
var installLocation = Path.Combine(
settingsManager.LibraryDir,
"Packages",
selectedPackage.Name
);
if (Directory.Exists(installLocation)) if (Directory.Exists(installLocation))
{ {
var installPath = new DirectoryPath(installLocation); var installPath = new DirectoryPath(installLocation);
@ -148,6 +150,11 @@ public partial class NewOneClickInstallViewModel : ContentDialogViewModelBase
); );
steps.Add(downloadStep); steps.Add(downloadStep);
var unpackSiteCustomizeStep = new UnpackSiteCustomizeStep(
Path.Combine(installLocation, "venv")
);
steps.Add(unpackSiteCustomizeStep);
var installStep = new InstallPackageStep( var installStep = new InstallPackageStep(
selectedPackage, selectedPackage,
torchVersion, torchVersion,

6
StabilityMatrix.Avalonia/ViewModels/Dialogs/SelectModelVersionViewModel.cs

@ -99,7 +99,7 @@ public partial class SelectModelVersionViewModel(
var allImages = value var allImages = value
?.ModelVersion ?.ModelVersion
?.Images ?.Images
?.Where(img => nsfwEnabled || img.Nsfw == "None") ?.Where(img => nsfwEnabled || img.NsfwLevel <= 2)
?.Select(x => new ImageSource(x.Url)) ?.Select(x => new ImageSource(x.Url))
.ToList(); .ToList();
@ -316,7 +316,9 @@ public partial class SelectModelVersionViewModel(
installLocations.Add(downloadDirectory.ToString().Replace(rootModelsDirectory, "Models")); installLocations.Add(downloadDirectory.ToString().Replace(rootModelsDirectory, "Models"));
foreach (var directory in downloadDirectory.EnumerateDirectories()) foreach (
var directory in downloadDirectory.EnumerateDirectories(searchOption: SearchOption.AllDirectories)
)
{ {
installLocations.Add(directory.ToString().Replace(rootModelsDirectory, "Models")); installLocations.Add(directory.ToString().Replace(rootModelsDirectory, "Models"));
} }

5
StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs

@ -59,6 +59,11 @@ public partial class InstalledWorkflowsViewModel(
{ {
workflowsCache.Clear(); workflowsCache.Clear();
if (!Directory.Exists(settingsManager.WorkflowDirectory))
{
Directory.CreateDirectory(settingsManager.WorkflowDirectory);
}
foreach ( foreach (
var workflowPath in Directory.EnumerateFiles( var workflowPath in Directory.EnumerateFiles(
settingsManager.WorkflowDirectory, settingsManager.WorkflowDirectory,

3
StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallDetailViewModel.cs

@ -14,6 +14,7 @@ using Microsoft.Extensions.Logging;
using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Extensions; using StabilityMatrix.Avalonia.Extensions;
using StabilityMatrix.Avalonia.Languages; using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.Models.PackageSteps;
using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Attributes;
@ -188,6 +189,7 @@ public partial class PackageInstallDetailViewModel(
} }
var prereqStep = new SetupPrerequisitesStep(prerequisiteHelper, pyRunner, SelectedPackage); var prereqStep = new SetupPrerequisitesStep(prerequisiteHelper, pyRunner, SelectedPackage);
var unpackSiteCustomizeStep = new UnpackSiteCustomizeStep(Path.Combine(installLocation, "venv"));
var downloadOptions = new DownloadPackageVersionOptions(); var downloadOptions = new DownloadPackageVersionOptions();
var installedVersion = new InstalledPackageVersion(); var installedVersion = new InstalledPackageVersion();
@ -252,6 +254,7 @@ public partial class PackageInstallDetailViewModel(
setPackageInstallingStep, setPackageInstallingStep,
prereqStep, prereqStep,
downloadStep, downloadStep,
unpackSiteCustomizeStep,
installStep, installStep,
setupModelFoldersStep, setupModelFoldersStep,
addInstalledPackageStep addInstalledPackageStep

15
StabilityMatrix.Avalonia/ViewModels/Progress/PackageInstallProgressItemViewModel.cs

@ -49,10 +49,21 @@ public class PackageInstallProgressItemViewModel : ProgressItemViewModelBase
Name = packageModificationRunner.CurrentStep?.ProgressTitle; Name = packageModificationRunner.CurrentStep?.ProgressTitle;
Failed = packageModificationRunner.Failed; Failed = packageModificationRunner.Failed;
if (string.IsNullOrWhiteSpace(e.Message) || e.Message.Contains("Downloading...")) if (e.ProcessOutput == null && string.IsNullOrWhiteSpace(e.Message))
return; return;
Progress.Console.PostLine(e.Message); if (!string.IsNullOrWhiteSpace(e.Message) && e.Message.Contains("Downloading..."))
return;
if (e.ProcessOutput != null)
{
Progress.Console.Post(e.ProcessOutput.Value);
}
else
{
Progress.Console.PostLine(e.Message);
}
EventManager.Instance.OnScrollToBottomRequested(); EventManager.Instance.OnScrollToBottomRequested();
if ( if (

10
StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs

@ -104,6 +104,14 @@ public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, I
} }
} }
[RelayCommand]
private async Task Restart()
{
await Stop();
await Task.Delay(100);
LaunchPackage();
}
[RelayCommand] [RelayCommand]
private void LaunchPackage() private void LaunchPackage()
{ {
@ -113,10 +121,10 @@ public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, I
[RelayCommand] [RelayCommand]
private async Task Stop() private async Task Stop()
{ {
IsRunning = false;
await runningPackageService.StopPackage(RunningPackage.InstalledPackage.Id); await runningPackageService.StopPackage(RunningPackage.InstalledPackage.Id);
Console.PostLine($"{Environment.NewLine}Stopped process at {DateTimeOffset.Now}"); Console.PostLine($"{Environment.NewLine}Stopped process at {DateTimeOffset.Now}");
await Console.StopUpdatesAsync(); await Console.StopUpdatesAsync();
IsRunning = false;
} }
[RelayCommand] [RelayCommand]

10
StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml

@ -34,8 +34,16 @@
Command="{Binding LaunchPackageCommand}" Command="{Binding LaunchPackageCommand}"
VerticalAlignment="Center" VerticalAlignment="Center"
Label="{x:Static lang:Resources.Action_Launch}" /> Label="{x:Static lang:Resources.Action_Launch}" />
<ui:CommandBarButton
IconSource="Refresh"
Margin="4,0,0,0"
Classes="info"
IsVisible="{Binding IsRunning}"
Command="{Binding RestartCommand}"
VerticalAlignment="Center"
Label="{x:Static lang:Resources.Action_Restart}" />
<ui:CommandBarSeparator Margin="6,0,4,0"/> <ui:CommandBarSeparator Margin="16,0,16,0"/>
<ui:CommandBarToggleButton <ui:CommandBarToggleButton
VerticalAlignment="Center" VerticalAlignment="Center"

23
StabilityMatrix.Avalonia/Views/Dialogs/ImageViewerDialog.axaml

@ -128,7 +128,7 @@
PlacementMargin="16,0,16,0" PlacementMargin="16,0,16,0"
TailVisibility="Collapsed" TailVisibility="Collapsed"
Target="{Binding #InfoButton}"> Target="{Binding #InfoButton}">
<StackPanel Spacing="4" Margin="4,0" DataContext="{Binding LocalImageFile.GenerationParameters}"> <StackPanel Spacing="8" Margin="4,0" DataContext="{Binding LocalImageFile.GenerationParameters}">
<Grid RowDefinitions="Auto,*"> <Grid RowDefinitions="Auto,*">
<TextBlock Text="Prompt" Theme="{DynamicResource BodyStrongTextBlockStyle}" /> <TextBlock Text="Prompt" Theme="{DynamicResource BodyStrongTextBlockStyle}" />
<SelectableTextBlock <SelectableTextBlock
@ -150,6 +150,27 @@
Text="{Binding ModelName}" /> Text="{Binding ModelName}" />
</Grid> </Grid>
<Grid RowDefinitions="Auto,*">
<TextBlock Text="Sampler" Theme="{DynamicResource BodyStrongTextBlockStyle}" />
<SelectableTextBlock
Grid.Row="1"
Text="{Binding Sampler}" />
</Grid>
<Grid RowDefinitions="Auto,*">
<TextBlock Text="Steps" Theme="{DynamicResource BodyStrongTextBlockStyle}" />
<SelectableTextBlock
Grid.Row="1"
Text="{Binding Steps}" />
</Grid>
<Grid RowDefinitions="Auto,*">
<TextBlock Text="{x:Static lang:Resources.Label_CFGScale}" Theme="{DynamicResource BodyStrongTextBlockStyle}" />
<SelectableTextBlock
Grid.Row="1"
Text="{Binding CfgScale}" />
</Grid>
<Grid RowDefinitions="Auto,*"> <Grid RowDefinitions="Auto,*">
<TextBlock Text="Seed" Theme="{DynamicResource BodyStrongTextBlockStyle}" /> <TextBlock Text="Seed" Theme="{DynamicResource BodyStrongTextBlockStyle}" />
<SelectableTextBlock <SelectableTextBlock

11
StabilityMatrix.Core/Extensions/ProgressExtensions.cs

@ -7,16 +7,19 @@ namespace StabilityMatrix.Core.Extensions;
public static class ProgressExtensions public static class ProgressExtensions
{ {
[return: NotNullIfNotNull(nameof(progress))] [return: NotNullIfNotNull(nameof(progress))]
public static Action<ProcessOutput>? AsProcessOutputHandler( public static Action<ProcessOutput>? AsProcessOutputHandler(this IProgress<ProgressReport>? progress)
this IProgress<ProgressReport>? progress
)
{ {
return progress == null return progress == null
? null ? null
: output => : output =>
{ {
progress.Report( progress.Report(
new ProgressReport { IsIndeterminate = true, Message = output.Text } new ProgressReport
{
IsIndeterminate = true,
Message = output.Text,
ProcessOutput = output
}
); );
}; };
} }

14
StabilityMatrix.Core/Models/Api/CivitImage.cs

@ -6,18 +6,18 @@ public class CivitImage
{ {
[JsonPropertyName("url")] [JsonPropertyName("url")]
public string Url { get; set; } public string Url { get; set; }
[JsonPropertyName("nsfw")] [JsonPropertyName("nsfwLevel")]
public string Nsfw { get; set; } public int? NsfwLevel { get; set; }
[JsonPropertyName("width")] [JsonPropertyName("width")]
public int Width { get; set; } public int Width { get; set; }
[JsonPropertyName("height")] [JsonPropertyName("height")]
public int Height { get; set; } public int Height { get; set; }
[JsonPropertyName("hash")] [JsonPropertyName("hash")]
public string Hash { get; set; } public string Hash { get; set; }
// TODO: "meta" ( object? ) // TODO: "meta" ( object? )
} }

2
StabilityMatrix.Core/Models/PackageModification/InstallPackageStep.cs

@ -31,7 +31,7 @@ public class InstallPackageStep : IPackageStep
{ {
void OnConsoleOutput(ProcessOutput output) void OnConsoleOutput(ProcessOutput output)
{ {
progress?.Report(new ProgressReport { IsIndeterminate = true, Message = output.Text }); progress?.Report(new ProgressReport { IsIndeterminate = true, ProcessOutput = output });
} }
await package await package

9
StabilityMatrix.Core/Models/PackageModification/UpdatePackageStep.cs

@ -31,7 +31,14 @@ public class UpdatePackageStep : IPackageStep
void OnConsoleOutput(ProcessOutput output) void OnConsoleOutput(ProcessOutput output)
{ {
progress?.Report(new ProgressReport { IsIndeterminate = true, Message = output.Text }); progress?.Report(
new ProgressReport
{
IsIndeterminate = true,
Message = output.Text,
ProcessOutput = output
}
);
} }
var updateResult = await basePackage var updateResult = await basePackage

66
StabilityMatrix.Core/Models/Progress/ProgressReport.cs

@ -1,4 +1,6 @@
namespace StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Processes;
namespace StabilityMatrix.Core.Models.Progress;
public record struct ProgressReport public record struct ProgressReport
{ {
@ -6,21 +8,30 @@ public record struct ProgressReport
/// Progress value as percentage between 0 and 1. /// Progress value as percentage between 0 and 1.
/// </summary> /// </summary>
public double? Progress { get; init; } = 0; public double? Progress { get; init; } = 0;
/// <summary> /// <summary>
/// Current progress count. /// Current progress count.
/// </summary> /// </summary>
public ulong? Current { get; init; } = 0; public ulong? Current { get; init; } = 0;
/// <summary> /// <summary>
/// Total progress count. /// Total progress count.
/// </summary> /// </summary>
public ulong? Total { get; init; } = 0; public ulong? Total { get; init; } = 0;
public string? Title { get; init; } public string? Title { get; init; }
public string? Message { get; init; } public string? Message { get; init; }
public ProcessOutput? ProcessOutput { get; init; }
public bool IsIndeterminate { get; init; } = false; public bool IsIndeterminate { get; init; } = false;
public float Percentage => (float) Math.Ceiling(Math.Clamp(Progress ?? 0, 0, 1) * 100); public float Percentage => (float)Math.Ceiling(Math.Clamp(Progress ?? 0, 0, 1) * 100);
public ProgressType Type { get; init; } = ProgressType.Generic; public ProgressType Type { get; init; } = ProgressType.Generic;
public ProgressReport(double progress, string? title = null, string? message = null, bool isIndeterminate = false, ProgressType type = ProgressType.Generic) public ProgressReport(
double progress,
string? title = null,
string? message = null,
bool isIndeterminate = false,
ProgressType type = ProgressType.Generic
)
{ {
Progress = progress; Progress = progress;
Title = title; Title = title;
@ -28,32 +39,53 @@ public record struct ProgressReport
IsIndeterminate = isIndeterminate; IsIndeterminate = isIndeterminate;
Type = type; Type = type;
} }
public ProgressReport(ulong current, ulong total, string? title = null, string? message = null, bool isIndeterminate = false, ProgressType type = ProgressType.Generic) public ProgressReport(
ulong current,
ulong total,
string? title = null,
string? message = null,
bool isIndeterminate = false,
ProgressType type = ProgressType.Generic
)
{ {
Current = current; Current = current;
Total = total; Total = total;
Progress = (double) current / total; Progress = (double)current / total;
Title = title; Title = title;
Message = message; Message = message;
IsIndeterminate = isIndeterminate; IsIndeterminate = isIndeterminate;
Type = type; Type = type;
} }
public ProgressReport(int current, int total, string? title = null, string? message = null, bool isIndeterminate = false, ProgressType type = ProgressType.Generic) public ProgressReport(
int current,
int total,
string? title = null,
string? message = null,
bool isIndeterminate = false,
ProgressType type = ProgressType.Generic
)
{ {
if (current < 0) throw new ArgumentOutOfRangeException(nameof(current), "Current progress cannot negative."); if (current < 0)
if (total < 0) throw new ArgumentOutOfRangeException(nameof(total), "Total progress cannot be negative."); throw new ArgumentOutOfRangeException(nameof(current), "Current progress cannot negative.");
Current = (ulong) current; if (total < 0)
Total = (ulong) total; throw new ArgumentOutOfRangeException(nameof(total), "Total progress cannot be negative.");
Progress = (double) current / total; Current = (ulong)current;
Total = (ulong)total;
Progress = (double)current / total;
Title = title; Title = title;
Message = message; Message = message;
IsIndeterminate = isIndeterminate; IsIndeterminate = isIndeterminate;
Type = type; Type = type;
} }
public ProgressReport(ulong current, string? title = null, string? message = null, ProgressType type = ProgressType.Generic) public ProgressReport(
ulong current,
string? title = null,
string? message = null,
ProgressType type = ProgressType.Generic
)
{ {
Current = current; Current = current;
Title = title; Title = title;
@ -61,6 +93,6 @@ public record struct ProgressReport
IsIndeterminate = true; IsIndeterminate = true;
Type = type; Type = type;
} }
// Implicit conversion from action // Implicit conversion from action
} }

Loading…
Cancel
Save