JT
8 months ago
committed by
GitHub
112 changed files with 4688 additions and 1161 deletions
@ -1,7 +1,10 @@ |
|||||||
namespace StabilityMatrix.Avalonia.Models; |
using System.Collections.ObjectModel; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Models; |
||||||
|
|
||||||
public class PackageOutputCategory |
public class PackageOutputCategory |
||||||
{ |
{ |
||||||
|
public ObservableCollection<PackageOutputCategory> SubDirectories { get; set; } = new(); |
||||||
public required string Name { get; set; } |
public required string Name { get; set; } |
||||||
public required string Path { get; set; } |
public required string Path { get; set; } |
||||||
} |
} |
||||||
|
@ -0,0 +1,8 @@ |
|||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Services; |
||||||
|
|
||||||
|
public interface IModelDownloadLinkHandler |
||||||
|
{ |
||||||
|
Task StartListening(); |
||||||
|
} |
@ -0,0 +1,248 @@ |
|||||||
|
using System; |
||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using System.Web; |
||||||
|
using Avalonia.Controls.Notifications; |
||||||
|
using Avalonia.Threading; |
||||||
|
using MessagePipe; |
||||||
|
using Microsoft.Extensions.Logging; |
||||||
|
using StabilityMatrix.Avalonia.Helpers; |
||||||
|
using StabilityMatrix.Core.Api; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
using StabilityMatrix.Core.Extensions; |
||||||
|
using StabilityMatrix.Core.Models; |
||||||
|
using StabilityMatrix.Core.Models.Api; |
||||||
|
using StabilityMatrix.Core.Models.FileInterfaces; |
||||||
|
using StabilityMatrix.Core.Services; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Services; |
||||||
|
|
||||||
|
[Singleton(typeof(IModelDownloadLinkHandler)), Singleton(typeof(IAsyncDisposable))] |
||||||
|
public class ModelDownloadLinkHandler( |
||||||
|
IDistributedSubscriber<string, Uri> uriHandlerSubscriber, |
||||||
|
ILogger<ModelDownloadLinkHandler> logger, |
||||||
|
ICivitApi civitApi, |
||||||
|
INotificationService notificationService, |
||||||
|
ISettingsManager settingsManager, |
||||||
|
IDownloadService downloadService, |
||||||
|
ITrackedDownloadService trackedDownloadService |
||||||
|
) : IAsyncDisposable, IModelDownloadLinkHandler |
||||||
|
{ |
||||||
|
private IAsyncDisposable? uriHandlerSubscription; |
||||||
|
private const string DownloadCivitModel = "downloadCivitModel"; |
||||||
|
|
||||||
|
public async Task StartListening() |
||||||
|
{ |
||||||
|
uriHandlerSubscription = await uriHandlerSubscriber.SubscribeAsync( |
||||||
|
UriHandler.IpcKeySend, |
||||||
|
UriReceivedHandler |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
public async ValueTask DisposeAsync() |
||||||
|
{ |
||||||
|
if (uriHandlerSubscription is not null) |
||||||
|
{ |
||||||
|
await uriHandlerSubscription.DisposeAsync(); |
||||||
|
uriHandlerSubscription = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void UriReceivedHandler(Uri receivedUri) |
||||||
|
{ |
||||||
|
logger.LogDebug("ModelDownloadLinkHandler Received URI: {Uri}", receivedUri.PathAndQuery); |
||||||
|
if (!receivedUri.Host.Equals(DownloadCivitModel, StringComparison.OrdinalIgnoreCase)) |
||||||
|
return; |
||||||
|
|
||||||
|
var queryDict = HttpUtility.ParseQueryString(receivedUri.Query); |
||||||
|
var modelIdStr = queryDict["modelId"]; |
||||||
|
var modelVersionIdStr = queryDict["modelVersionId"]; |
||||||
|
var type = queryDict["type"]; |
||||||
|
var format = queryDict["format"]; |
||||||
|
var size = queryDict["size"]; |
||||||
|
var fp = queryDict["fp"]; |
||||||
|
|
||||||
|
if ( |
||||||
|
string.IsNullOrWhiteSpace(modelIdStr) |
||||||
|
|| string.IsNullOrWhiteSpace(type) |
||||||
|
|| string.IsNullOrWhiteSpace(format) |
||||||
|
|| !int.TryParse(modelIdStr, out var modelId) |
||||||
|
|| !Enum.TryParse<CivitFileType>(type, out var civitFileType) |
||||||
|
|| !Enum.TryParse<CivitModelFormat>(format, out var civitFormat) |
||||||
|
) |
||||||
|
{ |
||||||
|
logger.LogError("ModelDownloadLinkHandler: Invalid query parameters"); |
||||||
|
|
||||||
|
Dispatcher.UIThread.Post( |
||||||
|
() => |
||||||
|
notificationService.Show( |
||||||
|
new Notification( |
||||||
|
"Invalid Download Link", |
||||||
|
"The download link is invalid", |
||||||
|
NotificationType.Error |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
Dispatcher.UIThread.Post( |
||||||
|
() => |
||||||
|
notificationService.Show( |
||||||
|
"Link Received", |
||||||
|
"Successfully received download link", |
||||||
|
NotificationType.Warning |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
var modelTask = civitApi.GetModelById(modelId); |
||||||
|
modelTask.Wait(); |
||||||
|
var model = modelTask.Result; |
||||||
|
|
||||||
|
var useModelVersion = !string.IsNullOrWhiteSpace(modelVersionIdStr); |
||||||
|
var modelVersionId = useModelVersion ? int.Parse(modelVersionIdStr) : 0; |
||||||
|
|
||||||
|
var modelVersion = useModelVersion |
||||||
|
? model.ModelVersions?.FirstOrDefault(x => x.Id == modelVersionId) |
||||||
|
: model.ModelVersions?.FirstOrDefault(); |
||||||
|
|
||||||
|
if (modelVersion is null) |
||||||
|
{ |
||||||
|
logger.LogError("ModelDownloadLinkHandler: Model version not found"); |
||||||
|
Dispatcher.UIThread.Post( |
||||||
|
() => |
||||||
|
notificationService.Show( |
||||||
|
new Notification( |
||||||
|
"Model has no versions available", |
||||||
|
"This model has no versions available for download", |
||||||
|
NotificationType.Error |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var possibleFiles = modelVersion.Files?.Where( |
||||||
|
x => x.Type == civitFileType && x.Metadata.Format == civitFormat |
||||||
|
); |
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(fp) && Enum.TryParse<CivitModelFpType>(fp, out var fpType)) |
||||||
|
{ |
||||||
|
possibleFiles = possibleFiles?.Where(x => x.Metadata.Fp == fpType); |
||||||
|
} |
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(size) && Enum.TryParse<CivitModelSize>(size, out var modelSize)) |
||||||
|
{ |
||||||
|
possibleFiles = possibleFiles?.Where(x => x.Metadata.Size == modelSize); |
||||||
|
} |
||||||
|
|
||||||
|
possibleFiles = possibleFiles?.ToList(); |
||||||
|
|
||||||
|
if (possibleFiles is null) |
||||||
|
{ |
||||||
|
Dispatcher.UIThread.Post( |
||||||
|
() => |
||||||
|
notificationService.Show( |
||||||
|
new Notification( |
||||||
|
"Model has no files available", |
||||||
|
"This model has no files available for download", |
||||||
|
NotificationType.Error |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
logger.LogError("ModelDownloadLinkHandler: Model file not found"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var selectedFile = possibleFiles.FirstOrDefault() ?? modelVersion.Files?.FirstOrDefault(); |
||||||
|
|
||||||
|
var rootModelsDirectory = new DirectoryPath(settingsManager.ModelsDirectory); |
||||||
|
var downloadDirectory = rootModelsDirectory.JoinDir( |
||||||
|
selectedFile.Type == CivitFileType.VAE |
||||||
|
? SharedFolderType.VAE.GetStringValue() |
||||||
|
: model.Type.ConvertTo<SharedFolderType>().GetStringValue() |
||||||
|
); |
||||||
|
|
||||||
|
downloadDirectory.Create(); |
||||||
|
var downloadPath = downloadDirectory.JoinFile(selectedFile.Name); |
||||||
|
|
||||||
|
// Create tracked download |
||||||
|
var download = trackedDownloadService.NewDownload(selectedFile.DownloadUrl, downloadPath); |
||||||
|
|
||||||
|
// Download model info and preview first |
||||||
|
var saveCmInfoTask = SaveCmInfo(model, modelVersion, selectedFile, downloadDirectory); |
||||||
|
var savePreviewImageTask = SavePreviewImage(modelVersion, downloadPath); |
||||||
|
|
||||||
|
Task.WaitAll([saveCmInfoTask, savePreviewImageTask]); |
||||||
|
|
||||||
|
var cmInfoPath = saveCmInfoTask.Result; |
||||||
|
var previewImagePath = savePreviewImageTask.Result; |
||||||
|
|
||||||
|
// Add hash info |
||||||
|
download.ExpectedHashSha256 = selectedFile.Hashes.SHA256; |
||||||
|
|
||||||
|
// Add files to cleanup list |
||||||
|
download.ExtraCleanupFileNames.Add(cmInfoPath); |
||||||
|
if (previewImagePath is not null) |
||||||
|
{ |
||||||
|
download.ExtraCleanupFileNames.Add(previewImagePath); |
||||||
|
} |
||||||
|
|
||||||
|
// Add hash context action |
||||||
|
download.ContextAction = CivitPostDownloadContextAction.FromCivitFile(selectedFile); |
||||||
|
|
||||||
|
download.Start(); |
||||||
|
|
||||||
|
Dispatcher.UIThread.Post( |
||||||
|
() => notificationService.Show("Download Started", $"Downloading {selectedFile.Name}") |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
private static async Task<FilePath> SaveCmInfo( |
||||||
|
CivitModel model, |
||||||
|
CivitModelVersion modelVersion, |
||||||
|
CivitFile modelFile, |
||||||
|
DirectoryPath downloadDirectory |
||||||
|
) |
||||||
|
{ |
||||||
|
var modelFileName = Path.GetFileNameWithoutExtension(modelFile.Name); |
||||||
|
var modelInfo = new ConnectedModelInfo(model, modelVersion, modelFile, DateTime.UtcNow); |
||||||
|
|
||||||
|
await modelInfo.SaveJsonToDirectory(downloadDirectory, modelFileName); |
||||||
|
|
||||||
|
var jsonName = $"{modelFileName}.cm-info.json"; |
||||||
|
return downloadDirectory.JoinFile(jsonName); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Saves the preview image to the same directory as the model file |
||||||
|
/// </summary> |
||||||
|
/// <param name="modelVersion"></param> |
||||||
|
/// <param name="modelFilePath"></param> |
||||||
|
/// <returns>The file path of the saved preview image</returns> |
||||||
|
private async Task<FilePath?> SavePreviewImage(CivitModelVersion modelVersion, FilePath modelFilePath) |
||||||
|
{ |
||||||
|
// Skip if model has no images |
||||||
|
if (modelVersion.Images == null || modelVersion.Images.Count == 0) |
||||||
|
{ |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
var image = modelVersion.Images[0]; |
||||||
|
var imageExtension = Path.GetExtension(image.Url).TrimStart('.'); |
||||||
|
if (imageExtension is "jpg" or "jpeg" or "png") |
||||||
|
{ |
||||||
|
var imageDownloadPath = modelFilePath.Directory!.JoinFile( |
||||||
|
$"{modelFilePath.NameWithoutExtension}.preview.{imageExtension}" |
||||||
|
); |
||||||
|
|
||||||
|
var imageTask = downloadService.DownloadToFileAsync(image.Url, imageDownloadPath); |
||||||
|
await notificationService.TryAsync(imageTask, "Could not download preview image"); |
||||||
|
|
||||||
|
return imageDownloadPath; |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,148 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Immutable; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Avalonia.Controls.Notifications; |
||||||
|
using CommunityToolkit.Mvvm.ComponentModel; |
||||||
|
using Microsoft.Extensions.Logging; |
||||||
|
using StabilityMatrix.Avalonia.Models; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
using StabilityMatrix.Core.Extensions; |
||||||
|
using StabilityMatrix.Core.Helper.Factory; |
||||||
|
using StabilityMatrix.Core.Models; |
||||||
|
using StabilityMatrix.Core.Models.FileInterfaces; |
||||||
|
using StabilityMatrix.Core.Models.Packages; |
||||||
|
using StabilityMatrix.Core.Python; |
||||||
|
using StabilityMatrix.Core.Services; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Services; |
||||||
|
|
||||||
|
[Singleton] |
||||||
|
public partial class RunningPackageService( |
||||||
|
ILogger<RunningPackageService> logger, |
||||||
|
IPackageFactory packageFactory, |
||||||
|
INotificationService notificationService, |
||||||
|
ISettingsManager settingsManager, |
||||||
|
IPyRunner pyRunner |
||||||
|
) : ObservableObject |
||||||
|
{ |
||||||
|
// 🤔 what if we put the ConsoleViewModel inside the BasePackage? 🤔 |
||||||
|
[ObservableProperty] |
||||||
|
private ObservableDictionary<Guid, RunningPackageViewModel> runningPackages = []; |
||||||
|
|
||||||
|
public async Task<PackagePair?> StartPackage(InstalledPackage installedPackage, string? command = null) |
||||||
|
{ |
||||||
|
var activeInstallName = installedPackage.PackageName; |
||||||
|
var basePackage = string.IsNullOrWhiteSpace(activeInstallName) |
||||||
|
? null |
||||||
|
: packageFactory.GetNewBasePackage(installedPackage); |
||||||
|
|
||||||
|
if (basePackage == null) |
||||||
|
{ |
||||||
|
logger.LogWarning( |
||||||
|
"During launch, package name '{PackageName}' did not match a definition", |
||||||
|
activeInstallName |
||||||
|
); |
||||||
|
|
||||||
|
notificationService.Show( |
||||||
|
new Notification( |
||||||
|
"Package name invalid", |
||||||
|
"Install package name did not match a definition. Please reinstall and let us know about this issue.", |
||||||
|
NotificationType.Error |
||||||
|
) |
||||||
|
); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
// If this is the first launch (LaunchArgs is null), |
||||||
|
// load and save a launch options dialog vm |
||||||
|
// so that dynamic initial values are saved. |
||||||
|
if (installedPackage.LaunchArgs == null) |
||||||
|
{ |
||||||
|
var definitions = basePackage.LaunchOptions; |
||||||
|
// Create config cards and save them |
||||||
|
var cards = LaunchOptionCard |
||||||
|
.FromDefinitions(definitions, Array.Empty<LaunchOption>()) |
||||||
|
.ToImmutableArray(); |
||||||
|
|
||||||
|
var args = cards.SelectMany(c => c.Options).ToList(); |
||||||
|
|
||||||
|
logger.LogDebug( |
||||||
|
"Setting initial launch args: {Args}", |
||||||
|
string.Join(", ", args.Select(o => o.ToArgString()?.ToRepr())) |
||||||
|
); |
||||||
|
|
||||||
|
settingsManager.SaveLaunchArgs(installedPackage.Id, args); |
||||||
|
} |
||||||
|
|
||||||
|
if (basePackage is not StableSwarm) |
||||||
|
{ |
||||||
|
await pyRunner.Initialize(); |
||||||
|
} |
||||||
|
|
||||||
|
// Get path from package |
||||||
|
var packagePath = new DirectoryPath(settingsManager.LibraryDir, installedPackage.LibraryPath!); |
||||||
|
|
||||||
|
if (basePackage is not StableSwarm) |
||||||
|
{ |
||||||
|
// Unpack sitecustomize.py to venv |
||||||
|
await UnpackSiteCustomize(packagePath.JoinDir("venv")); |
||||||
|
} |
||||||
|
|
||||||
|
// Clear console and start update processing |
||||||
|
var console = new ConsoleViewModel(); |
||||||
|
console.StartUpdates(); |
||||||
|
|
||||||
|
// Update shared folder links (in case library paths changed) |
||||||
|
await basePackage.UpdateModelFolders( |
||||||
|
packagePath, |
||||||
|
installedPackage.PreferredSharedFolderMethod ?? basePackage.RecommendedSharedFolderMethod |
||||||
|
); |
||||||
|
|
||||||
|
// Load user launch args from settings and convert to string |
||||||
|
var userArgs = installedPackage.LaunchArgs ?? []; |
||||||
|
var userArgsString = string.Join(" ", userArgs.Select(opt => opt.ToArgString())); |
||||||
|
|
||||||
|
// Join with extras, if any |
||||||
|
userArgsString = string.Join(" ", userArgsString, basePackage.ExtraLaunchArguments); |
||||||
|
|
||||||
|
// Use input command if provided, otherwise use package launch command |
||||||
|
command ??= basePackage.LaunchCommand; |
||||||
|
|
||||||
|
await basePackage.RunPackage(packagePath, command, userArgsString, o => console.Post(o)); |
||||||
|
var runningPackage = new PackagePair(installedPackage, basePackage); |
||||||
|
|
||||||
|
var viewModel = new RunningPackageViewModel( |
||||||
|
settingsManager, |
||||||
|
notificationService, |
||||||
|
this, |
||||||
|
runningPackage, |
||||||
|
console |
||||||
|
); |
||||||
|
RunningPackages.Add(runningPackage.InstalledPackage.Id, viewModel); |
||||||
|
|
||||||
|
return runningPackage; |
||||||
|
} |
||||||
|
|
||||||
|
public async Task StopPackage(Guid id) |
||||||
|
{ |
||||||
|
if (RunningPackages.TryGetValue(id, out var vm)) |
||||||
|
{ |
||||||
|
var runningPackage = vm.RunningPackage; |
||||||
|
await runningPackage.BasePackage.WaitForShutdown(); |
||||||
|
RunningPackages.Remove(id); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public RunningPackageViewModel? GetRunningPackageViewModel(Guid id) => |
||||||
|
RunningPackages.TryGetValue(id, out var vm) ? vm : null; |
||||||
|
|
||||||
|
private static async Task UnpackSiteCustomize(DirectoryPath venvPath) |
||||||
|
{ |
||||||
|
var sitePackages = venvPath.JoinDir(PyVenvRunner.RelativeSitePackagesPath); |
||||||
|
var file = sitePackages.JoinFile("sitecustomize.py"); |
||||||
|
file.Directory?.Create(); |
||||||
|
await Assets.PyScriptSiteCustomize.ExtractTo(file, true); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,403 @@ |
|||||||
|
<Styles xmlns="https://github.com/avaloniaui" |
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"> |
||||||
|
<Design.PreviewWith> |
||||||
|
<Border Padding="20"> |
||||||
|
<ui:CommandBar |
||||||
|
Margin="8" |
||||||
|
VerticalAlignment="Center" |
||||||
|
VerticalContentAlignment="Center" |
||||||
|
HorizontalAlignment="Left" |
||||||
|
HorizontalContentAlignment="Left" |
||||||
|
DefaultLabelPosition="Right"> |
||||||
|
<ui:CommandBar.PrimaryCommands> |
||||||
|
<ui:CommandBarButton Classes="success" Label="Success Button" Margin="8" |
||||||
|
HorizontalAlignment="Center" /> |
||||||
|
<ui:CommandBarButton Classes="accent" Label="FA Accent Button" Margin="8" |
||||||
|
HorizontalAlignment="Center" /> |
||||||
|
<ui:CommandBarButton Classes="systemaccent" Label="System Accent Button" Margin="8" |
||||||
|
HorizontalAlignment="Center" /> |
||||||
|
<ui:CommandBarButton Classes="danger" Label="Danger Button" Margin="8" HorizontalAlignment="Center" /> |
||||||
|
<ui:CommandBarButton Classes="info" Label="Info Button" Margin="8" HorizontalAlignment="Center" /> |
||||||
|
<ui:CommandBarButton Classes="transparent-info" Label="Semi-Transparent Info Button" Margin="8" |
||||||
|
HorizontalAlignment="Center" /> |
||||||
|
<ui:CommandBarButton Classes="transparent" Label="Transparent Button" Margin="8" |
||||||
|
HorizontalAlignment="Center" /> |
||||||
|
<ui:CommandBarButton Classes="transparent-full" Label="Transparent Button" Margin="8" |
||||||
|
HorizontalAlignment="Center" /> |
||||||
|
<ui:CommandBarButton Label="Disabled Button" Margin="8" IsEnabled="False" |
||||||
|
HorizontalAlignment="Center" /> |
||||||
|
</ui:CommandBar.PrimaryCommands> |
||||||
|
</ui:CommandBar> |
||||||
|
</Border> |
||||||
|
</Design.PreviewWith> |
||||||
|
|
||||||
|
<!-- Success --> |
||||||
|
<Style Selector="ui|CommandBarButton.success"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeGreenColor}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeGreenColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^ /template/ TextBlock#TextLabel"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" /> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pointerover"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeDarkGreenColor}"/> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeDarkGreenColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="Green" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pressed"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeDarkDarkGreenColor}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeDarkDarkGreenColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:disabled"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<!-- Danger --> |
||||||
|
<Style Selector="ui|CommandBarButton.danger"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeRedColor}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeRedColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" /> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pointerover"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeDarkRedColor}"/> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeDarkRedColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pressed"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeDarkDarkRedColor}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeDarkDarkRedColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:disabled"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<!-- Info --> |
||||||
|
<Style Selector="ui|CommandBarButton.info"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeLightBlueColor}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeLightBlueColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" /> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pointerover"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeBlueColor}"/> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBlueColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pressed"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeDarkBlueColor}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeDarkBlueColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:disabled"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<!--Accent Button--> |
||||||
|
<Style Selector="ui|CommandBarButton.accent"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource AccentButtonBackground}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrush}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForeground}" /> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pointerover"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPointerOver}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPointerOver}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPointerOver}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pressed"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPressed}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPressed}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPressed}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:disabled"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundDisabled}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushDisabled}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<!-- SystemAccent --> |
||||||
|
<Style Selector="ui|CommandBarButton.systemaccent"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemAccentColor}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource SystemAccentColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" /> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pointerover"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemAccentColorDark1}"/> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource SystemAccentColorDark1}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pressed"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemAccentColorDark2}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource SystemAccentColorDark2}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:disabled"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<!-- Transparent --> |
||||||
|
<Style Selector="ui|CommandBarButton.transparent"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlTransparentBrush}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrush}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" /> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pointerover"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}"/> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBackgroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pressed"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPressed}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBackgroundPressed}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:disabled"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<!-- Semi-Transparent Info --> |
||||||
|
<Style Selector="ui|CommandBarButton.transparent-info"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeLightBlueColorTransparent}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeLightBlueColorTransparent}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" /> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pointerover"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeBlueColorTransparent}"/> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBlueColorTransparent}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pressed"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeDarkBlueColorTransparent}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeDarkBlueColorTransparent}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:disabled"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<!-- Transparent red --> |
||||||
|
<Style Selector="ui|CommandBarButton.transparent-red"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlTransparentBrush}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrush}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" /> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pointerover"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeCoralRedColor}"/> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeCoralRedColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pressed"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ThemeDarkCoralRedColor}"/> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ThemeDarkCoralRedColor}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:disabled"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<!-- Full Transparent --> |
||||||
|
<Style Selector="ui|CommandBarButton.transparent-full"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlTransparentBrush}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlTransparentBrush}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" /> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pointerover"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}"/> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBackgroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:pressed"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPressed}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBackgroundPressed}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
|
||||||
|
<Style Selector="^:disabled"> |
||||||
|
<Style Selector="^ /template/ Border#AppBarButtonInnerBorder"> |
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlTransparentBrush}" /> |
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlTransparentBrush}" /> |
||||||
|
</Style> |
||||||
|
<Style Selector="^"> |
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" /> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
</Style> |
||||||
|
</Styles> |
@ -0,0 +1,21 @@ |
|||||||
|
using System; |
||||||
|
using CommunityToolkit.Mvvm.ComponentModel; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels.Base; |
||||||
|
using StabilityMatrix.Avalonia.Views.Dialogs; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; |
||||||
|
|
||||||
|
[View(typeof(ConfirmPackageDeleteDialog))] |
||||||
|
[ManagedService] |
||||||
|
[Transient] |
||||||
|
public partial class ConfirmPackageDeleteDialogViewModel : ContentDialogViewModelBase |
||||||
|
{ |
||||||
|
public required string ExpectedPackageName { get; set; } |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
[NotifyPropertyChangedFor(nameof(IsValid))] |
||||||
|
private string packageName = string.Empty; |
||||||
|
|
||||||
|
public bool IsValid => ExpectedPackageName.Equals(PackageName, StringComparison.Ordinal); |
||||||
|
} |
@ -0,0 +1,161 @@ |
|||||||
|
using System; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using CommunityToolkit.Mvvm.ComponentModel; |
||||||
|
using CommunityToolkit.Mvvm.Input; |
||||||
|
using FluentAvalonia.UI.Controls; |
||||||
|
using StabilityMatrix.Avalonia.Services; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels.Base; |
||||||
|
using StabilityMatrix.Avalonia.Views; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
using StabilityMatrix.Core.Helper; |
||||||
|
using StabilityMatrix.Core.Models; |
||||||
|
using StabilityMatrix.Core.Models.Packages; |
||||||
|
using StabilityMatrix.Core.Processes; |
||||||
|
using StabilityMatrix.Core.Services; |
||||||
|
using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; |
||||||
|
using TeachingTip = StabilityMatrix.Core.Models.Settings.TeachingTip; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.ViewModels; |
||||||
|
|
||||||
|
[View(typeof(ConsoleOutputPage))] |
||||||
|
public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, IAsyncDisposable |
||||||
|
{ |
||||||
|
private readonly ISettingsManager settingsManager; |
||||||
|
private readonly INotificationService notificationService; |
||||||
|
private readonly RunningPackageService runningPackageService; |
||||||
|
|
||||||
|
public PackagePair RunningPackage { get; } |
||||||
|
public ConsoleViewModel Console { get; } |
||||||
|
public override string Title => RunningPackage.InstalledPackage.PackageName ?? "Running Package"; |
||||||
|
public override IconSource IconSource => new SymbolIconSource(); |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private bool autoScrollToEnd; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private bool showWebUiButton; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private string webUiUrl = string.Empty; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private bool isRunning = true; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private string consoleInput = string.Empty; |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private bool showWebUiTeachingTip; |
||||||
|
|
||||||
|
/// <inheritdoc/> |
||||||
|
public RunningPackageViewModel( |
||||||
|
ISettingsManager settingsManager, |
||||||
|
INotificationService notificationService, |
||||||
|
RunningPackageService runningPackageService, |
||||||
|
PackagePair runningPackage, |
||||||
|
ConsoleViewModel console |
||||||
|
) |
||||||
|
{ |
||||||
|
this.settingsManager = settingsManager; |
||||||
|
this.notificationService = notificationService; |
||||||
|
this.runningPackageService = runningPackageService; |
||||||
|
|
||||||
|
RunningPackage = runningPackage; |
||||||
|
Console = console; |
||||||
|
Console.Document.LineCountChanged += DocumentOnLineCountChanged; |
||||||
|
RunningPackage.BasePackage.StartupComplete += BasePackageOnStartupComplete; |
||||||
|
RunningPackage.BasePackage.Exited += BasePackageOnExited; |
||||||
|
|
||||||
|
settingsManager.RelayPropertyFor( |
||||||
|
this, |
||||||
|
vm => vm.AutoScrollToEnd, |
||||||
|
settings => settings.AutoScrollLaunchConsoleToEnd, |
||||||
|
true |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
private void BasePackageOnExited(object? sender, int e) |
||||||
|
{ |
||||||
|
IsRunning = false; |
||||||
|
ShowWebUiButton = false; |
||||||
|
Console.Document.LineCountChanged -= DocumentOnLineCountChanged; |
||||||
|
RunningPackage.BasePackage.StartupComplete -= BasePackageOnStartupComplete; |
||||||
|
RunningPackage.BasePackage.Exited -= BasePackageOnExited; |
||||||
|
runningPackageService.RunningPackages.Remove(RunningPackage.InstalledPackage.Id); |
||||||
|
} |
||||||
|
|
||||||
|
private void BasePackageOnStartupComplete(object? sender, string url) |
||||||
|
{ |
||||||
|
WebUiUrl = url.Replace("0.0.0.0", "127.0.0.1"); |
||||||
|
ShowWebUiButton = !string.IsNullOrWhiteSpace(WebUiUrl); |
||||||
|
|
||||||
|
if (settingsManager.Settings.SeenTeachingTips.Contains(TeachingTip.WebUiButtonMovedTip)) |
||||||
|
return; |
||||||
|
|
||||||
|
ShowWebUiTeachingTip = true; |
||||||
|
settingsManager.Transaction(s => s.SeenTeachingTips.Add(TeachingTip.WebUiButtonMovedTip)); |
||||||
|
} |
||||||
|
|
||||||
|
private void DocumentOnLineCountChanged(object? sender, EventArgs e) |
||||||
|
{ |
||||||
|
if (AutoScrollToEnd) |
||||||
|
{ |
||||||
|
EventManager.Instance.OnScrollToBottomRequested(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[RelayCommand] |
||||||
|
private void LaunchPackage() |
||||||
|
{ |
||||||
|
EventManager.Instance.OnPackageRelaunchRequested(RunningPackage.InstalledPackage); |
||||||
|
} |
||||||
|
|
||||||
|
[RelayCommand] |
||||||
|
private async Task Stop() |
||||||
|
{ |
||||||
|
await runningPackageService.StopPackage(RunningPackage.InstalledPackage.Id); |
||||||
|
Console.PostLine($"{Environment.NewLine}Stopped process at {DateTimeOffset.Now}"); |
||||||
|
await Console.StopUpdatesAsync(); |
||||||
|
IsRunning = false; |
||||||
|
} |
||||||
|
|
||||||
|
[RelayCommand] |
||||||
|
private void LaunchWebUi() |
||||||
|
{ |
||||||
|
if (string.IsNullOrEmpty(WebUiUrl)) |
||||||
|
return; |
||||||
|
|
||||||
|
notificationService.TryAsync( |
||||||
|
Task.Run(() => ProcessRunner.OpenUrl(WebUiUrl)), |
||||||
|
"Failed to open URL", |
||||||
|
$"{WebUiUrl}" |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
[RelayCommand] |
||||||
|
private async Task SendToConsole() |
||||||
|
{ |
||||||
|
Console.PostLine(ConsoleInput); |
||||||
|
if (RunningPackage?.BasePackage is BaseGitPackage gitPackage) |
||||||
|
{ |
||||||
|
var venv = gitPackage.VenvRunner; |
||||||
|
var process = venv?.Process; |
||||||
|
if (process is not null) |
||||||
|
{ |
||||||
|
await process.StandardInput.WriteLineAsync(ConsoleInput); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ConsoleInput = string.Empty; |
||||||
|
} |
||||||
|
|
||||||
|
public void Dispose() |
||||||
|
{ |
||||||
|
Console.Dispose(); |
||||||
|
} |
||||||
|
|
||||||
|
public async ValueTask DisposeAsync() |
||||||
|
{ |
||||||
|
await Console.DisposeAsync(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,93 @@ |
|||||||
|
<controls:UserControlBase xmlns="https://github.com/avaloniaui" |
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||||
|
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" |
||||||
|
xmlns:avaloniaEdit="https://github.com/avaloniaui/avaloniaedit" |
||||||
|
xmlns:viewModels="clr-namespace:StabilityMatrix.Avalonia.ViewModels" |
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" |
||||||
|
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" |
||||||
|
xmlns:avalonia="https://github.com/projektanker/icons.avalonia" |
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||||
|
x:DataType="viewModels:RunningPackageViewModel" |
||||||
|
x:Class="StabilityMatrix.Avalonia.Views.ConsoleOutputPage"> |
||||||
|
<Grid RowDefinitions="Auto, *, Auto"> |
||||||
|
<ui:CommandBar Grid.Row="0" |
||||||
|
Margin="12,0,0,4" |
||||||
|
VerticalAlignment="Center" |
||||||
|
VerticalContentAlignment="Center" |
||||||
|
HorizontalAlignment="Left" |
||||||
|
HorizontalContentAlignment="Left" |
||||||
|
DefaultLabelPosition="Right"> |
||||||
|
<ui:CommandBar.PrimaryCommands> |
||||||
|
<ui:CommandBarButton |
||||||
|
IconSource="Stop" |
||||||
|
IsVisible="{Binding IsRunning}" |
||||||
|
Classes="danger" |
||||||
|
Command="{Binding StopCommand}" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Label="{x:Static lang:Resources.Action_Stop}" /> |
||||||
|
<ui:CommandBarButton |
||||||
|
IconSource="Play" |
||||||
|
IsVisible="{Binding !IsRunning}" |
||||||
|
Classes="success" |
||||||
|
Command="{Binding LaunchPackageCommand}" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Label="{x:Static lang:Resources.Action_Launch}" /> |
||||||
|
|
||||||
|
<ui:CommandBarSeparator Margin="6,0,4,0"/> |
||||||
|
|
||||||
|
<ui:CommandBarToggleButton |
||||||
|
VerticalAlignment="Center" |
||||||
|
IsChecked="{Binding AutoScrollToEnd}" |
||||||
|
Label="{x:Static lang:Resources.Label_ToggleAutoScrolling}" |
||||||
|
ToolTip.Tip="{x:Static lang:Resources.Label_AutoScrollToEnd}"> |
||||||
|
<ui:CommandBarToggleButton.IconSource> |
||||||
|
<controls:FASymbolIconSource Symbol="fa-solid fa-arrow-down-wide-short" /> |
||||||
|
</ui:CommandBarToggleButton.IconSource> |
||||||
|
</ui:CommandBarToggleButton> |
||||||
|
|
||||||
|
<ui:CommandBarButton |
||||||
|
Command="{Binding LaunchWebUiCommand}" |
||||||
|
IsVisible="{Binding ShowWebUiButton}" |
||||||
|
VerticalAlignment="Center" |
||||||
|
x:Name="OpenWebUiButton" |
||||||
|
Label="{x:Static lang:Resources.Action_OpenWebUI}"> |
||||||
|
<ui:CommandBarButton.IconSource> |
||||||
|
<controls:FASymbolIconSource Symbol="fa-solid fa-up-right-from-square"/> |
||||||
|
</ui:CommandBarButton.IconSource> |
||||||
|
</ui:CommandBarButton> |
||||||
|
</ui:CommandBar.PrimaryCommands> |
||||||
|
</ui:CommandBar> |
||||||
|
|
||||||
|
<avaloniaEdit:TextEditor |
||||||
|
Grid.Row="1" |
||||||
|
x:Name="Console" |
||||||
|
Margin="8,8,16,10" |
||||||
|
DataContext="{Binding Console}" |
||||||
|
Document="{Binding Document}" |
||||||
|
FontFamily="Cascadia Code,Consolas,Menlo,Monospace" |
||||||
|
IsReadOnly="True" |
||||||
|
LineNumbersForeground="DarkSlateGray" |
||||||
|
ShowLineNumbers="True" |
||||||
|
VerticalScrollBarVisibility="Auto" |
||||||
|
WordWrap="True" /> |
||||||
|
|
||||||
|
<Grid Grid.Row="2" ColumnDefinitions="*, Auto" |
||||||
|
Margin="16,4,16,16"> |
||||||
|
<TextBox Grid.Column="0" Text="{Binding ConsoleInput, Mode=TwoWay}" |
||||||
|
Margin="0,0,8,0"/> |
||||||
|
<Button Grid.Column="1" |
||||||
|
Classes="accent" |
||||||
|
IsDefault="True" |
||||||
|
Content="{x:Static lang:Resources.Action_Send}" |
||||||
|
Command="{Binding SendToConsoleCommand}"/> |
||||||
|
</Grid> |
||||||
|
|
||||||
|
<ui:TeachingTip Grid.Row="0" Grid.Column="0" Name="TeachingTip1" |
||||||
|
Target="{Binding #OpenWebUiButton}" |
||||||
|
Title="{x:Static lang:Resources.TeachingTip_WebUiButtonMoved}" |
||||||
|
PreferredPlacement="Bottom" |
||||||
|
IsOpen="{Binding ShowWebUiTeachingTip}"/> |
||||||
|
</Grid> |
||||||
|
</controls:UserControlBase> |
@ -0,0 +1,54 @@ |
|||||||
|
using System; |
||||||
|
using Avalonia.Controls; |
||||||
|
using Avalonia.Controls.Primitives; |
||||||
|
using Avalonia.Interactivity; |
||||||
|
using Avalonia.Threading; |
||||||
|
using AvaloniaEdit; |
||||||
|
using StabilityMatrix.Avalonia.Controls; |
||||||
|
using StabilityMatrix.Avalonia.Helpers; |
||||||
|
using StabilityMatrix.Avalonia.Models; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
using StabilityMatrix.Core.Helper; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Views; |
||||||
|
|
||||||
|
[Transient] |
||||||
|
public partial class ConsoleOutputPage : UserControlBase |
||||||
|
{ |
||||||
|
private const int LineOffset = 5; |
||||||
|
|
||||||
|
public ConsoleOutputPage() |
||||||
|
{ |
||||||
|
InitializeComponent(); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) |
||||||
|
{ |
||||||
|
base.OnApplyTemplate(e); |
||||||
|
TextEditorConfigs.Configure(Console, TextEditorPreset.Console); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnUnloaded(RoutedEventArgs e) |
||||||
|
{ |
||||||
|
base.OnUnloaded(e); |
||||||
|
EventManager.Instance.ScrollToBottomRequested -= OnScrollToBottomRequested; |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnLoaded(RoutedEventArgs e) |
||||||
|
{ |
||||||
|
base.OnLoaded(e); |
||||||
|
EventManager.Instance.ScrollToBottomRequested += OnScrollToBottomRequested; |
||||||
|
} |
||||||
|
|
||||||
|
private void OnScrollToBottomRequested(object? sender, EventArgs e) |
||||||
|
{ |
||||||
|
Dispatcher.UIThread.Invoke(() => |
||||||
|
{ |
||||||
|
var editor = this.FindControl<TextEditor>("Console"); |
||||||
|
if (editor?.Document == null) |
||||||
|
return; |
||||||
|
var line = Math.Max(editor.Document.LineCount - LineOffset, 1); |
||||||
|
editor.ScrollToLine(line); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
<controls:UserControlBase xmlns="https://github.com/avaloniaui" |
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||||
|
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" |
||||||
|
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" |
||||||
|
xmlns:dialogs="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Dialogs" |
||||||
|
xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" |
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||||
|
x:DataType="dialogs:ConfirmPackageDeleteDialogViewModel" |
||||||
|
x:Class="StabilityMatrix.Avalonia.Views.Dialogs.ConfirmPackageDeleteDialog"> |
||||||
|
<Grid RowDefinitions="Auto, Auto, Auto, Auto, *" |
||||||
|
Margin="8"> |
||||||
|
<TextBlock Text="{x:Static lang:Resources.Text_PackageUninstall_Details}" |
||||||
|
FontWeight="Bold" |
||||||
|
FontSize="20" |
||||||
|
TextAlignment="Center" |
||||||
|
TextWrapping="Wrap"/> |
||||||
|
<TextBlock Grid.Row="1" |
||||||
|
Margin="0,32,0,8" |
||||||
|
TextAlignment="Center"> |
||||||
|
<Run Text="Please type"/> |
||||||
|
<Run FontWeight="Bold" Text="{Binding ExpectedPackageName}"/> |
||||||
|
<Run Text="to confirm the deletion of the package:"/> |
||||||
|
</TextBlock> |
||||||
|
|
||||||
|
<TextBox Grid.Row="2" |
||||||
|
Text="{Binding PackageName, Mode=TwoWay}" |
||||||
|
Margin="0,16,0,0"/> |
||||||
|
|
||||||
|
<controls1:InfoBar Grid.Row="3" |
||||||
|
Margin="0,16,0,0" |
||||||
|
IsClosable="False" |
||||||
|
IsOpen="True" |
||||||
|
Title="{x:Static lang:Resources.Label_ActionCannotBeUndone}" |
||||||
|
Severity="Warning"/> |
||||||
|
|
||||||
|
<UniformGrid Grid.Row="4" HorizontalAlignment="Stretch" |
||||||
|
VerticalAlignment="Bottom" |
||||||
|
Margin="0,32,0,0"> |
||||||
|
<Button Content="{x:Static lang:Resources.Action_Delete}" |
||||||
|
Classes="danger" |
||||||
|
IsEnabled="{Binding IsValid}" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
Margin="0,0,4,0" |
||||||
|
Command="{Binding OnPrimaryButtonClick}" |
||||||
|
FontSize="16"/> |
||||||
|
<Button Content="{x:Static lang:Resources.Action_Cancel}" |
||||||
|
Command="{Binding OnCloseButtonClick}" |
||||||
|
Margin="4,0,0,0" |
||||||
|
HorizontalAlignment="Stretch" |
||||||
|
FontSize="16"/> |
||||||
|
</UniformGrid> |
||||||
|
</Grid> |
||||||
|
</controls:UserControlBase> |
@ -0,0 +1,13 @@ |
|||||||
|
using StabilityMatrix.Avalonia.Controls; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Views.Dialogs; |
||||||
|
|
||||||
|
[Transient] |
||||||
|
public partial class ConfirmPackageDeleteDialog : UserControlBase |
||||||
|
{ |
||||||
|
public ConfirmPackageDeleteDialog() |
||||||
|
{ |
||||||
|
InitializeComponent(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,124 @@ |
|||||||
|
using System.Diagnostics.CodeAnalysis; |
||||||
|
using JetBrains.Annotations; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Core.Models.Api.Comfy; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Collection of preprocessors included in |
||||||
|
/// </summary> |
||||||
|
/// <param name="Value"></param> |
||||||
|
[PublicAPI] |
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")] |
||||||
|
public record ComfyAuxPreprocessor(string Value) : StringValue(Value) |
||||||
|
{ |
||||||
|
public static ComfyAuxPreprocessor None { get; } = new("none"); |
||||||
|
public static ComfyAuxPreprocessor AnimeFaceSemSegPreprocessor { get; } = |
||||||
|
new("AnimeFace_SemSegPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor BinaryPreprocessor { get; } = new("BinaryPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor CannyEdgePreprocessor { get; } = new("CannyEdgePreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor ColorPreprocessor { get; } = new("ColorPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor DensePosePreprocessor { get; } = new("DensePosePreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor DepthAnythingPreprocessor { get; } = new("DepthAnythingPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor ZoeDepthAnythingPreprocessor { get; } = |
||||||
|
new("Zoe_DepthAnythingPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor DiffusionEdgePreprocessor { get; } = new("DiffusionEdge_Preprocessor"); |
||||||
|
public static ComfyAuxPreprocessor DWPreprocessor { get; } = new("DWPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor AnimalPosePreprocessor { get; } = new("AnimalPosePreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor HEDPreprocessor { get; } = new("HEDPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor FakeScribblePreprocessor { get; } = new("FakeScribblePreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor LeReSDepthMapPreprocessor { get; } = new("LeReS-DepthMapPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor LineArtPreprocessor { get; } = new("LineArtPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor AnimeLineArtPreprocessor { get; } = new("AnimeLineArtPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor LineartStandardPreprocessor { get; } = |
||||||
|
new("LineartStandardPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor Manga2AnimeLineArtPreprocessor { get; } = |
||||||
|
new("Manga2Anime_LineArt_Preprocessor"); |
||||||
|
public static ComfyAuxPreprocessor MediaPipeFaceMeshPreprocessor { get; } = |
||||||
|
new("MediaPipe-FaceMeshPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor MeshGraphormerDepthMapPreprocessor { get; } = |
||||||
|
new("MeshGraphormer-DepthMapPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor MiDaSNormalMapPreprocessor { get; } = |
||||||
|
new("MiDaS-NormalMapPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor MiDaSDepthMapPreprocessor { get; } = new("MiDaS-DepthMapPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor MLSDPreprocessor { get; } = new("M-LSDPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor BAENormalMapPreprocessor { get; } = new("BAE-NormalMapPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor OneFormerCOCOSemSegPreprocessor { get; } = |
||||||
|
new("OneFormer-COCO-SemSegPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor OneFormerADE20KSemSegPreprocessor { get; } = |
||||||
|
new("OneFormer-ADE20K-SemSegPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor OpenposePreprocessor { get; } = new("OpenposePreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor PiDiNetPreprocessor { get; } = new("PiDiNetPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor SavePoseKpsAsJsonFile { get; } = new("SavePoseKpsAsJsonFile"); |
||||||
|
public static ComfyAuxPreprocessor FacialPartColoringFromPoseKps { get; } = |
||||||
|
new("FacialPartColoringFromPoseKps"); |
||||||
|
public static ComfyAuxPreprocessor ImageLuminanceDetector { get; } = new("ImageLuminanceDetector"); |
||||||
|
public static ComfyAuxPreprocessor ImageIntensityDetector { get; } = new("ImageIntensityDetector"); |
||||||
|
public static ComfyAuxPreprocessor ScribblePreprocessor { get; } = new("ScribblePreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor ScribbleXDoGPreprocessor { get; } = new("Scribble_XDoG_Preprocessor"); |
||||||
|
public static ComfyAuxPreprocessor SAMPreprocessor { get; } = new("SAMPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor ShufflePreprocessor { get; } = new("ShufflePreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor TEEDPreprocessor { get; } = new("TEEDPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor TilePreprocessor { get; } = new("TilePreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor UniFormerSemSegPreprocessor { get; } = |
||||||
|
new("UniFormer-SemSegPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor SemSegPreprocessor { get; } = new("SemSegPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor UnimatchOptFlowPreprocessor { get; } = |
||||||
|
new("Unimatch_OptFlowPreprocessor"); |
||||||
|
public static ComfyAuxPreprocessor MaskOptFlow { get; } = new("MaskOptFlow"); |
||||||
|
public static ComfyAuxPreprocessor ZoeDepthMapPreprocessor { get; } = new("Zoe-DepthMapPreprocessor"); |
||||||
|
|
||||||
|
private static Dictionary<ComfyAuxPreprocessor, string> DisplayNamesMapping { get; } = |
||||||
|
new() |
||||||
|
{ |
||||||
|
[None] = "None", |
||||||
|
[AnimeFaceSemSegPreprocessor] = "Anime Face SemSeg Preprocessor", |
||||||
|
[BinaryPreprocessor] = "Binary Preprocessor", |
||||||
|
[CannyEdgePreprocessor] = "Canny Edge Preprocessor", |
||||||
|
[ColorPreprocessor] = "Color Preprocessor", |
||||||
|
[DensePosePreprocessor] = "DensePose Preprocessor", |
||||||
|
[DepthAnythingPreprocessor] = "Depth Anything Preprocessor", |
||||||
|
[ZoeDepthAnythingPreprocessor] = "Zoe Depth Anything Preprocessor", |
||||||
|
[DiffusionEdgePreprocessor] = "Diffusion Edge Preprocessor", |
||||||
|
[DWPreprocessor] = "DW Preprocessor", |
||||||
|
[AnimalPosePreprocessor] = "Animal Pose Preprocessor", |
||||||
|
[HEDPreprocessor] = "HED Preprocessor", |
||||||
|
[FakeScribblePreprocessor] = "Fake Scribble Preprocessor", |
||||||
|
[LeReSDepthMapPreprocessor] = "LeReS-DepthMap Preprocessor", |
||||||
|
[LineArtPreprocessor] = "LineArt Preprocessor", |
||||||
|
[AnimeLineArtPreprocessor] = "Anime LineArt Preprocessor", |
||||||
|
[LineartStandardPreprocessor] = "Lineart Standard Preprocessor", |
||||||
|
[Manga2AnimeLineArtPreprocessor] = "Manga2Anime LineArt Preprocessor", |
||||||
|
[MediaPipeFaceMeshPreprocessor] = "MediaPipe FaceMesh Preprocessor", |
||||||
|
[MeshGraphormerDepthMapPreprocessor] = "MeshGraphormer DepthMap Preprocessor", |
||||||
|
[MiDaSNormalMapPreprocessor] = "MiDaS NormalMap Preprocessor", |
||||||
|
[MiDaSDepthMapPreprocessor] = "MiDaS DepthMap Preprocessor", |
||||||
|
[MLSDPreprocessor] = "M-LSD Preprocessor", |
||||||
|
[BAENormalMapPreprocessor] = "BAE NormalMap Preprocessor", |
||||||
|
[OneFormerCOCOSemSegPreprocessor] = "OneFormer COCO SemSeg Preprocessor", |
||||||
|
[OneFormerADE20KSemSegPreprocessor] = "OneFormer ADE20K SemSeg Preprocessor", |
||||||
|
[OpenposePreprocessor] = "Openpose Preprocessor", |
||||||
|
[PiDiNetPreprocessor] = "PiDiNet Preprocessor", |
||||||
|
[SavePoseKpsAsJsonFile] = "Save Pose Kps As Json File", |
||||||
|
[FacialPartColoringFromPoseKps] = "Facial Part Coloring From Pose Kps", |
||||||
|
[ImageLuminanceDetector] = "Image Luminance Detector", |
||||||
|
[ImageIntensityDetector] = "Image Intensity Detector", |
||||||
|
[ScribblePreprocessor] = "Scribble Preprocessor", |
||||||
|
[ScribbleXDoGPreprocessor] = "Scribble XDoG Preprocessor", |
||||||
|
[SAMPreprocessor] = "SAM Preprocessor", |
||||||
|
[ShufflePreprocessor] = "Shuffle Preprocessor", |
||||||
|
[TEEDPreprocessor] = "TEED Preprocessor", |
||||||
|
[TilePreprocessor] = "Tile Preprocessor", |
||||||
|
[UniFormerSemSegPreprocessor] = "UniFormer SemSeg Preprocessor", |
||||||
|
[SemSegPreprocessor] = "SemSeg Preprocessor", |
||||||
|
[UnimatchOptFlowPreprocessor] = "Unimatch OptFlow Preprocessor", |
||||||
|
[MaskOptFlow] = "Mask OptFlow", |
||||||
|
[ZoeDepthMapPreprocessor] = "Zoe DepthMap Preprocessor" |
||||||
|
}; |
||||||
|
|
||||||
|
public static IEnumerable<ComfyAuxPreprocessor> Defaults => DisplayNamesMapping.Keys; |
||||||
|
|
||||||
|
public string DisplayName => DisplayNamesMapping.GetValueOrDefault(this, Value); |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
public override string ToString() => Value; |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Core.Models.Inference; |
||||||
|
|
||||||
|
public class ModuleApplyStepTemporaryArgs |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Temporary Primary apply step, used by ControlNet ReferenceOnly which changes the latent. |
||||||
|
/// </summary> |
||||||
|
public PrimaryNodeConnection? Primary { get; set; } |
||||||
|
|
||||||
|
public VAENodeConnection? PrimaryVAE { get; set; } |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Used by Reference-Only ControlNet to indicate that <see cref="Primary"/> has been batched. |
||||||
|
/// </summary> |
||||||
|
public bool IsPrimaryTempBatched { get; set; } |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// When <see cref="IsPrimaryTempBatched"/> is true, this is the index of the temp batch to pick after sampling. |
||||||
|
/// </summary> |
||||||
|
public int PrimaryTempBatchPickIndex { get; set; } |
||||||
|
|
||||||
|
public Dictionary<string, ModelConnections> Models { get; set; } = |
||||||
|
new() { ["Base"] = new ModelConnections("Base"), ["Refiner"] = new ModelConnections("Refiner") }; |
||||||
|
|
||||||
|
public ModelConnections Base => Models["Base"]; |
||||||
|
public ModelConnections Refiner => Models["Refiner"]; |
||||||
|
|
||||||
|
public ConditioningConnections GetRefinerOrBaseConditioning() |
||||||
|
{ |
||||||
|
return Refiner.Conditioning |
||||||
|
?? Base.Conditioning |
||||||
|
?? throw new NullReferenceException("No Refiner or Base Conditioning"); |
||||||
|
} |
||||||
|
|
||||||
|
public ModelNodeConnection GetRefinerOrBaseModel() |
||||||
|
{ |
||||||
|
return Refiner.Model ?? Base.Model ?? throw new NullReferenceException("No Refiner or Base Model"); |
||||||
|
} |
||||||
|
|
||||||
|
public VAENodeConnection GetDefaultVAE() |
||||||
|
{ |
||||||
|
return PrimaryVAE ?? Refiner.VAE ?? Base.VAE ?? throw new NullReferenceException("No VAE"); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
using StabilityMatrix.Core.Models.Api.Comfy.Nodes; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Core.Models; |
||||||
|
|
||||||
|
public class InferenceQueueCustomPromptEventArgs : EventArgs |
||||||
|
{ |
||||||
|
public ComfyNodeBuilder Builder { get; } = new(); |
||||||
|
|
||||||
|
public NodeDictionary Nodes => Builder.Nodes; |
||||||
|
|
||||||
|
public long? SeedOverride { get; init; } |
||||||
|
|
||||||
|
public List<(string SourcePath, string DestinationRelativePath)> FilesToTransfer { get; init; } = []; |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue