Browse Source

Add confirm dialog for model downloads

pull/165/head
Ionite 1 year ago
parent
commit
c3b4f5afad
No known key found for this signature in database
  1. 3
      StabilityMatrix.Avalonia/App.axaml.cs
  2. 8
      StabilityMatrix.Avalonia/DesignData/DesignData.cs
  3. 20
      StabilityMatrix.Avalonia/Services/InferenceClientManager.cs
  4. 78
      StabilityMatrix.Avalonia/ViewModels/Dialogs/DownloadResourceViewModel.cs
  5. 17
      StabilityMatrix.Avalonia/ViewModels/Inference/UpscalerCardViewModel.cs
  6. 50
      StabilityMatrix.Avalonia/Views/Dialogs/DownloadResourceDialog.axaml
  7. 27
      StabilityMatrix.Avalonia/Views/Dialogs/DownloadResourceDialog.axaml.cs
  8. 1
      StabilityMatrix.Core/Models/IContextAction.cs
  9. 17
      StabilityMatrix.Core/Models/ModelPostDownloadContextAction.cs

3
StabilityMatrix.Avalonia/App.axaml.cs

@ -296,6 +296,7 @@ public sealed class App : Application
services.AddTransient<ImageViewerViewModel>();
services.AddTransient<PackageImportViewModel>();
services.AddTransient<InferenceConnectionHelpViewModel>();
services.AddTransient<DownloadResourceViewModel>();
// Dialog view models (singleton)
services.AddSingleton<FirstLaunchSetupViewModel>();
@ -365,6 +366,7 @@ public sealed class App : Application
.Register(provider.GetRequiredService<SelectImageCardViewModel>)
.Register(provider.GetRequiredService<InferenceConnectionHelpViewModel>)
.Register(provider.GetRequiredService<SharpenCardViewModel>)
.Register(provider.GetRequiredService<DownloadResourceViewModel>)
);
}
@ -408,6 +410,7 @@ public sealed class App : Application
services.AddTransient<ImageViewerDialog>();
services.AddTransient<PackageImportDialog>();
services.AddTransient<InferenceConnectionHelpDialog>();
services.AddTransient<DownloadResourceDialog>();
// Controls
services.AddTransient<RefreshBadge>();

8
StabilityMatrix.Avalonia/DesignData/DesignData.cs

@ -614,6 +614,14 @@ The gallery images are often inpainted, but you will get something very similar
vm.ImageSizeText = "1280 x 1792";
});
public static DownloadResourceViewModel DownloadResourceViewModel =>
DialogFactory.Get<DownloadResourceViewModel>(vm =>
{
vm.FileName = ComfyUpscaler.DefaultDownloadableModels[0].Name;
vm.FileSize = Convert.ToInt64(2 * Size.GiB);
vm.Resource = ComfyUpscaler.DefaultDownloadableModels[0].DownloadableResource!.Value;
});
public static SharpenCardViewModel SharpenCardViewModel =>
DialogFactory.Get<SharpenCardViewModel>();

20
StabilityMatrix.Avalonia/Services/InferenceClientManager.cs

@ -1,6 +1,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
@ -98,12 +99,7 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
vaeModelsDefaults.AddOrUpdate(HybridModelFile.Default);
vaeModelsDefaults
.Connect()
.Or(vaeModelsSource.Connect())
.DeferUntilLoaded()
.Bind(VaeModels)
.Subscribe();
vaeModelsDefaults.Connect().Or(vaeModelsSource.Connect()).Bind(VaeModels).Subscribe();
samplersSource.Connect().DeferUntilLoaded().Bind(Samplers).Subscribe();
@ -111,7 +107,11 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
.Connect()
.Or(modelUpscalersSource.Connect())
.Or(downloadableUpscalersSource.Connect())
.DeferUntilLoaded()
.Sort(
SortExpressionComparer<ComfyUpscaler>
.Ascending(f => f.Type)
.ThenByAscending(f => f.Name)
)
.Bind(Upscalers)
.Subscribe();
@ -129,6 +129,8 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
if (!settingsManager.IsLibraryDirSet)
return;
ResetSharedProperties();
if (IsConnected)
{
LoadSharedPropertiesAsync()
@ -136,10 +138,6 @@ public partial class InferenceClientManager : ObservableObject, IInferenceClient
onException: ex => logger.LogError(ex, "Error loading shared properties")
);
}
else
{
ResetSharedProperties();
}
};
}

