Ionite
1 year ago
18 changed files with 693 additions and 13 deletions
After Width: | Height: | Size: 18 KiB |
@ -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> |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
}*/ |
||||||
|
} |
@ -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> |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
); |
||||||
|
} |
@ -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 }); |
||||||
|
} |
||||||
|
} |
@ -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…
Reference in new issue