This commit is contained in:
BlossomiShymae
2024-08-08 21:16:02 -05:00
parent a8741cd352
commit ed89a1d543
61 changed files with 1745 additions and 338 deletions

View File

@@ -8,8 +8,10 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.AboutView"
x:DataType="vm:AboutViewModel">
<ScrollViewer>
<WrapPanel Margin="8"
<Grid Margin="8"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<WrapPanel
theme:WrapPanelExtensions.AnimatedScroll="true"
Orientation="Horizontal">
<suki:GlassCard Margin="8">
@@ -27,13 +29,13 @@
<suki:GlassCard Width="400" Margin="8">
<suki:GroupBox Header="About">
<TextBlock TextWrapping="Wrap">
Needlework.Net is the sister project of Needlework. Like Needlework, this project is inspired by
LCU Explorer. This tool was made to help others with LCU development. Feel free to ask any questions
Needlework.Net is .NET rewrite of Needlework. Like Needlework, this project is inspired by
LCU Explorer. This tool was made to help others with LCU development. Feel free to ask any questions
or help contribute to the project! 💜
</TextBlock>
</suki:GroupBox>
</suki:GlassCard>
</StackPanel>
</WrapPanel>
</ScrollViewer>
</Grid>
</UserControl>

View File

@@ -9,57 +9,78 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.ConsoleView"
x:DataType="vm:ConsoleViewModel">
<Grid Margin="16" RowDefinitions="auto,*" ColumnDefinitions="*,*">
<Grid Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2">
<suki:GlassCard Margin="0 0 0 16">
<suki:GroupBox Header="Console">
<Grid RowDefinitions="auto,auto" ColumnDefinitions="auto,*">
<ComboBox ItemsSource="{Binding RequestMethods}" SelectedItem="{Binding RequestMethodSelected}"
Grid.Row="0" Grid.Column="0"/>
<TextBox Text="{Binding RequestPath}"
Grid.Row="0" Grid.Column="1"
Watermark="E.g. /lol-summoner/v1/current-summoner"/>
<TextBox Text="{Binding RequestBody}" Height="200" AcceptsReturn="True" TextWrapping="Wrap"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>
</Grid>
</suki:GroupBox>
</suki:GlassCard>
<Button Classes="Flat Rounded"
Margin="0 0 0 0"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
FontWeight="DemiBold"
Command="{Binding SendRequestCommand}">
Send
</Button>
</Grid>
<StackPanel
Margin="0 0 8 0"
Grid.Row="1"
Grid.Column="0">
<suki:GlassCard Margin="0 4">
<TextBlock Text="{Binding ResponsePath}"/>
</suki:GlassCard>
<suki:GlassCard Margin="0 4">
<TextBlock Text="{Binding ResponseStatus}"/>
</suki:GlassCard>
<suki:GlassCard Margin="0 4">
<TextBlock Text="{Binding ResponseAuthentication}" />
</suki:GlassCard>
</StackPanel>
<suki:GlassCard
Margin="0 8"
Grid.Row="1"
Grid.Column="1">
<avaloniaEdit:TextEditor Name="ResponseEditor"
<suki:BusyArea IsBusy="{Binding IsBusy}" BusyText="Loading...">
<Grid Margin="16" RowDefinitions="auto,*" ColumnDefinitions="*,*">
<Grid Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2">
<suki:GlassCard Margin="0 0 0 16">
<suki:GroupBox Header="Console">
<Grid RowDefinitions="auto,auto" ColumnDefinitions="auto,*">
<ComboBox ItemsSource="{Binding RequestMethods}" SelectedItem="{Binding RequestMethodSelected}"
Grid.Row="0" Grid.Column="0"/>
<AutoCompleteBox
ItemsSource="{Binding RequestPaths}"
Text="{Binding RequestPath}"
MaxDropDownHeight="400"
FilterMode="StartsWith"
Grid.Row="0" Grid.Column="1"/>
<avaloniaEdit:TextEditor
Name="RequestEditor"
Text=""
FontFamily="Cascadia Code,Consolas,Menlo,Monospace"
ShowLineNumbers="True"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
FontWeight="Light"
FontSize="14"/>
</suki:GlassCard>
</Grid>
FontSize="12"
Height="100"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"/>
</Grid>
</suki:GroupBox>
</suki:GlassCard>
<Button Classes="Flat Rounded"
Margin="0 0 0 0"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
FontWeight="DemiBold"
Command="{Binding SendRequestCommand}"
theme:ButtonExtensions.ShowProgress="{Binding IsRequestBusy}">
Send
</Button>
</Grid>
<StackPanel
Margin="0 0 8 0"
Grid.Row="1"
Grid.Column="0">
<suki:GlassCard Margin="0 4">
<suki:GroupBox Header="Path">
<TextBlock Text="{Binding ResponsePath}"/>
</suki:GroupBox>
</suki:GlassCard>
<suki:GlassCard Margin="0 4">
<suki:GroupBox Header="Status">
<TextBlock Text="{Binding ResponseStatus}"/>
</suki:GroupBox>
</suki:GlassCard>
<suki:GlassCard Margin="0 4">
<suki:GroupBox Header="Authentication">
<TextBlock Text="{Binding ResponseAuthentication}" />
</suki:GroupBox>
</suki:GlassCard>
</StackPanel>
<suki:GlassCard
Margin="0 8"
Grid.Row="1"
Grid.Column="1">
<avaloniaEdit:TextEditor
Name="ResponseEditor"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
ShowLineNumbers="True"
Text=""
FontSize="12"/>
</suki:GlassCard>
</Grid>
</suki:BusyArea>
</UserControl>

