Browse Source

Add WIP user accounts page for debug mode

pull/324/head
Ionite 1 year ago
parent
commit
1b2ccb7c15
No known key found for this signature in database
  1. 1
      StabilityMatrix.Avalonia/App.axaml
  2. BIN
      StabilityMatrix.Avalonia/Assets/brands-civitai.png
  3. 98
      StabilityMatrix.Avalonia/Controls/SettingsAccountLinkExpander.axaml
  4. 130
      StabilityMatrix.Avalonia/Controls/SettingsAccountLinkExpander.axaml.cs
  5. 3
      StabilityMatrix.Avalonia/DesignData/DesignData.cs
  6. 18
      StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
  7. 6
      StabilityMatrix.Avalonia/Languages/Resources.resx
  8. 5
      StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
  9. 1
      StabilityMatrix.Avalonia/Styles/ThemeColors.axaml
  10. 138
      StabilityMatrix.Avalonia/ViewModels/Settings/AccountSettingsViewModel.cs
  11. 8
      StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs
  12. 6
      StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs
  13. 124
      StabilityMatrix.Avalonia/Views/Settings/AccountSettingsPage.axaml
  14. 13
      StabilityMatrix.Avalonia/Views/Settings/AccountSettingsPage.axaml.cs
  15. 28
      StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml
  16. 16
      StabilityMatrix.Core/Api/ICivitTRPCApi.cs
  17. 20
      StabilityMatrix.Core/Models/Api/CivitTRPC/CivitUserProfileRequest.cs
  18. 91
      StabilityMatrix.Core/Models/Api/CivitTRPC/CivitUserProfileResponse.cs

1
StabilityMatrix.Avalonia/App.axaml

@ -65,6 +65,7 @@
<StyleInclude Source="Controls/FreeUCard.axaml"/>
<StyleInclude Source="Controls/Paginator.axaml"/>
<StyleInclude Source="Controls/SelectableImageCard/SelectableImageButton.axaml"/>
<StyleInclude Source="Controls/SettingsAccountLinkExpander.axaml"/>
<Style Selector="DockControl">
<Setter Property="(DockProperties.ControlRecycling)" Value="{StaticResource ControlRecyclingKey}" />

BIN
StabilityMatrix.Avalonia/Assets/brands-civitai.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

98
StabilityMatrix.Avalonia/Controls/SettingsAccountLinkExpander.axaml

