Ionite
1 year ago
8 changed files with 680 additions and 6 deletions
@ -0,0 +1,393 @@
|
||||
using System; |
||||
using System.Collections.ObjectModel; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
using AsyncAwaitBestPractices; |
||||
using Avalonia.Controls; |
||||
using Avalonia.Controls.Notifications; |
||||
using Avalonia.Layout; |
||||
using Avalonia.Media; |
||||
using Avalonia.Media.Imaging; |
||||
using Avalonia.Threading; |
||||
using CommunityToolkit.Mvvm.ComponentModel; |
||||
using CommunityToolkit.Mvvm.Input; |
||||
using FluentAvalonia.UI.Controls; |
||||
using NLog; |
||||
using Octokit; |
||||
using StabilityMatrix.Avalonia.Services; |
||||
using StabilityMatrix.Core.Helper; |
||||
using StabilityMatrix.Core.Models; |
||||
using StabilityMatrix.Core.Models.FileInterfaces; |
||||
using StabilityMatrix.Core.Models.Packages; |
||||
using StabilityMatrix.Core.Models.Progress; |
||||
using StabilityMatrix.Core.Processes; |
||||
using StabilityMatrix.Core.Python; |
||||
using StabilityMatrix.Core.Services; |
||||
using Notification = Avalonia.Controls.Notifications.Notification; |
||||
using PackageVersion = StabilityMatrix.Core.Models.PackageVersion; |
||||
|
||||
namespace StabilityMatrix.Avalonia.ViewModels.Dialogs; |
||||
|
||||
|
||||
public partial class InstallerViewModel : ViewModelBase |
||||
{ |
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); |
||||
|
||||
private readonly ISettingsManager settingsManager; |
||||
private readonly IPyRunner pyRunner; |
||||
private readonly IDownloadService downloadService; |
||||
private readonly INotificationService notificationService; |
||||
private readonly ISharedFolders sharedFolders; |
||||
private readonly IPrerequisiteHelper prerequisiteHelper; |
||||
|
||||
[ObservableProperty] private BasePackage selectedPackage; |
||||
[ObservableProperty] private PackageVersion? selectedVersion; |
||||
|
||||
[ObservableProperty] private ObservableCollection<BasePackage>? availablePackages; |
||||
[ObservableProperty] private ObservableCollection<GitHubCommit>? availableCommits; |
||||
[ObservableProperty] private ObservableCollection<PackageVersion>? availableVersions; |
||||
|
||||
[ObservableProperty] private GitHubCommit? selectedCommit; |
||||
|
||||
[ObservableProperty] private string? releaseNotes; |
||||
// [ObservableProperty] private bool isReleaseMode; |
||||
|
||||
// Version types (release or commit) |
||||
[ObservableProperty] |
||||
[NotifyPropertyChangedFor(nameof(ReleaseLabelText), |
||||
nameof(IsReleaseMode), nameof(SelectedVersion))] |
||||
private PackageVersionType selectedVersionType = PackageVersionType.Commit; |
||||
|
||||
[ObservableProperty] |
||||
[NotifyPropertyChangedFor(nameof(IsReleaseModeAvailable))] |
||||
private PackageVersionType availableVersionTypes = |
||||
PackageVersionType.GithubRelease | PackageVersionType.Commit; |
||||
public string ReleaseLabelText => SelectedVersionType == PackageVersionType.GithubRelease |
||||
? "Version" : "Branch"; |
||||
public bool IsReleaseMode |
||||
{ |
||||
get => SelectedVersionType == PackageVersionType.GithubRelease; |
||||
set => SelectedVersionType = value ? PackageVersionType.GithubRelease : PackageVersionType.Commit; |
||||
} |
||||
|
||||
public bool IsReleaseModeAvailable => AvailableVersionTypes.HasFlag(PackageVersionType.GithubRelease); |
||||
|
||||
[ObservableProperty] private bool showDuplicateWarning; |
||||
|
||||
[ObservableProperty] private string? installName; |
||||
|
||||
internal event EventHandler? PackageInstalled; |
||||
|
||||
public ProgressViewModel InstallProgress { get; } = new() |
||||
{ |
||||
|
||||
}; |
||||
|
||||
public InstallerViewModel( |
||||
ISettingsManager settingsManager, |
||||
IPyRunner pyRunner, |
||||
IDownloadService downloadService, INotificationService notificationService, |
||||
ISharedFolders sharedFolders, |
||||
IPrerequisiteHelper prerequisiteHelper) |
||||
{ |
||||
this.settingsManager = settingsManager; |
||||
this.pyRunner = pyRunner; |
||||
this.downloadService = downloadService; |
||||
this.notificationService = notificationService; |
||||
this.sharedFolders = sharedFolders; |
||||
this.prerequisiteHelper = prerequisiteHelper; |
||||
|
||||
// AvailablePackages and SelectedPackage need to be set in init |
||||
} |
||||
|
||||
public override async Task OnLoadedAsync() |
||||
{ |
||||
if (IsReleaseMode) |
||||
{ |
||||
var versions = (await SelectedPackage.GetAllVersions()).ToList(); |
||||
AvailableVersions = new ObservableCollection<PackageVersion>(versions); |
||||
if (!AvailableVersions.Any()) return; |
||||
|
||||
SelectedVersion = AvailableVersions[0]; |
||||
} |
||||
else |
||||
{ |
||||
var branches = (await SelectedPackage.GetAllBranches()).ToList(); |
||||
AvailableVersions = new ObservableCollection<PackageVersion>(branches.Select(b => new PackageVersion |
||||
{ |
||||
TagName = b.Name, |
||||
ReleaseNotesMarkdown = b.Commit.Label |
||||
})); |
||||
SelectedVersion = AvailableVersions.FirstOrDefault(x => |
||||
x.TagName.ToLowerInvariant() is "master" or "main") ?? AvailableVersions[0]; |
||||
} |
||||
|
||||
ReleaseNotes = SelectedVersion.ReleaseNotesMarkdown; |
||||
} |
||||
|
||||
[RelayCommand] |
||||
private async Task Install() |
||||
{ |
||||
await ActuallyInstall(); |
||||
notificationService.Show(new Notification( |
||||
$"Package {SelectedPackage.Name} installed successfully!", |
||||
"Success", NotificationType.Success)); |
||||
OnPackageInstalled(); |
||||
} |
||||
|
||||
private async Task ActuallyInstall() |
||||
{ |
||||
if (string.IsNullOrWhiteSpace(InstallName)) |
||||
{ |
||||
notificationService.Show(new Notification("Package name is empty", |
||||
"Please enter a name for the package", NotificationType.Error)); |
||||
} |
||||
|
||||
await InstallGitIfNecessary(); |
||||
|
||||
var libraryDir = new DirectoryPath(settingsManager.LibraryDir, "Packages", InstallName); |
||||
SelectedPackage.InstallLocation = $"{settingsManager.LibraryDir}\\Packages\\{InstallName}"; |
||||
// SelectedPackage.DisplayName = InstallName; |
||||
|
||||
if (!PyRunner.PipInstalled || !PyRunner.VenvInstalled) |
||||
{ |
||||
InstallProgress.Text = "Installing dependencies..."; |
||||
await pyRunner.Initialize(); |
||||
if (!PyRunner.PipInstalled) |
||||
{ |
||||
await pyRunner.SetupPip(); |
||||
} |
||||
if (!PyRunner.VenvInstalled) |
||||
{ |
||||
await pyRunner.InstallPackage("virtualenv"); |
||||
} |
||||
} |
||||
|
||||
var version = IsReleaseMode |
||||
? await DownloadPackage(SelectedVersion!.TagName, false) |
||||
: await DownloadPackage(SelectedCommit!.Sha, true); |
||||
|
||||
await InstallPackage(); |
||||
|
||||
InstallProgress.Text = "Setting up shared folder links..."; |
||||
sharedFolders.SetupLinksForPackage(SelectedPackage, SelectedPackage.InstallLocation); |
||||
|
||||
InstallProgress.Text = "Done"; |
||||
InstallProgress.IsIndeterminate = false; |
||||
InstallProgress.Value = 100; |
||||
EventManager.Instance.OnGlobalProgressChanged(100); |
||||
|
||||
var branch = SelectedVersionType == PackageVersionType.GithubRelease ? |
||||
null : SelectedVersion!.TagName; |
||||
|
||||
var package = new InstalledPackage |
||||
{ |
||||
DisplayName = SelectedPackage.DisplayName, |
||||
LibraryPath = $"Packages\\{InstallName}", |
||||
Id = Guid.NewGuid(), |
||||
PackageName = SelectedPackage.Name, |
||||
PackageVersion = version, |
||||
DisplayVersion = GetDisplayVersion(version, branch), |
||||
InstalledBranch = branch, |
||||
LaunchCommand = SelectedPackage.LaunchCommand, |
||||
LastUpdateCheck = DateTimeOffset.Now |
||||
}; |
||||
await using var st = settingsManager.BeginTransaction(); |
||||
st.Settings.InstalledPackages.Add(package); |
||||
st.Settings.ActiveInstalledPackage = package.Id; |
||||
|
||||
InstallProgress.Value = 0; |
||||
} |
||||
|
||||
private static string GetDisplayVersion(string version, string? branch) |
||||
{ |
||||
return branch == null ? version : $"{branch}@{version[..7]}"; |
||||
} |
||||
|
||||
private Task<string?> DownloadPackage(string version, bool isCommitHash) |
||||
{ |
||||
InstallProgress.Text = "Downloading package..."; |
||||
|
||||
var progress = new Progress<ProgressReport>(progress => |
||||
{ |
||||
InstallProgress.IsIndeterminate = progress.IsIndeterminate; |
||||
InstallProgress.Value = progress.Percentage; |
||||
EventManager.Instance.OnGlobalProgressChanged((int) progress.Percentage); |
||||
}); |
||||
|
||||
return SelectedPackage.DownloadPackage(version, isCommitHash, progress); |
||||
} |
||||
|
||||
private async Task InstallPackage() |
||||
{ |
||||
InstallProgress.Text = "Installing package..."; |
||||
SelectedPackage.ConsoleOutput += SelectedPackageOnConsoleOutput; |
||||
try |
||||
{ |
||||
var progress = new Progress<ProgressReport>(progress => |
||||
{ |
||||
InstallProgress.IsIndeterminate = progress.IsIndeterminate; |
||||
InstallProgress.Value = progress.Percentage; |
||||
EventManager.Instance.OnGlobalProgressChanged((int) progress.Percentage); |
||||
}); |
||||
|
||||
await SelectedPackage.InstallPackage(progress); |
||||
} |
||||
finally |
||||
{ |
||||
SelectedPackage.ConsoleOutput -= SelectedPackageOnConsoleOutput; |
||||
} |
||||
} |
||||
|
||||
private void SelectedPackageOnConsoleOutput(object? sender, ProcessOutput e) |
||||
{ |
||||
InstallProgress.Description = e.Text; |
||||
} |
||||
|
||||
[RelayCommand] |
||||
private async Task ShowPreview() |
||||
{ |
||||
var url = SelectedPackage.PreviewImageUri.ToString(); |
||||
var imageStream = await downloadService.GetImageStreamFromUrl(url); |
||||
var bitmap = new Bitmap(imageStream); |
||||
|
||||
var dialog = new ContentDialog |
||||
{ |
||||
Title = "Test title", |
||||
PrimaryButtonText = "Open in Browser", |
||||
CloseButtonText = "Close", |
||||
Content = new Image |
||||
{ |
||||
Source = bitmap, |
||||
Stretch = Stretch.Uniform, |
||||
MaxHeight = 500, |
||||
HorizontalAlignment = HorizontalAlignment.Center |
||||
} |
||||
}; |
||||
|
||||
var result = await dialog.ShowAsync(); |
||||
if (result == ContentDialogResult.Primary) |
||||
{ |
||||
ProcessRunner.OpenUrl(url); |
||||
} |
||||
} |
||||
|
||||
partial void OnSelectedPackageChanged(BasePackage? value) |
||||
{ |
||||
if (value == null) return; |
||||
|
||||
ReleaseNotes = string.Empty; |
||||
AvailableVersions?.Clear(); |
||||
AvailableCommits?.Clear(); |
||||
|
||||
AvailableVersionTypes = SelectedPackage.ShouldIgnoreReleases |
||||
? PackageVersionType.Commit |
||||
: PackageVersionType.GithubRelease | PackageVersionType.Commit; |
||||
|
||||
// Reset selected if not compatible |
||||
if (!AvailableVersionTypes.HasFlag(SelectedVersionType)) |
||||
{ |
||||
SelectedVersionType = PackageVersionType.Commit; |
||||
} |
||||
|
||||
var isReleaseMode = SelectedVersionType == PackageVersionType.GithubRelease; |
||||
|
||||
if (Design.IsDesignMode) return; |
||||
|
||||
Task.Run(async () => |
||||
{ |
||||
var versions = (await value.GetAllVersions(isReleaseMode)).ToList(); |
||||
if (!versions.Any()) return; |
||||
|
||||
Dispatcher.UIThread.Post(() => |
||||
{ |
||||
AvailableVersions = new ObservableCollection<PackageVersion>(versions); |
||||
SelectedVersion = AvailableVersions[0]; |
||||
ReleaseNotes = versions.First().ReleaseNotesMarkdown; |
||||
}); |
||||
|
||||
if (!isReleaseMode) |
||||
{ |
||||
var commits = await value.GetAllCommits(SelectedVersion!.TagName); |
||||
if (commits is null || commits.Count == 0) return; |
||||
|
||||
Dispatcher.UIThread.Post(() => |
||||
{ |
||||
AvailableCommits = new ObservableCollection<GitHubCommit>(commits); |
||||
SelectedCommit = AvailableCommits[0]; |
||||
SelectedVersion = AvailableVersions?.FirstOrDefault(packageVersion => |
||||
packageVersion.TagName.ToLowerInvariant() is "master" or "main"); |
||||
}); |
||||
} |
||||
}).SafeFireAndForget(); |
||||
} |
||||
|
||||
private async Task InstallGitIfNecessary() |
||||
{ |
||||
var progressHandler = new Progress<ProgressReport>(progress => |
||||
{ |
||||
if (progress.Message != null && progress.Message.Contains("Downloading")) |
||||
{ |
||||
InstallProgress.Text = $"Downloading prerequisites... {progress.Percentage:N0}%"; |
||||
} |
||||
else if (progress.Type == ProgressType.Extract) |
||||
{ |
||||
InstallProgress.Text = $"Installing git... {progress.Percentage:N0}%"; |
||||
} |
||||
else if (progress.Title != null && progress.Title.Contains("Unpacking")) |
||||
{ |
||||
InstallProgress.Text = $"Unpacking resources... {progress.Percentage:N0}%"; |
||||
} |
||||
else |
||||
{ |
||||
InstallProgress.Text = progress.Message; |
||||
} |
||||
|
||||
InstallProgress.IsIndeterminate = progress.IsIndeterminate; |
||||
InstallProgress.Value = Convert.ToInt32(progress.Percentage); |
||||
}); |
||||
|
||||
await prerequisiteHelper.InstallAllIfNecessary(progressHandler); |
||||
} |
||||
|
||||
partial void OnInstallNameChanged(string? value) |
||||
{ |
||||
ShowDuplicateWarning = |
||||
settingsManager.Settings.InstalledPackages.Any(p => |
||||
p.LibraryPath == $"Packages{Path.DirectorySeparatorChar}{value}"); |
||||
} |
||||
|
||||
partial void OnSelectedVersionChanged(PackageVersion? value) |
||||
{ |
||||
ReleaseNotes = value?.ReleaseNotesMarkdown ?? string.Empty; |
||||
if (value == null) return; |
||||
|
||||
SelectedCommit = null; |
||||
AvailableCommits?.Clear(); |
||||
|
||||
if (!IsReleaseMode) |
||||
{ |
||||
Task.Run(async () => |
||||
{ |
||||
try |
||||
{ |
||||
var hashes = await SelectedPackage.GetAllCommits(value.TagName); |
||||
if (hashes is null) throw new Exception("No commits found"); |
||||
|
||||
Dispatcher.UIThread.Post(() => |
||||
{ |
||||
AvailableCommits = new ObservableCollection<GitHubCommit>(hashes); |
||||
SelectedCommit = AvailableCommits[0]; |
||||
}); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
Logger.Warn($"Error getting commits: {e.Message}"); |
||||
} |
||||
}).SafeFireAndForget(); |
||||
} |
||||
} |
||||
|
||||
private void OnPackageInstalled() => PackageInstalled?.Invoke(this, EventArgs.Empty); |
||||
} |
@ -0,0 +1,232 @@
|
||||
<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:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels" |
||||
xmlns:ui="using:FluentAvalonia.UI.Controls" |
||||
xmlns:md="https://github.com/whistyun/Markdown.Avalonia" |
||||
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" |
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime" |
||||
xmlns:dialogs="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Dialogs" |
||||
xmlns:packages="clr-namespace:StabilityMatrix.Core.Models.Packages;assembly=StabilityMatrix.Core" |
||||
xmlns:models="clr-namespace:StabilityMatrix.Core.Models;assembly=StabilityMatrix.Core" |
||||
xmlns:octokit="clr-namespace:Octokit;assembly=Octokit" |
||||
xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight" |
||||
x:DataType="dialogs:InstallerViewModel" |
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
d:DataContext="{x:Static mocks:DesignData.InstallerViewModel}" |
||||
x:Class="StabilityMatrix.Avalonia.Views.Dialogs.InstallerDialog"> |
||||
|
||||
<controls:UserControlBase.Resources> |
||||
</controls:UserControlBase.Resources> |
||||
|
||||
<Grid> |
||||
<Grid.RowDefinitions> |
||||
<RowDefinition Height="Auto" /> |
||||
<RowDefinition Height="Auto" /> |
||||
<RowDefinition Height="*" /> |
||||
</Grid.RowDefinitions> |
||||
|
||||
<StackPanel |
||||
Grid.Row="1" |
||||
Margin="16,8,16,0" |
||||
Orientation="Vertical" |
||||
DataContext="{Binding InstallProgress}" |
||||
IsVisible="{Binding IsProgressVisible}"> |
||||
|
||||
<TextBlock |
||||
HorizontalAlignment="Center" |
||||
Padding="8" |
||||
Text="{Binding Text}" /> |
||||
<ProgressBar |
||||
IsIndeterminate="{Binding IsIndeterminate}" |
||||
Maximum="100" |
||||
Width="500" |
||||
Value="{Binding Value}" /> |
||||
<TextBlock |
||||
FontSize="10" |
||||
HorizontalAlignment="Center" |
||||
Padding="4" |
||||
Text="{Binding Description}" |
||||
TextWrapping="Wrap" /> |
||||
</StackPanel> |
||||
|
||||
<Grid Grid.Row="2" HorizontalAlignment="Left" ColumnDefinitions="Auto,Auto,*"> |
||||
<ListBox |
||||
Margin="16" |
||||
ItemsSource="{Binding AvailablePackages}" |
||||
SelectedItem="{Binding SelectedPackage, Mode=TwoWay}"> |
||||
|
||||
<!--<ListView.Style> |
||||
<Style TargetType="ListView"> |
||||
<Setter Property="Background" Value="#191919" /> |
||||
</Style> |
||||
</ListView.Style>--> |
||||
|
||||
<ListBox.Template> |
||||
<ControlTemplate> |
||||
<!-- BorderBrush="{KeyboardFocusBorderColorBrush}" --> |
||||
<Border |
||||
BorderThickness="1" |
||||
CornerRadius="5"> |
||||
<ItemsPresenter /> |
||||
</Border> |
||||
</ControlTemplate> |
||||
</ListBox.Template> |
||||
|
||||
<ListBox.ItemTemplate> |
||||
<DataTemplate DataType="{x:Type packages:BasePackage}"> |
||||
<StackPanel Margin="8" VerticalAlignment="Top"> |
||||
<TextBlock Margin="0,5,0,5" Text="{Binding DisplayName}" /> |
||||
<TextBlock Margin="0,0,0,5" Text="{Binding ByAuthor}" /> |
||||
</StackPanel> |
||||
</DataTemplate> |
||||
</ListBox.ItemTemplate> |
||||
</ListBox> |
||||
|
||||
<StackPanel |
||||
Grid.Column="1" |
||||
Margin="16,16,0,16" |
||||
Orientation="Vertical"> |
||||
<TextBlock |
||||
FontSize="24" |
||||
FontWeight="Bold" |
||||
Text="{Binding SelectedPackage.DisplayName, FallbackValue=Stable Diffusion Web UI}" /> |
||||
<TextBlock FontSize="12" Text="{Binding SelectedPackage.ByAuthor, FallbackValue=by Automatic111}" /> |
||||
|
||||
<Button |
||||
Background="Transparent" |
||||
BorderBrush="Transparent" |
||||
Command="{Binding ShowPreviewCommand}" |
||||
Content="UI Preview" |
||||
Margin="0,8,0,0"> |
||||
<!--<Button.Style> |
||||
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}"> |
||||
<Setter Property="Foreground"> |
||||
<Setter.Value> |
||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" /> |
||||
</Setter.Value> |
||||
</Setter> |
||||
</Style> |
||||
</Button.Style>--> |
||||
</Button> |
||||
|
||||
<ui:HyperlinkButton Margin="0,0,0,8" NavigateUri="{Binding SelectedPackage.GithubUrl}"> |
||||
<TextBlock TextWrapping="Wrap"> |
||||
<Run Text="GitHub Page:" /> |
||||
<Run Text="{Binding SelectedPackage.GithubUrl, Mode=OneWay}" TextDecorations="Underline" /> |
||||
</TextBlock> |
||||
</ui:HyperlinkButton> |
||||
|
||||
<StackPanel Orientation="Horizontal"> |
||||
<ToggleButton |
||||
Content="Releases" |
||||
IsChecked="{Binding IsReleaseMode}" |
||||
IsEnabled="{Binding IsReleaseModeAvailable}" /> |
||||
<ToggleButton |
||||
Content="Branches" |
||||
IsChecked="{Binding !IsReleaseMode}" |
||||
Margin="8,0,0,0" /> |
||||
</StackPanel> |
||||
|
||||
<StackPanel Margin="0,16,0,0" Orientation="Horizontal"> |
||||
<StackPanel Orientation="Vertical"> |
||||
<Label Content="{Binding ReleaseLabelText, FallbackValue=Version}" /> |
||||
<ComboBox |
||||
ItemsSource="{Binding AvailableVersions}" |
||||
MinWidth="200" |
||||
SelectedItem="{Binding SelectedVersion}"> |
||||
<ComboBox.ItemTemplate> |
||||
<DataTemplate DataType="{x:Type models:PackageVersion}"> |
||||
<StackPanel Margin="8,0,0,0" VerticalAlignment="Top"> |
||||
<TextBlock |
||||
Margin="0,4,0,4" |
||||
Name="NameTextBlock" |
||||
Text="{Binding TagName}" /> |
||||
</StackPanel> |
||||
</DataTemplate> |
||||
</ComboBox.ItemTemplate> |
||||
</ComboBox> |
||||
</StackPanel> |
||||
|
||||
<StackPanel |
||||
Margin="8,0,0,0" |
||||
Orientation="Vertical" |
||||
IsVisible="{Binding !IsReleaseMode}"> |
||||
<Label Content="Commit" /> |
||||
<ComboBox |
||||
ItemsSource="{Binding AvailableCommits}" |
||||
MinWidth="100" |
||||
SelectedItem="{Binding SelectedCommit}"> |
||||
<ComboBox.ItemTemplate> |
||||
<DataTemplate DataType="{x:Type octokit:GitHubCommit}"> |
||||
<StackPanel Margin="8,0,0,0" VerticalAlignment="Top"> |
||||
<TextBlock |
||||
Margin="0,4,0,4" |
||||
Name="NameTextBlock" |
||||
Text="{Binding Sha}" /> |
||||
</StackPanel> |
||||
</DataTemplate> |
||||
</ComboBox.ItemTemplate> |
||||
</ComboBox> |
||||
</StackPanel> |
||||
</StackPanel> |
||||
|
||||
<Label Content="Display Name" Margin="0,16,0,0" /> |
||||
<StackPanel Orientation="Horizontal" IsVisible="{Binding ShowDuplicateWarning}"> |
||||
<ui:SymbolIcon |
||||
Foreground="{DynamicResource ThemeRedColor}" |
||||
Margin="8" |
||||
Symbol="Alert" /> |
||||
<TextBlock |
||||
Foreground="{DynamicResource ThemeRedColor}" |
||||
Margin="0,8,8,8" |
||||
TextAlignment="Left" |
||||
TextWrapping="Wrap"> |
||||
<Run Text="An installation with this name already exists." /> |
||||
<LineBreak /> |
||||
<Run Text="Please choose a different name or select a different Install Location." /> |
||||
</TextBlock> |
||||
</StackPanel> |
||||
|
||||
<TextBox |
||||
Margin="0,0,0,8" |
||||
Text="{Binding SelectedPackage.DisplayName}" /> |
||||
|
||||
<StackPanel Orientation="Horizontal"> |
||||
<Button |
||||
Command="{Binding InstallCommand}" |
||||
Content="Install" |
||||
Height="50" |
||||
IsEnabled="{Binding !ShowDuplicateWarning}" |
||||
Margin="0,16,0,0" |
||||
VerticalAlignment="Top" |
||||
Width="100" /> |
||||
<controls:ProgressRing |
||||
Height="25" |
||||
IsIndeterminate="True" |
||||
Margin="8,16,0,0" |
||||
VerticalAlignment="Center" |
||||
IsVisible="{Binding InstallProgress.IsProgressVisible}" |
||||
Width="25" /> |
||||
<TextBlock |
||||
Margin="8,16,0,0" |
||||
Text="Installing..." |
||||
VerticalAlignment="Center" |
||||
IsVisible="{Binding InstallProgress.IsProgressVisible}" /> |
||||
</StackPanel> |
||||
</StackPanel> |
||||
|
||||
<mdxaml:MarkdownScrollViewer |
||||
Grid.Column="2" |
||||
Margin="16" |
||||
Source="{Binding ReleaseNotes, Mode=OneWay}"/> |
||||
<ContentPresenter |
||||
Grid.Column="0" |
||||
Grid.ColumnSpan="3" |
||||
x:Name="InstallerContentDialog" /> |
||||
</Grid> |
||||
</Grid> |
||||
|
||||
</controls:UserControlBase> |
@ -0,0 +1,17 @@
|
||||
using Avalonia.Markup.Xaml; |
||||
using StabilityMatrix.Avalonia.Controls; |
||||
|
||||
namespace StabilityMatrix.Avalonia.Views.Dialogs; |
||||
|
||||
public partial class InstallerDialog : UserControlBase |
||||
{ |
||||
public InstallerDialog() |
||||
{ |
||||
InitializeComponent(); |
||||
} |
||||
|
||||
private void InitializeComponent() |
||||
{ |
||||
AvaloniaXamlLoader.Load(this); |
||||
} |
||||
} |
Loading…
Reference in new issue