View File

@@ -3,9 +3,10 @@ using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Styling;
using AvaloniaEdit;
using AvaloniaEdit.Highlighting;
using AvaloniaEdit.Indentation.CSharp;
using AvaloniaEdit.TextMate;
using CommunityToolkit.Mvvm.Messaging;
using Needlework.Net.Desktop.Extensions;
using Needlework.Net.Desktop.Messages;
using Needlework.Net.Desktop.ViewModels;
using SukiUI;
using System.Text.Json;
@@ -13,35 +14,58 @@ using TextMateSharp.Grammars;
namespace Needlework.Net.Desktop.Views;
public partial class ConsoleView : UserControl
public partial class ConsoleView : UserControl, IRecipient<ResponseUpdatedMessage>, IRecipient<ContentRequestMessage>
{
private TextEditor? _responseEditor;
private TextEditor? _requestEditor;
public ConsoleView()
{
InitializeComponent();
}
public void Receive(ResponseUpdatedMessage message)
{
if (!string.IsNullOrEmpty(message.Value))
{
var text = JsonSerializer.Serialize(JsonSerializer.Deserialize<object>(message.Value), App.JsonSerializerOptions);
if (text.Length >= App.MaxCharacters)
{
WeakReferenceMessenger.Default.Send(new OopsiesWindowRequestedMessage(text), nameof(ConsoleView));
_responseEditor!.Text = string.Empty;
}
else _responseEditor!.Text = text;
}
else _responseEditor!.Text = message.Value;
}
public void Receive(ContentRequestMessage message)
{
message.Reply(_requestEditor!.Text);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_responseEditor = this.FindControl<TextEditor>("ResponseEditor");
_responseEditor!.TextArea.IndentationStrategy = new CSharpIndentationStrategy(_responseEditor.Options);
_responseEditor!.TextArea.RightClickMovesCaret = true;
_responseEditor!.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("JavaScript");
_requestEditor = this.FindControl<TextEditor>("RequestEditor");
_responseEditor?.ApplyJsonEditorSettings();
_requestEditor?.ApplyJsonEditorSettings();
((ConsoleViewModel)DataContext!)!.ResponseBodyUpdated += ConsoleView_ResponseBodyUpdated;
WeakReferenceMessenger.Default.Register<ResponseUpdatedMessage, string>(this, nameof(ConsoleViewModel));
WeakReferenceMessenger.Default.Register<ContentRequestMessage, string>(this, "ConsoleRequestEditor");
OnBaseThemeChanged(Application.Current!.ActualThemeVariant);
SukiTheme.GetInstance().OnBaseThemeChanged += OnBaseThemeChanged;
}
private void ConsoleView_ResponseBodyUpdated(object? sender, TextUpdatedEventArgs e)
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
if (!string.IsNullOrEmpty(e.Text))
_responseEditor!.Text = JsonSerializer.Serialize(JsonSerializer.Deserialize<object>(e.Text), App.JsonSerializerOptions);
else _responseEditor!.Text = e.Text;
base.OnDetachedFromVisualTree(e);
WeakReferenceMessenger.Default.UnregisterAll(this);
SukiTheme.GetInstance().OnBaseThemeChanged -= OnBaseThemeChanged;
}
private void OnBaseThemeChanged(ThemeVariant currentTheme)
@@ -49,8 +73,11 @@ public partial class ConsoleView : UserControl
var registryOptions = new RegistryOptions(
currentTheme == ThemeVariant.Dark ? ThemeName.DarkPlus : ThemeName.LightPlus);
var textMateInstallation = _responseEditor.InstallTextMate(registryOptions);
textMateInstallation.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions
var responseTmi = _responseEditor.InstallTextMate(registryOptions);
responseTmi.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions
.GetLanguageByExtension(".json").Id));
var requestTmi = _requestEditor.InstallTextMate(registryOptions);
requestTmi.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions
.GetLanguageByExtension(".json").Id));
}
}

