Browse Source

Add SelectImageCard state loading, improve card visuals

pull/324/head
Ionite 12 months ago
parent
commit
6d2a17a408
No known key found for this signature in database
  1. 187
      StabilityMatrix.Avalonia/Controls/ControlNetCard.axaml
  2. 65
      StabilityMatrix.Avalonia/Controls/SelectImageCard.axaml
  3. 2
      StabilityMatrix.Avalonia/Controls/StackCard.axaml
  4. 8
      StabilityMatrix.Avalonia/Controls/StackCard.axaml.cs
  5. 8
      StabilityMatrix.Avalonia/Controls/StackEditableCard.axaml
  6. 7
      StabilityMatrix.Avalonia/Controls/StackExpander.axaml
  7. 27
      StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
  8. 9
      StabilityMatrix.Avalonia/Languages/Resources.resx
  9. 20
      StabilityMatrix.Avalonia/Models/ImageSource.cs
  10. 3
      StabilityMatrix.Avalonia/Styles/ListBoxStyles.axaml
  11. 34
      StabilityMatrix.Avalonia/ViewModels/Inference/SelectImageCardViewModel.cs

187
StabilityMatrix.Avalonia/Controls/ControlNetCard.axaml

@ -2,91 +2,89 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:StabilityMatrix.Avalonia.Controls"
xmlns:extensions="clr-namespace:StabilityMatrix.Avalonia.Controls.Extensions"
xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia"
xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData"
xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core"
xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:vmInference="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference"
xmlns:input="clr-namespace:FluentAvalonia.UI.Input;assembly=FluentAvalonia"
xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia"
x:DataType="vmInference:ControlNetCardViewModel">
<Design.PreviewWith>
<StackPanel Width="350" Height="400">
<StackPanel Width="400" Height="500">
<controls:ControlNetCard DataContext="{x:Static mocks:DesignData.ControlNetCardViewModel}" />
</StackPanel>
</Design.PreviewWith>
<Styles.Resources>
<ToolTip x:Key="WipFeatureToolTip">
<StackPanel>
<TextBlock Text="{x:Static lang:Resources.Label_WipFeature}" Theme="{DynamicResource BodyStrongTextBlockStyle}" />
<TextBlock Foreground="{DynamicResource TextFillColorTertiaryBrush}" Text="{x:Static lang:Resources.Label_WipFeatureDescription}" />
</StackPanel>
</ToolTip>
</Styles.Resources>
<Style Selector="controls|ControlNetCard">
<!-- Set Defaults -->
<Setter Property="Template">
<ControlTemplate>
<controls:Card Padding="12">
<sg:SpacedGrid
ColumnDefinitions="0.8*,*"
ColumnSpacing="8"
RowDefinitions="Auto,Auto,Auto,Auto,5,Auto"
RowSpacing="6">
<StackPanel Spacing="6">
<sg:SpacedGrid
ColumnDefinitions="0.34*,0.65*"
ColumnSpacing="8"
RowDefinitions="Auto,Auto,Auto"
RowSpacing="4">
<!-- Image Select -->
<controls:SelectImageCard
Grid.RowSpan="4"
Padding="6"
DataContext="{Binding SelectImageCardViewModel}"
FontSize="13" />
<!-- Image Select -->
<controls:SelectImageCard
Grid.RowSpan="2"
Padding="6"
VerticalAlignment="Stretch"
DataContext="{Binding SelectImageCardViewModel}"
FontSize="13" />
<!-- TODO: Preprocessor Model -->
<TextBlock
Grid.Row="0"
Grid.Column="1"
MinWidth="60"
Foreground="{StaticResource ThemeGreyColor}"
VerticalAlignment="Bottom"
Text="{x:Static lang:Resources.Label_Preprocessor}"
TextAlignment="Left" />
<ui:FAComboBox
Grid.Row="1"
Grid.Column="1"
IsEnabled="False"
Margin="0,0,0,4"
HorizontalAlignment="Stretch"
Theme="{StaticResource FAComboBoxHybridModelTheme}" />
<!-- TODO: Preprocessor Model -->
<ui:FAComboBox
Grid.Row="0"
Grid.Column="1"
Margin="0,0,0,4"
HorizontalAlignment="Stretch"
extensions:ShowDisabledTooltipExtension.ShowOnDisabled="True"
Header="{x:Static lang:Resources.Label_Preprocessor}"
IsEnabled="False"
Theme="{StaticResource FAComboBoxHybridModelTheme}"
ToolTip.ShowDelay="1200"
ToolTip.Tip="{StaticResource WipFeatureToolTip}" />
<!-- ControlNet Model -->
<TextBlock
Grid.Row="2"
Grid.Column="1"
MinWidth="60"
VerticalAlignment="Bottom"
Text="{x:Static lang:Resources.Label_Model}"
TextAlignment="Left" />
<ui:FAComboBox
x:Name="PART_ModelComboBox"
Grid.Row="3"
Grid.Column="1"
HorizontalAlignment="Stretch"
ItemsSource="{Binding ClientManager.ControlNetModels}"
SelectedItem="{Binding SelectedModel}"
ItemContainerTheme="{StaticResource FAComboBoxItemHybridModelTheme}">
<ui:FAComboBox.Resources>
<input:StandardUICommand
x:Key="RemoteDownloadCommand"
Command="{Binding RemoteDownloadCommand}"/>
<!-- ControlNet Model -->
<ui:FAComboBox
x:Name="PART_ModelComboBox"
Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Stretch"
Header="{x:Static lang:Resources.Label_Model}"
ItemContainerTheme="{StaticResource FAComboBoxItemHybridModelTheme}"
ItemsSource="{Binding ClientManager.ControlNetModels}"
SelectedItem="{Binding SelectedModel}">
<ui:FAComboBox.Resources>
<input:StandardUICommand x:Key="RemoteDownloadCommand" Command="{Binding RemoteDownloadCommand}" />
</ui:FAComboBox.Resources>
<ui:FAComboBox.DataTemplates>
<controls:HybridModelTemplateSelector>
<DataTemplate DataType="models:HybridModelFile" x:Key="{x:Static models:HybridModelType.Downloadable}">
<DataTemplate x:Key="{x:Static models:HybridModelType.Downloadable}" DataType="models:HybridModelFile">
<Grid ColumnDefinitions="*,Auto">
<TextBlock
Text="{Binding ShortDisplayName}"
Foreground="{DynamicResource ThemeGreyColor}"/>
<Button
Grid.Column="1"
Classes="transparent-full"
<TextBlock Foreground="{DynamicResource ThemeGreyColor}" Text="{Binding ShortDisplayName}" />
<Button
Grid.Column="1"
Margin="8,0,0,0"
Padding="0">
Padding="0"
Classes="transparent-full">
<fluentIcons:SymbolIcon
VerticalAlignment="Center"
FontSize="18"
@ -96,117 +94,88 @@
</Button>
</Grid>
</DataTemplate>
<DataTemplate DataType="models:HybridModelFile" x:Key="{x:Static models:HybridModelType.None}">
<TextBlock Text="{Binding ShortDisplayName}"/>
<DataTemplate x:Key="{x:Static models:HybridModelType.None}" DataType="models:HybridModelFile">
<TextBlock Text="{Binding ShortDisplayName}" />
</DataTemplate>
</controls:HybridModelTemplateSelector>
</ui:FAComboBox.DataTemplates>
</ui:FAComboBox>
</ui:FAComboBox>
</sg:SpacedGrid>
<sg:SpacedGrid
RowDefinitions="Auto,Auto,Auto,Auto"
ColumnDefinitions="*,Auto,Auto"
Grid.Row="5"
Grid.Column="0"
Grid.ColumnSpan="2">
RowDefinitions="Auto,Auto,Auto,Auto"
RowSpacing="0">
<!-- Strength -->
<TextBlock
Text="{x:Static lang:Resources.Label_ControlWeight}"
<TextBlock
VerticalAlignment="Center"
Text="{x:Static lang:Resources.Label_ControlWeight}"
TextAlignment="Left" />
<ui:NumberBox
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
HorizontalAlignment="Stretch"
SpinButtonPlacementMode="Inline"
Maximum="10"
Minimum="0"
SmallChange="0.01"
SimpleNumberFormat="F2"
SmallChange="0.01"
SpinButtonPlacementMode="Inline"
Value="{Binding Strength}" />
<Slider
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="0,-8,0,0"
IsSnapToTickEnabled="True"
Maximum="1"
Minimum="0"
TickFrequency="0.01"
IsSnapToTickEnabled="True"
SmallChange="0.01"
TickFrequency="0.01"
Value="{Binding Strength}" />
<!-- Start end percent -->
<TextBlock
<TextBlock
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Static lang:Resources.Label_ControlSteps}"
Text="{x:Static lang:Resources.Label_ControlSteps}"
TextAlignment="Left" />
<ui:NumberBox
Grid.Row="2"
Grid.Column="1"
HorizontalAlignment="Stretch"
SimpleNumberFormat="P0"
Maximum="10"
Minimum="0"
SimpleNumberFormat="P0"
SmallChange="0.01"
Value="{Binding StartPercent}" />
<ui:NumberBox
Grid.Row="2"
Grid.Column="2"
HorizontalAlignment="Stretch"
SimpleNumberFormat="P0"
Maximum="10"
Minimum="0"
SimpleNumberFormat="P0"
SmallChange="0.01"
Value="{Binding EndPercent}" />
<!--<sg:SpacedGrid Grid.Row="2"
Grid.Column="1"
HorizontalAlignment="Right"
ColumnDefinitions="*,*">
<ui:NumberBox
HorizontalAlignment="Stretch"
Maximum="10"
Minimum="0"
SmallChange="0.01"
Value="{Binding StartPercent}" />
<ui:NumberBox
Grid.Column="1"
HorizontalAlignment="Stretch"
Maximum="10"
Minimum="0"
SmallChange="0.01"
Value="{Binding EndPercent}" />
</sg:SpacedGrid>-->
<ui:RangeSlider
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="0,4,0,0"
ShowValueToolTip="False"
Maximum="1"
Minimum="0"
RangeEnd="{Binding EndPercent}"
RangeStart="{Binding StartPercent}"
ShowValueToolTip="False"
StepFrequency="0.01"
ToolTipStringFormat="P" />
</sg:SpacedGrid>
<StackPanel
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="2">
</StackPanel>
</sg:SpacedGrid>
</StackPanel>
</controls:Card>
</ControlTemplate>
</Setter>

