Ionite
1 year ago
committed by
GitHub
29 changed files with 1702 additions and 510 deletions
@ -0,0 +1,408 @@ |
|||||||
|
// Modified from https://github.com/AvaloniaUI/AvaloniaAutoGrid |
||||||
|
/*The MIT License (MIT) |
||||||
|
|
||||||
|
Copyright (c) 2013 Charles Brown (carbonrobot) |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of |
||||||
|
this software and associated documentation files (the "Software"), to deal in |
||||||
|
the Software without restriction, including without limitation the rights to |
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so, |
||||||
|
subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all |
||||||
|
copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.ComponentModel; |
||||||
|
using System.Diagnostics.CodeAnalysis; |
||||||
|
using System.Linq; |
||||||
|
using Avalonia; |
||||||
|
using Avalonia.Controls; |
||||||
|
using Avalonia.Data; |
||||||
|
using Avalonia.Layout; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Controls; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Defines a flexible grid area that consists of columns and rows. |
||||||
|
/// Depending on the orientation, either the rows or the columns are auto-generated, |
||||||
|
/// and the children's position is set according to their index. |
||||||
|
/// </summary> |
||||||
|
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] |
||||||
|
public class AutoGrid : Grid |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Gets or sets the child horizontal alignment. |
||||||
|
/// </summary> |
||||||
|
/// <value>The child horizontal alignment.</value> |
||||||
|
[Category("Layout"), Description("Presets the horizontal alignment of all child controls")] |
||||||
|
public HorizontalAlignment? ChildHorizontalAlignment |
||||||
|
{ |
||||||
|
get => (HorizontalAlignment?)GetValue(ChildHorizontalAlignmentProperty); |
||||||
|
set => SetValue(ChildHorizontalAlignmentProperty, value); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets the child margin. |
||||||
|
/// </summary> |
||||||
|
/// <value>The child margin.</value> |
||||||
|
[Category("Layout"), Description("Presets the margin of all child controls")] |
||||||
|
public Thickness? ChildMargin |
||||||
|
{ |
||||||
|
get => (Thickness?)GetValue(ChildMarginProperty); |
||||||
|
set => SetValue(ChildMarginProperty, value); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets the child vertical alignment. |
||||||
|
/// </summary> |
||||||
|
/// <value>The child vertical alignment.</value> |
||||||
|
[Category("Layout"), Description("Presets the vertical alignment of all child controls")] |
||||||
|
public VerticalAlignment? ChildVerticalAlignment |
||||||
|
{ |
||||||
|
get => (VerticalAlignment?)GetValue(ChildVerticalAlignmentProperty); |
||||||
|
set => SetValue(ChildVerticalAlignmentProperty, value); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets the column count |
||||||
|
/// </summary> |
||||||
|
[Category("Layout"), Description("Defines a set number of columns")] |
||||||
|
public int ColumnCount |
||||||
|
{ |
||||||
|
get => (int)GetValue(ColumnCountProperty)!; |
||||||
|
set => SetValue(ColumnCountProperty, value); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets the fixed column width |
||||||
|
/// </summary> |
||||||
|
[Category("Layout"), Description("Presets the width of all columns set using the ColumnCount property")] |
||||||
|
|
||||||
|
public GridLength ColumnWidth |
||||||
|
{ |
||||||
|
get => (GridLength)GetValue(ColumnWidthProperty)!; |
||||||
|
set => SetValue(ColumnWidthProperty, value); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets a value indicating whether the children are automatically indexed. |
||||||
|
/// <remarks> |
||||||
|
/// The default is <c>true</c>. |
||||||
|
/// Note that if children are already indexed, setting this property to <c>false</c> will not remove their indices. |
||||||
|
/// </remarks> |
||||||
|
/// </summary> |
||||||
|
[Category("Layout"), Description("Set to false to disable the auto layout functionality")] |
||||||
|
public bool IsAutoIndexing |
||||||
|
{ |
||||||
|
get => (bool)GetValue(IsAutoIndexingProperty)!; |
||||||
|
set => SetValue(IsAutoIndexingProperty, value); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets the orientation. |
||||||
|
/// <remarks>The default is Vertical.</remarks> |
||||||
|
/// </summary> |
||||||
|
/// <value>The orientation.</value> |
||||||
|
[Category("Layout"), Description("Defines the directionality of the autolayout. Use vertical for a column first layout, horizontal for a row first layout.")] |
||||||
|
public Orientation Orientation |
||||||
|
{ |
||||||
|
get => (Orientation)GetValue(OrientationProperty)!; |
||||||
|
set => SetValue(OrientationProperty, value); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets the number of rows |
||||||
|
/// </summary> |
||||||
|
[Category("Layout"), Description("Defines a set number of rows")] |
||||||
|
public int RowCount |
||||||
|
{ |
||||||
|
get => (int)GetValue(RowCountProperty)!; |
||||||
|
set => SetValue(RowCountProperty, value); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets the fixed row height |
||||||
|
/// </summary> |
||||||
|
[Category("Layout"), Description("Presets the height of all rows set using the RowCount property")] |
||||||
|
public GridLength RowHeight |
||||||
|
{ |
||||||
|
get => (GridLength)GetValue(RowHeightProperty)!; |
||||||
|
set => SetValue(RowHeightProperty, value); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Handles the column count changed event |
||||||
|
/// </summary> |
||||||
|
public static void ColumnCountChanged(AvaloniaPropertyChangedEventArgs e) |
||||||
|
{ |
||||||
|
if ((int)e.NewValue! < 0) |
||||||
|
return; |
||||||
|
|
||||||
|
var grid = (AutoGrid)e.Sender; |
||||||
|
|
||||||
|
|
||||||
|
// look for an existing column definition for the height |
||||||
|
var width = grid.ColumnWidth; |
||||||
|
if (!grid.IsSet(ColumnWidthProperty) && grid.ColumnDefinitions.Count > 0) |
||||||
|
width = grid.ColumnDefinitions[0].Width; |
||||||
|
|
||||||
|
// clear and rebuild |
||||||
|
grid.ColumnDefinitions.Clear(); |
||||||
|
for (var i = 0; i < (int)e.NewValue; i++) |
||||||
|
grid.ColumnDefinitions.Add( |
||||||
|
new ColumnDefinition() { Width = width }); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Handle the fixed column width changed event |
||||||
|
/// </summary> |
||||||
|
public static void FixedColumnWidthChanged(AvaloniaPropertyChangedEventArgs e) |
||||||
|
{ |
||||||
|
var grid = (AutoGrid)e.Sender; |
||||||
|
|
||||||
|
// add a default column if missing |
||||||
|
if (grid.ColumnDefinitions.Count == 0) |
||||||
|
grid.ColumnDefinitions.Add(new ColumnDefinition()); |
||||||
|
|
||||||
|
// set all existing columns to this width |
||||||
|
foreach (var t in grid.ColumnDefinitions) |
||||||
|
t.Width = (GridLength)e.NewValue!; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Handle the fixed row height changed event |
||||||
|
/// </summary> |
||||||
|
public static void FixedRowHeightChanged(AvaloniaPropertyChangedEventArgs e) |
||||||
|
{ |
||||||
|
var grid = (AutoGrid)e.Sender; |
||||||
|
|
||||||
|
// add a default row if missing |
||||||
|
if (grid.RowDefinitions.Count == 0) |
||||||
|
grid.RowDefinitions.Add(new RowDefinition()); |
||||||
|
|
||||||
|
// set all existing rows to this height |
||||||
|
foreach (var t in grid.RowDefinitions) |
||||||
|
t.Height = (GridLength)e.NewValue!; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Handles the row count changed event |
||||||
|
/// </summary> |
||||||
|
public static void RowCountChanged(AvaloniaPropertyChangedEventArgs e) |
||||||
|
{ |
||||||
|
if ((int)e.NewValue! < 0) |
||||||
|
return; |
||||||
|
|
||||||
|
var grid = (AutoGrid)e.Sender; |
||||||
|
|
||||||
|
// look for an existing row to get the height |
||||||
|
var height = grid.RowHeight; |
||||||
|
if (!grid.IsSet(RowHeightProperty) && grid.RowDefinitions.Count > 0) |
||||||
|
height = grid.RowDefinitions[0].Height; |
||||||
|
|
||||||
|
// clear and rebuild |
||||||
|
grid.RowDefinitions.Clear(); |
||||||
|
for (var i = 0; i < (int)e.NewValue; i++) |
||||||
|
grid.RowDefinitions.Add( |
||||||
|
new RowDefinition() { Height = height }); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Called when [child horizontal alignment changed]. |
||||||
|
/// </summary> |
||||||
|
private static void OnChildHorizontalAlignmentChanged(AvaloniaPropertyChangedEventArgs e) |
||||||
|
{ |
||||||
|
var grid = (AutoGrid)e.Sender; |
||||||
|
foreach (var child in grid.Children) |
||||||
|
{ |
||||||
|
child.SetValue(HorizontalAlignmentProperty, |
||||||
|
grid.ChildHorizontalAlignment ?? AvaloniaProperty.UnsetValue); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Called when [child layout changed]. |
||||||
|
/// </summary> |
||||||
|
private static void OnChildMarginChanged(AvaloniaPropertyChangedEventArgs e) |
||||||
|
{ |
||||||
|
var grid = (AutoGrid)e.Sender; |
||||||
|
foreach (var child in grid.Children) |
||||||
|
{ |
||||||
|
child.SetValue(MarginProperty, grid.ChildMargin ?? AvaloniaProperty.UnsetValue); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Called when [child vertical alignment changed]. |
||||||
|
/// </summary> |
||||||
|
private static void OnChildVerticalAlignmentChanged(AvaloniaPropertyChangedEventArgs e) |
||||||
|
{ |
||||||
|
var grid = (AutoGrid)e.Sender; |
||||||
|
foreach (var child in grid.Children) |
||||||
|
{ |
||||||
|
child.SetValue(VerticalAlignmentProperty, grid.ChildVerticalAlignment ?? AvaloniaProperty.UnsetValue); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Apply child margins and layout effects such as alignment |
||||||
|
/// </summary> |
||||||
|
private void ApplyChildLayout(Control child) |
||||||
|
{ |
||||||
|
if (ChildMargin != null) |
||||||
|
{ |
||||||
|
child.SetValue(MarginProperty, ChildMargin.Value, BindingPriority.Template); |
||||||
|
} |
||||||
|
if (ChildHorizontalAlignment != null) |
||||||
|
{ |
||||||
|
child.SetValue(HorizontalAlignmentProperty, ChildHorizontalAlignment.Value, BindingPriority.Template); |
||||||
|
} |
||||||
|
if (ChildVerticalAlignment != null) |
||||||
|
{ |
||||||
|
child.SetValue(VerticalAlignmentProperty, ChildVerticalAlignment.Value, BindingPriority.Template); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Clamp a value to its maximum. |
||||||
|
/// </summary> |
||||||
|
private int Clamp(int value, int max) |
||||||
|
{ |
||||||
|
return (value > max) ? max : value; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Perform the grid layout of row and column indexes |
||||||
|
/// </summary> |
||||||
|
private void PerformLayout() |
||||||
|
{ |
||||||
|
var fillRowFirst = Orientation == Orientation.Horizontal; |
||||||
|
var rowCount = RowDefinitions.Count; |
||||||
|
var colCount = ColumnDefinitions.Count; |
||||||
|
|
||||||
|
if (rowCount == 0 || colCount == 0) |
||||||
|
return; |
||||||
|
|
||||||
|
var position = 0; |
||||||
|
var skip = new bool[rowCount, colCount]; |
||||||
|
foreach (var child in Children.OfType<Control>()) |
||||||
|
{ |
||||||
|
var childIsCollapsed = !child.IsVisible; |
||||||
|
if (IsAutoIndexing && !childIsCollapsed) |
||||||
|
{ |
||||||
|
if (fillRowFirst) |
||||||
|
{ |
||||||
|
var row = Clamp(position / colCount, rowCount - 1); |
||||||
|
var col = Clamp(position % colCount, colCount - 1); |
||||||
|
if (skip[row, col]) |
||||||
|
{ |
||||||
|
position++; |
||||||
|
row = (position / colCount); |
||||||
|
col = (position % colCount); |
||||||
|
} |
||||||
|
|
||||||
|
SetRow(child, row); |
||||||
|
SetColumn(child, col); |
||||||
|
position += GetColumnSpan(child); |
||||||
|
|
||||||
|
var offset = GetRowSpan(child) - 1; |
||||||
|
while (offset > 0) |
||||||
|
{ |
||||||
|
skip[row + offset--, col] = true; |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
var row = Clamp(position % rowCount, rowCount - 1); |
||||||
|
var col = Clamp(position / rowCount, colCount - 1); |
||||||
|
if (skip[row, col]) |
||||||
|
{ |
||||||
|
position++; |
||||||
|
row = position % rowCount; |
||||||
|
col = position / rowCount; |
||||||
|
} |
||||||
|
|
||||||
|
SetRow(child, row); |
||||||
|
SetColumn(child, col); |
||||||
|
position += GetRowSpan(child); |
||||||
|
|
||||||
|
var offset = GetColumnSpan(child) - 1; |
||||||
|
while (offset > 0) |
||||||
|
{ |
||||||
|
skip[row, col + offset--] = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ApplyChildLayout(child); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static readonly AvaloniaProperty<HorizontalAlignment?> ChildHorizontalAlignmentProperty = |
||||||
|
AvaloniaProperty.Register<AutoGrid, HorizontalAlignment?>("ChildHorizontalAlignment"); |
||||||
|
|
||||||
|
public static readonly AvaloniaProperty<Thickness?> ChildMarginProperty = |
||||||
|
AvaloniaProperty.Register<AutoGrid, Thickness?>("ChildMargin"); |
||||||
|
|
||||||
|
public static readonly AvaloniaProperty<VerticalAlignment?> ChildVerticalAlignmentProperty = |
||||||
|
AvaloniaProperty.Register<AutoGrid, VerticalAlignment?>("ChildVerticalAlignment"); |
||||||
|
|
||||||
|
public static readonly AvaloniaProperty<int> ColumnCountProperty = |
||||||
|
AvaloniaProperty.RegisterAttached<Control, int>("ColumnCount", typeof(AutoGrid), 1); |
||||||
|
|
||||||
|
public static readonly AvaloniaProperty<GridLength> ColumnWidthProperty = |
||||||
|
AvaloniaProperty.RegisterAttached<Control, GridLength>("ColumnWidth", typeof(AutoGrid), GridLength.Auto); |
||||||
|
|
||||||
|
public static readonly AvaloniaProperty<bool> IsAutoIndexingProperty = |
||||||
|
AvaloniaProperty.Register<AutoGrid, bool>("IsAutoIndexing", true); |
||||||
|
|
||||||
|
public static readonly AvaloniaProperty<Orientation> OrientationProperty = |
||||||
|
AvaloniaProperty.Register<AutoGrid, Orientation>("Orientation", Orientation.Vertical); |
||||||
|
|
||||||
|
public static readonly AvaloniaProperty<int> RowCountProperty = |
||||||
|
AvaloniaProperty.RegisterAttached<Control, int>("RowCount", typeof(AutoGrid), 1); |
||||||
|
|
||||||
|
public static readonly AvaloniaProperty<GridLength> RowHeightProperty = |
||||||
|
AvaloniaProperty.RegisterAttached<Control, GridLength>("RowHeight", typeof(AutoGrid), GridLength.Auto); |
||||||
|
|
||||||
|
static AutoGrid() |
||||||
|
{ |
||||||
|
AffectsMeasure<AutoGrid>(ChildHorizontalAlignmentProperty, ChildMarginProperty, |
||||||
|
ChildVerticalAlignmentProperty, ColumnCountProperty, ColumnWidthProperty, IsAutoIndexingProperty, OrientationProperty, |
||||||
|
RowHeightProperty); |
||||||
|
|
||||||
|
ChildHorizontalAlignmentProperty.Changed.Subscribe(OnChildHorizontalAlignmentChanged); |
||||||
|
ChildMarginProperty.Changed.Subscribe(OnChildMarginChanged); |
||||||
|
ChildVerticalAlignmentProperty.Changed.Subscribe(OnChildVerticalAlignmentChanged); |
||||||
|
ColumnCountProperty.Changed.Subscribe(ColumnCountChanged); |
||||||
|
RowCountProperty.Changed.Subscribe(RowCountChanged); |
||||||
|
ColumnWidthProperty.Changed.Subscribe(FixedColumnWidthChanged); |
||||||
|
RowHeightProperty.Changed.Subscribe(FixedRowHeightChanged); |
||||||
|
} |
||||||
|
|
||||||
|
#region Overrides |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Measures the children of a <see cref="T:System.Windows.Controls.Grid"/> in anticipation of arranging them during the <see cref="M:ArrangeOverride"/> pass. |
||||||
|
/// </summary> |
||||||
|
/// <param name="constraint">Indicates an upper limit size that should not be exceeded.</param> |
||||||
|
/// <returns> |
||||||
|
/// <see cref="Size"/> that represents the required size to arrange child content. |
||||||
|
/// </returns> |
||||||
|
protected override Size MeasureOverride(Size constraint) |
||||||
|
{ |
||||||
|
PerformLayout(); |
||||||
|
return base.MeasureOverride(constraint); |
||||||
|
} |
||||||
|
|
||||||
|
#endregion Overrides |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.Immutable; |
||||||
|
using System.Diagnostics.CodeAnalysis; |
||||||
|
using System.Globalization; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Languages; |
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] |
||||||
|
public static class Cultures |
||||||
|
{ |
||||||
|
public static CultureInfo Default { get; } = new("en-US"); |
||||||
|
|
||||||
|
public static CultureInfo Current => Resources.Culture; |
||||||
|
|
||||||
|
public static readonly Dictionary<string, CultureInfo> SupportedCulturesByCode = |
||||||
|
new Dictionary<string, CultureInfo> |
||||||
|
{ |
||||||
|
["en-US"] = Default, |
||||||
|
["ja-JP"] = new("ja-JP") |
||||||
|
}; |
||||||
|
|
||||||
|
public static IReadOnlyList<CultureInfo> SupportedCultures |
||||||
|
=> SupportedCulturesByCode.Values.ToImmutableList(); |
||||||
|
|
||||||
|
public static CultureInfo GetSupportedCultureOrDefault(string? cultureCode) |
||||||
|
{ |
||||||
|
if (cultureCode is null |
||||||
|
|| !SupportedCulturesByCode.TryGetValue(cultureCode, out var culture)) |
||||||
|
{ |
||||||
|
return Default; |
||||||
|
} |
||||||
|
|
||||||
|
return culture; |
||||||
|
} |
||||||
|
|
||||||
|
public static bool TrySetSupportedCulture(string? cultureCode) |
||||||
|
{ |
||||||
|
if (cultureCode is null |
||||||
|
|| !SupportedCulturesByCode.TryGetValue(cultureCode, out var culture)) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
Resources.Culture = culture; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public static bool TrySetSupportedCulture(CultureInfo? cultureInfo) |
||||||
|
{ |
||||||
|
return cultureInfo is not null && TrySetSupportedCulture(cultureInfo.Name); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,143 @@ |
|||||||
|
//------------------------------------------------------------------------------ |
||||||
|
// <auto-generated> |
||||||
|
// This code was generated by a tool. |
||||||
|
// |
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if |
||||||
|
// the code is regenerated. |
||||||
|
// </auto-generated> |
||||||
|
//------------------------------------------------------------------------------ |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Languages { |
||||||
|
using System; |
||||||
|
|
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc. |
||||||
|
/// </summary> |
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder |
||||||
|
// class via a tool like ResGen or Visual Studio. |
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen |
||||||
|
// with the /str option, or rebuild your VS project. |
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] |
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] |
||||||
|
public class Resources { |
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan; |
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture; |
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] |
||||||
|
internal Resources() { |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Returns the cached ResourceManager instance used by this class. |
||||||
|
/// </summary> |
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] |
||||||
|
public static global::System.Resources.ResourceManager ResourceManager { |
||||||
|
get { |
||||||
|
if (object.ReferenceEquals(resourceMan, null)) { |
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StabilityMatrix.Avalonia.Languages.Resources", typeof(Resources).Assembly); |
||||||
|
resourceMan = temp; |
||||||
|
} |
||||||
|
return resourceMan; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Overrides the current thread's CurrentUICulture property for all |
||||||
|
/// resource lookups using this strongly typed resource class. |
||||||
|
/// </summary> |
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] |
||||||
|
public static global::System.Globalization.CultureInfo Culture { |
||||||
|
get { |
||||||
|
return resourceCulture; |
||||||
|
} |
||||||
|
set { |
||||||
|
resourceCulture = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Looks up a localized string similar to Cancel. |
||||||
|
/// </summary> |
||||||
|
public static string Action_Cancel { |
||||||
|
get { |
||||||
|
return ResourceManager.GetString("Action_Cancel", resourceCulture); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Looks up a localized string similar to Launch. |
||||||
|
/// </summary> |
||||||
|
public static string Action_Launch { |
||||||
|
get { |
||||||
|
return ResourceManager.GetString("Action_Launch", resourceCulture); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Looks up a localized string similar to Quit. |
||||||
|
/// </summary> |
||||||
|
public static string Action_Quit { |
||||||
|
get { |
||||||
|
return ResourceManager.GetString("Action_Quit", resourceCulture); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Looks up a localized string similar to Relaunch. |
||||||
|
/// </summary> |
||||||
|
public static string Action_Relaunch { |
||||||
|
get { |
||||||
|
return ResourceManager.GetString("Action_Relaunch", resourceCulture); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Looks up a localized string similar to Relaunch Later. |
||||||
|
/// </summary> |
||||||
|
public static string Action_RelaunchLater { |
||||||
|
get { |
||||||
|
return ResourceManager.GetString("Action_RelaunchLater", resourceCulture); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Looks up a localized string similar to Save. |
||||||
|
/// </summary> |
||||||
|
public static string Action_Save { |
||||||
|
get { |
||||||
|
return ResourceManager.GetString("Action_Save", resourceCulture); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Looks up a localized string similar to Language. |
||||||
|
/// </summary> |
||||||
|
public static string Label_Language { |
||||||
|
get { |
||||||
|
return ResourceManager.GetString("Label_Language", resourceCulture); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Looks up a localized string similar to Relaunch Required. |
||||||
|
/// </summary> |
||||||
|
public static string Label_RelaunchRequired { |
||||||
|
get { |
||||||
|
return ResourceManager.GetString("Label_RelaunchRequired", resourceCulture); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Looks up a localized string similar to Relaunch is required for new language option to take effect. |
||||||
|
/// </summary> |
||||||
|
public static string Text_RelaunchRequiredToApplyLanguage { |
||||||
|
get { |
||||||
|
return ResourceManager.GetString("Text_RelaunchRequiredToApplyLanguage", resourceCulture); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
<root> |
||||||
|
<resheader name="resmimetype"> |
||||||
|
<value>text/microsoft-resx</value> |
||||||
|
</resheader> |
||||||
|
<resheader name="version"> |
||||||
|
<value>1.3</value> |
||||||
|
</resheader> |
||||||
|
<resheader name="reader"> |
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
||||||
|
</resheader> |
||||||
|
<resheader name="writer"> |
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
||||||
|
</resheader> |
||||||
|
<data name="Action_Save" xml:space="preserve"> |
||||||
|
<value>保存</value> |
||||||
|
</data> |
||||||
|
<data name="Action_Cancel" xml:space="preserve"> |
||||||
|
<value>戻る</value> |
||||||
|
</data> |
||||||
|
<data name="Label_Language" xml:space="preserve"> |
||||||
|
<value>言語</value> |
||||||
|
</data> |
||||||
|
</root> |
@ -0,0 +1,48 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
|
||||||
|
<root> |
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> |
||||||
|
<xsd:element name="root" msdata:IsDataSet="true"> |
||||||
|
|
||||||
|
</xsd:element> |
||||||
|
</xsd:schema> |
||||||
|
<resheader name="resmimetype"> |
||||||
|
<value>text/microsoft-resx</value> |
||||||
|
</resheader> |
||||||
|
<resheader name="version"> |
||||||
|
<value>1.3</value> |
||||||
|
</resheader> |
||||||
|
<resheader name="reader"> |
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
||||||
|
</resheader> |
||||||
|
<resheader name="writer"> |
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
||||||
|
</resheader> |
||||||
|
<data name="Action_Launch" xml:space="preserve"> |
||||||
|
<value>Launch</value> |
||||||
|
</data> |
||||||
|
<data name="Action_Quit" xml:space="preserve"> |
||||||
|
<value>Quit</value> |
||||||
|
</data> |
||||||
|
<data name="Action_Save" xml:space="preserve"> |
||||||
|
<value>Save</value> |
||||||
|
</data> |
||||||
|
<data name="Action_Cancel" xml:space="preserve"> |
||||||
|
<value>Cancel</value> |
||||||
|
</data> |
||||||
|
<data name="Label_Language" xml:space="preserve"> |
||||||
|
<value>Language</value> |
||||||
|
</data> |
||||||
|
<data name="Text_RelaunchRequiredToApplyLanguage" xml:space="preserve"> |
||||||
|
<value>Relaunch is required for new language option to take effect</value> |
||||||
|
</data> |
||||||
|
<data name="Action_Relaunch" xml:space="preserve"> |
||||||
|
<value>Relaunch</value> |
||||||
|
</data> |
||||||
|
<data name="Action_RelaunchLater" xml:space="preserve"> |
||||||
|
<value>Relaunch Later</value> |
||||||
|
</data> |
||||||
|
<data name="Label_RelaunchRequired" xml:space="preserve"> |
||||||
|
<value>Relaunch Required</value> |
||||||
|
</data> |
||||||
|
</root> |
@ -0,0 +1,221 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.Immutable; |
||||||
|
using System.Collections.ObjectModel; |
||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using System.Net.Http; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using AsyncAwaitBestPractices; |
||||||
|
using Avalonia.Controls; |
||||||
|
using Avalonia.Controls.Notifications; |
||||||
|
using AvaloniaEdit.Utils; |
||||||
|
using CommunityToolkit.Mvvm.ComponentModel; |
||||||
|
using FluentAvalonia.UI.Controls; |
||||||
|
using Microsoft.Extensions.Logging; |
||||||
|
using Refit; |
||||||
|
using StabilityMatrix.Avalonia.Controls; |
||||||
|
using StabilityMatrix.Avalonia.Services; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels.Base; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels.CheckpointManager; |
||||||
|
using StabilityMatrix.Avalonia.ViewModels.Dialogs; |
||||||
|
using StabilityMatrix.Avalonia.Views; |
||||||
|
using StabilityMatrix.Avalonia.Views.Dialogs; |
||||||
|
using StabilityMatrix.Core.Api; |
||||||
|
using StabilityMatrix.Core.Attributes; |
||||||
|
using StabilityMatrix.Core.Database; |
||||||
|
using StabilityMatrix.Core.Extensions; |
||||||
|
using StabilityMatrix.Core.Helper; |
||||||
|
using StabilityMatrix.Core.Models; |
||||||
|
using StabilityMatrix.Core.Models.Api; |
||||||
|
using StabilityMatrix.Core.Services; |
||||||
|
using Symbol = FluentIcons.Common.Symbol; |
||||||
|
using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.ViewModels; |
||||||
|
|
||||||
|
[View(typeof(NewCheckpointsPage))] |
||||||
|
public partial class NewCheckpointsPageViewModel : PageViewModelBase |
||||||
|
{ |
||||||
|
private readonly ILogger<NewCheckpointsPageViewModel> logger; |
||||||
|
private readonly ISettingsManager settingsManager; |
||||||
|
private readonly ILiteDbContext liteDbContext; |
||||||
|
private readonly ICivitApi civitApi; |
||||||
|
private readonly ServiceManager<ViewModelBase> dialogFactory; |
||||||
|
private readonly INotificationService notificationService; |
||||||
|
public override string Title => "Checkpoint Manager"; |
||||||
|
public override IconSource IconSource => new SymbolIconSource |
||||||
|
{Symbol = Symbol.Cellular5g, IsFilled = true}; |
||||||
|
|
||||||
|
public NewCheckpointsPageViewModel(ILogger<NewCheckpointsPageViewModel> logger, |
||||||
|
ISettingsManager settingsManager, ILiteDbContext liteDbContext, ICivitApi civitApi, |
||||||
|
ServiceManager<ViewModelBase> dialogFactory, INotificationService notificationService) |
||||||
|
{ |
||||||
|
this.logger = logger; |
||||||
|
this.settingsManager = settingsManager; |
||||||
|
this.liteDbContext = liteDbContext; |
||||||
|
this.civitApi = civitApi; |
||||||
|
this.dialogFactory = dialogFactory; |
||||||
|
this.notificationService = notificationService; |
||||||
|
} |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
[NotifyPropertyChangedFor(nameof(ConnectedCheckpoints))] |
||||||
|
[NotifyPropertyChangedFor(nameof(NonConnectedCheckpoints))] |
||||||
|
private ObservableCollection<CheckpointFile> allCheckpoints = new(); |
||||||
|
|
||||||
|
[ObservableProperty] |
||||||
|
private ObservableCollection<CivitModel> civitModels = new(); |
||||||
|
|
||||||
|
public ObservableCollection<CheckpointFile> ConnectedCheckpoints => new( |
||||||
|
AllCheckpoints.Where(x => x.IsConnectedModel) |
||||||
|
.OrderBy(x => x.ConnectedModel!.ModelName) |
||||||
|
.ThenBy(x => x.ModelType) |
||||||
|
.GroupBy(x => x.ConnectedModel!.ModelId) |
||||||
|
.Select(x => x.First())); |
||||||
|
|
||||||
|
public ObservableCollection<CheckpointFile> NonConnectedCheckpoints => new( |
||||||
|
AllCheckpoints.Where(x => !x.IsConnectedModel).OrderBy(x => x.ModelType)); |
||||||
|
|
||||||
|
public override async Task OnLoadedAsync() |
||||||
|
{ |
||||||
|
if (Design.IsDesignMode) return; |
||||||
|
|
||||||
|
var files = CheckpointFile.GetAllCheckpointFiles(settingsManager.ModelsDirectory); |
||||||
|
AllCheckpoints = new ObservableCollection<CheckpointFile>(files); |
||||||
|
|
||||||
|
var connectedModelIds = ConnectedCheckpoints.Select(x => x.ConnectedModel.ModelId); |
||||||
|
var modelRequest = new CivitModelsRequest |
||||||
|
{ |
||||||
|
CommaSeparatedModelIds = string.Join(',', connectedModelIds) |
||||||
|
}; |
||||||
|
|
||||||
|
// See if query is cached |
||||||
|
var cachedQuery = await liteDbContext.CivitModelQueryCache |
||||||
|
.IncludeAll() |
||||||
|
.FindByIdAsync(ObjectHash.GetMd5Guid(modelRequest)); |
||||||
|
|
||||||
|
// If cached, update model cards |
||||||
|
if (cachedQuery is not null) |
||||||
|
{ |
||||||
|
CivitModels = new ObservableCollection<CivitModel>(cachedQuery.Items); |
||||||
|
|
||||||
|
// Start remote query (background mode) |
||||||
|
// Skip when last query was less than 2 min ago |
||||||
|
var timeSinceCache = DateTimeOffset.UtcNow - cachedQuery.InsertedAt; |
||||||
|
if (timeSinceCache?.TotalMinutes >= 2) |
||||||
|
{ |
||||||
|
CivitQuery(modelRequest).SafeFireAndForget(); |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
await CivitQuery(modelRequest); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public async Task ShowVersionDialog(int modelId) |
||||||
|
{ |
||||||
|
var model = CivitModels.FirstOrDefault(m => m.Id == modelId); |
||||||
|
if (model == null) |
||||||
|
{ |
||||||
|
notificationService.Show(new Notification("Model has no versions available", |
||||||
|
"This model has no versions available for download", NotificationType.Warning)); |
||||||
|
return; |
||||||
|
} |
||||||
|
var versions = model.ModelVersions; |
||||||
|
if (versions is null || versions.Count == 0) |
||||||
|
{ |
||||||
|
notificationService.Show(new Notification("Model has no versions available", |
||||||
|
"This model has no versions available for download", NotificationType.Warning)); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var dialog = new BetterContentDialog |
||||||
|
{ |
||||||
|
Title = model.Name, |
||||||
|
IsPrimaryButtonEnabled = false, |
||||||
|
IsSecondaryButtonEnabled = false, |
||||||
|
IsFooterVisible = false, |
||||||
|
MaxDialogWidth = 750, |
||||||
|
}; |
||||||
|
|
||||||
|
var viewModel = dialogFactory.Get<SelectModelVersionViewModel>(); |
||||||
|
viewModel.Dialog = dialog; |
||||||
|
viewModel.Versions = versions.Select(version => |
||||||
|
new ModelVersionViewModel( |
||||||
|
settingsManager.Settings.InstalledModelHashes ?? new HashSet<string>(), version)) |
||||||
|
.ToImmutableArray(); |
||||||
|
viewModel.SelectedVersionViewModel = viewModel.Versions[0]; |
||||||
|
|
||||||
|
dialog.Content = new SelectModelVersionDialog |
||||||
|
{ |
||||||
|
DataContext = viewModel |
||||||
|
}; |
||||||
|
|
||||||
|
var result = await dialog.ShowAsync(); |
||||||
|
|
||||||
|
if (result != ContentDialogResult.Primary) |
||||||
|
{ |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var selectedVersion = viewModel?.SelectedVersionViewModel?.ModelVersion; |
||||||
|
var selectedFile = viewModel?.SelectedFile?.CivitFile; |
||||||
|
} |
||||||
|
|
||||||
|
private async Task CivitQuery(CivitModelsRequest request) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
var modelResponse = await civitApi.GetModels(request); |
||||||
|
var models = modelResponse.Items; |
||||||
|
// Filter out unknown model types and archived/taken-down models |
||||||
|
models = models.Where(m => m.Type.ConvertTo<SharedFolderType>() > 0) |
||||||
|
.Where(m => m.Mode == null).ToList(); |
||||||
|
|
||||||
|
// Database update calls will invoke `OnModelsUpdated` |
||||||
|
// Add to database |
||||||
|
await liteDbContext.UpsertCivitModelAsync(models); |
||||||
|
// Add as cache entry |
||||||
|
var cacheNew = await liteDbContext.UpsertCivitModelQueryCacheEntryAsync( |
||||||
|
new CivitModelQueryCacheEntry |
||||||
|
{ |
||||||
|
Id = ObjectHash.GetMd5Guid(request), |
||||||
|
InsertedAt = DateTimeOffset.UtcNow, |
||||||
|
Request = request, |
||||||
|
Items = models, |
||||||
|
Metadata = modelResponse.Metadata |
||||||
|
}); |
||||||
|
|
||||||
|
if (cacheNew) |
||||||
|
{ |
||||||
|
CivitModels = new ObservableCollection<CivitModel>(models); |
||||||
|
} |
||||||
|
} |
||||||
|
catch (OperationCanceledException) |
||||||
|
{ |
||||||
|
notificationService.Show(new Notification("Request to CivitAI timed out", |
||||||
|
"Could not check for checkpoint updates. Please try again later.")); |
||||||
|
logger.LogWarning($"CivitAI query timed out ({request})"); |
||||||
|
} |
||||||
|
catch (HttpRequestException e) |
||||||
|
{ |
||||||
|
notificationService.Show(new Notification("CivitAI can't be reached right now", |
||||||
|
"Could not check for checkpoint updates. Please try again later.")); |
||||||
|
logger.LogWarning(e, $"CivitAI query HttpRequestException ({request})"); |
||||||
|
} |
||||||
|
catch (ApiException e) |
||||||
|
{ |
||||||
|
notificationService.Show(new Notification("CivitAI can't be reached right now", |
||||||
|
"Could not check for checkpoint updates. Please try again later.")); |
||||||
|
logger.LogWarning(e, $"CivitAI query ApiException ({request})"); |
||||||
|
} |
||||||
|
catch (Exception e) |
||||||
|
{ |
||||||
|
notificationService.Show(new Notification("CivitAI can't be reached right now", |
||||||
|
$"Unknown exception during CivitAI query: {e.GetType().Name}")); |
||||||
|
logger.LogError(e, $"CivitAI query unknown exception ({request})"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,105 @@ |
|||||||
|
<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:viewModels="clr-namespace:StabilityMatrix.Avalonia.ViewModels" |
||||||
|
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" |
||||||
|
xmlns:checkpointManager="clr-namespace:StabilityMatrix.Avalonia.ViewModels.CheckpointManager" |
||||||
|
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" |
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||||
|
x:Class="StabilityMatrix.Avalonia.Views.NewCheckpointsPage" |
||||||
|
d:DataContext="{x:Static mocks:DesignData.NewCheckpointsPageViewModel}" |
||||||
|
x:CompileBindings="True" |
||||||
|
x:Name="ControlBase" |
||||||
|
x:DataType="viewModels:NewCheckpointsPageViewModel"> |
||||||
|
<ScrollViewer> |
||||||
|
<Grid RowDefinitions="Auto, Auto" Margin="8"> |
||||||
|
<TextBlock Text="Installed Checkpoints" |
||||||
|
FontSize="24" |
||||||
|
Margin="8"/> |
||||||
|
|
||||||
|
<ItemsRepeater Grid.Row="1" ItemsSource="{Binding ConnectedCheckpoints}"> |
||||||
|
<ItemsRepeater.Layout> |
||||||
|
<UniformGridLayout /> |
||||||
|
</ItemsRepeater.Layout> |
||||||
|
<ItemsRepeater.ItemTemplate> |
||||||
|
<DataTemplate DataType="{x:Type checkpointManager:CheckpointFile}"> |
||||||
|
<controls:Card |
||||||
|
Margin="8" |
||||||
|
MaxHeight="450" |
||||||
|
Width="300" |
||||||
|
CornerRadius="8"> |
||||||
|
<Grid RowDefinitions="Auto, Auto, Auto, Auto"> |
||||||
|
<TextBlock Grid.Row="0" |
||||||
|
Margin="0,0,0,8" |
||||||
|
Text="{Binding ConnectedModel.ModelName}" /> |
||||||
|
|
||||||
|
<controls:BetterAdvancedImage |
||||||
|
Grid.Row="1" |
||||||
|
Height="250" |
||||||
|
Stretch="UniformToFill" |
||||||
|
CornerRadius="8" |
||||||
|
Source="{Binding PreviewImagePath}" /> |
||||||
|
|
||||||
|
<Grid Grid.Row="1" |
||||||
|
Margin="8,8,0,0" |
||||||
|
ColumnDefinitions="Auto, Auto"> |
||||||
|
<controls:Card |
||||||
|
Grid.Column="0" |
||||||
|
Classes="info" |
||||||
|
Height="24" |
||||||
|
HorizontalAlignment="Left" |
||||||
|
Padding="4" |
||||||
|
Margin="0,0,4,0" |
||||||
|
VerticalAlignment="Top"> |
||||||
|
|
||||||
|
<TextBlock |
||||||
|
FontSize="11" |
||||||
|
FontWeight="Medium" |
||||||
|
HorizontalAlignment="Center" |
||||||
|
Text="{Binding ModelType}" |
||||||
|
VerticalAlignment="Center" /> |
||||||
|
</controls:Card> |
||||||
|
<controls:Card |
||||||
|
Grid.Column="1" |
||||||
|
Classes="info" |
||||||
|
Height="24" |
||||||
|
Margin="4,0" |
||||||
|
HorizontalAlignment="Left" |
||||||
|
Padding="4" |
||||||
|
VerticalAlignment="Top"> |
||||||
|
|
||||||
|
<TextBlock |
||||||
|
FontSize="11" |
||||||
|
FontWeight="Medium" |
||||||
|
HorizontalAlignment="Center" |
||||||
|
Text="{Binding ConnectedModel.BaseModel}" |
||||||
|
VerticalAlignment="Center" /> |
||||||
|
</controls:Card> |
||||||
|
</Grid> |
||||||
|
|
||||||
|
<Grid Grid.Row="2" |
||||||
|
Margin="0,16,0,0" |
||||||
|
ColumnDefinitions="*, *"> |
||||||
|
<Button Grid.Column="0" |
||||||
|
Content="Update" |
||||||
|
Classes="accent" |
||||||
|
Margin="0,0,4,0" |
||||||
|
HorizontalAlignment="Stretch" /> |
||||||
|
<Button Grid.Column="1" |
||||||
|
Margin="4,0,0,0" |
||||||
|
Content="All Versions" |
||||||
|
Classes="accent" |
||||||
|
Command="{Binding $parent[ItemsRepeater].((viewModels:NewCheckpointsPageViewModel)DataContext).ShowVersionDialog}" |
||||||
|
CommandParameter="{Binding ConnectedModel.ModelId}" |
||||||
|
HorizontalAlignment="Stretch" /> |
||||||
|
</Grid> |
||||||
|
|
||||||
|
</Grid> |
||||||
|
</controls:Card> |
||||||
|
</DataTemplate> |
||||||
|
</ItemsRepeater.ItemTemplate> |
||||||
|
</ItemsRepeater> |
||||||
|
</Grid> |
||||||
|
</ScrollViewer> |
||||||
|
</controls:UserControlBase> |
@ -0,0 +1,11 @@ |
|||||||
|
using StabilityMatrix.Avalonia.Controls; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Views; |
||||||
|
|
||||||
|
public partial class NewCheckpointsPage : UserControlBase |
||||||
|
{ |
||||||
|
public NewCheckpointsPage() |
||||||
|
{ |
||||||
|
InitializeComponent(); |
||||||
|
} |
||||||
|
} |
@ -1,429 +1,368 @@ |
|||||||
<controls:UserControlBase xmlns="https://github.com/avaloniaui" |
<controls:UserControlBase |
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
x:Class="StabilityMatrix.Avalonia.Views.SettingsPage" |
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
xmlns="https://github.com/avaloniaui" |
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||||
xmlns:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels" |
xmlns:avalonia="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia" |
||||||
xmlns:ui="using:FluentAvalonia.UI.Controls" |
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" |
||||||
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" |
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||||
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls" |
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||||
xmlns:avalonia="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia" |
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData" |
||||||
xmlns:icons="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia" |
xmlns:ui="using:FluentAvalonia.UI.Controls" |
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="700" |
xmlns:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels" |
||||||
x:DataType="vm:SettingsViewModel" |
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages" |
||||||
x:CompileBindings="True" |
d:DataContext="{x:Static mocks:DesignData.SettingsViewModel}" |
||||||
d:DataContext="{x:Static mocks:DesignData.SettingsViewModel}" |
d:DesignHeight="700" |
||||||
x:Class="StabilityMatrix.Avalonia.Views.SettingsPage"> |
d:DesignWidth="800" |
||||||
|
x:CompileBindings="True" |
||||||
<Grid> |
x:DataType="vm:SettingsViewModel" |
||||||
<ScrollViewer VerticalScrollBarVisibility="Auto"> |
mc:Ignorable="d"> |
||||||
<Grid RowDefinitions="Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto" |
|
||||||
Margin="8, 16"> |
|
||||||
<!-- Theme --> |
|
||||||
<Grid Grid.Row="0" RowDefinitions="auto,*"> |
|
||||||
<TextBlock |
|
||||||
FontWeight="Medium" |
|
||||||
Text="Appearance" |
|
||||||
Margin="0,0,0,8" /> |
|
||||||
<ui:SettingsExpander |
|
||||||
Grid.Row="1" |
|
||||||
Header="Theme" |
|
||||||
IconSource="WeatherMoon" |
|
||||||
Margin="8,0,8,4"> |
|
||||||
<ui:SettingsExpander.Footer> |
|
||||||
<ComboBox |
|
||||||
ItemsSource="{Binding AvailableThemes}" |
|
||||||
SelectedItem="{Binding SelectedTheme}" |
|
||||||
MinWidth="100"/> |
|
||||||
</ui:SettingsExpander.Footer> |
|
||||||
</ui:SettingsExpander> |
|
||||||
</Grid> |
|
||||||
|
|
||||||
<!-- TODO: Text2Image host port settings --> |
|
||||||
|
|
||||||
<!-- Checkpoints Manager Options --> |
|
||||||
<Grid Grid.Row="1" Margin="0,8,0,0" RowDefinitions="auto,*,Auto"> |
|
||||||
<TextBlock |
|
||||||
FontWeight="Medium" |
|
||||||
Text="Checkpoint Manager" |
|
||||||
Margin="0,0,0,8" /> |
|
||||||
<ui:SettingsExpander |
|
||||||
Grid.Row="1" |
|
||||||
IconSource="Folder" |
|
||||||
Header="Remove shared checkpoints directory symbolic links on shutdown" |
|
||||||
Description="Select this option if you're having problems moving Stability Matrix to another drive" |
|
||||||
Margin="8,0"> |
|
||||||
<ui:SettingsExpander.Footer> |
|
||||||
<CheckBox Margin="8" |
|
||||||
IsChecked="{Binding RemoveSymlinksOnShutdown}"/> |
|
||||||
</ui:SettingsExpander.Footer> |
|
||||||
</ui:SettingsExpander> |
|
||||||
<ui:SettingsExpander |
|
||||||
Grid.Row="2" |
|
||||||
IconSource="Refresh" |
|
||||||
Header="Reset Checkpoints Cache" |
|
||||||
Description="Rebuilds the installed checkpoints cache. Use if checkpoints are incorrectly labeled in the Model Browser." |
|
||||||
Margin="8, 4"> |
|
||||||
<ui:SettingsExpander.Footer> |
|
||||||
<Button Command="{Binding ResetCheckpointCache}" |
|
||||||
Content="Reset Checkpoints Cache"/> |
|
||||||
</ui:SettingsExpander.Footer> |
|
||||||
</ui:SettingsExpander> |
|
||||||
</Grid> |
|
||||||
|
|
||||||
<!-- Environment Options --> |
|
||||||
<Grid Grid.Row="2" Margin="0,8,0,0" RowDefinitions="Auto, Auto, Auto"> |
|
||||||
<TextBlock |
|
||||||
FontWeight="Medium" |
|
||||||
Text="Package Environment" |
|
||||||
Margin="0,0,0,8" /> |
|
||||||
|
|
||||||
<ui:SettingsExpander Grid.Row="1" |
|
||||||
Header="Environment Variables" |
|
||||||
IconSource="OtherUser" |
|
||||||
Margin="8,0"> |
|
||||||
<ui:SettingsExpander.Footer> |
|
||||||
<Button Content="Edit" |
|
||||||
Command="{Binding OpenEnvVarsDialogCommand}"/> |
|
||||||
</ui:SettingsExpander.Footer> |
|
||||||
</ui:SettingsExpander> |
|
||||||
|
|
||||||
<ui:SettingsExpander Grid.Row="2" |
|
||||||
Header="Embedded Python" |
|
||||||
Margin="8,4"> |
|
||||||
<ui:SettingsExpander.IconSource> |
|
||||||
<controls:FASymbolIconSource Symbol="fa-brands fa-python"/> |
|
||||||
</ui:SettingsExpander.IconSource> |
|
||||||
<ui:SettingsExpander.Footer> |
|
||||||
<StackPanel Orientation="Horizontal" Spacing="16"> |
|
||||||
<controls:ProgressRing |
|
||||||
IsEnabled="{Binding CheckPythonVersionCommand.IsRunning}" |
|
||||||
IsVisible="{Binding CheckPythonVersionCommand.IsRunning}" |
|
||||||
IsIndeterminate="True" |
|
||||||
BorderThickness="3"/> |
|
||||||
<Button Content="Check Version" Command="{Binding CheckPythonVersionCommand}"/> |
|
||||||
</StackPanel> |
|
||||||
</ui:SettingsExpander.Footer> |
|
||||||
</ui:SettingsExpander> |
|
||||||
</Grid> |
|
||||||
|
|
||||||
<!-- Inference UI --> |
|
||||||
<Grid Grid.Row="3" Margin="0,8,0,0" RowDefinitions="auto,*"> |
|
||||||
<TextBlock |
|
||||||
FontWeight="Medium" |
|
||||||
Text="Inference UI" |
|
||||||
Margin="0,0,0,8" /> |
|
||||||
<!-- Auto Completion --> |
|
||||||
<ui:SettingsExpander Grid.Row="1" |
|
||||||
Header="Prompt Auto Completion" |
|
||||||
Margin="8,0,8,4"> |
|
||||||
<ui:SettingsExpander.IconSource> |
|
||||||
<controls:FASymbolIconSource Symbol="fa-solid fa-wand-magic-sparkles"/> |
|
||||||
</ui:SettingsExpander.IconSource> |
|
||||||
|
|
||||||
<!-- Enable toggle --> |
|
||||||
<ui:SettingsExpanderItem Content="Enable"> |
|
||||||
<ui:SettingsExpanderItem.Footer> |
|
||||||
<ToggleSwitch |
|
||||||
IsChecked="{Binding IsPromptCompletionEnabled}" /> |
|
||||||
</ui:SettingsExpanderItem.Footer> |
|
||||||
</ui:SettingsExpanderItem> |
|
||||||
|
|
||||||
<!-- Tag csv selection --> |
|
||||||
<ui:SettingsExpanderItem Content="Tag Source" |
|
||||||
IconSource="Tag" |
|
||||||
IsEnabled="{Binding IsPromptCompletionEnabled}" |
|
||||||
Description="Tags to use for completion in .csv format (Compatible with a1111-sd-webui-tagcomplete)"> |
|
||||||
<ui:SettingsExpanderItem.Footer> |
|
||||||
<ui:FAComboBox |
|
||||||
ItemsSource="{Binding AvailableTagCompletionCsvs}" |
|
||||||
SelectedItem="{Binding SelectedTagCompletionCsv}"/> |
|
||||||
</ui:SettingsExpanderItem.Footer> |
|
||||||
</ui:SettingsExpanderItem> |
|
||||||
|
|
||||||
<!-- Tag csv import --> |
|
||||||
<ui:SettingsExpanderItem Content="Import Tag Source .csv" |
|
||||||
IconSource="Add" |
|
||||||
IsEnabled="{Binding IsPromptCompletionEnabled}"> |
|
||||||
<ui:SettingsExpanderItem.Footer> |
|
||||||
<Button |
|
||||||
Command="{Binding ImportTagCsvCommand}" |
|
||||||
Content="Import"/> |
|
||||||
</ui:SettingsExpanderItem.Footer> |
|
||||||
</ui:SettingsExpanderItem> |
|
||||||
|
|
||||||
<!-- Remove underscores --> |
|
||||||
<ui:SettingsExpanderItem |
|
||||||
Content="Replace underscores with spaces when inserting completions" |
|
||||||
IconSource="Underline" |
|
||||||
IsEnabled="{Binding IsPromptCompletionEnabled}"> |
|
||||||
<ui:SettingsExpanderItem.Footer> |
|
||||||
<CheckBox Margin="8" |
|
||||||
IsChecked="{Binding IsCompletionRemoveUnderscoresEnabled}"/> |
|
||||||
</ui:SettingsExpanderItem.Footer> |
|
||||||
</ui:SettingsExpanderItem> |
|
||||||
</ui:SettingsExpander> |
|
||||||
</Grid> |
|
||||||
|
|
||||||
<!-- Integrations --> |
|
||||||
<Grid Grid.Row="4" Margin="0,8,0,0" RowDefinitions="auto,*"> |
|
||||||
<TextBlock |
|
||||||
FontWeight="Medium" |
|
||||||
Text="Integrations" |
|
||||||
Margin="0,0,0,8" /> |
|
||||||
<ui:SettingsExpander Grid.Row="1" |
|
||||||
Header="Discord Rich Presence" |
|
||||||
Margin="8,0,8,4"> |
|
||||||
<ui:SettingsExpander.IconSource> |
|
||||||
<controls:FASymbolIconSource Symbol="fa-brands fa-discord"/> |
|
||||||
</ui:SettingsExpander.IconSource> |
|
||||||
<ui:SettingsExpander.Footer> |
|
||||||
<ToggleSwitch |
|
||||||
IsChecked="{Binding IsDiscordRichPresenceEnabled}" /> |
|
||||||
</ui:SettingsExpander.Footer> |
|
||||||
</ui:SettingsExpander> |
|
||||||
</Grid> |
|
||||||
|
|
||||||
<!-- System Options --> |
|
||||||
<Grid Grid.Row="5" Margin="0,8,0,0" RowDefinitions="auto,*,*"> |
|
||||||
<TextBlock |
|
||||||
FontWeight="Medium" |
|
||||||
Text="System" |
|
||||||
Margin="0,0,0,8" /> |
|
||||||
<ui:SettingsExpander |
|
||||||
Grid.Row="1" |
|
||||||
ToolTip.Tip="{OnPlatform Default='Only available on Windows', Windows={x:Null}}" |
|
||||||
Header="Add Stability Matrix to the Start Menu" |
|
||||||
Description="Uses the current app location, you can run this again if you move the app" |
|
||||||
IconSource="StarAdd" |
|
||||||
Margin="8,0,8,4"> |
|
||||||
<ui:SettingsExpander.Footer> |
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8"> |
|
||||||
<controls:ProgressRing |
|
||||||
IsIndeterminate="True" |
|
||||||
IsEnabled="{Binding IsVisible, RelativeSource={RelativeSource Self}}" |
|
||||||
BorderThickness="3"> |
|
||||||
<controls:ProgressRing.IsVisible> |
|
||||||
<MultiBinding Converter="{x:Static BoolConverters.Or}"> |
|
||||||
<Binding Path="AddToStartMenuCommand.IsRunning"/> |
|
||||||
<Binding Path="AddToGlobalStartMenuCommand.IsRunning"/> |
|
||||||
</MultiBinding> |
|
||||||
</controls:ProgressRing.IsVisible> |
|
||||||
</controls:ProgressRing> |
|
||||||
|
|
||||||
<SplitButton |
|
||||||
Command="{Binding AddToStartMenuCommand}" |
|
||||||
IsEnabled="{OnPlatform Default=False, Windows=True}" |
|
||||||
Content="Add for Current User"> |
|
||||||
<SplitButton.Flyout> |
|
||||||
<ui:FAMenuFlyout Placement="Bottom"> |
|
||||||
<ui:MenuFlyoutItem |
|
||||||
Command="{Binding AddToGlobalStartMenuCommand}" |
|
||||||
IconSource="Admin" |
|
||||||
Text="Add for All Users"/> |
|
||||||
</ui:FAMenuFlyout> |
|
||||||
</SplitButton.Flyout> |
|
||||||
</SplitButton> |
|
||||||
</StackPanel> |
|
||||||
</ui:SettingsExpander.Footer> |
|
||||||
</ui:SettingsExpander> |
|
||||||
<ui:SettingsExpander Grid.Row="2" |
|
||||||
Header="Select New Data Directory" |
|
||||||
Description="Does not move existing data" |
|
||||||
IconSource="MoveToFolder" |
|
||||||
Margin="8,0"> |
|
||||||
<ui:SettingsExpander.Footer> |
|
||||||
<Button Command="{Binding PickNewDataDirectory}"> |
|
||||||
<Grid ColumnDefinitions="Auto, Auto"> |
|
||||||
<avalonia:Icon Grid.Row="0" Value="fa-solid fa-folder-open" |
|
||||||
Margin="0,0,8,0" |
|
||||||
VerticalAlignment="Center" /> |
|
||||||
<TextBlock Grid.Column="1" |
|
||||||
VerticalAlignment="Center" |
|
||||||
Text="Select Directory"/> |
|
||||||
</Grid> |
|
||||||
</Button> |
|
||||||
</ui:SettingsExpander.Footer> |
|
||||||
</ui:SettingsExpander> |
|
||||||
</Grid> |
|
||||||
|
|
||||||
<!-- Debug Options --> |
|
||||||
<Grid Grid.Row="6" RowDefinitions="auto,*" |
|
||||||
Margin="0,8,0,0" |
|
||||||
IsVisible="{Binding SharedState.IsDebugMode}" > |
|
||||||
<TextBlock |
|
||||||
FontWeight="Medium" |
|
||||||
Text="Debug Options" |
|
||||||
Margin="0,0,0,8" /> |
|
||||||
<ui:SettingsExpander |
|
||||||
Grid.Row="1" |
|
||||||
IconSource="Code" |
|
||||||
Command="{Binding LoadDebugInfo}" |
|
||||||
Header="Debug Options" |
|
||||||
Margin="8, 0,8,0"> |
|
||||||
|
|
||||||
<ui:SettingsExpanderItem Description="Paths" IconSource="Folder" |
|
||||||
Margin="4, 0"> |
|
||||||
<SelectableTextBlock Text="{Binding DebugPaths}" |
|
||||||
Foreground="{DynamicResource TextControlPlaceholderForeground}" |
|
||||||
TextWrapping="WrapWithOverflow" /> |
|
||||||
</ui:SettingsExpanderItem> |
|
||||||
|
|
||||||
<ui:SettingsExpanderItem Description="Compat Info" IconSource="StarFilled" |
<ScrollViewer VerticalScrollBarVisibility="Auto"> |
||||||
Margin="4,0"> |
<StackPanel Margin="8,16" Spacing="8"> |
||||||
<SelectableTextBlock Text="{Binding DebugCompatInfo}" |
<!-- Theme --> |
||||||
Foreground="{DynamicResource TextControlPlaceholderForeground}" |
<Grid RowDefinitions="Auto,*,*"> |
||||||
TextWrapping="WrapWithOverflow" /> |
<TextBlock |
||||||
</ui:SettingsExpanderItem> |
Margin="0,0,0,8" |
||||||
|
FontWeight="Medium" |
||||||
<ui:SettingsExpanderItem Description="GPU Info" IconSource="FullScreenMaximize" |
Text="Appearance" /> |
||||||
Margin="4,0"> |
<ui:SettingsExpander |
||||||
<SelectableTextBlock Text="{Binding DebugGpuInfo}" |
Grid.Row="1" |
||||||
Foreground="{DynamicResource TextControlPlaceholderForeground}" |
Margin="8,0,8,4" |
||||||
TextWrapping="WrapWithOverflow" /> |
Header="Theme" |
||||||
</ui:SettingsExpanderItem> |
IconSource="WeatherMoon"> |
||||||
|
<ui:SettingsExpander.Footer> |
||||||
|
<ComboBox |
||||||
|
MinWidth="100" |
||||||
|
ItemsSource="{Binding AvailableThemes}" |
||||||
|
SelectedItem="{Binding SelectedTheme}" /> |
||||||
|
</ui:SettingsExpander.Footer> |
||||||
|
</ui:SettingsExpander> |
||||||
|
<ui:SettingsExpander |
||||||
|
Grid.Row="2" |
||||||
|
IsVisible="{Binding SharedState.IsDebugMode}" |
||||||
|
Margin="8,0,8,4" |
||||||
|
Header="{x:Static lang:Resources.Label_Language}" |
||||||
|
IconSource="Character"> |
||||||
|
<ui:SettingsExpander.Footer> |
||||||
|
<ComboBox |
||||||
|
MinWidth="100" |
||||||
|
ItemsSource="{Binding AvailableLanguages}" |
||||||
|
DisplayMemberBinding="{Binding NativeName}" |
||||||
|
SelectedItem="{Binding SelectedLanguage}" /> |
||||||
|
</ui:SettingsExpander.Footer> |
||||||
|
</ui:SettingsExpander> |
||||||
|
</Grid> |
||||||
|
|
||||||
<ui:SettingsExpanderItem Content="Animation Scale" IconSource="Clock" |
<!-- Checkpoints Manager Options --> |
||||||
Description="Lower values = faster animations. 0x means animations are instant." |
<Grid RowDefinitions="auto,*,Auto"> |
||||||
Margin="4,0"> |
<TextBlock |
||||||
<ui:SettingsExpanderItem.Footer> |
Margin="0,0,0,8" |
||||||
<ComboBox ItemsSource="{Binding AnimationScaleOptions}" |
FontWeight="Medium" |
||||||
SelectedItem="{Binding SelectedAnimationScale}"> |
Text="Checkpoint Manager" /> |
||||||
<ComboBox.ItemTemplate> |
<ui:SettingsExpander |
||||||
<DataTemplate> |
Grid.Row="1" |
||||||
<TextBlock> |
Margin="8,0" |
||||||
<Run Text="{Binding }"/><Run Text="x"/> |
Description="Select this option if you're having problems moving Stability Matrix to another drive" |
||||||
</TextBlock> |
Header="Remove shared checkpoints directory symbolic links on shutdown" |
||||||
</DataTemplate> |
IconSource="Folder"> |
||||||
</ComboBox.ItemTemplate> |
<ui:SettingsExpander.Footer> |
||||||
</ComboBox> |
<CheckBox Margin="8" IsChecked="{Binding RemoveSymlinksOnShutdown}" /> |
||||||
</ui:SettingsExpanderItem.Footer> |
</ui:SettingsExpander.Footer> |
||||||
</ui:SettingsExpanderItem> |
</ui:SettingsExpander> |
||||||
|
<ui:SettingsExpander |
||||||
<ui:SettingsExpanderItem Content="Notification" IconSource="CommentAdd" |
Grid.Row="2" |
||||||
Margin="4,0"> |
Margin="8,4" |
||||||
<ui:SettingsExpanderItem.Footer> |
Description="Rebuilds the installed checkpoints cache. Use if checkpoints are incorrectly labeled in the Model Browser." |
||||||
<Button |
Header="Reset Checkpoints Cache" |
||||||
Command="{Binding DebugNotificationCommand}" |
IconSource="Refresh"> |
||||||
Content="New Notification"/> |
<ui:SettingsExpander.Footer> |
||||||
</ui:SettingsExpanderItem.Footer> |
<Button Command="{Binding ResetCheckpointCache}" Content="Reset Checkpoints Cache" /> |
||||||
</ui:SettingsExpanderItem> |
</ui:SettingsExpander.Footer> |
||||||
|
</ui:SettingsExpander> |
||||||
<ui:SettingsExpanderItem Content="Content Dialog" IconSource="NewWindow" |
</Grid> |
||||||
Margin="4,0"> |
|
||||||
<ui:SettingsExpanderItem.Footer> |
<!-- Environment Options --> |
||||||
<Button |
<Grid RowDefinitions="Auto, Auto, Auto"> |
||||||
Command="{Binding DebugContentDialogCommand}" |
<TextBlock |
||||||
Content="Show Dialog"/> |
Margin="0,0,0,8" |
||||||
</ui:SettingsExpanderItem.Footer> |
FontWeight="Medium" |
||||||
</ui:SettingsExpanderItem> |
Text="Package Environment" /> |
||||||
|
|
||||||
<ui:SettingsExpanderItem Content="Exceptions" IconSource="Flag" |
<ui:SettingsExpander |
||||||
Margin="4,0"> |
Grid.Row="1" |
||||||
<ui:SettingsExpanderItem.Footer> |
Margin="8,0" |
||||||
<Button |
Header="Environment Variables" |
||||||
Command="{Binding DebugThrowExceptionCommand}" |
IconSource="OtherUser"> |
||||||
Content="Unhandled Exception"/> |
<ui:SettingsExpander.Footer> |
||||||
</ui:SettingsExpanderItem.Footer> |
<Button Command="{Binding OpenEnvVarsDialogCommand}" Content="Edit" /> |
||||||
</ui:SettingsExpanderItem> |
</ui:SettingsExpander.Footer> |
||||||
|
</ui:SettingsExpander> |
||||||
<ui:SettingsExpanderItem Content="Download Manager tests" IconSource="Flag" |
|
||||||
Margin="4,0,4,4"> |
<ui:SettingsExpander |
||||||
<ui:SettingsExpanderItem.Footer> |
Grid.Row="2" |
||||||
<SplitButton |
Margin="8,4" |
||||||
Margin="0, 8" |
Header="Embedded Python"> |
||||||
Command="{Binding DebugThrowExceptionCommand}" |
<ui:SettingsExpander.IconSource> |
||||||
Content="Command Exception"> |
<controls:FASymbolIconSource Symbol="fa-brands fa-python" /> |
||||||
|
</ui:SettingsExpander.IconSource> |
||||||
<SplitButton.Flyout> |
<ui:SettingsExpander.Footer> |
||||||
<ui:FAMenuFlyout> |
<StackPanel Orientation="Horizontal" Spacing="16"> |
||||||
|
<controls:ProgressRing |
||||||
<ui:MenuFlyoutItem |
BorderThickness="3" |
||||||
Text="Async Command Exception" |
IsEnabled="{Binding CheckPythonVersionCommand.IsRunning}" |
||||||
Command="{Binding DebugThrowAsyncExceptionCommand}"/> |
IsIndeterminate="True" |
||||||
|
IsVisible="{Binding CheckPythonVersionCommand.IsRunning}" /> |
||||||
</ui:FAMenuFlyout> |
<Button Command="{Binding CheckPythonVersionCommand}" Content="Check Version" /> |
||||||
</SplitButton.Flyout> |
</StackPanel> |
||||||
|
</ui:SettingsExpander.Footer> |
||||||
</SplitButton> |
</ui:SettingsExpander> |
||||||
</ui:SettingsExpanderItem.Footer> |
</Grid> |
||||||
</ui:SettingsExpanderItem> |
|
||||||
|
<!-- Integrations --> |
||||||
<ui:SettingsExpanderItem Content="Image Processor Demos" IconSource="ImageCopy"> |
<Grid RowDefinitions="auto,*"> |
||||||
<ui:SettingsExpanderItem.Footer> |
<TextBlock |
||||||
<Button |
Margin="0,0,0,8" |
||||||
Command="{Binding DebugMakeImageGridCommand}" |
FontWeight="Medium" |
||||||
Content="Make Image Grid from Files"/> |
Text="Integrations" /> |
||||||
</ui:SettingsExpanderItem.Footer> |
<ui:SettingsExpander |
||||||
</ui:SettingsExpanderItem> |
Grid.Row="1" |
||||||
|
Margin="8,0,8,4" |
||||||
<ui:SettingsExpanderItem Content="Load Completion Source" IconSource="ImageCopy"> |
Header="Discord Rich Presence"> |
||||||
<ui:SettingsExpanderItem.Footer> |
<ui:SettingsExpander.IconSource> |
||||||
<Button |
<controls:FASymbolIconSource Symbol="fa-brands fa-discord" /> |
||||||
Command="{Binding DebugLoadCompletionCsvCommand}" |
</ui:SettingsExpander.IconSource> |
||||||
Content="Load CSV File"/> |
<ui:SettingsExpander.Footer> |
||||||
</ui:SettingsExpanderItem.Footer> |
<ToggleSwitch IsChecked="{Binding IsDiscordRichPresenceEnabled}" /> |
||||||
</ui:SettingsExpanderItem> |
</ui:SettingsExpander.Footer> |
||||||
|
</ui:SettingsExpander> |
||||||
</ui:SettingsExpander> |
</Grid> |
||||||
</Grid> |
|
||||||
|
<!-- System Options --> |
||||||
<!-- TODO: Python card --> |
<Grid RowDefinitions="auto, auto, auto"> |
||||||
|
<TextBlock |
||||||
<!-- TODO: Debug card --> |
Margin="0,0,0,8" |
||||||
|
FontWeight="Medium" |
||||||
<!-- TODO: Directories card --> |
Text="System" /> |
||||||
|
<ui:SettingsExpander |
||||||
<Grid Grid.Row="7" RowDefinitions="auto,*" Margin="0,4,0,0"> |
Grid.Row="1" |
||||||
<StackPanel |
Margin="8,0,8,4" |
||||||
Grid.Row="1" |
Description="Uses the current app location, you can run this again if you move the app" |
||||||
HorizontalAlignment="Left" |
Header="Add Stability Matrix to the Start Menu" |
||||||
Orientation="Vertical"> |
IconSource="StarAdd" |
||||||
<TextBlock |
ToolTip.Tip="{OnPlatform Default='Only available on Windows', |
||||||
FontSize="15" |
Windows={x:Null}}"> |
||||||
FontWeight="Bold" |
<ui:SettingsExpander.Footer> |
||||||
Margin="0,8" |
<StackPanel Orientation="Horizontal" Spacing="8"> |
||||||
Text="About" /> |
<controls:ProgressRing |
||||||
<Image |
BorderThickness="3" |
||||||
Height="112" |
IsEnabled="{Binding IsVisible, RelativeSource={RelativeSource Self}}" |
||||||
HorizontalAlignment="Left" |
IsIndeterminate="True"> |
||||||
Margin="8" |
<controls:ProgressRing.IsVisible> |
||||||
Source="/Assets/Icon.png" |
<MultiBinding Converter="{x:Static BoolConverters.Or}"> |
||||||
Width="112" /> |
<Binding Path="AddToStartMenuCommand.IsRunning" /> |
||||||
<TextBlock |
<Binding Path="AddToGlobalStartMenuCommand.IsRunning" /> |
||||||
FontWeight="Medium" |
</MultiBinding> |
||||||
Margin="8" |
</controls:ProgressRing.IsVisible> |
||||||
Text="Stability Matrix" /> |
</controls:ProgressRing> |
||||||
<Panel> |
|
||||||
<Button |
<SplitButton |
||||||
Name="VersionButton" |
Command="{Binding AddToStartMenuCommand}" |
||||||
Command="{Binding OnVersionClick}" |
Content="Add for Current User" |
||||||
Classes="transparent" |
IsEnabled="{OnPlatform Default=False, |
||||||
BorderThickness="0" |
Windows=True}"> |
||||||
Content="{Binding AppVersion}" |
<SplitButton.Flyout> |
||||||
Margin="8,0,8,8" |
<ui:FAMenuFlyout Placement="Bottom"> |
||||||
Padding="2,0,2,0"/> |
<ui:MenuFlyoutItem |
||||||
<ui:TeachingTip |
Command="{Binding AddToGlobalStartMenuCommand}" |
||||||
PreferredPlacement="RightTop" |
IconSource="Admin" |
||||||
Target="{Binding #VersionButton}" |
Text="Add for All Users" /> |
||||||
IsOpen="{Binding IsVersionTapTeachingTipOpen}" |
</ui:FAMenuFlyout> |
||||||
Title="{Binding VersionFlyoutText}"/> |
</SplitButton.Flyout> |
||||||
</Panel> |
</SplitButton> |
||||||
|
|
||||||
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal"> |
|
||||||
<Button |
|
||||||
Content="License and Open Source Notices" |
|
||||||
Command="{Binding ShowLicensesDialogCommand}" |
|
||||||
HorizontalAlignment="Left" |
|
||||||
Margin="8" /> |
|
||||||
</StackPanel> |
|
||||||
</StackPanel> |
</StackPanel> |
||||||
</Grid> |
</ui:SettingsExpander.Footer> |
||||||
|
</ui:SettingsExpander> |
||||||
<!-- Extra space at the bottom --> |
<ui:SettingsExpander |
||||||
<Panel Grid.Row="8" Margin="0,0,0,16" /> |
Grid.Row="2" |
||||||
|
Margin="8,0" |
||||||
|
Description="Does not move existing data" |
||||||
|
Header="Select New Data Directory" |
||||||
|
IconSource="MoveToFolder"> |
||||||
|
<ui:SettingsExpander.Footer> |
||||||
|
<Button Command="{Binding PickNewDataDirectory}"> |
||||||
|
<Grid ColumnDefinitions="Auto, Auto"> |
||||||
|
<avalonia:Icon |
||||||
|
Grid.Row="0" |
||||||
|
Margin="0,0,8,0" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Value="fa-solid fa-folder-open" /> |
||||||
|
<TextBlock |
||||||
|
Grid.Column="1" |
||||||
|
VerticalAlignment="Center" |
||||||
|
Text="Select Directory" /> |
||||||
|
</Grid> |
||||||
|
</Button> |
||||||
|
</ui:SettingsExpander.Footer> |
||||||
|
</ui:SettingsExpander> |
||||||
</Grid> |
</Grid> |
||||||
</ScrollViewer> |
|
||||||
</Grid> |
<!-- Debug Options --> |
||||||
|
<Grid |
||||||
|
IsVisible="{Binding SharedState.IsDebugMode}" |
||||||
|
RowDefinitions="auto,*"> |
||||||
|
<TextBlock |
||||||
|
Margin="0,0,0,8" |
||||||
|
FontWeight="Medium" |
||||||
|
Text="Debug Options" /> |
||||||
|
<ui:SettingsExpander |
||||||
|
Grid.Row="1" |
||||||
|
Margin="8,0,8,0" |
||||||
|
Command="{Binding LoadDebugInfo}" |
||||||
|
Header="Debug Options" |
||||||
|
IconSource="Code"> |
||||||
|
|
||||||
|
<ui:SettingsExpanderItem |
||||||
|
Margin="4,0" |
||||||
|
Description="Paths" |
||||||
|
IconSource="Folder"> |
||||||
|
<SelectableTextBlock |
||||||
|
Foreground="{DynamicResource TextControlPlaceholderForeground}" |
||||||
|
Text="{Binding DebugPaths}" |
||||||
|
TextWrapping="WrapWithOverflow" /> |
||||||
|
</ui:SettingsExpanderItem> |
||||||
|
|
||||||
|
<ui:SettingsExpanderItem |
||||||
|
Margin="4,0" |
||||||
|
Description="Compat Info" |
||||||
|
IconSource="StarFilled"> |
||||||
|
<SelectableTextBlock |
||||||
|
Foreground="{DynamicResource TextControlPlaceholderForeground}" |
||||||
|
Text="{Binding DebugCompatInfo}" |
||||||
|
TextWrapping="WrapWithOverflow" /> |
||||||
|
</ui:SettingsExpanderItem> |
||||||
|
|
||||||
|
<ui:SettingsExpanderItem |
||||||
|
Margin="4,0" |
||||||
|
Description="GPU Info" |
||||||
|
IconSource="FullScreenMaximize"> |
||||||
|
<SelectableTextBlock |
||||||
|
Foreground="{DynamicResource TextControlPlaceholderForeground}" |
||||||
|
Text="{Binding DebugGpuInfo}" |
||||||
|
TextWrapping="WrapWithOverflow" /> |
||||||
|
</ui:SettingsExpanderItem> |
||||||
|
|
||||||
|
<ui:SettingsExpanderItem |
||||||
|
Margin="4,0" |
||||||
|
Content="Animation Scale" |
||||||
|
Description="Lower values = faster animations. 0x means animations are instant." |
||||||
|
IconSource="Clock"> |
||||||
|
<ui:SettingsExpanderItem.Footer> |
||||||
|
<ComboBox ItemsSource="{Binding AnimationScaleOptions}" SelectedItem="{Binding SelectedAnimationScale}"> |
||||||
|
<ComboBox.ItemTemplate> |
||||||
|
<DataTemplate> |
||||||
|
<TextBlock> |
||||||
|
<Run Text="{Binding}" /><Run Text="x" /> |
||||||
|
</TextBlock> |
||||||
|
</DataTemplate> |
||||||
|
</ComboBox.ItemTemplate> |
||||||
|
</ComboBox> |
||||||
|
</ui:SettingsExpanderItem.Footer> |
||||||
|
</ui:SettingsExpanderItem> |
||||||
|
|
||||||
|
<ui:SettingsExpanderItem |
||||||
|
Margin="4,0" |
||||||
|
Content="Notification" |
||||||
|
IconSource="CommentAdd"> |
||||||
|
<ui:SettingsExpanderItem.Footer> |
||||||
|
<Button Command="{Binding DebugNotificationCommand}" Content="New Notification" /> |
||||||
|
</ui:SettingsExpanderItem.Footer> |
||||||
|
</ui:SettingsExpanderItem> |
||||||
|
|
||||||
|
<ui:SettingsExpanderItem |
||||||
|
Margin="4,0" |
||||||
|
Content="Content Dialog" |
||||||
|
IconSource="NewWindow"> |
||||||
|
<ui:SettingsExpanderItem.Footer> |
||||||
|
<Button Command="{Binding DebugContentDialogCommand}" Content="Show Dialog" /> |
||||||
|
</ui:SettingsExpanderItem.Footer> |
||||||
|
</ui:SettingsExpanderItem> |
||||||
|
|
||||||
|
<ui:SettingsExpanderItem |
||||||
|
Margin="4,0" |
||||||
|
Content="Exceptions" |
||||||
|
IconSource="Flag"> |
||||||
|
<ui:SettingsExpanderItem.Footer> |
||||||
|
<Button Command="{Binding DebugThrowExceptionCommand}" Content="Unhandled Exception" /> |
||||||
|
</ui:SettingsExpanderItem.Footer> |
||||||
|
</ui:SettingsExpanderItem> |
||||||
|
|
||||||
|
<ui:SettingsExpanderItem |
||||||
|
Margin="4,0,4,4" |
||||||
|
Content="Download Manager tests" |
||||||
|
IconSource="Flag"> |
||||||
|
<ui:SettingsExpanderItem.Footer> |
||||||
|
<Button |
||||||
|
Margin="0,8" |
||||||
|
Command="{Binding DebugTrackedDownloadCommand}" |
||||||
|
Content="Add Tracked Download" /> |
||||||
|
</ui:SettingsExpanderItem.Footer> |
||||||
|
</ui:SettingsExpanderItem> |
||||||
|
|
||||||
|
</ui:SettingsExpander> |
||||||
|
</Grid> |
||||||
|
|
||||||
|
<!-- TODO: Directories card --> |
||||||
|
|
||||||
|
<Grid RowDefinitions="auto,*"> |
||||||
|
<StackPanel |
||||||
|
Grid.Row="1" |
||||||
|
HorizontalAlignment="Left" |
||||||
|
Orientation="Vertical"> |
||||||
|
<TextBlock |
||||||
|
Margin="0,8" |
||||||
|
FontSize="15" |
||||||
|
FontWeight="Bold" |
||||||
|
Text="About" /> |
||||||
|
<Image |
||||||
|
Width="112" |
||||||
|
Height="112" |
||||||
|
Margin="8" |
||||||
|
HorizontalAlignment="Left" |
||||||
|
Source="/Assets/Icon.png" /> |
||||||
|
<TextBlock |
||||||
|
Margin="8" |
||||||
|
FontWeight="Medium" |
||||||
|
Text="Stability Matrix" /> |
||||||
|
<Panel> |
||||||
|
<Button |
||||||
|
Name="VersionButton" |
||||||
|
Margin="8,0,8,8" |
||||||
|
Padding="2,0,2,0" |
||||||
|
BorderThickness="0" |
||||||
|
Classes="transparent" |
||||||
|
Command="{Binding OnVersionClick}" |
||||||
|
Content="{Binding AppVersion}" /> |
||||||
|
<ui:TeachingTip |
||||||
|
Title="{Binding VersionFlyoutText}" |
||||||
|
IsOpen="{Binding IsVersionTapTeachingTipOpen}" |
||||||
|
PreferredPlacement="RightTop" |
||||||
|
Target="{Binding #VersionButton}" /> |
||||||
|
</Panel> |
||||||
|
|
||||||
|
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal"> |
||||||
|
<Button |
||||||
|
Margin="8" |
||||||
|
HorizontalAlignment="Left" |
||||||
|
Command="{Binding ShowLicensesDialogCommand}" |
||||||
|
Content="License and Open Source Notices" /> |
||||||
|
</StackPanel> |
||||||
|
</StackPanel> |
||||||
|
</Grid> |
||||||
|
|
||||||
|
<!-- Extra space at the bottom --> |
||||||
|
<Panel Margin="0,0,0,16" /> |
||||||
|
</StackPanel> |
||||||
|
</ScrollViewer> |
||||||
|
|
||||||
|
|
||||||
</controls:UserControlBase> |
</controls:UserControlBase> |
||||||
|
Loading…
Reference in new issue