View File

@@ -1,19 +1,313 @@
<Window xmlns="https://github.com/avaloniaui"
<UserControl 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:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
xmlns:theme="clr-namespace:SukiUI.Theme;assembly=SukiUI"
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
xmlns:avalonEdit="https://github.com/avaloniaui/avaloniaedit"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.EndpointView"
x:DataType="vm:EndpointViewModel"
Title="{Binding Title}"
Width="1280"
Height="720">
<Grid Margin="8" RowDefinitions="auto,*" ColumnDefinitions="*">
<TextBlock Classes="h3" Grid.Row="0" Grid.Column="0" Text="{Binding Endpoint}"/>
<ScrollViewer Grid.Row="1" Grid.Column="0">
</ScrollViewer>
x:DataType="vm:EndpointViewModel">
<Grid RowDefinitions="auto,*" ColumnDefinitions="3*,2,4*,2,4*">
<Grid Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="2"
RowDefinitions="auto,*"
ColumnDefinitions="*">
<ListBox ItemsSource="{Binding PathOperations}"
SelectedItem="{Binding SelectedPathOperation}"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
Margin="0 0 0 0"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid
RowDefinitions="*"
ColumnDefinitions="auto,*">
<Button
VerticalAlignment="Center"
Classes="Flat"
Margin="0 0 8 0"
Content="{Binding Method}"
Background="{Binding Color}"
FontSize="8"
Width="45"
Padding="10 2 10 2"
Grid.Row="0"
Grid.Column="0"/>
<TextBlock
VerticalAlignment="Center"
Text="{Binding Path}"
FontSize="11"
Grid.Row="0"
Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
<GridSplitter Background="Gray"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"/>
<Grid Grid.Row="0"
Grid.Column="2"
RowDefinitions="*"
ColumnDefinitions="auto,*,auto">
<TextBox Grid.Row="0"
Grid.Column="0"
Text="{Binding SelectedPathOperation.Method}"
FontSize="12"
IsReadOnly="True"/>
<TextBox Grid.Row="0"
Grid.Column="1"
FontSize="12"
Text="{Binding SelectedPathOperation.ResponsePath}"
IsReadOnly="True"/>
<StackPanel Grid.Row="0"
Grid.Column="2"
Orientation="Horizontal">
<Button Classes="Flat"
Margin="4"
FontSize="12"
HorizontalAlignment="Right"
Padding="12 4 12 4"
VerticalAlignment="Center"
Command="{Binding SelectedPathOperation.SendRequestCommand}">Send</Button>
</StackPanel>
</Grid>
<Grid Grid.Row="1" Grid.Column="2">
<TabControl>
<TabItem Header="Params">
<ScrollViewer>
<StackPanel IsVisible="{Binding SelectedPathOperation, Converter={StaticResource NullBoolConverter}}">
<suki:GroupBox Header="Path Parameters"
Margin="0 4"
IsVisible="{Binding SelectedPathOperation.Operation.PathParameters, Converter={StaticResource EnumerableBoolConverter}}">
<DataGrid
ItemsSource="{Binding SelectedPathOperation.Operation.PathParameters}"
IsReadOnly="True"
GridLinesVisibility="Horizontal">
<DataGrid.Styles>
<Style Selector="DataGridRow DataGridCell">
<Setter Property="FontSize" Value="12"></Setter>
</Style>
</DataGrid.Styles>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridCheckBoxColumn Header="Required" Binding="{Binding IsRequired}"/>
<DataGridTemplateColumn Header="Value">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="vm:ParameterViewModel">
<TextBox Text="{Binding Value}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
</DataGrid.Columns>
</DataGrid>
</suki:GroupBox>
<suki:GroupBox Header="Query Parameters"
Margin="0 4"
IsVisible="{Binding SelectedPathOperation.Operation.QueryParameters, Converter={StaticResource EnumerableBoolConverter}}">
<DataGrid
ItemsSource="{Binding SelectedPathOperation.Operation.QueryParameters}"
IsReadOnly="True"
GridLinesVisibility="Horizontal">
<DataGrid.Styles>
<Style Selector="DataGridRow DataGridCell">
<Setter Property="FontSize" Value="12"></Setter>
</Style>
</DataGrid.Styles>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridCheckBoxColumn Header="Required" Binding="{Binding IsRequired}"/>
<DataGridTemplateColumn Header="Value">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="vm:ParameterViewModel">
<TextBox Text="{Binding Value}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
</DataGrid.Columns>
</DataGrid>
</suki:GroupBox>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem Header="Body">
<avalonEdit:TextEditor
Name="EndpointRequestEditor"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
Text=""
ShowLineNumbers="True"
FontSize="12"/>
</TabItem>
<TabItem Header="Auth">
<Grid RowDefinitions="auto,auto,auto,*" ColumnDefinitions="*,4*">
<TextBlock FontSize="12"
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center">
Username
</TextBlock>
<TextBox FontSize="12"
Grid.Row="0"
Grid.Column="1"
IsReadOnly="True"
Text="{Binding SelectedPathOperation.ResponseUsername}" />
<TextBlock FontSize="12"
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center">
Password
</TextBlock>
<TextBox FontSize="12"
Grid.Row="1"
Grid.Column="1"
IsReadOnly="True"
Text="{Binding SelectedPathOperation.ResponsePassword}"/>
<TextBlock FontSize="12"
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center">
Authorization
</TextBlock>
<TextBox FontSize="12"
Grid.Row="2"
Grid.Column="1"
IsReadOnly="True"
Text="{Binding SelectedPathOperation.ResponseAuthorization}"/>
</Grid>
</TabItem>
<TabItem Header="Schemas">
<ScrollViewer>
<StackPanel>
<suki:GlassCard Margin="0 4" IsVisible="{Binding SelectedPathOperation.Operation.RequestBodyType, Converter={StaticResource NullBoolConverter}}">
<TextBlock>
<Run Text="Request body: " FontWeight="DemiBold" FontSize="12"/>
<Run Text="{Binding SelectedPathOperation.Operation.RequestBodyType}" FontSize="12"/>
</TextBlock>
</suki:GlassCard>
<Border Margin="0 4" IsVisible="{Binding SelectedPathOperation.Operation.RequestClasses, Converter={StaticResource EnumerableBoolConverter}}">
<ItemsRepeater ItemsSource="{Binding SelectedPathOperation.Operation.RequestClasses}">
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0 4 0 8">
<suki:GlassCard IsVisible="{Binding PropertyFields, Converter={StaticResource EnumerableBoolConverter}}">
<suki:GroupBox Header="{Binding Id}">
<DataGrid
ItemsSource="{Binding PropertyFields}"
AutoGenerateColumns="True"
IsReadOnly="True"
GridLinesVisibility="Horizontal">
<DataGrid.Styles>
<Style Selector="DataGridRow DataGridCell">
<Setter Property="FontSize" Value="12"></Setter>
</Style>
</DataGrid.Styles>
</DataGrid>
</suki:GroupBox>
</suki:GlassCard>
<suki:GlassCard Margin="0 0 0 8" IsVisible="{Binding PropertyEnums, Converter={StaticResource EnumerableBoolConverter}}">
<suki:GroupBox Header="{Binding Id}">
<DataGrid
ItemsSource="{Binding PropertyEnums}"
AutoGenerateColumns="True"
IsReadOnly="True"
GridLinesVisibility="Horizontal">
<DataGrid.Styles>
<Style Selector="DataGridRow DataGridCell">
<Setter Property="FontSize" Value="12"></Setter>
</Style>
</DataGrid.Styles>
</DataGrid>
</suki:GroupBox>
</suki:GlassCard>
</StackPanel>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</Border>
<suki:GlassCard Margin="0 4">
<TextBlock>
<Run Text="Return value: " FontWeight="DemiBold" FontSize="12"/>
<Run Text="{Binding SelectedPathOperation.Operation.ReturnType}" FontSize="12"/>
</TextBlock>
</suki:GlassCard>
<Border Margin="0 4" IsVisible="{Binding SelectedPathOperation.Operation.ResponseClasses, Converter={StaticResource EnumerableBoolConverter}}">
<ItemsRepeater ItemsSource="{Binding SelectedPathOperation.Operation.ResponseClasses}">
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0 4 0 8">
<suki:GlassCard IsVisible="{Binding PropertyFields, Converter={StaticResource EnumerableBoolConverter}}">
<suki:GroupBox Header="{Binding Id}">
<DataGrid
ItemsSource="{Binding PropertyFields}"
AutoGenerateColumns="True"
IsReadOnly="True"
GridLinesVisibility="Horizontal">
<DataGrid.Styles>
<Style Selector="DataGridRow DataGridCell">
<Setter Property="FontSize" Value="12"></Setter>
</Style>
</DataGrid.Styles>
</DataGrid>
</suki:GroupBox>
</suki:GlassCard>
<suki:GlassCard Margin="0 0 0 8" IsVisible="{Binding PropertyEnums, Converter={StaticResource EnumerableBoolConverter}}">
<suki:GroupBox Header="{Binding Id}">
<DataGrid
ItemsSource="{Binding PropertyEnums}"
AutoGenerateColumns="True"
IsReadOnly="True"
GridLinesVisibility="Horizontal">
<DataGrid.Styles>
<Style Selector="DataGridRow DataGridCell">
<Setter Property="FontSize" Value="12"></Setter>
</Style>
</DataGrid.Styles>
</DataGrid>
</suki:GroupBox>
</suki:GlassCard>
</StackPanel>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</Border>
</StackPanel>
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>
<GridSplitter Grid.Row="0" Grid.Column="3" Grid.RowSpan="2" Background="Gray"/>
<StackPanel Grid.Row="0" Grid.Column="4" Orientation="Horizontal">
<Button HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="4"
FontSize="10"
Padding="12 4 12 4"
Classes="Flat"
Content="{Binding SelectedPathOperation.ResponseStatus}"/>
</StackPanel>
<Grid Grid.Row="1" Grid.Column="4">
<TabControl>
<TabItem Header="Preview">
<avalonEdit:TextEditor
Name="EndpointResponseEditor"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
ShowLineNumbers="True"
Text=""
FontSize="12"/>
</TabItem>
</TabControl>
</Grid>
</Grid>
</Window>
</UserControl>