65
StabilityMatrix.Avalonia/Controls/SelectImageCard.axaml

@ -3,11 +3,11 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:StabilityMatrix.Avalonia.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
xmlns:mocks="using:StabilityMatrix.Avalonia.DesignData"
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:vmInference="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference"
xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
x:DataType="vmInference:SelectImageCardViewModel">
<Design.PreviewWith>
@ -31,8 +31,7 @@
Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalAlignment}"
IsCardVisualsEnabled="True">
VerticalContentAlignment="{TemplateBinding VerticalAlignment}">
<!-- Background frame -->
<ExperimentalAcrylicBorder
@ -47,16 +46,52 @@
CornerRadius="4"
CurrentImage="{Binding CurrentBitmap, Mode=OneWayToSource}"
IsVisible="{Binding !IsSelectionAvailable}"
Source="{Binding ImageSource}" />
RenderOptions.BitmapInterpolationMode="HighQuality"
Source="{Binding ImageSource}"
Stretch="UniformToFill"
StretchDirection="Both" />
<!-- Missing image -->
<Border
BorderThickness="3"
BorderBrush="{StaticResource ThemeCoralRedColor}"
BoxShadow="inset 1.2 0 20 1.8 #66000000"
CornerRadius="4"
IsVisible="{Binding IsImageFileNotFound}">
<Grid
HorizontalAlignment="Center"
VerticalAlignment="Center"
RowDefinitions="Auto,Auto,Auto">
<fluentIcons:SymbolIcon
FontSize="28"
IsFilled="True"
Symbol="DocumentQuestionMark" />
<TextBlock
Grid.Row="1"
FontSize="{TemplateBinding FontSize}"
Text="{x:Static lang:Resources.Label_MissingImageFile}"
TextAlignment="Center"
TextWrapping="WrapWithOverflow" />
<SelectableTextBlock
Grid.Row="2"
FontSize="10"
Margin="0,4,0,0"
Foreground="{DynamicResource TextFillColorTertiaryBrush}"
Text="{Binding NotFoundImagePath}"
TextAlignment="Center"
TextWrapping="WrapWithOverflow" />
</Grid>
</Border>
<!-- Active Selection Prompt -->
<Border
IsVisible="{Binding !IsSelectionAvailable}"
Margin="4"
HorizontalAlignment="Right"
VerticalAlignment="Top"
BoxShadow="inset 1.2 0 80 1.8 #66000000"
CornerRadius="10">
CornerRadius="10"
IsVisible="{Binding !IsSelectionAvailable}">
<Border.Resources>
<DropShadowEffect
x:Key="TextDropShadowEffect"
@ -70,22 +105,24 @@
Color="#FF000000" />
</Border.Resources>
<Button
ToolTip.Tip="{x:Static lang:Resources.Action_ReplaceContents}"
Padding="2"
Classes="transparent"
Command="{Binding SelectImageFromFilePickerCommand}"
CornerRadius="10"
FontSize="{TemplateBinding FontSize}">
FontSize="{TemplateBinding FontSize}"
ToolTip.Tip="{x:Static lang:Resources.Action_ReplaceContents}">
<fluentIcons:SymbolIcon
Effect="{StaticResource ImageDropShadowEffect}"
FontSize="28"
FontSize="28"
IsFilled="True"
Symbol="ImageArrowCounterclockwise"/>
Symbol="ImageArrowCounterclockwise" />
</Button>
</Border>
<!-- No Image Selection Prompt -->
<controls:LineDashFrame
Padding="8,4"
CornerRadius="8"
IsVisible="{Binding IsSelectionAvailable}"
Stroke="DimGray"
StrokeDashLine="6"
@ -95,18 +132,18 @@
<Grid
HorizontalAlignment="Center"
VerticalAlignment="Center"
Cursor="Hand"
RowDefinitions="*,Auto,Auto">
<fluentIcons:SymbolIcon
FontSize="28"
FontSize="28"
IsFilled="True"
Symbol="ImageCopy"/>
Symbol="ImageCopy" />
<TextBlock
Grid.Row="1"
FontSize="{TemplateBinding FontSize}"
Foreground="DarkGray"
Text="Drag an image here"
TextAlignment="Center"
TextWrapping="WrapWithOverflow" />
<StackPanel

