Browse Source

redesigned packages page & made it the first tab & removed old launch page from tabs

pull/629/head
JT 9 months ago
parent
commit
2303759eec
  1. 3
      StabilityMatrix.Avalonia/App.axaml.cs
  2. 73
      StabilityMatrix.Avalonia/Styles/ButtonStyles.axaml
  3. 12
      StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs
  4. 73
      StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs
  5. 11
      StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs
  6. 8
      StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml
  7. 272
      StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml
  8. 603
      StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml
  9. 3
      StabilityMatrix.Core/Models/DownloadPackageVersionOptions.cs

3
StabilityMatrix.Avalonia/App.axaml.cs

@ -328,9 +328,8 @@ public sealed class App : Application
{ {
Pages = Pages =
{ {
provider.GetRequiredService<LaunchPageViewModel>(),
provider.GetRequiredService<InferenceViewModel>(),
provider.GetRequiredService<NewPackageManagerViewModel>(), provider.GetRequiredService<NewPackageManagerViewModel>(),
provider.GetRequiredService<InferenceViewModel>(),
provider.GetRequiredService<CheckpointsPageViewModel>(), provider.GetRequiredService<CheckpointsPageViewModel>(),
provider.GetRequiredService<CheckpointBrowserViewModel>(), provider.GetRequiredService<CheckpointBrowserViewModel>(),
provider.GetRequiredService<OutputsPageViewModel>() provider.GetRequiredService<OutputsPageViewModel>()

73
StabilityMatrix.Avalonia/Styles/ButtonStyles.axaml

@ -99,6 +99,43 @@
</Style> </Style>
</Style> </Style>
<!-- Danger -->
<Style Selector="Button.borderless-danger">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ThemeRedColor}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" />
</Style>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ThemeDarkRedColor}"/>
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ThemeDarkDarkRedColor}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
</Style>
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
</Style>
</Style>
</Style>
<!-- Info --> <!-- Info -->
<Style Selector="Button.info"> <Style Selector="Button.info">
<Style Selector="^ /template/ ui|FABorder#Root"> <Style Selector="^ /template/ ui|FABorder#Root">
@ -140,6 +177,42 @@
</Style> </Style>
</Style> </Style>
<Style Selector="Button.borderless-info">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ThemeLightBlueColor}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" />
</Style>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ThemeBlueColor}"/>
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
</Style>
</Style>
<Style Selector="^:pressed">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ThemeDarkBlueColor}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
</Style>
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ui|FABorder#Root">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
</Style>
</Style>
</Style>
<!--Accent Button--> <!--Accent Button-->
<Style Selector="Button.accent"> <Style Selector="Button.accent">
<Style Selector="^ /template/ ui|FABorder#Root"> <Style Selector="^ /template/ ui|FABorder#Root">

12
StabilityMatrix.Avalonia/ViewModels/CheckpointManager/CheckpointFolder.cs

@ -111,6 +111,10 @@ public partial class CheckpointFolder : ViewModelBase
public IObservableCollection<string> BaseModelOptions { get; } = public IObservableCollection<string> BaseModelOptions { get; } =
new ObservableCollectionExtended<string>(); new ObservableCollectionExtended<string>();
private IEnumerable<string> allModelOptions = Enum.GetValues<CivitBaseModelType>()
.Where(x => x != CivitBaseModelType.All)
.Select(x => x.GetStringValue());
public CheckpointFolder( public CheckpointFolder(
ISettingsManager settingsManager, ISettingsManager settingsManager,
IDownloadService downloadService, IDownloadService downloadService,
@ -175,11 +179,7 @@ public partial class CheckpointFolder : ViewModelBase
SubFoldersCache.Refresh(); SubFoldersCache.Refresh();
}); });
BaseModelOptionsCache.AddOrUpdate( BaseModelOptionsCache.AddOrUpdate(allModelOptions);
Enum.GetValues<CivitBaseModelType>()
.Where(x => x != CivitBaseModelType.All)
.Select(x => x.GetStringValue())
);
CheckpointFiles.CollectionChanged += OnCheckpointFilesChanged; CheckpointFiles.CollectionChanged += OnCheckpointFilesChanged;
// DisplayedCheckpointFiles = CheckpointFiles; // DisplayedCheckpointFiles = CheckpointFiles;
@ -187,7 +187,7 @@ public partial class CheckpointFolder : ViewModelBase
private bool BaseModelFilter(CheckpointFile file) private bool BaseModelFilter(CheckpointFile file)
{ {
return file.IsConnectedModel return file.IsConnectedModel && allModelOptions.Contains(file.ConnectedModel!.BaseModel)
? BaseModelOptions.Contains(file.ConnectedModel!.BaseModel) ? BaseModelOptions.Contains(file.ConnectedModel!.BaseModel)
: BaseModelOptions.Contains("Other"); : BaseModelOptions.Contains("Other");
} }