View File

@@ -1,11 +1,83 @@
using SukiUI.Controls;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Styling;
using AvaloniaEdit;
using AvaloniaEdit.TextMate;
using CommunityToolkit.Mvvm.Messaging;
using Needlework.Net.Desktop.Extensions;
using Needlework.Net.Desktop.Messages;
using Needlework.Net.Desktop.ViewModels;
using SukiUI;
using TextMateSharp.Grammars;
namespace Needlework.Net.Desktop.Views;
public partial class EndpointView : SukiWindow
public partial class EndpointView : UserControl, IRecipient<EditorUpdateMessage>, IRecipient<ContentRequestMessage>
{
private TextEditor? _requestEditor;
private TextEditor? _responseEditor;
public EndpointView()
{
InitializeComponent();
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
var vm = (EndpointViewModel)DataContext!;
_requestEditor = this.FindControl<TextEditor>("EndpointRequestEditor");
_responseEditor = this.FindControl<TextEditor>("EndpointResponseEditor");
_requestEditor?.ApplyJsonEditorSettings();
_responseEditor?.ApplyJsonEditorSettings();
WeakReferenceMessenger.Default.Register<EditorUpdateMessage>(this);
WeakReferenceMessenger.Default.Register<ContentRequestMessage, string>(this, "EndpointRequestEditor");
OnBaseThemeChanged(Application.Current!.ActualThemeVariant);
SukiTheme.GetInstance().OnBaseThemeChanged += OnBaseThemeChanged;
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
WeakReferenceMessenger.Default.UnregisterAll(this);
SukiTheme.GetInstance().OnBaseThemeChanged -= OnBaseThemeChanged;
}
private void OnBaseThemeChanged(ThemeVariant currentTheme)
{
var registryOptions = new RegistryOptions(
currentTheme == ThemeVariant.Dark ? ThemeName.DarkPlus : ThemeName.LightPlus);
var requestTmi = _requestEditor.InstallTextMate(registryOptions);
requestTmi.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions
.GetLanguageByExtension(".json").Id));
var responseTmi = _requestEditor.InstallTextMate(registryOptions);
responseTmi.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions
.GetLanguageByExtension(".json").Id));
}
public void Receive(EditorUpdateMessage message)
{
switch (message.Value.Key)
{
case "EndpointRequestEditor":
_requestEditor!.Text = message.Value.Text;
break;
case "EndpointResponseEditor":
_responseEditor!.Text = message.Value.Text;
break;
default:
break;
}
}
public void Receive(ContentRequestMessage message)
{
message.Reply(_requestEditor!.Text);
}
}

