Browse Source

updated one-click stuff & confirm exit dialog for multi-package

pull/629/head
JT 9 months ago
parent
commit
8f53c281b3
  1. 36
      StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
  2. 12
      StabilityMatrix.Avalonia/Languages/Resources.resx
  3. 12
      StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs
  4. 16
      StabilityMatrix.Avalonia/ViewModels/Base/InferenceTabViewModelBase.cs
  5. 20
      StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToImageViewModel.cs
  6. 5
      StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs
  7. 15
      StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageUpscaleViewModel.cs
  8. 5
      StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs
  9. 8
      StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs
  10. 12
      StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs
  11. 46
      StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs
  12. 26
      StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
  13. 33
      StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml.cs

36
StabilityMatrix.Avalonia/Languages/Resources.Designer.cs generated

@ -959,6 +959,24 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
/// <summary>
/// Looks up a localized string similar to Confirm Exit.
/// </summary>
public static string Label_ConfirmExit {
get {
return ResourceManager.GetString("Label_ConfirmExit", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Are you sure you want to exit? This will also close any currently running packages..
/// </summary>
public static string Label_ConfirmExitDetail {
get {
return ResourceManager.GetString("Label_ConfirmExitDetail", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Confirm Password.
/// </summary>
@ -1004,6 +1022,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
/// <summary>
/// Looks up a localized string similar to Console.
/// </summary>
public static string Label_Console {
get {
return ResourceManager.GetString("Label_Console", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This will move all generated images from the selected packages to the Consolidated directory of the shared outputs folder. This action cannot be undone..
/// </summary>
@ -2399,6 +2426,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
/// <summary>
/// Looks up a localized string similar to Web UI.
/// </summary>
public static string Label_WebUi {
get {
return ResourceManager.GetString("Label_WebUi", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Width.
/// </summary>

12
StabilityMatrix.Avalonia/Languages/Resources.resx

@ -978,4 +978,16 @@
<data name="Label_ToggleAutoScrolling" xml:space="preserve">
<value>Auto-Scroll to End</value>
</data>
<data name="Label_ConfirmExit" xml:space="preserve">
<value>Confirm Exit</value>
</data>
<data name="Label_ConfirmExitDetail" xml:space="preserve">
<value>Are you sure you want to exit? This will also close any currently running packages.</value>
</data>
<data name="Label_Console" xml:space="preserve">
<value>Console</value>
</data>
<data name="Label_WebUi" xml:space="preserve">
<value>Web UI</value>
</data>
</root>

12
StabilityMatrix.Avalonia/ViewModels/Base/InferenceGenerationViewModelBase.cs

@ -59,6 +59,7 @@ public abstract partial class InferenceGenerationViewModelBase
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly ISettingsManager settingsManager;
private readonly RunningPackageService runningPackageService;
private readonly INotificationService notificationService;
private readonly ServiceManager<ViewModelBase> vmFactory;
@ -79,12 +80,14 @@ public abstract partial class InferenceGenerationViewModelBase
ServiceManager<ViewModelBase> vmFactory,
IInferenceClientManager inferenceClientManager,
INotificationService notificationService,
ISettingsManager settingsManager
ISettingsManager settingsManager,
RunningPackageService runningPackageService
)
: base(notificationService)
{
this.notificationService = notificationService;
this.settingsManager = settingsManager;
this.runningPackageService = runningPackageService;
this.vmFactory = vmFactory;
ClientManager = inferenceClientManager;
@ -722,15 +725,12 @@ public abstract partial class InferenceGenerationViewModelBase
return;
// Restart Package
// TODO: This should be handled by some DI package manager service
var launchPage = App.Services.GetRequiredService<LaunchPageViewModel>();
try
{
await Dispatcher.UIThread.InvokeAsync(async () =>
{
await launchPage.Stop();
await launchPage.LaunchAsync();
await runningPackageService.StopPackage(localPackagePair.InstalledPackage.Id);
await runningPackageService.StartPackage(localPackagePair.InstalledPackage);
});
}
catch (Exception e)

16
StabilityMatrix.Avalonia/ViewModels/Base/InferenceTabViewModelBase.cs

@ -98,11 +98,7 @@ public abstract partial class InferenceTabViewModelBase
protected async Task<ViewState> SaveViewState()
{
var eventArgs = new SaveViewStateEventArgs();
saveViewStateRequestedEventManager?.RaiseEvent(
this,
eventArgs,
nameof(SaveViewStateRequested)
);
saveViewStateRequestedEventManager?.RaiseEvent(this, eventArgs, nameof(SaveViewStateRequested));
if (eventArgs.StateTask is not { } stateTask)
{
@ -128,7 +124,7 @@ public abstract partial class InferenceTabViewModelBase
// TODO: Dock reset not working, using this hack for now to get a new view
var navService = App.Services.GetRequiredService<INavigationService<MainWindowViewModel>>();
navService.NavigateTo<LaunchPageViewModel>(new SuppressNavigationTransitionInfo());
navService.NavigateTo<NewPackageManagerViewModel>(new SuppressNavigationTransitionInfo());
((IPersistentViewProvider)this).AttachedPersistentView = null;
navService.NavigateTo<InferenceViewModel>(new BetterEntranceNavigationTransition());
}
@ -157,9 +153,7 @@ public abstract partial class InferenceTabViewModelBase
if (result == ContentDialogResult.Primary && textFields[0].Text is { } json)
{
LoadViewState(
new LoadViewStateEventArgs { State = new ViewState { DockLayout = json } }
);
LoadViewState(new LoadViewStateEventArgs { State = new ViewState { DockLayout = json } });
}
}
@ -226,9 +220,7 @@ public abstract partial class InferenceTabViewModelBase
if (this is IParametersLoadableState paramsLoadableVm)
{
Dispatcher.UIThread.Invoke(
() => paramsLoadableVm.LoadStateFromParameters(parameters)
);
Dispatcher.UIThread.Invoke(() => paramsLoadableVm.LoadStateFromParameters(parameters));
}
else
{

20
StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToImageViewModel.cs

@ -27,9 +27,17 @@ public class InferenceImageToImageViewModel : InferenceTextToImageViewModel
IInferenceClientManager inferenceClientManager,
INotificationService notificationService,
ISettingsManager settingsManager,
IModelIndexService modelIndexService
IModelIndexService modelIndexService,
RunningPackageService runningPackageService
)
: base(notificationService, inferenceClientManager, settingsManager, vmFactory, modelIndexService)
: base(
notificationService,
inferenceClientManager,
settingsManager,
vmFactory,
modelIndexService,
runningPackageService
)
{
SelectImageCardViewModel = vmFactory.Get<SelectImageCardViewModel>();
@ -77,12 +85,12 @@ public class InferenceImageToImageViewModel : InferenceTextToImageViewModel
var mainImages = SelectImageCardViewModel.GetInputImages();
var samplerImages = SamplerCardViewModel
.ModulesCardViewModel
.Cards
.OfType<IInputImageProvider>()
.ModulesCardViewModel.Cards.OfType<IInputImageProvider>()
.SelectMany(m => m.GetInputImages());
var moduleImages = ModulesCardViewModel.Cards.OfType<IInputImageProvider>().SelectMany(m => m.GetInputImages());
var moduleImages = ModulesCardViewModel
.Cards.OfType<IInputImageProvider>()
.SelectMany(m => m.GetInputImages());
return mainImages.Concat(samplerImages).Concat(moduleImages);
}

5
StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageToVideoViewModel.cs

@ -65,9 +65,10 @@ public partial class InferenceImageToVideoViewModel
IInferenceClientManager inferenceClientManager,
ISettingsManager settingsManager,
ServiceManager<ViewModelBase> vmFactory,
IModelIndexService modelIndexService
IModelIndexService modelIndexService,
RunningPackageService runningPackageService
)
: base(vmFactory, inferenceClientManager, notificationService, settingsManager)
: base(vmFactory, inferenceClientManager, notificationService, settingsManager, runningPackageService)
{
this.notificationService = notificationService;
this.modelIndexService = modelIndexService;

15
StabilityMatrix.Avalonia/ViewModels/Inference/InferenceImageUpscaleViewModel.cs

@ -59,9 +59,10 @@ public class InferenceImageUpscaleViewModel : InferenceGenerationViewModelBase
INotificationService notificationService,
IInferenceClientManager inferenceClientManager,
ISettingsManager settingsManager,
ServiceManager<ViewModelBase> vmFactory
ServiceManager<ViewModelBase> vmFactory,
RunningPackageService runningPackageService
)
: base(vmFactory, inferenceClientManager, notificationService, settingsManager)
: base(vmFactory, inferenceClientManager, notificationService, settingsManager, runningPackageService)
{
this.notificationService = notificationService;
@ -142,7 +143,10 @@ public class InferenceImageUpscaleViewModel : InferenceGenerationViewModelBase
}
/// <inheritdoc />
protected override async Task GenerateImageImpl(GenerateOverrides overrides, CancellationToken cancellationToken)
protected override async Task GenerateImageImpl(
GenerateOverrides overrides,
CancellationToken cancellationToken
)
{
if (!ClientManager.IsConnected)
{
@ -169,7 +173,10 @@ public class InferenceImageUpscaleViewModel : InferenceGenerationViewModelBase
Client = ClientManager.Client,
Nodes = buildPromptArgs.Builder.ToNodeDictionary(),
OutputNodeNames = buildPromptArgs.Builder.Connections.OutputNodeNames.ToArray(),
Parameters = new GenerationParameters { ModelName = UpscalerCardViewModel.SelectedUpscaler?.Name, },
Parameters = new GenerationParameters
{
ModelName = UpscalerCardViewModel.SelectedUpscaler?.Name,
},
Project = InferenceProjectDocument.FromLoadable(this)
};

5
StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs

@ -59,9 +59,10 @@ public class InferenceTextToImageViewModel : InferenceGenerationViewModelBase, I
IInferenceClientManager inferenceClientManager,
ISettingsManager settingsManager,
ServiceManager<ViewModelBase> vmFactory,
IModelIndexService modelIndexService
IModelIndexService modelIndexService,
RunningPackageService runningPackageService
)
: base(vmFactory, inferenceClientManager, notificationService, settingsManager)
: base(vmFactory, inferenceClientManager, notificationService, settingsManager, runningPackageService)
{
this.notificationService = notificationService;
this.modelIndexService = modelIndexService;

8
StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs

@ -139,14 +139,6 @@ public partial class MainWindowViewModel : ViewModelBase
Content = new NewOneClickInstallDialog { DataContext = viewModel },
};
EventManager.Instance.OneClickInstallFinished += (_, skipped) =>
{
if (skipped)
return;
EventManager.Instance.OnTeachingTooltipNeeded();
};
var firstDialogResult = await dialog.ShowAsync(App.TopLevel);
if (firstDialogResult != ContentDialogResult.Primary)

12
StabilityMatrix.Avalonia/ViewModels/PackageManagerViewModel.cs

@ -6,8 +6,6 @@ using System.Linq;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Controls;
using Avalonia.Controls.Notifications;
using Avalonia.Controls.Primitives;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.Input;
using DynamicData;
@ -15,18 +13,14 @@ using DynamicData.Binding;
using FluentAvalonia.UI.Controls;
using Microsoft.Extensions.Logging;
using StabilityMatrix.Avalonia.Animations;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Avalonia.ViewModels.PackageManager;
using StabilityMatrix.Avalonia.Views;
using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.FileInterfaces;
using StabilityMatrix.Core.Models.PackageModification;
using StabilityMatrix.Core.Models.Packages;
using StabilityMatrix.Core.Services;
using Symbol = FluentIcons.Common.Symbol;
@ -84,6 +78,7 @@ public partial class PackageManagerViewModel : PageViewModelBase
this.logger = logger;
EventManager.Instance.InstalledPackagesChanged += OnInstalledPackagesChanged;
EventManager.Instance.OneClickInstallFinished += OnOneClickInstallFinished;
var installed = installedPackages.Connect();
var unknown = unknownInstalledPackages.Connect();
@ -107,6 +102,11 @@ public partial class PackageManagerViewModel : PageViewModelBase
timer.Tick += async (_, _) => await CheckPackagesForUpdates();
}
private void OnOneClickInstallFinished(object? sender, bool e)
{
OnLoadedAsync().SafeFireAndForget();
}
public void SetPackages(IEnumerable<InstalledPackage> packages)
{
installedPackages.Edit(s => s.Load(packages));

46
StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs

@ -6,6 +6,7 @@ using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using AsyncAwaitBestPractices;
using AsyncImageLoader;
using Avalonia;
using Avalonia.Controls;
@ -193,13 +194,52 @@ public partial class MainWindow : AppWindowBase
protected override void OnClosing(WindowClosingEventArgs e)
{
// Show confirmation if package running
var launchPageViewModel = App.Services.GetRequiredService<LaunchPageViewModel>();
launchPageViewModel.OnMainWindowClosing(e);
var runningPackageService = App.Services.GetRequiredService<RunningPackageService>();
if (
runningPackageService.RunningPackages.Count > 0
&& e.CloseReason is WindowCloseReason.WindowClosing
)
{
e.Cancel = true;
var dialog = CreateExitConfirmDialog();
Dispatcher
.UIThread.InvokeAsync(async () =>
{
if (
(TaskDialogStandardResult)await dialog.ShowAsync(true) == TaskDialogStandardResult.Yes
)
{
App.Services.GetRequiredService<MainWindow>().Hide();
App.Shutdown();
}
})
.SafeFireAndForget();
}
base.OnClosing(e);
}
private static TaskDialog CreateExitConfirmDialog()
{
var dialog = DialogHelper.CreateTaskDialog(
Languages.Resources.Label_ConfirmExit,
Languages.Resources.Label_ConfirmExitDetail
);
dialog.ShowProgressBar = false;
dialog.FooterVisibility = TaskDialogFooterVisibility.Never;
dialog.Buttons = new List<TaskDialogButton>
{
new("Exit", TaskDialogStandardResult.Yes),
TaskDialogButton.CancelButton
};
dialog.Buttons[0].IsDefault = true;
return dialog;
}
/// <inheritdoc />
protected override void OnClosed(EventArgs e)
{

26
StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml

@ -26,6 +26,7 @@
<Grid Margin="16" RowDefinitions="Auto,*,Auto">
<ScrollViewer Grid.Row="1">
<ItemsRepeater
x:Name="PackageCardsRepeater"
ItemsSource="{Binding PackageCards}">
<ItemsRepeater.Layout>
<UniformGridLayout MinColumnSpacing="12" MinRowSpacing="12" />
@ -284,6 +285,17 @@
<ui:SymbolIcon Symbol="SettingsFilled"
FontSize="20"/>
</Button>
<Button Classes="transparent-full"
Margin="6,2,0,0"
Padding="4"
ToolTip.Tip="Extensions"
IsVisible="{Binding CanUseExtensions}"
Command="{Binding OpenExtensionsDialogCommand}">
<icons:Icon FontSize="18"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Value="fa-solid fa-puzzle-piece" />
</Button>
</StackPanel>
<UniformGrid Grid.Column="0"
Grid.ColumnSpan="2"
@ -291,6 +303,7 @@
VerticalAlignment="Bottom"
Margin="8,8,8,0">
<Button Classes="accent"
Name="LaunchButton"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
Command="{Binding Launch}">
@ -344,7 +357,7 @@
<icons:Icon Value="fa-solid fa-terminal"
Margin="0,0,8,0"
FontSize="14" />
<TextBlock Text="Console" />
<TextBlock Text="{x:Static lang:Resources.Label_Console}" />
</StackPanel>
</Button>
<Button Classes="accent"
@ -356,7 +369,7 @@
<icons:Icon Value="fa-solid fa-up-right-from-square"
Margin="0,0,8,0"
FontSize="14" />
<TextBlock Text="Web UI" />
<TextBlock Text="{x:Static lang:Resources.Label_WebUi}" />
</StackPanel>
</Button>
<Button Classes="transparent-info"
@ -419,6 +432,15 @@
Title="{x:Static lang:Resources.TeachingTip_AddPackageToGetStarted}"
PreferredPlacement="Top"
IsOpen="{Binding !Packages.Count}" />
<ui:TeachingTip Grid.Row="0"
Name="LaunchTeachingTip"
MinWidth="100"
Title="{x:Static lang:Resources.TeachingTip_ClickLaunchToGetStarted}"
PreferredPlacement="Bottom"
Margin="8,0,0,0"
PlacementMargin="0,0,0,0"
TailVisibility="Auto"/>
<!-- Add Packages Button -->
<Button Grid.Row="2"

33
StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml.cs

@ -1,12 +1,18 @@
using Avalonia.Interactivity;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Threading;
using Avalonia.VisualTree;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Navigation;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.ViewModels;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Models.Packages;
namespace StabilityMatrix.Avalonia.Views;
@ -19,6 +25,31 @@ public partial class PackageManagerPage : UserControlBase
InitializeComponent();
AddHandler(Frame.NavigatedToEvent, OnNavigatedTo, RoutingStrategies.Direct);
EventManager.Instance.OneClickInstallFinished += OnOneClickInstallFinished;
}
private void OnOneClickInstallFinished(object? sender, bool skipped)
{
if (skipped)
return;
Dispatcher.UIThread.Invoke(() =>
{
var target = this.FindDescendantOfType<UniformGrid>()
?.GetVisualChildren()
.OfType<Button>()
.FirstOrDefault(x => x is { Name: "LaunchButton" });
if (target == null)
return;
var teachingTip = this.FindControl<TeachingTip>("LaunchTeachingTip");
if (teachingTip == null)
return;
teachingTip.Target = target;
teachingTip.IsOpen = true;
});
}
private void InitializeComponent()

Loading…
Cancel
Save