78
StabilityMatrix.Avalonia/ViewModels/Dialogs/DownloadResourceViewModel.cs

@ -0,0 +1,78 @@
using System.Threading.Tasks;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FluentAvalonia.UI.Controls;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Languages;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Processes;
using StabilityMatrix.Core.Services;
namespace StabilityMatrix.Avalonia.ViewModels.Dialogs;
[View(typeof(DownloadResourceDialog))]
public partial class DownloadResourceViewModel : ContentDialogViewModelBase
{
private readonly IDownloadService downloadService;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FileNameWithHash))]
private string? fileName;
public string FileNameWithHash => $"{FileName} [{Resource.HashSha256.ToLowerInvariant()[..7]}]";
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FileSizeText))]
private long fileSize;
[ObservableProperty]
private RemoteResource resource;
public string? FileSizeText => FileSize == 0 ? null : Size.FormatBase10Bytes(FileSize);
public string ShortHash => Resource.HashSha256.ToLowerInvariant();
public DownloadResourceViewModel(IDownloadService downloadService)
{
this.downloadService = downloadService;
}
/// <inheritdoc />
public override async Task OnLoadedAsync()
{
await base.OnLoadedAsync();
// Get download size
if (!Design.IsDesignMode && Resource.Url is { } url)
{
FileSize = await downloadService.GetFileSizeAsync(url.ToString());
}
}
[RelayCommand]
private void OpenInfoUrl()
{
if (Resource.InfoUrl is { } url)
{
ProcessRunner.OpenUrl(url);
}
}
public BetterContentDialog GetDialog()
{
return new BetterContentDialog
{
MinDialogWidth = 400,
Title = "Download Model",
Content = new DownloadResourceDialog { DataContext = this },
PrimaryButtonText = Resources.Action_Continue,
CloseButtonText = Resources.Action_Cancel,
DefaultButton = ContentDialogButton.Primary
};
}
}

17
StabilityMatrix.Avalonia/ViewModels/Inference/UpscalerCardViewModel.cs

@ -3,10 +3,12 @@ using System.Text.Json.Nodes;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FluentAvalonia.UI.Controls;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Models.Inference;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Extensions;
using StabilityMatrix.Core.Helper;
@ -23,6 +25,7 @@ public partial class UpscalerCardViewModel : LoadableViewModelBase
private readonly INotificationService notificationService;
private readonly ITrackedDownloadService trackedDownloadService;
private readonly ISettingsManager settingsManager;
private readonly ServiceManager<ViewModelBase> vmFactory;
[ObservableProperty]
private double scale = 1;
@ -36,12 +39,14 @@ public partial class UpscalerCardViewModel : LoadableViewModelBase
IInferenceClientManager clientManager,
INotificationService notificationService,
ITrackedDownloadService trackedDownloadService,
ISettingsManager settingsManager
ISettingsManager settingsManager,
ServiceManager<ViewModelBase> vmFactory
)
{
this.notificationService = notificationService;
this.trackedDownloadService = trackedDownloadService;
this.settingsManager = settingsManager;
this.vmFactory = vmFactory;
ClientManager = clientManager;
}
@ -56,6 +61,15 @@ public partial class UpscalerCardViewModel : LoadableViewModelBase
resource.ContextType as SharedFolderType?
?? throw new InvalidOperationException("ContextType is not SharedFolderType");
var confirmDialog = vmFactory.Get<DownloadResourceViewModel>();
confirmDialog.Resource = resource;
confirmDialog.FileName = upscaler.Value.Name;
if (await confirmDialog.GetDialog().ShowAsync() != ContentDialogResult.Primary)
{
return;
}
var modelsDir = new DirectoryPath(settingsManager.ModelsDirectory).JoinDir(
sharedFolderType.GetStringValue()
);
@ -64,6 +78,7 @@ public partial class UpscalerCardViewModel : LoadableViewModelBase
resource.Url,
modelsDir.JoinFile(upscaler.Value.Name)
);
download.ContextAction = new ModelPostDownloadContextAction();
download.Start();
EventManager.Instance.OnToggleProgressFlyout();