View File

@@ -0,0 +1,14 @@
<UserControl 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:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
xmlns:theme="clr-namespace:SukiUI.Theme;assembly=SukiUI"
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
xmlns:avalonEdit="https://github.com/avaloniaui/avaloniaedit"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.EndpointsContainerView"
x:DataType="vm:EndpointsContainerViewModel">
<suki:SukiStackPage Content="{Binding ActiveViewModel}"
Margin="-24 -4 0 0"/>
</UserControl>

View File

@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace Needlework.Net.Desktop.Views;
public partial class EndpointsContainerView : UserControl
{
public EndpointsContainerView()
{
InitializeComponent();
}
}

View File

@@ -8,10 +8,8 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.EndpointsView"
x:DataType="vm:EndpointsViewModel">
<!-- TOP LEVEL -->
<suki:BusyArea IsBusy="{Binding IsBusy}" BusyText="Loading...">
<Grid Margin="16" RowDefinitions="auto,auto,*" ColumnDefinitions="*">
<TextBlock Classes="h3" Margin="0 4" Grid.Row="0" Grid.Column="0">Endpoints</TextBlock>
<TextBox Watermark="Search" Margin="0 4" Text="{Binding Search}" Grid.Row="1" Grid.Column="0"/>
<ScrollViewer Grid.Row="2" Grid.Column="0">
<ListBox ItemsSource="{Binding Query}" SelectedItem="{Binding SelectedQuery}">

