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