50
StabilityMatrix.Avalonia/Views/Dialogs/DownloadResourceDialog.axaml

@ -0,0 +1,50 @@
<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:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels"
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData"
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:vmDialogs="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Dialogs"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
xmlns:processes="clr-namespace:StabilityMatrix.Core.Processes;assembly=StabilityMatrix.Core"
d:DataContext="{x:Static mocks:DesignData.DownloadResourceViewModel}"
x:DataType="vmDialogs:DownloadResourceViewModel"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="StabilityMatrix.Avalonia.Views.Dialogs.DownloadResourceDialog">
<Grid RowDefinitions="*,*" Margin="8,4">
<StackPanel>
<ui:SettingsExpander
Command="{Binding OpenInfoUrlCommand}"
Header="{Binding FileNameWithHash}"
Description="{Binding Resource.ByAuthor}"
Footer="{Binding FileSizeText}">
</ui:SettingsExpander>
<ui:SettingsExpander
Header="{x:Static lang:Resources.Label_License}" >
<ui:SettingsExpander.Footer>
<Button
Tapped="LicenseButton_OnTapped"
Classes="transparent-full"
Foreground="{DynamicResource HyperlinkButtonForeground}">
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon
Symbol="Link"
FontSize="15"
Foreground="{DynamicResource HyperlinkButtonForeground}"
Margin="0,1,4,0"/>
<TextBlock
Foreground="{DynamicResource HyperlinkButtonForeground}"
Text="{Binding Resource.LicenseType}"/>
</StackPanel>
</Button>
</ui:SettingsExpander.Footer>
</ui:SettingsExpander>
</StackPanel>
</Grid>
</controls:UserControlBase>

27
StabilityMatrix.Avalonia/Views/Dialogs/DownloadResourceDialog.axaml.cs

@ -0,0 +1,27 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Core.Processes;
namespace StabilityMatrix.Avalonia.Views.Dialogs;
public partial class DownloadResourceDialog : UserControl
{
public DownloadResourceDialog()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void LicenseButton_OnTapped(object? sender, TappedEventArgs e)
{
var url = ((DownloadResourceViewModel)DataContext!).Resource.LicenseUrl;
ProcessRunner.OpenUrl(url!.ToString());
}
}

1
StabilityMatrix.Core/Models/IContextAction.cs

@ -3,6 +3,7 @@
namespace StabilityMatrix.Core.Models;
[JsonDerivedType(typeof(CivitPostDownloadContextAction), "CivitPostDownload")]
[JsonDerivedType(typeof(ModelPostDownloadContextAction), "ModelPostDownload")]
public interface IContextAction
{
object? Context { get; set; }

17
StabilityMatrix.Core/Models/ModelPostDownloadContextAction.cs

@ -0,0 +1,17 @@
using System.Diagnostics.CodeAnalysis;
using StabilityMatrix.Core.Services;
namespace StabilityMatrix.Core.Models;
public class ModelPostDownloadContextAction : IContextAction
{
/// <inheritdoc />
public object? Context { get; set; }
[SuppressMessage("Performance", "CA1822:Mark members as static")]
public void Invoke(IModelIndexService modelIndexService)
{
// Request reindex
modelIndexService.BackgroundRefreshIndex();
}
}
Loading…
Cancel
Save