View File

@@ -1,4 +1,5 @@
<Window xmlns="https://github.com/avaloniaui"
<suki:SukiWindow
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"
@@ -10,8 +11,15 @@
x:Class="Needlework.Net.Desktop.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Title="Needlework.Net"
Icon="/Assets/app.ico"
Width="1280"
Height="720">
<suki:SukiWindow.LogoContent>
<Image Source="/Assets/app.png"
Width="20"
Height="20"
VerticalAlignment="Center"/>
</suki:SukiWindow.LogoContent>
<!-- TOP LEVEL -->
<suki:SukiSideMenu ItemsSource="{Binding Pages}">
<!-- ITEMS -->
@@ -40,13 +48,25 @@
</Style>
</StackPanel.Styles>
<Button Classes="Flat"
Content="{Binding Version}" />
Content="{Binding Version}"
FontSize="12"
Margin="0 0 4 0"
Padding="12 4 12 4"
VerticalAlignment="Center"/>
<Button Classes="Basic"
VerticalAlignment="Center"
CommandParameter="https://github.com/BlossomiShymae/Needlework.Net"
ToolTip.Tip="Open on GitHub.">
<materialIcons:MaterialIcon Kind="Github" />
ToolTip.Tip="Open on GitHub."
Margin="0 0 4 0">
<StackPanel Orientation="Horizontal">
<materialIcons:MaterialIcon Kind="Github" Margin="0 0 4 0" />
<TextBlock FontSize="12"
VerticalAlignment="Center"
Foreground="White">Star</TextBlock>
</StackPanel>
</Button>
<Button Classes="Basic"
VerticalAlignment="Center"
CommandParameter="https://discord.gg/chEvEX5J4E"
ToolTip.Tip="Open Discord server.">
<i:Icon Value="fa-brand fa-discord" />
@@ -54,4 +74,4 @@
</StackPanel>
</suki:SukiSideMenu.FooterContent>
</suki:SukiSideMenu>
</Window>
</suki:SukiWindow>