2
StabilityMatrix.Avalonia/Controls/StackCard.axaml

@ -20,7 +20,7 @@
<!-- Set Defaults -->
<Setter Property="Template">
<ControlTemplate>
<ScrollViewer Padding="8,0,8,0">
<ScrollViewer Padding="4,0,4,0">
<ItemsControl
VerticalAlignment="Top"
ItemsSource="{Binding Cards}">

8
StabilityMatrix.Avalonia/Controls/StackCard.axaml.cs

@ -9,10 +9,10 @@ namespace StabilityMatrix.Avalonia.Controls;
[Transient]
public class StackCard : TemplatedControl
{
public static readonly StyledProperty<int> SpacingProperty = AvaloniaProperty.Register<
StackCard,
int
>("Spacing", 8);
public static readonly StyledProperty<int> SpacingProperty = AvaloniaProperty.Register<StackCard, int>(
"Spacing",
4
);
public int Spacing
{

8
StabilityMatrix.Avalonia/Controls/StackEditableCard.axaml

@ -11,7 +11,7 @@
x:DataType="vmInference:StackEditableCardViewModel">
<Design.PreviewWith>
<Grid Width="600" Height="800">
<Grid Width="500" Height="600">
<controls:StackEditableCard
DataContext="{x:Static mocks:DesignData.StackEditableCardViewModel}"/>
</Grid>
@ -58,11 +58,15 @@
Grid.Row="1"
Theme="{StaticResource DraggableListBoxTheme}"
ItemsSource="{Binding Cards}">
<ListBox.DataTemplates>
<local:ViewLocator/>
</ListBox.DataTemplates>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Spacing="0" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>

7
StabilityMatrix.Avalonia/Controls/StackExpander.axaml

@ -21,10 +21,13 @@
<Style Selector="controls|StackExpander">
<!-- Set Defaults -->
<Setter Property="CornerRadius" Value="8"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Template">
<ControlTemplate>
<Expander
MinHeight="0"
CornerRadius="{TemplateBinding CornerRadius}"
ExpandDirection="{TemplateBinding ExpandDirection}"
IsExpanded="{TemplateBinding IsExpanded}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
@ -39,9 +42,9 @@
</Expander.Styles>
<Expander.Header>
<Grid ColumnDefinitions="Auto,Auto,*,Auto,Auto">
<Grid ColumnDefinitions="Auto,Auto,*,Auto,Auto" Margin="0,-4">
<ToggleSwitch
Margin="2,0,0,2"
Margin="2,0,0,4"
VerticalContentAlignment="Center"
IsChecked="{Binding IsEnabled}"
OffContent=""

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

@ -1418,6 +1418,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
/// <summary>
/// Looks up a localized string similar to Missing Image File.
/// </summary>
public static string Label_MissingImageFile {
get {
return ResourceManager.GetString("Label_MissingImageFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Model.
/// </summary>
@ -2156,6 +2165,24 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
/// <summary>
/// Looks up a localized string similar to Not yet available.
/// </summary>
public static string Label_WipFeature {
get {
return ResourceManager.GetString("Label_WipFeature", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Feature will be available in a future update.
/// </summary>
public static string Label_WipFeatureDescription {
get {
return ResourceManager.GetString("Label_WipFeatureDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to You&apos;re up to date.
/// </summary>

9
StabilityMatrix.Avalonia/Languages/Resources.resx

@ -885,4 +885,13 @@
<data name="Action_ReplaceContents" xml:space="preserve">
<value>Replace Contents</value>
</data>
<data name="Label_WipFeature" xml:space="preserve">
<value>Not yet available</value>
</data>
<data name="Label_WipFeatureDescription" xml:space="preserve">
<value>Feature will be available in a future update</value>
</data>
<data name="Label_MissingImageFile" xml:space="preserve">
<value>Missing Image File</value>
</data>
</root>

20
StabilityMatrix.Avalonia/Models/ImageSource.cs

@ -1,5 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using AsyncImageLoader;
using Avalonia.Media.Imaging;
@ -27,6 +29,7 @@ public record ImageSource : IDisposable
/// <summary>
/// Bitmap
/// </summary>
[JsonIgnore]
public Bitmap? Bitmap { get; set; }
/// <summary>
@ -34,6 +37,9 @@ public record ImageSource : IDisposable
/// </summary>
public string? Label { get; set; }
[JsonConstructor]
public ImageSource() { }
public ImageSource(FilePath localFile)
{
LocalFile = localFile;
@ -49,6 +55,7 @@ public record ImageSource : IDisposable
Bitmap = bitmap;
}
[JsonIgnore]
public Task<Bitmap?> BitmapAsync => GetBitmapAsync();
/// <summary>
@ -121,9 +128,20 @@ public record ImageSource : IDisposable
throw new InvalidOperationException("ImageSource is not a local file");
}
// Calculate hash if not available
if (contentHashBlake3 is null)
{
throw new InvalidOperationException("Blake3 hash has not been calculated yet");
// File must exist
if (!LocalFile.Exists)
{
throw new FileNotFoundException("Image file does not exist", LocalFile);
}
// Fail in debug since hash should have been pre-calculated
Debug.Fail("Hash has not been calculated when GetHashGuidFileNameCached() was called");
var data = LocalFile.ReadAllBytes();
contentHashBlake3 = FileHash.GetBlake3Parallel(data);
}
var extension = LocalFile.Info.Extension;

3
StabilityMatrix.Avalonia/Styles/ListBoxStyles.axaml

@ -22,7 +22,7 @@
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="Background" Value="{DynamicResource ListViewItemBackground}" />
<Setter Property="CornerRadius" Value="7" />
<!--<Setter Property="CornerRadius" Value="7" />-->
<Setter Property="Foreground" Value="{DynamicResource ListViewItemForeground}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
@ -34,7 +34,6 @@
<Panel>
<ContentPresenter
Name="PART_ContentPresenter"
Margin="0,4"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"

34
StabilityMatrix.Avalonia/ViewModels/Inference/SelectImageCardViewModel.cs

@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Input;
@ -21,6 +22,7 @@ using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Models.Database;
using Size = System.Drawing.Size;
#pragma warning disable CS0657 // Not a valid attribute location for this declaration
namespace StabilityMatrix.Avalonia.ViewModels.Inference;
@ -28,7 +30,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Inference;
[ManagedService]
[Transient]
public partial class SelectImageCardViewModel(INotificationService notificationService)
: ViewModelBase,
: LoadableViewModelBase,
IDropTarget,
IComfyStep
{
@ -36,17 +38,31 @@ public partial class SelectImageCardViewModel(INotificationService notificationS
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(IsSelectionAvailable))]
[NotifyPropertyChangedFor(nameof(IsImageFileNotFound))]
private ImageSource? imageSource;
[ObservableProperty]
[property: JsonIgnore]
[NotifyPropertyChangedFor(nameof(CurrentBitmapSize))]
private IImage? currentBitmap;
[ObservableProperty]
[property: JsonIgnore]
[NotifyPropertyChangedFor(nameof(IsSelectionAvailable))]
private bool isSelectionEnabled = true;
public bool IsSelectionAvailable => IsSelectionEnabled && ImageSource == null;
/// <summary>
/// True if the image file is set but the local file does not exist.
/// </summary>
[MemberNotNullWhen(true, nameof(NotFoundImagePath))]
public bool IsImageFileNotFound => ImageSource?.LocalFile?.Exists == false;
public bool IsSelectionAvailable => IsSelectionEnabled && ImageSource == null && !IsImageFileNotFound;
/// <summary>
/// Path of the not found image
/// </summary>
public string? NotFoundImagePath => ImageSource?.LocalFile?.FullPath;
public Size? CurrentBitmapSize =>
CurrentBitmap is null
@ -63,6 +79,15 @@ public partial class SelectImageCardViewModel(INotificationService notificationS
);
}
partial void OnImageSourceChanged(ImageSource? value)
{
// Cache the hash for later upload use
if (value?.LocalFile is { Exists: true })
{
value.GetBlake3HashAsync().SafeFireAndForget();
}
}
[RelayCommand]
private async Task SelectImageFromFilePickerAsync()
{
@ -139,8 +164,5 @@ public partial class SelectImageCardViewModel(INotificationService notificationS
ImageSource = image;
current?.Dispose();
// Cache the hash for later upload use
image.GetBlake3HashAsync().SafeFireAndForget();
}
}

Loading…
Cancel
Save