73
StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -96,13 +97,10 @@ public partial class PackageCardViewModel(
private void RunningPackagesOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) private void RunningPackagesOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{ {
if ( if (runningPackageService.RunningPackages.Select(x => x.Value) is not { } runningPackages)
e.NewItems?.OfType<KeyValuePair<Guid, RunningPackageViewModel>>().Select(x => x.Value)
is not { } newItems
)
return; return;
var runningViewModel = newItems.FirstOrDefault( var runningViewModel = runningPackages.FirstOrDefault(
x => x.RunningPackage.InstalledPackage.Id == Package?.Id x => x.RunningPackage.InstalledPackage.Id == Package?.Id
); );
if (runningViewModel is not null) if (runningViewModel is not null)
@ -114,6 +112,7 @@ public partial class PackageCardViewModel(
else if (runningViewModel is null && IsRunning) else if (runningViewModel is null && IsRunning)
{ {
IsRunning = false; IsRunning = false;
ShowWebUiButton = false;
} }
} }
@ -165,6 +164,7 @@ public partial class PackageCardViewModel(
if (Design.IsDesignMode && Package?.DisplayName == "Running Comfy") if (Design.IsDesignMode && Package?.DisplayName == "Running Comfy")
{ {
IsRunning = true; IsRunning = true;
IsUpdateAvailable = true;
ShowWebUiButton = true; ShowWebUiButton = true;
} }
@ -422,6 +422,21 @@ public partial class PackageCardViewModel(
versionOptions.CommitHash = latest.Sha; versionOptions.CommitHash = latest.Sha;
} }
var confirmationDialog = new BetterContentDialog
{
Title = Resources.Label_AreYouSure,
Content =
$"{Package.DisplayName} will be updated to the latest version ({versionOptions.GetReadableVersionString()})",
PrimaryButtonText = Resources.Action_Continue,
SecondaryButtonText = Resources.Action_Cancel,
DefaultButton = ContentDialogButton.Primary,
IsSecondaryButtonEnabled = true,
};
var dialogResult = await confirmationDialog.ShowAsync();
if (dialogResult != ContentDialogResult.Primary)
return;
var updatePackageStep = new UpdatePackageStep( var updatePackageStep = new UpdatePackageStep(
settingsManager, settingsManager,
Package, Package,
@ -583,6 +598,54 @@ public partial class PackageCardViewModel(
await runningPackageService.StopPackage(Package.Id); await runningPackageService.StopPackage(Package.Id);
IsRunning = false; IsRunning = false;
ShowWebUiButton = false;
}
[RelayCommand]
private async Task Restart()
{
await Stop();
await Launch();
}
[RelayCommand]
private async Task ShowLaunchOptions()
{
var basePackage = packageFactory.FindPackageByName(Package?.PackageName);
if (basePackage == null)
{
logger.LogWarning("Package {Name} not found", Package?.PackageName);
return;
}
var viewModel = vmFactory.Get<LaunchOptionsViewModel>();
viewModel.Cards = LaunchOptionCard
.FromDefinitions(basePackage.LaunchOptions, Package?.LaunchArgs ?? [])
.ToImmutableArray();
logger.LogDebug("Launching config dialog with cards: {CardsCount}", viewModel.Cards.Count);
var dialog = new BetterContentDialog
{
ContentVerticalScrollBarVisibility = ScrollBarVisibility.Disabled,
IsPrimaryButtonEnabled = true,
PrimaryButtonText = Resources.Action_Save,
CloseButtonText = Resources.Action_Cancel,
FullSizeDesired = true,
DefaultButton = ContentDialogButton.Primary,
ContentMargin = new Thickness(32, 16),
Padding = new Thickness(0, 16),
Content = new LaunchOptionsDialog { DataContext = viewModel, }
};
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary && Package != null)
{
// Save config
var args = viewModel.AsLaunchArgs();
settingsManager.SaveLaunchArgs(Package.Id, args);
}
} }
private async Task<bool> HasUpdate() private async Task<bool> HasUpdate()

11
StabilityMatrix.Avalonia/ViewModels/RunningPackageViewModel.cs

@ -39,6 +39,9 @@ public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, I
[ObservableProperty] [ObservableProperty]
private bool isRunning = true; private bool isRunning = true;
[ObservableProperty]
private string consoleInput = string.Empty;
/// <inheritdoc/> /// <inheritdoc/>
public RunningPackageViewModel( public RunningPackageViewModel(
ISettingsManager settingsManager, ISettingsManager settingsManager,
@ -118,18 +121,20 @@ public partial class RunningPackageViewModel : PageViewModelBase, IDisposable, I
} }
[RelayCommand] [RelayCommand]
private async Task SendToConsole(string input) private async Task SendToConsole()
{ {
Console.PostLine(input); Console.PostLine(ConsoleInput);
if (RunningPackage?.BasePackage is BaseGitPackage gitPackage) if (RunningPackage?.BasePackage is BaseGitPackage gitPackage)
{ {
var venv = gitPackage.VenvRunner; var venv = gitPackage.VenvRunner;
var process = venv?.Process; var process = venv?.Process;
if (process is not null) if (process is not null)
{ {
await process.StandardInput.WriteLineAsync(input); await process.StandardInput.WriteLineAsync(ConsoleInput);
} }
} }
ConsoleInput = string.Empty;
} }
public void Dispose() public void Dispose()

8
StabilityMatrix.Avalonia/Views/ConsoleOutputPage.axaml

@ -73,14 +73,14 @@
WordWrap="True" /> WordWrap="True" />
<Grid Grid.Row="2" ColumnDefinitions="*, Auto" <Grid Grid.Row="2" ColumnDefinitions="*, Auto"
Margin="8,4,8,8"> Margin="16,4,16,16">
<TextBox Grid.Column="0" Name="ManualInputBox" <TextBox Grid.Column="0" Text="{Binding ConsoleInput, Mode=TwoWay}"
Margin="0,0,8,0"/> Margin="0,0,8,0"/>
<Button Grid.Column="1" <Button Grid.Column="1"
Classes="accent" Classes="accent"
IsDefault="True"
Content="{x:Static lang:Resources.Action_Send}" Content="{x:Static lang:Resources.Action_Send}"
Command="{Binding SendToConsoleCommand}" Command="{Binding SendToConsoleCommand}"/>
CommandParameter="{Binding #ManualInputBox.Text}"/>
</Grid> </Grid>
</Grid> </Grid>
</controls:UserControlBase> </controls:UserControlBase>

272
StabilityMatrix.Avalonia/Views/PackageManager/PackageInstallBrowserView.axaml

@ -40,151 +40,151 @@
CornerRadius="4" CornerRadius="4"
Source="{Binding PreviewImageUri}" /> Source="{Binding PreviewImageUri}" />
<StackPanel Grid.Column="1" Orientation="Vertical"> <StackPanel Grid.Column="1" Orientation="Vertical">
<TextBlock Text="{Binding DisplayName}" <TextBlock Text="{Binding DisplayName}"
FontWeight="Light" FontWeight="Light"
Margin="16,0,0,0" Margin="16,0,0,0"
FontSize="20" /> FontSize="20" />
<TextBlock Text="{Binding ByAuthor}" <TextBlock Text="{Binding ByAuthor}"
FontWeight="Light" FontWeight="Light"
Margin="16,0,0,0" Margin="16,0,0,0"
FontSize="13" /> FontSize="13" />
<TextBlock TextWrapping="Wrap" <TextBlock TextWrapping="Wrap"
Text="{Binding Blurb}" Text="{Binding Blurb}"
FontWeight="Light" FontWeight="Light"
Margin="16,8,0,8" Margin="16,8,0,8"
FontSize="16" /> FontSize="16" />
<TextBlock TextWrapping="Wrap" <TextBlock TextWrapping="Wrap"
Text="{Binding Disclaimer}" Text="{Binding Disclaimer}"
IsVisible="{Binding Disclaimer, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" IsVisible="{Binding Disclaimer, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
Foreground="OrangeRed" Foreground="OrangeRed"
FontWeight="Light" FontWeight="Light"
Margin="16,-4,0,4" Margin="16,-4,0,4"
FontSize="14" /> FontSize="14" />
<ItemsRepeater Margin="16, 8, 0, 0" <ItemsRepeater Margin="16, 8, 0, 0"
ItemsSource="{Binding AvailableTorchVersions}"> ItemsSource="{Binding AvailableTorchVersions}">
<ItemsRepeater.Layout> <ItemsRepeater.Layout>
<StackLayout Orientation="Horizontal" /> <StackLayout Orientation="Horizontal" />
</ItemsRepeater.Layout> </ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate> <ItemsRepeater.ItemTemplate>
<DataTemplate DataType="{x:Type models:TorchVersion}"> <DataTemplate DataType="{x:Type models:TorchVersion}">
<controls:Card <controls:Card
Tag="{Binding }" Tag="{Binding }"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Padding="4" Padding="4"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Top"> VerticalAlignment="Top">
<controls:Card.Styles> <controls:Card.Styles>
<Style Selector="controls|Card[Tag=Cuda]"> <Style Selector="controls|Card[Tag=Cuda]">
<Setter Property="Background" <Setter Property="Background"
Value="{DynamicResource ThemeGreenColorTransparent}" /> Value="{DynamicResource ThemeGreenColorTransparent}" />
<Setter Property="BorderBrush" <Setter Property="BorderBrush"
Value="{DynamicResource ThemeGreenColorTransparent}" /> Value="{DynamicResource ThemeGreenColorTransparent}" />
<Style <Style
Selector="^ /template/ ContentPresenter#PART_ContentPresenter"> Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" <Setter Property="Foreground"
Value="{DynamicResource ButtonForeground}" /> Value="{DynamicResource ButtonForeground}" />
</Style>
<Setter Property="Content">
<Template>
<TextBlock
FontWeight="Medium"
HorizontalAlignment="Center"
Text="NVIDIA"
TextAlignment="Center"
VerticalAlignment="Center" />
</Template>
</Setter>
</Style> </Style>
<Setter Property="Content"> <Style Selector="controls|Card[Tag=Rocm]">
<Template> <Setter Property="Background"
<TextBlock Value="{DynamicResource ThemeDarkRedColor}" />
FontWeight="Medium" <Setter Property="BorderBrush"
HorizontalAlignment="Center" Value="{DynamicResource ThemeDarkRedColor}" />
Text="NVIDIA" <Style
TextAlignment="Center" Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
VerticalAlignment="Center" /> <Setter Property="Foreground"
</Template> Value="{DynamicResource ButtonForeground}" />
</Setter> </Style>
</Style> <Setter Property="Content">
<Style Selector="controls|Card[Tag=Rocm]"> <Template>
<Setter Property="Background" <TextBlock
Value="{DynamicResource ThemeDarkRedColor}" /> FontWeight="Medium"
<Setter Property="BorderBrush" HorizontalAlignment="Center"
Value="{DynamicResource ThemeDarkRedColor}" /> Text="AMD (Linux)"
<Style TextAlignment="Center"
Selector="^ /template/ ContentPresenter#PART_ContentPresenter"> VerticalAlignment="Center"
<Setter Property="Foreground" ToolTip.Tip="For AMD GPUs that support ROCm on Linux" />
Value="{DynamicResource ButtonForeground}" /> </Template>
</Setter>
</Style> </Style>
<Setter Property="Content"> <Style Selector="controls|Card[Tag=DirectMl]">
<Template> <Setter Property="Background"
<TextBlock Value="{DynamicResource ThemeDarkBlueColor}" />
FontWeight="Medium" <Setter Property="BorderBrush"
HorizontalAlignment="Center" Value="{DynamicResource ThemeDarkBlueColor}" />
Text="AMD (Linux)" <Setter Property="Content">
TextAlignment="Center" <Template>
VerticalAlignment="Center" <TextBlock
ToolTip.Tip="For AMD GPUs that support ROCm on Linux" /> FontWeight="Medium"
</Template> HorizontalAlignment="Center"
</Setter> Text="DirectML"
</Style> TextAlignment="Center"
<Style Selector="controls|Card[Tag=DirectMl]"> VerticalAlignment="Center"
<Setter Property="Background" ToolTip.Tip="For any DirectX compatible GPU on Windows" />
Value="{DynamicResource ThemeDarkBlueColor}" /> </Template>
<Setter Property="BorderBrush" </Setter>
Value="{DynamicResource ThemeDarkBlueColor}" />
<Setter Property="Content">
<Template>
<TextBlock
FontWeight="Medium"
HorizontalAlignment="Center"
Text="DirectML"
TextAlignment="Center"
VerticalAlignment="Center"
ToolTip.Tip="For any DirectX compatible GPU on Windows" />
</Template>
</Setter>
</Style>
<Style Selector="controls|Card[Tag=Mps]">
<Setter Property="Background" Value="White" />
<Setter Property="BorderBrush" Value="White" />
<Style
Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground"
Value="{DynamicResource ButtonForeground}" />
</Style> </Style>
<Setter Property="Content"> <Style Selector="controls|Card[Tag=Mps]">
<Template> <Setter Property="Background" Value="White" />
<TextBlock <Setter Property="BorderBrush" Value="White" />
FontWeight="Medium" <Style
HorizontalAlignment="Center" Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
Text="macOS" <Setter Property="Foreground"
TextAlignment="Center" Value="{DynamicResource ButtonForeground}" />
Foreground="Black" </Style>
VerticalAlignment="Center" /> <Setter Property="Content">
</Template> <Template>
</Setter> <TextBlock
</Style> FontWeight="Medium"
<Style Selector="controls|Card[Tag=Cpu]"> HorizontalAlignment="Center"
<Setter Property="Background" Text="macOS"
Value="{DynamicResource ThemeBlueGreyColor}" /> TextAlignment="Center"
<Setter Property="BorderBrush" Foreground="Black"
Value="{DynamicResource ThemeBlueGreyColor}" /> VerticalAlignment="Center" />
<Style </Template>
Selector="^ /template/ ContentPresenter#PART_ContentPresenter"> </Setter>
<Setter Property="Foreground"
Value="{DynamicResource ButtonForeground}" />
</Style> </Style>
<Setter Property="Content"> <Style Selector="controls|Card[Tag=Cpu]">
<Template> <Setter Property="Background"
<TextBlock Value="{DynamicResource ThemeBlueGreyColor}" />
FontWeight="Medium" <Setter Property="BorderBrush"
HorizontalAlignment="Center" Value="{DynamicResource ThemeBlueGreyColor}" />
Text="CPU" <Style
TextAlignment="Center" Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
VerticalAlignment="Center" /> <Setter Property="Foreground"
</Template> Value="{DynamicResource ButtonForeground}" />
</Setter> </Style>
</Style> <Setter Property="Content">
</controls:Card.Styles> <Template>
</controls:Card> <TextBlock
</DataTemplate> FontWeight="Medium"
</ItemsRepeater.ItemTemplate> HorizontalAlignment="Center"
</ItemsRepeater> Text="CPU"
TextAlignment="Center"
VerticalAlignment="Center" />
</Template>
</Setter>
</Style>
</controls:Card.Styles>
</controls:Card>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</StackPanel> </StackPanel>

603
StabilityMatrix.Avalonia/Views/PackageManagerPage.axaml

@ -12,7 +12,8 @@
xmlns:system="clr-namespace:System;assembly=System.Runtime" xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters"
xmlns:avalonia="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia" xmlns:avalonia="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" xmlns:markupExtensions="clr-namespace:StabilityMatrix.Avalonia.MarkupExtensions"
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="450"
x:DataType="viewModels:PackageManagerViewModel" x:DataType="viewModels:PackageManagerViewModel"
x:CompileBindings="True" x:CompileBindings="True"
d:DataContext="{x:Static designData:DesignData.PackageManagerViewModel}" d:DataContext="{x:Static designData:DesignData.PackageManagerViewModel}"
@ -32,216 +33,34 @@
<ItemsRepeater.ItemTemplate> <ItemsRepeater.ItemTemplate>
<DataTemplate DataType="{x:Type packageManager:PackageCardViewModel}"> <DataTemplate DataType="{x:Type packageManager:PackageCardViewModel}">
<controls:Card Padding="8" <controls:Card Padding="8"
MinWidth="400"
CornerRadius="8"> CornerRadius="8">
<controls:Card.Background> <controls:Card.Background>
<MultiBinding Converter="{StaticResource BoolChoiceMultiConverter}"> <MultiBinding Converter="{StaticResource BoolChoiceMultiConverter}">
<Binding Path="IsRunning" /> <Binding Path="IsRunning" />
<DynamicResource ResourceKey="ThemeDarkDarkGreenColorBrush"/> <DynamicResource ResourceKey="ThemeDarkDarkGreenColorBrush" />
<DynamicResource ResourceKey="ButtonBackground"/> <DynamicResource ResourceKey="ButtonBackground" />
</MultiBinding> </MultiBinding>
</controls:Card.Background> </controls:Card.Background>
<Grid RowDefinitions="Auto, Auto, Auto, Auto" <Grid ColumnDefinitions="Auto, *">
ColumnDefinitions="*,Auto">
<TextBlock Grid.Row="0"
Grid.Column="0"
ToolTip.Tip="{Binding Package.DisplayName, FallbackValue=''}"
Text="{Binding Package.DisplayName, FallbackValue=''}"
TextTrimming="WordEllipsis"
TextAlignment="Left" />
<Button
Grid.Row="0"
Grid.Column="1"
HorizontalContentAlignment="Right"
HorizontalAlignment="Right"
VerticalContentAlignment="Top"
VerticalAlignment="Top"
Padding="4,1"
Margin="4,0,0,0"
Classes="transparent"
Width="24"
BorderThickness="0">
<ui:SymbolIcon FontSize="18" Symbol="MoreVertical" />
<Button.Flyout>
<MenuFlyout Placement="BottomEdgeAlignedLeft">
<MenuItem Header="{x:Static lang:Resources.Action_CheckForUpdates}"
IsVisible="{Binding !IsUnknownPackage}"
Command="{Binding OnLoadedAsync}">
<MenuItem.Icon>
<ui:SymbolIcon Symbol="Refresh" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Header="{OnPlatform Default={x:Static lang:Resources.Action_OpenInExplorer}, macOS={x:Static lang:Resources.Action_OpenInFinder}}"
Command="{Binding OpenFolder}">
<MenuItem.Icon>
<ui:SymbolIcon Symbol="OpenFolder" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Header="{x:Static lang:Resources.Action_OpenGithub}"
IsVisible="{Binding !IsUnknownPackage}"
Command="{Binding OpenOnGitHubCommand}">
<MenuItem.Icon>
<icons:Icon
Value="fa-brands fa-github" />
</MenuItem.Icon>
</MenuItem>
<Separator/>
<MenuItem
Header="{x:Static lang:Resources.Label_PythonPackages}"
IsVisible="{Binding !IsUnknownPackage}"
Command="{Binding OpenPythonPackagesDialogCommand}">
<MenuItem.Icon>
<icons:Icon
Value="fa-brands fa-python" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Header="Extensions"
IsVisible="{Binding CanUseExtensions}"
Command="{Binding OpenExtensionsDialogCommand}">
<MenuItem.Icon>
<icons:Icon
Value="fa-solid fa-puzzle-piece" />
</MenuItem.Icon>
</MenuItem>
<Separator IsVisible="{Binding CanUseSharedOutput}" />
<MenuItem Header="{x:Static lang:Resources.Label_SharedModelStrategyShort}"
IsVisible="{Binding !IsUnknownPackage}">
<MenuItem.Icon>
<ui:SymbolIcon Symbol="FolderLink" />
</MenuItem.Icon>
<!-- ReSharper disable Xaml.RedundantResource -->
<MenuItem Header="Symlink"
Command="{Binding ToggleSharedModelSymlink}"
IsVisible="{Binding CanUseSymlinkMethod}">
<MenuItem.Icon>
<CheckBox IsChecked="{Binding IsSharedModelSymlink}"
Margin="8,0,0,0"
Padding="0"
Width="28" Height="28">
<CheckBox.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.RenderTransform>
</CheckBox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Config"
Command="{Binding ToggleSharedModelConfig}"
IsVisible="{Binding CanUseConfigMethod}">
<MenuItem.Icon>
<CheckBox Margin="8,0,0,0"
Padding="0"
Width="28" Height="28"
IsChecked="{Binding IsSharedModelConfig}">
<CheckBox.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.RenderTransform>
</CheckBox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="None"
Command="{Binding ToggleSharedModelNone}">
<MenuItem.Icon>
<CheckBox IsChecked="{Binding IsSharedModelDisabled}"
Margin="8,0,0,0"
Padding="0"
Width="28" Height="28">
<CheckBox.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.RenderTransform>
</CheckBox>
</MenuItem.Icon>
</MenuItem>
<!-- ReSharper enable Xaml.RedundantResource -->
</MenuItem>
<MenuItem
Header="{x:Static lang:Resources.Label_UseSharedOutputFolder}"
Command="{Binding ToggleSharedOutput}"
IsVisible="{Binding CanUseSharedOutput}">
<MenuItem.Icon>
<CheckBox Margin="8,0,0,0"
Padding="0"
Width="28" Height="28"
IsChecked="{Binding UseSharedOutput}">
<CheckBox.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
</CheckBox.RenderTransform>
</CheckBox>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="{x:Static lang:Resources.Action_Uninstall}"
Command="{Binding Uninstall}">
<MenuItem.Icon>
<ui:SymbolIcon Symbol="Delete" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Button.Flyout>
</Button>
<TextBlock Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="2,0,0,0"
VerticalAlignment="Center"
Text="{Binding InstalledVersion}" />
<Border Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0,8"
Background="#AA000000"
IsVisible="{Binding IsRunning}"
CornerRadius="4"
ZIndex="1">
<Button Classes="danger"
FontSize="16"
MinWidth="100"
MinHeight="40"
Command="{Binding StopCommand}"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center">
<StackPanel Orientation="Horizontal">
<icons:Icon Value="fa-solid fa-stop"
FontSize="20"
Margin="0,0,8,0"/>
<TextBlock Text="{x:Static lang:Resources.Action_Stop}"/>
</StackPanel>
</Button>
</Border>
<!-- Normal packages shows image -->
<controls:BetterAdvancedImage <controls:BetterAdvancedImage
Grid.Row="2"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="2" Height="150"
Margin="0,8,0,8" Width="150"
Height="180" Margin="4, 8"
Width="225" CornerRadius="8"
CornerRadius="4"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalContentAlignment="Top" VerticalContentAlignment="Top"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
Source="{Binding CardImageSource}" Source="{Binding CardImageSource}"
IsVisible="{Binding !IsUnknownPackage}" IsVisible="{Binding !IsUnknownPackage}"
Stretch="UniformToFill" /> Stretch="UniformToFill" />
<!-- Unknown packages panel -->
<Border <Border
Grid.Row="2"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="2" Height="150"
Margin="0,8,0,8" Width="150"
Height="180" Margin="4, 8"
Width="225" CornerRadius="8"
CornerRadius="4"
HorizontalAlignment="Center" HorizontalAlignment="Center"
IsVisible="{Binding IsUnknownPackage}" IsVisible="{Binding IsUnknownPackage}"
Background="#202020"> Background="#202020">
@ -252,114 +71,328 @@
TextWrapping="Wrap" TextWrapping="Wrap"
Text="{x:Static lang:Resources.Label_UnknownPackage}" /> Text="{x:Static lang:Resources.Label_UnknownPackage}" />
</Border> </Border>
<Grid Grid.Column="1" RowDefinitions="Auto, Auto, Auto, *"
ColumnDefinitions="Auto, *">
<TextBlock Grid.Column="0"
Grid.Row="0"
Text="{Binding Package.DisplayName}"
Margin="8,0,8,0"
FontWeight="SemiBold"
MaxWidth="200"
TextWrapping="NoWrap"
TextTrimming="CharacterEllipsis"
ToolTip.Tip="{Binding Package.DisplayName}"
FontSize="16" />
<TextBlock Grid.Column="0"
Grid.Row="1"
FontSize="13"
Foreground="{DynamicResource TextControlPlaceholderForeground}"
Margin="8,0,8,0"
VerticalAlignment="Center"
Text="{Binding InstalledVersion}" />
<Button
Grid.Row="0"
Grid.Column="1"
HorizontalContentAlignment="Right"
HorizontalAlignment="Right"
VerticalContentAlignment="Top"
VerticalAlignment="Top"
Padding="4"
Margin="4,0,0,0"
Classes="transparent"
Width="24"
BorderThickness="0">
<ui:SymbolIcon FontSize="18" Symbol="MoreVertical" />
<Button.Flyout>
<MenuFlyout Placement="BottomEdgeAlignedLeft">
<MenuItem Header="{x:Static lang:Resources.Action_CheckForUpdates}"
IsVisible="{Binding !IsUnknownPackage}"
Command="{Binding OnLoadedAsync}">
<MenuItem.Icon>
<ui:SymbolIcon Symbol="Refresh" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Header="{OnPlatform Default={x:Static lang:Resources.Action_OpenInExplorer}, macOS={x:Static lang:Resources.Action_OpenInFinder}}"
Command="{Binding OpenFolder}">
<MenuItem.Icon>
<ui:SymbolIcon Symbol="OpenFolder" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Header="{x:Static lang:Resources.Action_OpenGithub}"
IsVisible="{Binding !IsUnknownPackage}"
Command="{Binding OpenOnGitHubCommand}">
<MenuItem.Icon>
<icons:Icon
Value="fa-brands fa-github" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<Grid <MenuItem
Grid.Row="3" Header="{x:Static lang:Resources.Label_PythonPackages}"
Grid.Column="0" IsVisible="{Binding !IsUnknownPackage}"
Grid.ColumnSpan="2" Command="{Binding OpenPythonPackagesDialogCommand}">
IsVisible="{Binding !IsUnknownPackage}" <MenuItem.Icon>
ColumnDefinitions="*,Auto"> <icons:Icon
<!-- Launch and update buttons --> Value="fa-brands fa-python" />
<Button Grid.Column="0" Classes="accent" </MenuItem.Icon>
VerticalAlignment="Bottom" </MenuItem>
HorizontalAlignment="Stretch" <MenuItem
Command="{Binding Launch}"> Header="Extensions"
<Button.IsVisible> IsVisible="{Binding CanUseExtensions}"
<MultiBinding Converter="{x:Static BoolConverters.And}"> Command="{Binding OpenExtensionsDialogCommand}">
<Binding Path="!IsRunning" /> <MenuItem.Icon>
<Binding Path="!IsUnknownPackage" /> <icons:Icon
</MultiBinding> Value="fa-solid fa-puzzle-piece" />
</Button.IsVisible> </MenuItem.Icon>
<StackPanel Orientation="Horizontal" Margin="0,2,0,2"> </MenuItem>
<icons:Icon Value="fa-solid fa-rocket"
Margin="0,0,8,0" <Separator IsVisible="{Binding CanUseSharedOutput}" />
FontSize="14" />
<TextBlock Text="{x:Static lang:Resources.Action_Launch}" /> <MenuItem
</StackPanel> Header="{x:Static lang:Resources.Label_SharedModelStrategyShort}"
</Button> IsVisible="{Binding !IsUnknownPackage}">
<Button Grid.Column="1" Classes="accent" <MenuItem.Icon>
VerticalAlignment="Bottom" <ui:SymbolIcon Symbol="FolderLink" />
HorizontalAlignment="Stretch" </MenuItem.Icon>
Command="{Binding Update}"> <!-- ReSharper disable Xaml.RedundantResource -->
<Button.IsVisible> <MenuItem Header="Symlink"
<MultiBinding Converter="{x:Static BoolConverters.And}"> Command="{Binding ToggleSharedModelSymlink}"
<Binding Path="IsUpdateAvailable" /> IsVisible="{Binding CanUseSymlinkMethod}">
<Binding Path="!IsRunning" /> <MenuItem.Icon>
</MultiBinding> <CheckBox IsChecked="{Binding IsSharedModelSymlink}"
</Button.IsVisible> Margin="8,0,0,0"
<StackPanel Orientation="Horizontal" Padding="0"
Margin="10,2"> Width="28" Height="28">
<icons:Icon Value="fa-solid fa-download" <CheckBox.RenderTransform>
Margin="0,0,8,0" <ScaleTransform ScaleX="1.5" ScaleY="1.5" />
FontSize="14" /> </CheckBox.RenderTransform>
<TextBlock Text="{x:Static lang:Resources.Action_Update}" /> </CheckBox>
</StackPanel> </MenuItem.Icon>
</Button> </MenuItem>
<Button Grid.Column="0" Classes="accent" <MenuItem Header="Config"
VerticalAlignment="Bottom" Command="{Binding ToggleSharedModelConfig}"
HorizontalAlignment="Stretch" IsVisible="{Binding CanUseConfigMethod}">
IsVisible="{Binding IsRunning}" <MenuItem.Icon>
Command="{Binding NavToConsole}"> <CheckBox Margin="8,0,0,0"
<StackPanel Orientation="Horizontal" Padding="0"
Margin="0,2,0,2"> Width="28" Height="28"
<icons:Icon Value="fa-solid fa-terminal" IsChecked="{Binding IsSharedModelConfig}">
Margin="0,0,8,0" <CheckBox.RenderTransform>
FontSize="14" /> <ScaleTransform ScaleX="1.5" ScaleY="1.5" />
<TextBlock Text="Console"/> </CheckBox.RenderTransform>
</StackPanel> </CheckBox>
</Button> </MenuItem.Icon>
<Button Grid.Column="1" Classes="accent" </MenuItem>
VerticalAlignment="Bottom" <MenuItem Header="None"
HorizontalAlignment="Stretch" Command="{Binding ToggleSharedModelNone}">
IsVisible="{Binding ShowWebUiButton}" <MenuItem.Icon>
Command="{Binding LaunchWebUi}"> <CheckBox IsChecked="{Binding IsSharedModelDisabled}"
<StackPanel Orientation="Horizontal" Margin="8,2,8,2"> Margin="8,0,0,0"
<icons:Icon Value="fa-solid fa-up-right-from-square" Padding="0"
Margin="0,0,8,0" Width="28" Height="28">
FontSize="14" /> <CheckBox.RenderTransform>
<TextBlock Text="Web UI" /> <ScaleTransform ScaleX="1.5" ScaleY="1.5" />
</StackPanel> </CheckBox.RenderTransform>
</CheckBox>
</MenuItem.Icon>
</MenuItem>
<!-- ReSharper enable Xaml.RedundantResource -->
</MenuItem>
<MenuItem
Header="{x:Static lang:Resources.Label_UseSharedOutputFolder}"
Command="{Binding ToggleSharedOutput}"
IsVisible="{Binding CanUseSharedOutput}">
<MenuItem.Icon>
<CheckBox Margin="8,0,0,0"
Padding="0"
Width="28" Height="28"
IsChecked="{Binding UseSharedOutput}">
<CheckBox.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5" />
</CheckBox.RenderTransform>
</CheckBox>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="{x:Static lang:Resources.Action_Uninstall}"
Command="{Binding Uninstall}">
<MenuItem.Icon>
<ui:SymbolIcon Symbol="Delete" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Button.Flyout>
</Button> </Button>
</Grid>
<!-- Import button (for unknown) --> <StackPanel Grid.Row="2"
<Button Grid.Row="3" Grid.Column="0" Classes="transparent-info" Grid.Column="0"
Grid.ColumnSpan="2" Margin="0,4,0,0"
VerticalAlignment="Bottom" Orientation="Horizontal">
HorizontalAlignment="Stretch" <Button Classes="transparent-full"
Command="{Binding Import}" Margin="4,4,0,0"
IsVisible="{Binding IsUnknownPackage}"> Padding="4"
<StackPanel Orientation="Horizontal" Margin="0,2,0,2"> ToolTip.Tip="{x:Static lang:Resources.Action_CheckForUpdates}"
<icons:Icon Value="fa-solid fa-circle-question" Command="{Binding OnLoadedAsync}"
Margin="0,0,8,0" >
FontSize="14" /> <Button.IsVisible>
<TextBlock Text="{x:Static lang:Resources.Action_Import}" /> <MultiBinding Converter="{x:Static BoolConverters.And}">
</StackPanel> <Binding Path="!IsUnknownPackage" />
</Button> <Binding Path="!IsUpdateAvailable" />
</MultiBinding>
</Button.IsVisible>
<ui:SymbolIcon Symbol="Refresh"
FontSize="20"/>
</Button>
<Button Classes="transparent-full"
Margin="4,4,0,0"
Padding="4"
IsEnabled="{Binding !IsRunning}"
ToolTip.Tip="{x:Static lang:Resources.Label_UpdateAvailable}"
markupExtensions:ShowDisabledTooltipExtension.ShowOnDisabled="True"
Command="{Binding Update}">
<Button.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="!IsUnknownPackage" />
<Binding Path="IsUpdateAvailable" />
</MultiBinding>
</Button.IsVisible>
<ui:SymbolIcon Symbol="CloudDownload"
IsEnabled="{Binding !IsRunning}"
FontSize="24">
<ui:SymbolIcon.Styles>
<Style Selector="ui|SymbolIcon">
<Setter Property="Foreground" Value="Lime" />
</Style>
<Style Selector="ui|SymbolIcon:disabled">
<Setter Property="Foreground" Value="Gray" />
</Style>
</ui:SymbolIcon.Styles>
</ui:SymbolIcon>
</Button>
<Button Classes="transparent-full"
Margin="4,4,0,0"
Padding="4"
ToolTip.Tip="Launch Options"
IsVisible="{Binding !IsUnknownPackage}"
Command="{Binding ShowLaunchOptionsCommand}">
<ui:SymbolIcon Symbol="SettingsFilled"
FontSize="20"/>
</Button>
</StackPanel>
<UniformGrid Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="3"
VerticalAlignment="Bottom"
Margin="8,8,8,0">
<Button Classes="accent"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
Command="{Binding Launch}">
<Button.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="!IsRunning" />
<Binding Path="!IsUnknownPackage" />
</MultiBinding>
</Button.IsVisible>
<StackPanel Orientation="Horizontal" Margin="0,2,0,2">
<icons:Icon Value="fa-solid fa-rocket"
Margin="0,0,8,0"
FontSize="14" />
<TextBlock Text="{x:Static lang:Resources.Action_Launch}" />
</StackPanel>
</Button>
<Button Classes="borderless-danger"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
IsVisible="{Binding IsRunning}"
Command="{Binding StopCommand}">
<StackPanel Orientation="Horizontal"
Margin="0,2">
<icons:Icon Value="fa-solid fa-stop"
Margin="0,0,8,0"
FontSize="14" />
<TextBlock Text="{x:Static lang:Resources.Action_Stop}" />
</StackPanel>
</Button>
<Button Classes="borderless-info"
BorderBrush="Transparent"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
IsVisible="{Binding IsRunning}"
Command="{Binding RestartCommand}">
<StackPanel Orientation="Horizontal"
Margin="0,2">
<icons:Icon Value="fa-solid fa-arrow-rotate-left"
Margin="0,0,8,0"
FontSize="14" />
<TextBlock Text="{x:Static lang:Resources.Action_Restart}" />
</StackPanel>
</Button>
<Button Classes="accent"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
IsVisible="{Binding IsRunning}"
Command="{Binding NavToConsole}">
<StackPanel Orientation="Horizontal"
Margin="0,2,0,2">
<icons:Icon Value="fa-solid fa-terminal"
Margin="0,0,8,0"
FontSize="14" />
<TextBlock Text="Console" />
</StackPanel>
</Button>
<Button Classes="accent"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
IsVisible="{Binding ShowWebUiButton}"
Command="{Binding LaunchWebUi}">
<StackPanel Orientation="Horizontal" Margin="8,2,8,2">
<icons:Icon Value="fa-solid fa-up-right-from-square"
Margin="0,0,8,0"
FontSize="14" />
<TextBlock Text="Web UI" />
</StackPanel>
</Button>
<Button Classes="transparent-info"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
Command="{Binding Import}"
IsVisible="{Binding IsUnknownPackage}">
<StackPanel Orientation="Horizontal" Margin="0,2,0,2">
<icons:Icon Value="fa-solid fa-circle-question"
Margin="0,0,8,0"
FontSize="14" />
<TextBlock Text="{x:Static lang:Resources.Action_Import}" />
</StackPanel>
</Button>
</UniformGrid>
</Grid>
<!-- Update overlay --> <!-- Update overlay -->
<Border <Border
Grid.Row="0" Grid.RowSpan="4"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="2" Grid.ColumnSpan="2"
Background="#DD000000" Background="#DD000000"
CornerRadius="4" CornerRadius="8"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
IsVisible="{Binding IsProgressVisible}" /> IsVisible="{Binding IsProgressVisible}"/>
<Grid Grid.Row="0" Grid.RowSpan="4" <Grid Grid.Column="0"
Grid.Column="0"
Grid.ColumnSpan="2" Grid.ColumnSpan="2"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
RowDefinitions="Auto, *" IsVisible="{Binding IsProgressVisible}"
IsVisible="{Binding IsProgressVisible}"> RowDefinitions="Auto, *">
<controls:ProgressRing <controls:ProgressRing
HorizontalAlignment="Center" HorizontalAlignment="Center"
IsIndeterminate="{Binding IsIndeterminate}" IsIndeterminate="{Binding IsIndeterminate}"
Width="150" Width="120"
Height="150" Height="120"
StartAngle="90" StartAngle="90"
EndAngle="450" EndAngle="450"
Value="{Binding Value}" Value="{Binding Value}"

3
StabilityMatrix.Core/Models/DownloadPackageVersionOptions.cs

@ -7,4 +7,7 @@ public class DownloadPackageVersionOptions
public string? VersionTag { get; set; } public string? VersionTag { get; set; }
public bool IsLatest { get; set; } public bool IsLatest { get; set; }
public bool IsPrerelease { get; set; } public bool IsPrerelease { get; set; }
public string GetReadableVersionString() =>
!string.IsNullOrWhiteSpace(VersionTag) ? VersionTag : $"{BranchName}@{CommitHash?[..7]}";
} }

Loading…
Cancel
Save