View File

@@ -1,4 +1,3 @@
using Avalonia.Controls;
using SukiUI.Controls;
namespace Needlework.Net.Desktop.Views;

View File

@@ -0,0 +1,45 @@
<suki:SukiWindow
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:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.OopsiesWindow"
x:DataType="vm:OopsiesWindowViewModel"
Title="Needlework.Net - Oopsies"
WindowStartupLocation="CenterOwner"
Width="560"
Height="200">
<Grid RowDefinitions="auto,auto,auto" ColumnDefinitions="auto,auto"
Margin="8"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<TextBlock
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2">
This response is too large for Needlework.Net to handle for performance reasons.
</TextBlock>
<TextBlock
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0 0 0 12">
It can be viewed in an external editor or viewer.
</TextBlock>
<Button Command="{Binding OpenDefaultEditorCommand}"
Grid.Row="2"
Grid.Column="0"
Margin="0 0 8 0">
Open
</Button>
<Button Command="{Binding CloseDialogCommand}"
Grid.Row="2"
Grid.Column="1"
Margin="8 0 0 0">
Cancel
</Button>
</Grid>
</suki:SukiWindow>

View File

@@ -0,0 +1,11 @@
using SukiUI.Controls;
namespace Needlework.Net.Desktop.Views;
public partial class OopsiesWindow : SukiWindow
{
public OopsiesWindow()
{
InitializeComponent();
}
}

View File