@ -0,0 +1,98 @@
<Styles
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:StabilityMatrix.Avalonia.Controls"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
<Design.PreviewWith>
<StackPanel Width="600" Height="400">
<controls:SettingsAccountLinkExpander
Header="Service 1"
IconSource="OtherUser"
OffDescription="Manage account services like A, B, and C" />
<controls:SettingsAccountLinkExpander
Header="Service 2"
IconSource="CloudFilled"
IsConnected="True"
OffDescription="Manage account services like A, B, and C" />
</StackPanel>
</Design.PreviewWith>
<Style Selector="controls|SettingsAccountLinkExpander">
<!-- Set Defaults -->
<Setter Property="Template">
<ControlTemplate>
<ui:SettingsExpander IconSource="{TemplateBinding IconSource}">
<ui:SettingsExpander.Header>
<StackPanel>
<TextBlock Text="{TemplateBinding Header}" />
<TextBlock
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
IsVisible="{TemplateBinding IsConnected,
Mode=OneWay,
Converter={x:Static BoolConverters.Not}}"
Text="{TemplateBinding OffDescription}"
TextWrapping="Wrap"
Theme="{DynamicResource CaptionTextBlockStyle}" />
<StackPanel
x:Name="PART_OnDescriptionPanel"
IsVisible="{TemplateBinding IsConnected,
Mode=OneWay}"
Orientation="Horizontal"
Spacing="4">
<Ellipse
Width="5"
Height="5"
Fill="{StaticResource ThemeMediumSeaGreenColor}" />
<TextBlock
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
Text="{TemplateBinding OnDescription}"
TextWrapping="Wrap"
Theme="{DynamicResource CaptionTextBlockStyle}" />
</StackPanel>
</StackPanel>
</ui:SettingsExpander.Header>
<ui:SettingsExpander.Footer>
<StackPanel Margin="0,0,12,0">
<!-- for some reason direct bind to IsConnected doesn't work here -->
<!-- Connect button -->
<Button
x:Name="PART_ConnectButton"
Command="{TemplateBinding ConnectCommand}"
Padding="32,6"
Content="{x:Static lang:Resources.Action_Connect}"
IsVisible="{Binding !IsVisible, ElementName=PART_OnDescriptionPanel}" />
<!-- Disconnect button -->
<Button
x:Name="PART_DisconnectButton"
HorizontalAlignment="Right"
IsVisible="{Binding IsVisible, ElementName=PART_OnDescriptionPanel}"
Padding="6,8"
Classes="transparent"
BorderThickness="0">
<ui:SymbolIcon FontSize="20" Symbol="More" />
<Button.Flyout>
<ui:FAMenuFlyout Placement="BottomEdgeAlignedLeft">
<ui:MenuFlyoutItem
x:Name="PART_DisconnectMenuItem"
Command="{TemplateBinding DisconnectCommand}"
Text="{x:Static lang:Resources.Action_Disconnect}"/>
</ui:FAMenuFlyout>
</Button.Flyout>
</Button>
</StackPanel>
</ui:SettingsExpander.Footer>
</ui:SettingsExpander>
</ControlTemplate>
</Setter>
</Style>
</Styles>

130
StabilityMatrix.Avalonia/Controls/SettingsAccountLinkExpander.axaml.cs

@ -0,0 +1,130 @@
using System;
using System.Windows.Input;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.VisualTree;
using FluentAvalonia.UI.Controls;
namespace StabilityMatrix.Avalonia.Controls;
public class SettingsAccountLinkExpander : TemplatedControl
{
// ReSharper disable MemberCanBePrivate.Global
public static readonly StyledProperty<object?> HeaderProperty =
HeaderedItemsControl.HeaderProperty.AddOwner<SettingsAccountLinkExpander>();
public object? Header
{
get => GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
public static readonly StyledProperty<IconSource?> IconSourceProperty =
SettingsExpander.IconSourceProperty.AddOwner<SettingsAccountLinkExpander>();
public IconSource? IconSource
{
get => GetValue(IconSourceProperty);
set => SetValue(IconSourceProperty, value);
}
public static readonly StyledProperty<bool> IsConnectedProperty = AvaloniaProperty.Register<
SettingsAccountLinkExpander,
bool
>("IsConnected");
public bool IsConnected
{
get => GetValue(IsConnectedProperty);
set => SetValue(IsConnectedProperty, value);
}
public static readonly StyledProperty<object?> OnDescriptionProperty =
AvaloniaProperty.Register<SettingsAccountLinkExpander, object?>(
"OnDescription",
Languages.Resources.Label_Connected
);
public object? OnDescription
{
get => GetValue(OnDescriptionProperty);
set => SetValue(OnDescriptionProperty, value);
}
public static readonly StyledProperty<object?> OffDescriptionProperty =
AvaloniaProperty.Register<SettingsAccountLinkExpander, object?>("OffDescription");
public object? OffDescription
{
get => GetValue(OffDescriptionProperty);
set => SetValue(OffDescriptionProperty, value);
}
public static readonly StyledProperty<ICommand?> ConnectCommandProperty =
AvaloniaProperty.Register<SettingsAccountLinkExpander, ICommand?>(
nameof(ConnectCommand),
enableDataValidation: true
);
public ICommand? ConnectCommand
{
get => GetValue(ConnectCommandProperty);
set => SetValue(ConnectCommandProperty, value);
}
public static readonly StyledProperty<ICommand?> DisconnectCommandProperty =
AvaloniaProperty.Register<SettingsAccountLinkExpander, ICommand?>(
nameof(DisconnectCommand),
enableDataValidation: true
);
public ICommand? DisconnectCommand
{
get => GetValue(DisconnectCommandProperty);
set => SetValue(DisconnectCommandProperty, value);
}
// ReSharper restore MemberCanBePrivate.Global
/// <inheritdoc />
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
if (ConnectCommand is { } command)
{
var connectButton = e.NameScope.Get<Button>("PART_ConnectButton");
connectButton.Command = command;
}
if (DisconnectCommand is { } disconnectCommand)
{
var disconnectMenuItem = e.NameScope.Get<MenuFlyoutItem>("PART_DisconnectMenuItem");
disconnectMenuItem.Command = disconnectCommand;
}
}
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (!this.IsAttachedToVisualTree())
{
return;
}
if (change.Property == ConnectCommandProperty)
{
var button = this.GetControl<Button>("PART_ConnectButton");
button.Command = ConnectCommand;
}
if (change.Property == DisconnectCommandProperty)
{
var button = this.GetControl<Button>("PART_DisconnectButton");
button.Command = DisconnectCommand;
}
}
}