@@ -1,20 +0,0 @@
<UserControl 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:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.PluginView"
x:DataType="vm:PluginViewModel">
<!-- TOP LEVEL -->
<ScrollViewer>
<StackPanel Margin="8">
<suki:GlassCard>
<StackPanel>
</StackPanel>
</suki:GlassCard>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -1,12 +0,0 @@
using Avalonia.Controls;
namespace Needlework.Net.Desktop.Views
{
public partial class PluginView : UserControl
{
public PluginView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,68 @@
<UserControl 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:avaloniaEdit="https://github.com/avaloniaui/avaloniaedit"
xmlns:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.WebsocketView"
x:DataType="vm:WebsocketViewModel">
<Grid RowDefinitions="*,2,*" Margin="16">
<Border Grid.Row="0"
Padding="0 0 0 8">
<suki:GlassCard>
<Grid RowDefinitions="auto,*" ColumnDefinitions="*">
<Grid
Grid.Row="0"
Grid.Column="0"
RowDefinitions="*"
ColumnDefinitions="auto,*,auto,auto">
<Button Grid.Row="0"
Grid.Column="0"
Command="{Binding ClearCommand}"
Margin="0 0 8 0">Clear</Button>
<TextBox Grid.Row="0"
Grid.Column="1"
Margin="0 0 8 0"
Text="{Binding Search, Mode=TwoWay}"/>
<StackPanel Orientation="Horizontal"
Grid.Row="0"
Grid.Column="2"
Margin="0 0 8 0">
<ToggleSwitch Margin="0 0 0 8"
IsChecked="{Binding IsAttach}"/>
<TextBlock Margin="0 6 0 0"
FontSize="18">Attach</TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal"
Grid.Row="0"
Grid.Column="3">
<ToggleSwitch Margin="0 0 0 8"
IsChecked="{Binding IsTail}"/>
<TextBlock Margin="0 6 0 0"
FontSize="18">Tail</TextBlock>
</StackPanel>
</Grid>
<ListBox Grid.Row="1"
Grid.Column="0"
Name="EventViewer"
ItemsSource="{Binding FilteredEventLog}"
SelectedItem="{Binding SelectedEventLog}"/>
</Grid>
</suki:GlassCard>
</Border>
<GridSplitter Grid.Row="1" ResizeDirection="Rows" Background="Gray"/>
<Border Grid.Row="2"
Padding="0 8 0 0">
<suki:GlassCard>
<avaloniaEdit:TextEditor
Name="ResponseEditor"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
Text=""
FontSize="14"/>
</suki:GlassCard>
</Border>
</Grid>
</UserControl>

View File

@@ -0,0 +1,57 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Styling;
using AvaloniaEdit;
using AvaloniaEdit.TextMate;
using CommunityToolkit.Mvvm.Messaging;
using Needlework.Net.Desktop.Extensions;
using Needlework.Net.Desktop.Messages;
using Needlework.Net.Desktop.ViewModels;
using SukiUI;
using TextMateSharp.Grammars;
namespace Needlework.Net.Desktop.Views;
public partial class WebsocketView : UserControl, IRecipient<ResponseUpdatedMessage>
{
private TextEditor? _responseEditor;
public WebsocketView()
{
InitializeComponent();
}
public void Receive(ResponseUpdatedMessage message)
{
_responseEditor!.Text = message.Value;
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
var vm = (WebsocketViewModel)DataContext!;
var viewer = this.FindControl<ListBox>("EventViewer");
viewer!.PropertyChanged += (s, e) => { if (vm.IsTail) viewer.ScrollIntoView(vm.EventLog.Count - 1); };
_responseEditor = this.FindControl<TextEditor>("ResponseEditor");
_responseEditor?.ApplyJsonEditorSettings();
WeakReferenceMessenger.Default.Register(this, nameof(WebsocketViewModel));
OnBaseThemeChanged(Application.Current!.ActualThemeVariant);
SukiTheme.GetInstance().OnBaseThemeChanged += OnBaseThemeChanged;
}
private void OnBaseThemeChanged(ThemeVariant currentTheme)
{
var registryOptions = new RegistryOptions(
currentTheme == ThemeVariant.Dark ? ThemeName.DarkPlus : ThemeName.LightPlus);
var responseTmi = _responseEditor.InstallTextMate(registryOptions);
responseTmi.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions
.GetLanguageByExtension(".json").Id));
}
}