3
StabilityMatrix.Avalonia/DesignData/DesignData.cs

@ -439,6 +439,9 @@ public static class DesignData
public static MainSettingsViewModel MainSettingsViewModel =>
Services.GetRequiredService<MainSettingsViewModel>();
public static AccountSettingsViewModel AccountSettingsViewModel =>
Services.GetRequiredService<AccountSettingsViewModel>();
public static CheckpointBrowserViewModel CheckpointBrowserViewModel =>
Services.GetRequiredService<CheckpointBrowserViewModel>();

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

@ -176,6 +176,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
/// <summary>
/// Looks up a localized string similar to Disconnect.
/// </summary>
public static string Action_Disconnect {
get {
return ResourceManager.GetString("Action_Disconnect", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Downgrade.
/// </summary>
@ -743,6 +752,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
/// <summary>
/// Looks up a localized string similar to Connected.
/// </summary>
public static string Label_Connected {
get {
return ResourceManager.GetString("Label_Connected", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Connected Model.
/// </summary>

6
StabilityMatrix.Avalonia/Languages/Resources.resx

@ -750,4 +750,10 @@
<data name="Action_OpenGithub" xml:space="preserve">
<value>Open on GitHub</value>
</data>
<data name="Label_Connected" xml:space="preserve">
<value>Connected</value>
</data>
<data name="Action_Disconnect" xml:space="preserve">
<value>Disconnect</value>
</data>
</root>

5
StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj

@ -92,6 +92,11 @@
<AvaloniaResource Include="Assets\noimage.png" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\brands-*.png" />
<AvaloniaResource Include="Assets\brands-*.svg" />
</ItemGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\licenses.json" />
</ItemGroup>

1
StabilityMatrix.Avalonia/Styles/ThemeColors.axaml

@ -22,6 +22,7 @@
<Color x:Key="ThemeDarkGreenColor">#3A783C</Color>
<Color x:Key="ThemeGreenColor">#4BA04F</Color>
<Color x:Key="ThemeGreenColorTransparent">#AA4BA04F</Color>
<Color x:Key="ThemeMediumSeaGreenColor">#6CCB5F</Color>
<Color x:Key="ThemeLightGreenColor">#8BC34A</Color>
<Color x:Key="ThemeLimeColor">#CDDC39</Color>
<Color x:Key="ThemeYellowColor">#FFEB3B</Color>

138
StabilityMatrix.Avalonia/ViewModels/Settings/AccountSettingsViewModel.cs

@ -0,0 +1,138 @@
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Controls;
using AvaloniaEdit.Utils;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FluentAvalonia.UI.Controls;
using Refit;
using StabilityMatrix.Avalonia.Diagnostics.LogViewer.Core.ViewModels;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.Views.Settings;
using StabilityMatrix.Core.Api;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Models;
using StabilityMatrix.Core.Models.Api.CivitTRPC;
using Symbol = FluentIcons.Common.Symbol;
using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource;
namespace StabilityMatrix.Avalonia.ViewModels.Settings;
[View(typeof(AccountSettingsPage))]
[Singleton, ManagedService]
public partial class AccountSettingsViewModel : PageViewModelBase
{
private readonly ICivitTRPCApi civitTRPCApi;
/// <inheritdoc />
public override string Title => "Accounts";
/// <inheritdoc />
public override IconSource IconSource =>
new SymbolIconSource { Symbol = Symbol.Person, IsFilled = true };
[ObservableProperty]
private string? civitStatus;
[ObservableProperty]
private bool isCivitConnected;
public AccountSettingsViewModel(ICivitTRPCApi civitTRPCApi)
{
this.civitTRPCApi = civitTRPCApi;
}
/// <inheritdoc />
public override void OnLoaded()
{
base.OnLoaded();
if (Design.IsDesignMode)
{
return;
}
// RefreshCivitAccount().SafeFireAndForget();
}
private async Task RefreshCivitAccount()
{
var secrets = GlobalUserSecrets.LoadFromFile()!;
if (secrets.CivitApiToken is null)
return;
var provisionalUser = Guid.NewGuid().ToString()[..8];
try
{
var result = await civitTRPCApi.GetUserProfile(
new CivitUserProfileRequest { Username = "ionite", Authed = true },
secrets.CivitApiToken
);
CivitStatus = $"Connected with API Key as user '{result.Username}'";
}
catch (ApiException e)
{
Debug.WriteLine(e);
}
}
[RelayCommand]
private async Task ConnectCivit()
{
var textFields = new TextBoxField[] { new() { Label = "API Key" } };
var dialog = DialogHelper.CreateTextEntryDialog("Connect CivitAI Account", "", textFields);
if (
await dialog.ShowAsync() != ContentDialogResult.Primary
|| textFields[0].Text is not { } json
)
{
return;
}
var secrets = GlobalUserSecrets.LoadFromFile()!;
secrets.CivitApiToken = json;
secrets.SaveToFile();
// TODO
await Task.Delay(1000);
IsCivitConnected = true;
}
[RelayCommand]
private async Task DisconnectCivit()
{
IsCivitConnected = false;
}
/*[RelayCommand]
private async Task ConnectCivitAccountOld()
{
var textFields = new TextBoxField[] { new() { Label = "API Key" } };
var dialog = DialogHelper.CreateTextEntryDialog("Connect CivitAI Account", "", textFields);
if (
await dialog.ShowAsync() != ContentDialogResult.Primary
|| textFields[0].Text is not { } json
)
{
return;
}
var secrets = GlobalUserSecrets.LoadFromFile()!;
secrets.CivitApiToken = json;
secrets.SaveToFile();
RefreshCivitAccount().SafeFireAndForget();
}*/
}

8
StabilityMatrix.Avalonia/ViewModels/Settings/MainSettingsViewModel.cs

@ -366,13 +366,15 @@ public partial class MainSettingsViewModel : PageViewModelBase
}
[RelayCommand]
private void NavigateToInferenceSettings()
private void NavigateToSubPage(Type viewModelType)
{
Dispatcher.UIThread.Post(
() =>
settingsNavigationService.NavigateTo<InferenceSettingsViewModel>(
settingsNavigationService.NavigateTo(
viewModelType,
BetterSlideNavigationTransition.PageSlideFromRight
)
),
DispatcherPriority.Send
);
}

6
StabilityMatrix.Avalonia/ViewModels/SettingsViewModel.cs

@ -1,11 +1,8 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData;
using DynamicData.Binding;
using FluentAvalonia.UI.Controls;
using NLog;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.Settings;
@ -20,8 +17,6 @@ namespace StabilityMatrix.Avalonia.ViewModels;
[Singleton]
public partial class SettingsViewModel : PageViewModelBase
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public override string Title => "Settings";
public override IconSource IconSource =>
new SymbolIconSource { Symbol = Symbol.Settings, IsFilled = true };
@ -40,6 +35,7 @@ public partial class SettingsViewModel : PageViewModelBase
{
vmFactory.Get<MainSettingsViewModel>(),
vmFactory.Get<InferenceSettingsViewModel>(),
vmFactory.Get<AccountSettingsViewModel>()
};
CurrentPagePath.AddRange(SubPages);

124
StabilityMatrix.Avalonia/Views/Settings/AccountSettingsPage.axaml

@ -0,0 +1,124 @@
<controls:UserControlBase
x:Class="StabilityMatrix.Avalonia.Views.Settings.AccountSettingsPage"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fluentIcons="clr-namespace:FluentIcons.FluentAvalonia;assembly=FluentIcons.FluentAvalonia"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData"
xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels"
xmlns:vmSettings="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Settings"
d:DataContext="{x:Static mocks:DesignData.AccountSettingsViewModel}"
d:DesignHeight="450"
d:DesignWidth="800"
x:DataType="vmSettings:AccountSettingsViewModel"
mc:Ignorable="d">
<controls:UserControlBase.Resources>
<SolidColorBrush x:Key="Brush0" Color="#FF3C3C46" />
<SolidColorBrush x:Key="Brush1" Color="#FF3E4B77" />
<SolidColorBrush x:Key="Brush4" Color="#FF1375D5" />
<SolidColorBrush x:Key="Brush7" Color="#FF1B96E3" />
<SolidColorBrush x:Key="Brush13" Color="#FF5486BC" />
<DrawingImage x:Key="BrandsLykos">
<DrawingGroup>
<GeometryDrawing Brush="Transparent" Geometry="F1M0,0L587,0L587,618L0,618z" />
<DrawingGroup>
<DrawingGroup.Transform>
<MatrixTransform Matrix="0.99998295,0,0,0.99998295,0,0.24023438" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="{DynamicResource Brush0}" Geometry="F0 M359.12 181.81L290.92 263.57L202.31 422.8L296.41 349.51L341.33 282.47L359.12 181.81Z" />
<GeometryDrawing Brush="{DynamicResource Brush1}" Geometry="F0 M354.51 195.18L296.41 349.51L287.33 463.38L402.14 326.47L405.15 227.55L342.3 165.1L354.51 195.18Z" />
<GeometryDrawing Brush="{DynamicResource Brush1}" Geometry="F0 M354.51 195.18L373.25 246.84L402.14 326.47L475.55 241.31L506.38 172.37L432.6 170.07L354.51 195.18Z" />
<GeometryDrawing Brush="{DynamicResource Brush0}" Geometry="F0 M506.38 172.37L402.14 326.47L431.69 421.7L493.66 289.28L506.38 172.37Z" />
<GeometryDrawing Brush="{DynamicResource Brush4}" Geometry="F0 M354.51 195.18L431.14 183.67L506.38 172.37L581.91 114.38L577.7 83.96L459.71 128.22L354.51 195.18Z" />
<GeometryDrawing Brush="{DynamicResource Brush1}" Geometry="F0 M354.51 195.18L577.7 83.96L587.01 36.06L555.98 24.72L444.52 90.52L354.51 195.18Z" />
<GeometryDrawing Brush="{DynamicResource Brush4}" Geometry="F0 M354.51 195.18L451.44 116.55L551.26 35.59L570.72 16.37L543.04 5.86L469.78 26.31L346.91 82.41L330.57 157.07L354.51 195.18Z" />
<GeometryDrawing Brush="{DynamicResource Brush7}" Geometry="F0 M258.82 209.64L283.43 257.76L354.51 195.18L354.73 143.18L354.97 88.91L300.3 145.74L258.82 209.64Z" />
<GeometryDrawing Brush="{DynamicResource Brush4}" Geometry="F0 M284.89 201.03L283.82 132.98L245.45 133.94L209.32 211.39L209.53 265.05L202.31 422.8L277.33 274.62L284.89 201.03Z" />
<GeometryDrawing Brush="{DynamicResource Brush1}" Geometry="F0 M354.51 195.18L318.27 198.22L284.89 201.03L202.31 422.8L268.99 323.08L354.51 195.18Z" />
<GeometryDrawing Brush="{DynamicResource Brush1}" Geometry="F0 M209.53 265.05L225.86 205.45L245.45 133.94L157.16 269.41L209.53 265.05Z" />
<GeometryDrawing Brush="{DynamicResource Brush4}" Geometry="F0 M245.45 133.94L301.48 136.45L354.97 88.91L275.66 59.42L139 44.21L245.45 133.94Z" />
<GeometryDrawing Brush="{DynamicResource Brush7}" Geometry="F0 M139 44.21L287.77 75.01L354.97 88.91L348.14 53.88L306.32 49.68L139 44.21Z" />
<GeometryDrawing Brush="{DynamicResource Brush13}" Geometry="F0 M393.94 11.53L306.32 49.68L354.97 88.91L412.38 57.61L441.91 26.85L393.94 11.53Z" />
<GeometryDrawing Brush="{DynamicResource Brush7}" Geometry="F0 M441.91 26.85L354.97 88.91L543.04 5.86L571.25 0L441.91 26.85Z" />
<GeometryDrawing Brush="{DynamicResource Brush13}" Geometry="F0 M571.25 0L543.04 5.86L551.26 35.59L587.01 36.06L571.25 0Z" />
<GeometryDrawing Brush="{DynamicResource Brush13}" Geometry="F0 M151.49 224.62L33.55 321.2L103.23 316.08L151.49 224.62Z" />
<GeometryDrawing Brush="{DynamicResource Brush4}" Geometry="F0 M145.63 400.32L200.67 282.86L0 447.89L145.63 400.32Z" />
<GeometryDrawing Brush="{DynamicResource Brush13}" Geometry="F0 M262.66 413.33L132.89 597.28L236.55 530.32L262.66 413.33Z" />
<GeometryDrawing Brush="{DynamicResource Brush1}" Geometry="F0 M374.93 617.53L350.75 441.52L396.59 364.19L412.64 459.88L374.93 617.53Z" />
<GeometryDrawing Brush="{DynamicResource Brush1}" Geometry="F0 M277.5 507.65L312.09 557.16L324.24 472.27L277.5 507.65Z" />
<GeometryDrawing Brush="{DynamicResource Brush1}" Geometry="F0 M185.82 455.66L119.65 488.21L183.32 389.39L185.82 455.66Z" />
<GeometryDrawing Brush="{DynamicResource Brush4}" Geometry="F0 M441.13 526.17L473.16 366.86L489.5 454.43L441.13 526.17Z" />
<GeometryDrawing Brush="{DynamicResource Brush1}" Geometry="F0 M354.97 88.91L354.97 88.91L245.45 133.94L284.89 201.03L316.79 149.99L354.97 88.91Z" />
<GeometryDrawing Brush="{DynamicResource Brush4}" Geometry="F0 M353.83 211.72L346.35 393L402.14 326.47L373.25 246.84L356.02 199.33L354.51 195.18L353.83 211.72Z" />
</DrawingGroup>
</DrawingGroup>
</DrawingImage>
</controls:UserControlBase.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Margin="16,16" Spacing="6">
<sg:SpacedGrid ColumnDefinitions="*,*" Margin="0,4,0,16">
<StackPanel Orientation="Horizontal" Spacing="16">
<controls:BetterAdvancedImage
HorizontalAlignment="Left"
Source="Avares://StabilityMatrix.Avalonia/Assets/noimage.png"
Width="64"
Height="64"
CornerRadius="8" />
<StackPanel>
<TextBlock
Margin="-1,0,0,0"
Theme="{DynamicResource SubtitleTextBlockStyle}"
Text="Ionite"/>
<TextBlock
Text="user@example.org"/>
</StackPanel>
</StackPanel>
</sg:SpacedGrid>
<ui:SettingsExpander Header="Lykos" IsExpanded="True">
<ui:SettingsExpander.IconSource>
<ui:ImageIconSource Source="{StaticResource BrandsLykos}" />
</ui:SettingsExpander.IconSource>
<ui:SettingsExpander.Footer>
<Button Content="Login" />
</ui:SettingsExpander.Footer>
<ui:SettingsExpanderItem Content="Profile"
Description="Test" />
</ui:SettingsExpander>
<sg:SpacedGrid RowDefinitions="Auto,*,*" RowSpacing="4">
<TextBlock
Margin="0,0,0,4"
FontWeight="Medium"
Text="{x:Static lang:Resources.Label_Integrations}" />
<controls:SettingsAccountLinkExpander
Grid.Row="1"
Header="CivitAI"
IsConnected="{Binding IsCivitConnected}"
ConnectCommand="{Binding ConnectCivitCommand}"
DisconnectCommand="{Binding DisconnectCivitCommand}"
OffDescription="Connect to Download Models that require login">
<controls:SettingsAccountLinkExpander.IconSource>
<ui:BitmapIconSource UriSource="avares://StabilityMatrix.Avalonia/Assets/brands-civitai.png" />
</controls:SettingsAccountLinkExpander.IconSource>
</controls:SettingsAccountLinkExpander>
</sg:SpacedGrid>
</StackPanel>
</ScrollViewer>
</controls:UserControlBase>

13
StabilityMatrix.Avalonia/Views/Settings/AccountSettingsPage.axaml.cs

@ -0,0 +1,13 @@
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Core.Attributes;
namespace StabilityMatrix.Avalonia.Views.Settings;
[Singleton]
public partial class AccountSettingsPage : UserControlBase
{
public AccountSettingsPage()
{
InitializeComponent();
}
}

28
StabilityMatrix.Avalonia/Views/Settings/MainSettingsPage.axaml

@ -15,6 +15,7 @@
xmlns:ui="using:FluentAvalonia.UI.Controls"
xmlns:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels"
xmlns:vmSettings="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Settings"
xmlns:sg="clr-namespace:SpacedGridControl.Avalonia;assembly=SpacedGridControl.Avalonia"
Focusable="True"
d:DataContext="{x:Static mocks:DesignData.MainSettingsViewModel}"
d:DesignHeight="700"
@ -65,13 +66,14 @@
IsVisible="{Binding SharedState.IsDebugMode}"
Margin="8,0,8,4"
IsClickEnabled="True"
Command="{Binding NavigateToInferenceSettingsCommand}"
Command="{Binding NavigateToSubPageCommand}"
CommandParameter="{x:Type vmSettings:InferenceSettingsViewModel}"
Header="Inference (Test)"
IconSource="Code"
ActionIconSource="ChevronRight">
</ui:SettingsExpander>
</Grid>
<!-- Checkpoints Manager Options -->
<Grid RowDefinitions="auto,*,Auto">
<TextBlock
@ -244,13 +246,29 @@
</Grid>
<!-- Integrations -->
<Grid RowDefinitions="auto,*">
<sg:SpacedGrid RowDefinitions="Auto,*,*" RowSpacing="4">
<TextBlock
Margin="0,0,0,8"
Margin="0,0,0,4"
FontWeight="Medium"
Text="{x:Static lang:Resources.Label_Integrations}" />
<ui:SettingsExpander
Grid.Row="1"
Margin="8,0"
IsClickEnabled="True"
IsVisible="{Binding SharedState.IsDebugMode}"
Command="{Binding NavigateToSubPageCommand}"
CommandParameter="{x:Type vmSettings:AccountSettingsViewModel}"
Header="Accounts"
ActionIconSource="ChevronRight">
<ui:SettingsExpander.IconSource>
<fluentIcons:SymbolIconSource
FontSize="10"
IsFilled="True"
Symbol="Person"/>
</ui:SettingsExpander.IconSource>
</ui:SettingsExpander>
<ui:SettingsExpander
Grid.Row="2"
Margin="8,0,8,4"
Header="{x:Static lang:Resources.Label_DiscordRichPresence}">
<ui:SettingsExpander.IconSource>
@ -260,7 +278,7 @@
<ToggleSwitch IsChecked="{Binding IsDiscordRichPresenceEnabled}" />
</ui:SettingsExpander.Footer>
</ui:SettingsExpander>
</Grid>
</sg:SpacedGrid>
<!-- System Options -->
<Grid RowDefinitions="auto, auto, auto">

16
StabilityMatrix.Core/Api/ICivitTRPCApi.cs

@ -0,0 +1,16 @@
using Refit;
using StabilityMatrix.Core.Models.Api.CivitTRPC;
namespace StabilityMatrix.Core.Api;
[Headers("Referer: https://civitai.com")]
public interface ICivitTRPCApi
{
[Headers("Content-Type: application/x-www-form-urlencoded")]
[Get("/api/trpc/userProfile.get")]
Task<CivitUserProfileResponse> GetUserProfile(
[Query] CivitUserProfileRequest input,
[Authorize] string bearerToken,
CancellationToken cancellationToken = default
);
}

20
StabilityMatrix.Core/Models/Api/CivitTRPC/CivitUserProfileRequest.cs

@ -0,0 +1,20 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Web;
namespace StabilityMatrix.Core.Models.Api.CivitTRPC;
public record CivitUserProfileRequest : IFormattable
{
[JsonPropertyName("username")]
public required string Username { get; set; }
[JsonPropertyName("authed")]
public bool Authed { get; set; }
/// <inheritdoc />
public string ToString(string? format, IFormatProvider? formatProvider)
{
return JsonSerializer.Serialize(new { json = this });
}
}

91
StabilityMatrix.Core/Models/Api/CivitTRPC/CivitUserProfileResponse.cs

@ -0,0 +1,91 @@
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace StabilityMatrix.Core.Models.Api.CivitTRPC;
/*
* Example:
* {
"result": {
"data": {
"json": {
"id": 1020931,
"username": "owo",
"deletedAt": null,
"image": "https://lh3.googleusercontent.com/a/...",
"leaderboardShowcase": null,
"createdAt": "2023-02-01T21:05:31.125Z",
"cosmetics": [],
"links": [],
"rank": null,
"stats": null,
"profile": {
"bio": null,
"coverImageId": null,
"coverImage": null,
"message": null,
"messageAddedAt": null,
"profileSectionsSettings": [
{
"key": "showcase",
"enabled": true
},
{
"key": "popularModels",
"enabled": true
},
{
"key": "popularArticles",
"enabled": true
},
{
"key": "modelsOverview",
"enabled": true
},
{
"key": "imagesOverview",
"enabled": true
},
{
"key": "recentReviews",
"enabled": true
}
],
"privacySettings": {
"showFollowerCount": true,
"showReviewsRating": true,
"showFollowingCount": true
},
"showcaseItems": [],
"location": null,
"nsfw": false,
"userId": 1020931
}
},
"meta": {
"values": {
"createdAt": [
"Date"
]
}
}
}
}
}
*
*/
public record CivitUserProfileResponse
{
[JsonPropertyName("result")]
public required JsonObject Result { get; init; }
public int? UserId => Result["data"]?["json"]?["id"]?.GetValue<int>();
public string? Username => Result["data"]?["json"]?["username"]?.GetValue<string>();
public string? ImageUrl => Result["data"]?["json"]?["image"]?.GetValue<string>();
public DateTimeOffset? CreatedAt =>
Result["data"]?["json"]?["createdAt"]?.GetValue<DateTimeOffset>();
}
Loading…
Cancel
Save