Bump version, migrate to FluentAvalonia with bug fixes

This commit is contained in:
BlossomiShymae
2024-08-15 06:38:39 -05:00
parent 1133f2d785
commit 83400bceed
40 changed files with 781 additions and 523 deletions

View File

@@ -1,20 +1,20 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Needlework.Net.Desktop.App"
RequestedThemeVariant="Dark"
xmlns:local="using:Needlework.Net.Desktop"
xmlns:converters="using:Needlework.Net.Desktop.Converters"
xmlns:sukiUi="clr-namespace:SukiUI;assembly=SukiUI"
xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia">
xmlns:sty="using:FluentAvalonia.Styling"
xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
RequestedThemeVariant="Dark">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<FluentTheme></FluentTheme>
<sukiUi:SukiTheme ThemeColor="Blue" />
<sty:FluentAvaloniaTheme PreferSystemTheme="False" PreferUserAccentColor="False" />
<materialIcons:MaterialIconStyles />
<StyleInclude Source="Controls/Card.axaml"/>
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml" />
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
</Application.Styles>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

View File

@@ -0,0 +1,66 @@
<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:controls="using:Needlework.Net.Desktop.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Controls.BusyArea">
<UserControl.Styles>
<Style Selector="controls|BusyArea">
<Setter Property="Template">
<ControlTemplate>
<Panel>
<ContentControl Content="{TemplateBinding Content}"/>
<DockPanel Name="LoadingBusyArea"
HorizontalAlignment="Center"
VerticalAlignment="Center"
LastChildFill="True">
<TextBlock Margin="16"
DockPanel.Dock="Bottom"
HorizontalAlignment="Center"
FontWeight="DemiBold"
Text="{TemplateBinding BusyText}"/>
<ProgressBar
Width="100"
IsIndeterminate="True"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</DockPanel>
</Panel>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="controls|BusyArea DockPanel#LoadingBusyArea">
<Setter Property="Transitions">
<Transitions>
<DoubleTransition Property="Opacity" Duration="0:0:0.3" />
</Transitions>
</Setter>
</Style>
<Style Selector="controls|BusyArea[IsBusy=True] DockPanel#LoadingBusyArea">
<Setter Property="Opacity" Value="1"/>
</Style>
<Style Selector="controls|BusyArea[IsBusy=False] DockPanel#LoadingBusyArea">
<Setter Property="Opacity" Value="0"/>
</Style>
<Style Selector="controls|BusyArea ContentControl">
<Setter Property="Transitions">
<Transitions>
<DoubleTransition Property="Opacity" Duration="0:0:0.3"/>
</Transitions>
</Setter>
</Style>
<Style Selector="controls|BusyArea[IsBusy=True] ContentControl">
<Setter Property="Opacity" Value="0.1"/>
</Style>
<Style Selector="controls|BusyArea[IsBusy=False] ContentControl">
<Setter Property="Opacity" Value="1"/>
</Style>
</UserControl.Styles>
</UserControl>

View File

@@ -0,0 +1,30 @@
using Avalonia;
using Avalonia.Controls;
namespace Needlework.Net.Desktop.Controls;
public partial class BusyArea : UserControl
{
public BusyArea()
{
InitializeComponent();
}
public static readonly StyledProperty<bool> IsBusyProperty =
AvaloniaProperty.Register<BusyArea, bool>(nameof(IsBusy), defaultValue: false);
public bool IsBusy
{
get { return GetValue(IsBusyProperty); }
set { SetValue(IsBusyProperty, value); }
}
public static readonly StyledProperty<string?> BusyTextProperty =
AvaloniaProperty.Register<BusyArea, string?>(nameof(BusyText), defaultValue: null);
public string? BusyText
{
get => GetValue(BusyTextProperty);
set => SetValue(BusyTextProperty, value);
}
}

View File

@@ -0,0 +1,20 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Needlework.Net.Desktop.Controls">
<Design.PreviewWith>
<controls:Card />
</Design.PreviewWith>
<Style Selector="controls|Card">
<!-- Set Defaults -->
<Setter Property="Template">
<ControlTemplate>
<Border Padding="16"
CornerRadius="16,16,16,16"
Background="{DynamicResource CardBackgroundFillColorDefaultBrush}">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter>
</Style>
</Styles>

View File

@@ -0,0 +1,10 @@
using Avalonia.Controls;
namespace Needlework.Net.Desktop.Controls;
public class Card : ContentControl
{
public Card()
{
}
}

View File

@@ -0,0 +1,9 @@
using CommunityToolkit.Mvvm.Messaging.Messages;
using Needlework.Net.Desktop.ViewModels;
namespace Needlework.Net.Desktop.Messages
{
public class InfoBarUpdateMessage(InfoBarViewModel vm) : ValueChangedMessage<InfoBarViewModel>(vm)
{
}
}

View File

@@ -11,8 +11,8 @@
<AvaloniaXamlIlDebuggerLaunch>False</AvaloniaXamlIlDebuggerLaunch>
<ApplicationIcon>app.ico</ApplicationIcon>
<AssemblyName>NeedleworkDotNet</AssemblyName>
<AssemblyVersion>0.3.2.0</AssemblyVersion>
<FileVersion>0.3.2.0</FileVersion>
<AssemblyVersion>0.4.0.0</AssemblyVersion>
<FileVersion>0.4.0.0</FileVersion>
<AvaloniaXamlVerboseExceptions>False</AvaloniaXamlVerboseExceptions>
</PropertyGroup>
@@ -35,7 +35,6 @@
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Projektanker.Icons.Avalonia" Version="9.4.0" />
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.4.0" />
<PackageReference Include="SukiUI" Version="6.0.0-beta7" />
<PackageReference Include="TextMateSharp.Grammars" Version="1.0.62" />
</ItemGroup>
@@ -52,6 +51,9 @@
</ItemGroup>
<ItemGroup>
<Compile Update="Controls\BusyArea.axaml.cs">
<DependentUpon>BusyArea.axaml</DependentUpon>
</Compile>
<Compile Update="Views\EndpointView.axaml.cs">
<DependentUpon>EndpointView.axaml</DependentUpon>
</Compile>

View File

@@ -2,9 +2,7 @@
using Needlework.Net.Desktop.Messages;
using Needlework.Net.Desktop.ViewModels;
using Needlework.Net.Desktop.Views;
using SukiUI.Controls;
using System;
using System.Collections.Generic;
namespace Needlework.Net.Desktop.Services
{
@@ -12,9 +10,6 @@ namespace Needlework.Net.Desktop.Services
{
public IServiceProvider ServiceProvider { get; }
public Dictionary<string, SukiWindow> EndpointWindows { get; } = []; // Workaround memory leak by storing and reusing windows.
// Figure out why creating and closing windows leaks memory.
public OopsiesWindow? OopsiesWindow { get; set; }
public WindowService(IServiceProvider serviceProvider)

View File

@@ -2,7 +2,7 @@
{
public class AboutViewModel : PageBase
{
public AboutViewModel() : base("About", Material.Icons.MaterialIconKind.InfoCircle)
public AboutViewModel() : base("About", "info-circle")
{
}
}

View File

@@ -5,7 +5,6 @@ using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Needlework.Net.Desktop.Messages;
using Needlework.Net.Desktop.Services;
using SukiUI.Controls;
using System;
using System.Net.Http;
using System.Text.Json;
@@ -30,7 +29,7 @@ namespace Needlework.Net.Desktop.ViewModels
public WindowService WindowService { get; }
public ConsoleViewModel(WindowService windowService) : base("Console", Material.Icons.MaterialIconKind.Console, -200)
public ConsoleViewModel(WindowService windowService) : base("Console", "terminal", -200)
{
WindowService = windowService;
@@ -79,7 +78,7 @@ namespace Needlework.Net.Desktop.ViewModels
}
catch (Exception ex)
{
await SukiHost.ShowToast("Request Failed", ex.Message, SukiUI.Enums.NotificationType.Error);
WeakReferenceMessenger.Default.Send(new InfoBarUpdateMessage(new InfoBarViewModel("Request Failed", true, ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error, TimeSpan.FromSeconds(5))));
ResponseStatus = null;
ResponsePath = null;
ResponseAuthorization = null;

View File

@@ -2,12 +2,11 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Needlework.Net.Desktop.Messages;
using SukiUI.Controls;
using System.Linq;
namespace Needlework.Net.Desktop.ViewModels
{
public partial class EndpointViewModel : ObservableObject, ISukiStackPageTitleProvider
public partial class EndpointViewModel : ObservableObject
{
public string Endpoint { get; }
public string Title => Endpoint;
@@ -38,5 +37,11 @@ namespace Needlework.Net.Desktop.ViewModels
FilteredPathOperations = new AvaloniaList<PathOperationViewModel>(PathOperations.Where(o => o.Path.ToLower().Contains(value.ToLower())));
}
partial void OnSelectedPathOperationChanged(PathOperationViewModel? value)
{
if (value == null) return;
WeakReferenceMessenger.Default.Send(new EditorUpdateMessage(new(value.Operation.RequestTemplate ?? string.Empty, "EndpointRequestEditor")));
}
}
}

View File

@@ -1,21 +1,31 @@
using CommunityToolkit.Mvvm.ComponentModel;
using SukiUI.Controls;
using CommunityToolkit.Mvvm.Input;
using System.Net.Http;
namespace Needlework.Net.Desktop.ViewModels
{
public partial class EndpointsContainerViewModel : PageBase
{
[ObservableProperty] private ISukiStackPageTitleProvider _activeViewModel;
[ObservableProperty] private ObservableObject _activeViewModel;
[ObservableProperty] private ObservableObject _endpointsViewModel;
[ObservableProperty] private string _title = string.Empty;
public EndpointsContainerViewModel(HttpClient httpClient) : base("Endpoints", Material.Icons.MaterialIconKind.Hub, -500)
public EndpointsContainerViewModel(HttpClient httpClient) : base("Endpoints", "list-alt", -500)
{
_activeViewModel = new EndpointsViewModel(httpClient, OnClicked);
_activeViewModel = _endpointsViewModel = new EndpointsViewModel(httpClient, OnClicked);
}
private void OnClicked(ISukiStackPageTitleProvider viewModel)
private void OnClicked(ObservableObject viewModel)
{
ActiveViewModel = viewModel;
if (viewModel is EndpointViewModel endpoint) Title = endpoint.Title;
}
[RelayCommand]
private void GoBack()
{
ActiveViewModel = EndpointsViewModel;
Title = string.Empty;
}
}
}

View File

@@ -1,20 +1,20 @@
using Avalonia.Collections;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Needlework.Net.Desktop.Messages;
using SukiUI.Controls;
using System;
using System.Linq;
using System.Net.Http;
namespace Needlework.Net.Desktop.ViewModels
{
public partial class EndpointsViewModel : ObservableObject, IRecipient<DataReadyMessage>, ISukiStackPageTitleProvider
public partial class EndpointsViewModel : ObservableObject, IRecipient<DataReadyMessage>
{
public HttpClient HttpClient { get; }
public string Title => "Endpoints";
public Action<ISukiStackPageTitleProvider> OnClicked;
public Action<ObservableObject> OnClicked;
[ObservableProperty] private IAvaloniaReadOnlyList<string> _plugins = new AvaloniaList<string>();
[ObservableProperty] private bool _isBusy = true;
@@ -22,7 +22,7 @@ namespace Needlework.Net.Desktop.ViewModels
[ObservableProperty] private IAvaloniaReadOnlyList<string> _query = new AvaloniaList<string>();
[ObservableProperty] private string? _selectedQuery = string.Empty;
public EndpointsViewModel(HttpClient httpClient, Action<ISukiStackPageTitleProvider> onClicked)
public EndpointsViewModel(HttpClient httpClient, Action<ObservableObject> onClicked)
{
HttpClient = httpClient;
OnClicked = onClicked;
@@ -45,7 +45,8 @@ namespace Needlework.Net.Desktop.ViewModels
Query = Plugins;
}
partial void OnSelectedQueryChanged(string? value)
[RelayCommand]
private void OpenEndpoint(string? value)
{
if (string.IsNullOrEmpty(value)) return;

View File

@@ -1,62 +1,18 @@
using Avalonia.Media;
using BlossomiShymae.GrrrLCU;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using CommunityToolkit.Mvvm.Input;
using System.Diagnostics;
using System.Threading;
namespace Needlework.Net.Desktop.ViewModels
{
public partial class HomeViewModel : PageBase
{
[ObservableProperty] private string _statusText = string.Empty;
[ObservableProperty] private IBrush? _statusForeground;
[ObservableProperty] private string _statusAddress = string.Empty;
public HomeViewModel() : base("Home", Material.Icons.MaterialIconKind.Home, int.MinValue)
{
var thread = new Thread(StartProcessing) { IsBackground = true };
thread.Start();
}
private void StartProcessing()
{
while (true)
{
void Set(string text, Color color, string address)
{
Avalonia.Threading.Dispatcher.UIThread.Invoke(() =>
{
StatusText = text;
StatusForeground = new SolidColorBrush(color.ToUInt32());
StatusAddress = address;
});
}
try
{
var processInfo = Connector.GetProcessInfo();
Set("Online", Colors.Green, $"https://127.0.0.1:{processInfo.AppPort}/");
}
catch (InvalidOperationException)
{
Set("Offline", Colors.Red, "N/A");
}
Thread.Sleep(TimeSpan.FromSeconds(5));
}
}
public HomeViewModel() : base("Home", "home", int.MinValue) { }
[RelayCommand]
private void OpenUrl(string url)
{
var process = new Process()
{
StartInfo = new ProcessStartInfo(url)
{
UseShellExecute = true
}
StartInfo = new ProcessStartInfo(url) { UseShellExecute = true }
};
process.Start();
}

View File

@@ -0,0 +1,27 @@
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using FluentAvalonia.UI.Controls;
using System;
namespace Needlework.Net.Desktop.ViewModels
{
public partial class InfoBarViewModel : ObservableObject
{
[ObservableProperty] private string _title;
[ObservableProperty] private bool _isOpen;
[ObservableProperty] private string _message;
[ObservableProperty] private InfoBarSeverity _severity;
[ObservableProperty] private TimeSpan _duration;
[ObservableProperty] private Control? _actionButton;
public InfoBarViewModel(string title, bool isOpen, string message, InfoBarSeverity severity, TimeSpan duration, Control? actionButton = null)
{
_title = title;
_isOpen = isOpen;
_message = message;
_severity = severity;
_duration = duration;
_actionButton = actionButton;
}
}
}

View File

@@ -2,13 +2,14 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using FluentAvalonia.UI.Controls;
using Microsoft.OpenApi.Models;
using Needlework.Net.Core;
using Needlework.Net.Desktop.Messages;
using Needlework.Net.Desktop.Services;
using SukiUI.Controls;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
@@ -19,10 +20,15 @@ using System.Threading.Tasks;
namespace Needlework.Net.Desktop.ViewModels
{
public partial class MainWindowViewModel : ObservableObject, IRecipient<DataRequestMessage>, IRecipient<HostDocumentRequestMessage>, IRecipient<OopsiesWindowRequestedMessage>
public partial class MainWindowViewModel : ObservableObject, IRecipient<DataRequestMessage>, IRecipient<HostDocumentRequestMessage>, IRecipient<OopsiesWindowRequestedMessage>, IRecipient<InfoBarUpdateMessage>
{
public IAvaloniaReadOnlyList<PageBase> Pages { get; }
public IAvaloniaReadOnlyList<NavigationViewItem> MenuItems { get; }
[NotifyPropertyChangedFor(nameof(CurrentPage))]
[ObservableProperty] private NavigationViewItem _selectedMenuItem;
public PageBase CurrentPage => (PageBase)SelectedMenuItem.Tag!;
public string Version { get; } = Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0.0.0.0";
[ObservableProperty] private bool _isUpdateShown = false;
public HttpClient HttpClient { get; }
public WindowService WindowService { get; }
@@ -30,11 +36,22 @@ namespace Needlework.Net.Desktop.ViewModels
public OpenApiDocument? HostDocument { get; set; }
[ObservableProperty] private bool _isBusy = true;
[ObservableProperty] private bool _isUpdateShown = false;
[ObservableProperty] private ObservableCollection<InfoBarViewModel> _infoBarItems = [];
public MainWindowViewModel(IEnumerable<PageBase> pages, HttpClient httpClient, WindowService windowService)
{
Pages = new AvaloniaList<PageBase>(pages.OrderBy(x => x.Index).ThenBy(x => x.DisplayName));
MenuItems = new AvaloniaList<NavigationViewItem>(pages
.OrderBy(p => p.Index)
.ThenBy(p => p.DisplayName)
.Select(p => new NavigationViewItem()
{
Content = p.DisplayName,
Tag = p,
IconSource = new BitmapIconSource() { UriSource = new Uri($"avares://NeedleworkDotNet/Assets/Icons/{p.Icon}.png") }
}));
SelectedMenuItem = MenuItems[0];
HttpClient = httpClient;
WindowService = windowService;
@@ -69,9 +86,14 @@ namespace Needlework.Net.Desktop.ViewModels
if (release.IsLatest(currentVersion) && !IsUpdateShown)
{
await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(async () =>
Avalonia.Threading.Dispatcher.UIThread.Post(async () =>
{
await SukiHost.ShowToast("Needlework.Net Update", $"There is a new version available: {release.TagName}.", SukiUI.Enums.NotificationType.Info, TimeSpan.FromSeconds(10), () => OpenUrl("https://github.com/BlossomiShymae/Needlework.Net/releases"));
await ShowInfoBarAsync(new("Needlework.Net Update", true, $"There is a new version available: {release.TagName}.", InfoBarSeverity.Informational, TimeSpan.FromSeconds(10), new Avalonia.Controls.Button()
{
Command = OpenUrlCommand,
CommandParameter = "https://github.com/BlossomiShymae/Needlework.Net/releases",
Content = "Download"
}));
IsUpdateShown = true;
});
}
@@ -87,7 +109,6 @@ namespace Needlework.Net.Desktop.ViewModels
LcuSchemaHandler = handler;
WeakReferenceMessenger.Default.Send(new DataReadyMessage(handler));
await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(async () => await SukiHost.ShowToast("OpenAPI Data Processed", "Some pages can now be used.", SukiUI.Enums.NotificationType.Success, TimeSpan.FromSeconds(5)));
IsBusy = false;
}
@@ -118,5 +139,17 @@ namespace Needlework.Net.Desktop.ViewModels
{
WindowService.ShowOopsiesWindow(message.Value);
}
public void Receive(InfoBarUpdateMessage message)
{
Avalonia.Threading.Dispatcher.UIThread.Post(async () => await ShowInfoBarAsync(message.Value));
}
private async Task ShowInfoBarAsync(InfoBarViewModel vm)
{
InfoBarItems.Add(vm);
await Task.Delay(vm.Duration);
InfoBarItems.Remove(vm);
}
}
}

View File

@@ -4,6 +4,8 @@ using CommunityToolkit.Mvvm.Messaging;
using Microsoft.OpenApi.Models;
using Needlework.Net.Desktop.Messages;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
namespace Needlework.Net.Desktop.ViewModels
{
@@ -18,6 +20,7 @@ namespace Needlework.Net.Desktop.ViewModels
public IAvaloniaReadOnlyList<PropertyClassViewModel> ResponseClasses { get; }
public IAvaloniaReadOnlyList<ParameterViewModel> PathParameters { get; }
public IAvaloniaReadOnlyList<ParameterViewModel> QueryParameters { get; }
public string? RequestTemplate { get; }
public OperationViewModel(OpenApiOperation operation)
{
@@ -30,6 +33,71 @@ namespace Needlework.Net.Desktop.ViewModels
PathParameters = GetParameters(operation.Parameters, ParameterLocation.Path);
QueryParameters = GetParameters(operation.Parameters, ParameterLocation.Query);
RequestBodyType = GetRequestBodyType(operation.RequestBody);
RequestTemplate = GetRequestTemplate(operation.RequestBody);
}
private string? GetRequestTemplate(OpenApiRequestBody? requestBody)
{
var requestClasses = GetRequestClasses(requestBody);
if (requestClasses.Count == 0)
{
var type = GetRequestBodyType(requestBody);
if (type == null) return null;
return GetRequestDefaultValue(type);
}
var template = CreateTemplate(requestClasses);
return JsonSerializer.Serialize(JsonSerializer.Deserialize<object>(string.Join(string.Empty, template)), App.JsonSerializerOptions);
}
private List<string> CreateTemplate(AvaloniaList<PropertyClassViewModel> requestClasses)
{
if (requestClasses.Count == 0) return [];
List<string> template = [];
template.Add("{");
var rootClass = requestClasses.First();
if (rootClass.PropertyEnums.Any()) return [rootClass.PropertyEnums.First().Values];
var propertyFields = rootClass.PropertyFields;
for (int i = 0; i < propertyFields.Count; i++)
{
template.Add($"\"{propertyFields[i].Name}\"");
template.Add(":");
template.Add($"#{propertyFields[i].Type}");
if (i == propertyFields.Count - 1) template.Add("}");
else template.Add(",");
}
for (int i = 0; i < template.Count; i++)
{
var type = template[i];
if (!type.Contains("#")) continue;
if (requestClasses.Where(c => c.Id == type.Replace("#", string.Empty)).Any())
{
AvaloniaList<PropertyClassViewModel> classes = [.. requestClasses];
classes.Remove(rootClass);
template[i] = string.Join(string.Empty, CreateTemplate(classes));
}
else
{
template[i] = GetRequestDefaultValue(type);
}
}
return template;
}
private static string GetRequestDefaultValue(string type)
{
var defaultValue = string.Empty;
if (type.Contains("[]")) defaultValue = "[]";
else if (type.Contains("string")) defaultValue = "\"\"";
else if (type.Contains("boolean")) defaultValue = "false";
else if (type.Contains("integer")) defaultValue = "0";
else if (type.Contains("double") || type.Contains("float")) defaultValue = "0.0";
else if (type.Contains("object")) defaultValue = "{}";
return defaultValue;
}
private string? GetRequestBodyType(OpenApiRequestBody? requestBody)
@@ -78,6 +146,8 @@ namespace Needlework.Net.Desktop.ViewModels
string componentId = GetComponentId(schema);
var componentSchema = document.Components.Schemas[componentId];
var responseClass = new PropertyClassViewModel(componentId, componentSchema.Properties, componentSchema.Enum);
if (propertyClasses.Where(c => c.Id == componentId).Any()) return; // Avoid adding duplicate schemas in classes
propertyClasses.Add(responseClass);
foreach ((var _, var property) in componentSchema.Properties)

View File

@@ -1,13 +1,12 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Material.Icons;
namespace Needlework.Net.Desktop.ViewModels
{
public abstract partial class PageBase(string displayName, MaterialIconKind icon, int index = 0) : ObservableValidator
public abstract partial class PageBase(string displayName, string icon, int index = 0) : ObservableValidator
{
[ObservableProperty] private string _displayName = displayName;
[ObservableProperty] private MaterialIconKind _icon = icon;
[ObservableProperty] private string _icon = icon;
[ObservableProperty] private int _index = index;
}
}

View File

@@ -5,7 +5,6 @@ using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Needlework.Net.Core;
using Needlework.Net.Desktop.Messages;
using SukiUI.Controls;
using System;
using System.Net.Http;
using System.Text.Json;
@@ -114,7 +113,7 @@ namespace Needlework.Net.Desktop.ViewModels
}
catch (Exception ex)
{
await SukiHost.ShowToast("Request Failed", ex.Message, SukiUI.Enums.NotificationType.Error);
WeakReferenceMessenger.Default.Send(new InfoBarUpdateMessage(new InfoBarViewModel("Request Failed", true, ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error, TimeSpan.FromSeconds(5))));
WeakReferenceMessenger.Default.Send(new EditorUpdateMessage(new(string.Empty, "EndpointResponseEditor")));
}
finally

View File

@@ -11,7 +11,7 @@ namespace Needlework.Net.Desktop.ViewModels
public PropertyEnumViewModel(IList<IOpenApiAny> enumValue)
{
Values = $"[{string.Join(", ", enumValue.Select(x => ((OpenApiString)x).Value).ToList())}]";
Values = $"[{string.Join(", ", enumValue.Select(x => $"\"{((OpenApiString)x).Value}\"").ToList())}]";
}
}
}

View File

@@ -2,7 +2,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Material.Icons;
using Needlework.Net.Desktop.Messages;
using Needlework.Net.Desktop.Services;
using System;
@@ -34,7 +33,7 @@ namespace Needlework.Net.Desktop.ViewModels
public List<string> FilteredEventLog => string.IsNullOrWhiteSpace(Search) ? [.. EventLog] : [.. EventLog.Where(x => x.ToLower().Contains(Search.ToLower()))];
public WebsocketViewModel(WindowService windowService) : base("Event Viewer", MaterialIconKind.Connection, -100)
public WebsocketViewModel(WindowService windowService) : base("Event Viewer", "plug", -100)
{
WindowService = windowService;

View File

@@ -2,39 +2,37 @@
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:controls="using:Needlework.Net.Desktop.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.AboutView"
x:DataType="vm:AboutViewModel">
<Grid Margin="8"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<WrapPanel
theme:WrapPanelExtensions.AnimatedScroll="true"
Orientation="Horizontal">
<suki:GlassCard Margin="8">
<WrapPanel Orientation="Horizontal">
<controls:Card Margin="8">
<Image Source="/Assets/about.png"
RenderOptions.BitmapInterpolationMode="MediumQuality"
Width="200"
Height="200"/>
</suki:GlassCard>
</controls:Card>
<StackPanel Margin="8 0 0 0">
<controls:Card Width="400" Margin="8">
<StackPanel>
<suki:GlassCard Width="400" Margin="8">
<StackPanel>
<TextBlock Classes="h3">Blossomi Shymae</TextBlock>
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">Blossomi Shymae</TextBlock>
</StackPanel>
</suki:GlassCard>
<suki:GlassCard Width="400" Margin="8">
<suki:GroupBox Header="About">
</controls:Card>
<controls:Card Width="400" Margin="8">
<StackPanel >
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">About</TextBlock>
<TextBlock TextWrapping="Wrap">
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! 💜
Needlework.Net is the .NET rewrite of Needlework. This tool was made to help others with LCU development. Feel free to ask any questions
or help contribute to the project! Made with love. 💜
</TextBlock>
</suki:GroupBox>
</suki:GlassCard>
</StackPanel>
</controls:Card>
</StackPanel>
</WrapPanel>
</Grid>

View File

@@ -2,85 +2,86 @@
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:avaloniaEdit="https://github.com/avaloniaui/avaloniaedit"
xmlns:theme="clr-namespace:SukiUI.Theme;assembly=SukiUI"
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
xmlns:controls="using:Needlework.Net.Desktop.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.ConsoleView"
x:DataType="vm:ConsoleViewModel">
<suki:BusyArea IsBusy="{Binding IsBusy}" BusyText="Loading...">
<controls: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"/>
<StackPanel Margin="0 0 0 16">
<Grid RowDefinitions="auto" ColumnDefinitions="auto,*,auto">
<ComboBox ItemsSource="{Binding RequestMethods}"
SelectedItem="{Binding RequestMethodSelected}"
Margin="0 0 8 0"
Grid.Row="0"
Grid.Column="0"/>
<AutoCompleteBox
ItemsSource="{Binding RequestPaths}"
Text="{Binding RequestPath}"
MaxDropDownHeight="400"
FilterMode="StartsWith"
Grid.Row="0" Grid.Column="1"/>
Grid.Row="0"
Grid.Column="1"/>
<Button Margin="8 0 0 0"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
FontWeight="DemiBold"
Grid.Row="0"
Grid.Column="2"
Command="{Binding SendRequestCommand}">
Send
</Button>
</Grid>
</StackPanel>
</Grid>
<Grid Grid.Row="1"
Grid.Column="0"
RowDefinitions="auto,*"
ColumnDefinitions="*">
<TextBox IsReadOnly="True"
Grid.Row="0"
Grid.Column="0"
Text="{Binding ResponsePath}"/>
<avaloniaEdit:TextEditor
Name="RequestEditor"
Text=""
ShowLineNumbers="True"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
Margin="0 8 0 0"
FontSize="12"
Height="100"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"/>
Grid.Column="0"/>
</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="Authorization">
<TextBlock Text="{Binding ResponseAuthorization}" />
</suki:GroupBox>
</suki:GlassCard>
</StackPanel>
<suki:GlassCard
Margin="0 8"
<Grid RowDefinitions="35,*"
ColumnDefinitions="*"
Margin="8 0 0 0"
Grid.Row="1"
Grid.Column="1">
<StackPanel Orientation="Horizontal"
Grid.Row="0"
Grid.Column="0">
<Button Content="{Binding ResponseStatus}"
FontSize="12"
VerticalAlignment="Center"/>
</StackPanel>
<avaloniaEdit:TextEditor
Grid.Row="1"
Grid.Column="0"
Name="ResponseEditor"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
ShowLineNumbers="True"
IsReadOnly="True"
Text=""
FontSize="12"/>
</suki:GlassCard>
</Grid>
</suki:BusyArea>
</Grid>
</controls:BusyArea>
</UserControl>

View File

@@ -3,12 +3,10 @@ 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;
@@ -46,7 +44,6 @@ public partial class ConsoleView : UserControl, IRecipient<ResponseUpdatedMessag
WeakReferenceMessenger.Default.Register<ContentRequestMessage, string>(this, "ConsoleRequestEditor");
OnBaseThemeChanged(Application.Current!.ActualThemeVariant);
SukiTheme.GetInstance().OnBaseThemeChanged += OnBaseThemeChanged;
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
@@ -54,19 +51,11 @@ public partial class ConsoleView : UserControl, IRecipient<ResponseUpdatedMessag
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 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

@@ -2,15 +2,35 @@
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:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:theme="clr-namespace:SukiUI.Theme;assembly=SukiUI"
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
xmlns:avalonEdit="https://github.com/avaloniaui/avaloniaedit"
xmlns:controls="using:Needlework.Net.Desktop.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.EndpointView"
x:DataType="vm:EndpointViewModel">
<Grid RowDefinitions="auto,*" ColumnDefinitions="3*,2,4*,2,4*">
<UserControl.Styles>
<Style Selector="DataGrid">
<Setter Property="HorizontalGridLinesBrush" Value="{DynamicResource ControlElevationBorderBrush}"/>
</Style>
<Style Selector="DataGridColumnHeader TextBlock">
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}"/>
</Style>
<Style Selector="DataGridRow DataGridCell">
<Setter Property="FontSize" Value="12"></Setter>
</Style>
<Style Selector="DataGridRow">
<Setter Property="Margin" Value="0 0 0 4"></Setter>
</Style>
<Style Selector="TabItem > TextBlock">
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="DemiBold"/>
</Style>
<Style Selector="ListBox ListBoxItem">
<Setter Property="MinHeight" Value="30"/>
</Style>
</UserControl.Styles>
<Grid RowDefinitions="auto,*" ColumnDefinitions="3*,auto,4*,auto,4*">
<Grid Grid.Row="0"
Grid.Column="0"
RowDefinitions="*"
@@ -42,7 +62,7 @@
Content="{Binding Method}"
Background="{Binding Color}"
FontSize="8"
Width="45"
Width="50"
Padding="10 2 10 2"
Grid.Row="0"
Grid.Column="0"/>
@@ -58,6 +78,7 @@
</ListBox>
</Grid>
<GridSplitter Background="Gray"
Margin="8 0 8 0"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"/>
@@ -69,7 +90,8 @@
Grid.Column="0"
Text="{Binding SelectedPathOperation.Method}"
FontSize="12"
IsReadOnly="True"/>
IsReadOnly="True"
Margin="0 0 8 0"/>
<TextBox Grid.Row="0"
Grid.Column="1"
FontSize="12"
@@ -92,18 +114,16 @@
<TabItem Header="Params">
<ScrollViewer>
<StackPanel IsVisible="{Binding SelectedPathOperation, Converter={StaticResource NullBoolConverter}}">
<suki:GroupBox Header="Path Parameters"
<controls:Card
Margin="0 4"
IsVisible="{Binding SelectedPathOperation.Operation.PathParameters, Converter={StaticResource EnumerableBoolConverter}}">
<StackPanel>
<TextBlock FontSize="14"
FontWeight="DemiBold">Path Parameters</TextBlock>
<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>
GridLinesVisibility="All">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridCheckBoxColumn Header="Required" Binding="{Binding IsRequired}"/>
@@ -117,19 +137,18 @@
<DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
</DataGrid.Columns>
</DataGrid>
</suki:GroupBox>
<suki:GroupBox Header="Query Parameters"
</StackPanel>
</controls:Card>
<controls:Card
Margin="0 4"
IsVisible="{Binding SelectedPathOperation.Operation.QueryParameters, Converter={StaticResource EnumerableBoolConverter}}">
<StackPanel>
<TextBlock FontSize="14"
FontWeight="DemiBold">Query Parameters</TextBlock>
<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}"/>
@@ -143,7 +162,8 @@
<DataGridTextColumn Header="Type" Binding="{Binding Type}"/>
</DataGrid.Columns>
</DataGrid>
</suki:GroupBox>
</StackPanel>
</controls:Card>
</StackPanel>
</ScrollViewer>
</TabItem>
@@ -167,6 +187,7 @@
<TextBox FontSize="12"
Grid.Row="0"
Grid.Column="1"
Margin="0 0 0 8"
IsReadOnly="True"
Text="{Binding SelectedPathOperation.ResponseUsername}" />
<TextBlock FontSize="12"
@@ -178,6 +199,7 @@
<TextBox FontSize="12"
Grid.Row="1"
Grid.Column="1"
Margin="0 0 0 8"
IsReadOnly="True"
Text="{Binding SelectedPathOperation.ResponsePassword}"/>
<TextBlock FontSize="12"
@@ -196,104 +218,85 @@
<TabItem Header="Schemas">
<ScrollViewer>
<StackPanel>
<suki:GlassCard Margin="0 4" IsVisible="{Binding SelectedPathOperation.Operation.RequestBodyType, Converter={StaticResource NullBoolConverter}}">
<controls:Card 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>
</controls:Card>
<Border Margin="0 4" IsVisible="{Binding SelectedPathOperation.Operation.RequestClasses, Converter={StaticResource EnumerableBoolConverter}}">
<StackPanel>
<TextBlock FontSize="14" FontWeight="DemiBold" Margin="0 0 0 4">Request Classes</TextBlock>
<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}">
<TextBlock FontSize="12" FontWeight="DemiBold" Text="{Binding Id}"/>
<controls:Card IsVisible="{Binding PropertyFields, Converter={StaticResource EnumerableBoolConverter}}">
<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}">
</controls:Card>
<controls:Card Margin="0 0 0 8" IsVisible="{Binding PropertyEnums, Converter={StaticResource EnumerableBoolConverter}}">
<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>
</controls:Card>
</StackPanel>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</StackPanel>
</Border>
<suki:GlassCard Margin="0 4">
<controls:Card Margin="0 4">
<TextBlock>
<Run Text="Return value: " FontWeight="DemiBold" FontSize="12"/>
<Run Text="{Binding SelectedPathOperation.Operation.ReturnType}" FontSize="12"/>
</TextBlock>
</suki:GlassCard>
</controls:Card>
<Border Margin="0 4" IsVisible="{Binding SelectedPathOperation.Operation.ResponseClasses, Converter={StaticResource EnumerableBoolConverter}}">
<StackPanel>
<TextBlock FontSize="14" FontWeight="DemiBold">Response Classes</TextBlock>
<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}">
<TextBlock FontSize="12" FontWeight="DemiBold" Text="{Binding Id}" Margin="0 0 0 4"/>
<controls:Card IsVisible="{Binding PropertyFields, Converter={StaticResource EnumerableBoolConverter}}">
<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}">
</controls:Card>
<controls:Card Margin="0 0 0 8" IsVisible="{Binding PropertyEnums, Converter={StaticResource EnumerableBoolConverter}}">
<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>
</controls:Card>
</StackPanel>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>
<GridSplitter Grid.Row="0" Grid.Column="3" Grid.RowSpan="2" Background="Gray"/>
<GridSplitter Grid.Row="0" Grid.Column="3" Grid.RowSpan="2" Background="Gray"
Margin="8 0 8 0"/>
<StackPanel Grid.Row="0" Grid.Column="4" Orientation="Horizontal">
<Button HorizontalAlignment="Left"
VerticalAlignment="Center"
@@ -312,6 +315,7 @@
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
ShowLineNumbers="True"
IsReadOnly="True"
Text=""
FontSize="12"/>
</TabItem>

View File

@@ -3,12 +3,10 @@ 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;
@@ -37,7 +35,6 @@ public partial class EndpointView : UserControl, IRecipient<EditorUpdateMessage>
WeakReferenceMessenger.Default.Register<ContentRequestMessage, string>(this, "EndpointRequestEditor");
OnBaseThemeChanged(Application.Current!.ActualThemeVariant);
SukiTheme.GetInstance().OnBaseThemeChanged += OnBaseThemeChanged;
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
@@ -45,20 +42,12 @@ public partial class EndpointView : UserControl, IRecipient<EditorUpdateMessage>
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)

View File

@@ -2,13 +2,31 @@
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"
xmlns:i="https://github.com/projektanker/icons.avalonia"
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"/>
<Grid RowDefinitions="auto,*"
ColumnDefinitions="*"
Margin="16">
<StackPanel Orientation="Horizontal"
Grid.Row="0"
Grid.Column="0"
Margin="0 0 0 8">
<Button Command="{Binding GoBackCommand}"
Theme="{StaticResource TransparentButton}"
Margin="0 0 8 0">
<i:Icon Value="fa-arrow-left"
FontSize="20"/>
</Button>
<TextBlock Theme="{StaticResource TitleTextBlockStyle}"
Text="{Binding Title}"/>
</StackPanel>
<TransitioningContentControl
Grid.Row="1"
Grid.Column="0"
Content="{Binding ActiveViewModel}"/>
</Grid>
</UserControl>

View File

@@ -2,24 +2,31 @@
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:controls="using:Needlework.Net.Desktop.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
Name="EndpointsControl"
x:Class="Needlework.Net.Desktop.Views.EndpointsView"
x:DataType="vm:EndpointsViewModel">
<suki:BusyArea IsBusy="{Binding IsBusy}" BusyText="Loading...">
<Grid Margin="16" RowDefinitions="auto,auto,*" ColumnDefinitions="*">
<controls:BusyArea IsBusy="{Binding IsBusy}"
BusyText="Loading...">
<Grid RowDefinitions="auto,auto,*" ColumnDefinitions="*">
<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}">
<ListBox.ItemTemplate>
<ItemsRepeater ItemsSource="{Binding Query}">
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="White" />
<Button Command="{Binding #EndpointsControl.((vm:EndpointsViewModel)DataContext).OpenEndpointCommand}"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
CommandParameter="{Binding}"
Content="{Binding}"
Theme="{StaticResource TransparentButton}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ScrollViewer>
</Grid>
</suki:BusyArea>
</controls:BusyArea>
</UserControl>

View File

@@ -2,74 +2,62 @@
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:controls="using:Needlework.Net.Desktop.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Needlework.Net.Desktop.Views.HomeView"
x:DataType="vm:HomeViewModel">
<!-- TOP LEVEL -->
<ScrollViewer>
<WrapPanel Margin="8"
theme:WrapPanelExtensions.AnimatedScroll="true"
Orientation="Horizontal">
<!-- WELCOME -->
<StackPanel>
<suki:GlassCard Margin="8">
<Border Margin="12">
<StackPanel>
<TextBlock Classes="h3">Welcome to Needlework.Net</TextBlock>
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">
Welcome to Needlework.Net
</TextBlock>
<TextBlock>Get started with LCU development by clicking on the endpoints tab in the left panel.</TextBlock>
</StackPanel>
</suki:GlassCard>
<suki:GlassCard Margin="8" Classes="Accent">
</Border>
<controls:Card Margin="12">
<TextBlock TextWrapping="Wrap">THE PROGRAM IS PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGMENT, OR OF FITNESS FOR A PARTICULAR PURPOSE. LICENSOR DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE PROGRAM WILL MEET YOUR REQUIREMENTS OR THAT OPERATION WILL BE UNINTERRUPTED OR ERROR FREE. LICENSOR MAKES NO WARRANTIES RESPECTING ANY HARM THAT MAY BE CAUSED BY MALICIOUS USE OF THIS SOFTWARE. LICENSOR FURTHER EXPRESSLY DISCLAIMS ANY WARRANTY OR REPRESENTATION TO AUTHORIZED USERS OR TO ANY THIRD PARTY.</TextBlock>
</suki:GlassCard>
</controls:Card>
</StackPanel>
<!-- STATUS -->
<StackPanel>
<suki:GlassCard Margin="8" Width="250">
<suki:GroupBox Header="Status">
<TextBlock FontSize="24" FontWeight="Bold" Margin="0 4" Foreground="{Binding StatusForeground}" Text="{Binding StatusText}" />
</suki:GroupBox>
</suki:GlassCard>
<suki:GlassCard Margin="8" Width="250">
<suki:GroupBox Header="Address">
<TextBlock Text="{Binding StatusAddress}"/>
</suki:GroupBox>
</suki:GlassCard>
</StackPanel>
<!-- LEGAL -->
<suki:GlassCard Margin="8" Width="300">
<suki:GroupBox Header="Disclaimer">
<TextBlock TextWrapping="Wrap">Needlework.Net isn't endorsed by Riot Games and doesn't reflect the views or opinions of Riot Games or anyone officially involved in producing or managing Riot Games properties. Riot Games, and all associated properties are trademarks or registered trademarks of Riot Games, Inc.</TextBlock>
</suki:GroupBox>
</suki:GlassCard>
<!-- FOOTER -->
<StackPanel>
<suki:GlassCard Margin="8" Width="400">
<controls:Card Margin="12" Width="300">
<StackPanel>
<TextBlock>© 2024 - Blossomi Shymae</TextBlock>
<TextBlock>MIT License</TextBlock>
</StackPanel>
</suki:GlassCard>
<suki:GlassCard Margin="8" Width="400">
<suki:GroupBox Header="Resources">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock
Theme="{StaticResource SubtitleTextBlockStyle}"
Margin="0 0 0 8">Resources</TextBlock>
<StackPanel Orientation="Horizontal">
<StackPanel.Styles>
<Style Selector="Button">
<Setter Property="Command" Value="{Binding OpenUrlCommand}"/>
</Style>
</StackPanel.Styles>
<Button CommandParameter="https://hextechdocs.dev/tag/lcu/" Margin="0 0 16 0">
<Button CommandParameter="https://hextechdocs.dev/tag/lcu/" Margin="0 0 8 0">
Hextech Docs
</Button>
<Button CommandParameter="https://hextechdocs.dev/getting-started-with-the-lcu-api/">
Getting Started
</Button>
</StackPanel>
</suki:GroupBox>
</suki:GlassCard>
</StackPanel>
</controls:Card>
<controls:Card Margin="12" Width="300">
<StackPanel>
<TextBlock>© 2024 - Blossomi Shymae</TextBlock>
<TextBlock>MIT License</TextBlock>
</StackPanel>
</controls:Card>
</StackPanel>
<!-- LEGAL -->
<controls:Card Margin="12" Width="300">
<TextBlock TextWrapping="Wrap">Needlework.Net isn't endorsed by Riot Games and doesn't reflect the views or opinions of Riot Games or anyone officially involved in producing or managing Riot Games properties. Riot Games, and all associated properties are trademarks or registered trademarks of Riot Games, Inc.</TextBlock>
</controls:Card>
</WrapPanel>
</ScrollViewer>
</UserControl>

View File

@@ -1,9 +1,10 @@
<suki:SukiWindow
<Window
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:ui="using:FluentAvalonia.UI.Controls"
xmlns:uip="using:FluentAvalonia.UI.Controls.Primitives"
xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:i="https://github.com/projektanker/icons.avalonia"
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
@@ -14,64 +15,85 @@
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 -->
<suki:SukiSideMenu.ItemTemplate>
<DataTemplate>
<suki:SukiSideMenuItem Header="{Binding DisplayName}">
<suki:SukiSideMenuItem.Icon>
<materialIcons:MaterialIcon Kind="{Binding Icon}" />
</suki:SukiSideMenuItem.Icon>
</suki:SukiSideMenuItem>
</DataTemplate>
</suki:SukiSideMenu.ItemTemplate>
<!-- FOOTER -->
<suki:SukiSideMenu.FooterContent>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<Grid RowDefinitions="auto,*">
<Grid ColumnDefinitions="auto,auto,*,auto"
Background="Transparent"
Height="40"
Grid.Row="0">
<Image Margin="12 4"
IsHitTestVisible="False"
Source="/Assets/app.png"
Width="18"
Height="18"
DockPanel.Dock="Left"
Grid.Column="0"/>
<TextBlock FontSize="12"
IsHitTestVisible="False"
VerticalAlignment="Center"
Grid.Column="1">
Needlework.Net
</TextBlock>
</Grid>
<ui:NavigationView AlwaysShowHeader="False"
PaneDisplayMode="Left"
IsSettingsVisible="False"
Grid.Row="1"
MenuItemsSource="{Binding MenuItems}"
SelectedItem="{Binding SelectedMenuItem}">
<ui:NavigationView.PaneFooter>
<StackPanel Orientation="Vertical">
<StackPanel.Styles>
<Style Selector="Button.Basic">
<Setter Property="Command" Value="{Binding OpenUrlCommand}" />
</Style>
<Style Selector="materialIcons|MaterialIcon">
<Setter Property="Width" Value="25" />
<Setter Property="Height" Value="25" />
<Setter Property="Width" Value="20" />
<Setter Property="Height" Value="20" />
</Style>
<Style Selector="i|Icon">
<Setter Property="FontSize" Value="25" />
<Setter Property="FontSize" Value="20" />
</Style>
</StackPanel.Styles>
<Button Classes="Flat"
Content="{Binding Version}"
FontSize="12"
Margin="0 0 4 0"
Padding="12 4 12 4"
VerticalAlignment="Center"/>
<Button Classes="Basic"
<Button
Theme="{StaticResource TransparentButton}"
VerticalAlignment="Center"
CommandParameter="https://github.com/BlossomiShymae/Needlework.Net"
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>
Margin="4">
<materialIcons:MaterialIcon Kind="Github" />
</Button>
<Button Classes="Basic"
<Button
Theme="{StaticResource TransparentButton}"
VerticalAlignment="Center"
CommandParameter="https://discord.gg/chEvEX5J4E"
ToolTip.Tip="Open Discord server.">
ToolTip.Tip="Open Discord server."
Margin="4">
<i:Icon Value="fa-brand fa-discord" />
</Button>
</StackPanel>
</suki:SukiSideMenu.FooterContent>
</suki:SukiSideMenu>
</suki:SukiWindow>
</ui:NavigationView.PaneFooter>
<Grid>
<TransitioningContentControl Content="{Binding CurrentPage}"/>
<Button Content="{Binding Version}"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="16"/>
<ItemsRepeater ItemsSource="{Binding InfoBarItems}"
VerticalAlignment="Bottom">
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<Border Margin="4">
<ui:InfoBar
Title="{Binding Title}"
IsOpen="{Binding IsOpen}"
Severity="{Binding Severity}"
Message="{Binding Message}"
ActionButton="{Binding ActionButton}"/>
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</Grid>
</ui:NavigationView>
</Grid>
</Window>

View File

@@ -1,11 +1,13 @@
using SukiUI.Controls;
using FluentAvalonia.UI.Windowing;
namespace Needlework.Net.Desktop.Views;
public partial class MainWindow : SukiWindow
public partial class MainWindow : AppWindow
{
public MainWindow()
{
InitializeComponent();
TitleBar.ExtendsContentIntoTitleBar = true;
}
}

View File

@@ -1,9 +1,8 @@
<suki:SukiWindow
<Window
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"
@@ -12,7 +11,29 @@
WindowStartupLocation="CenterOwner"
Width="560"
Height="200">
<Grid RowDefinitions="auto,auto,auto" ColumnDefinitions="auto,auto"
<Grid RowDefinitions="auto,*">
<Grid ColumnDefinitions="auto,auto,*,auto"
Background="Transparent"
Height="40"
Grid.Row="0">
<Image Margin="12 4"
IsHitTestVisible="False"
Source="/Assets/app.png"
Width="18"
Height="18"
DockPanel.Dock="Left"
Grid.Column="0"/>
<TextBlock FontSize="12"
IsHitTestVisible="False"
VerticalAlignment="Center"
Grid.Column="1">
Needlework.Net - Oopsies
</TextBlock>
</Grid>
<Grid RowDefinitions="auto,auto,auto"
ColumnDefinitions="auto,auto"
Grid.Row="1"
Grid.Column="0"
Margin="8"
VerticalAlignment="Center"
HorizontalAlignment="Center">
@@ -30,16 +51,19 @@
It can be viewed in an external editor or viewer.
</TextBlock>
<Button Command="{Binding OpenDefaultEditorCommand}"
HorizontalAlignment="Stretch"
Grid.Row="2"
Grid.Column="0"
Margin="0 0 8 0">
Open
</Button>
<Button Command="{Binding CloseDialogCommand}"
HorizontalAlignment="Stretch"
Grid.Row="2"
Grid.Column="1"
Margin="8 0 0 0">
Cancel
</Button>
</Grid>
</suki:SukiWindow>
</Grid>
</Window>

View File

@@ -1,11 +1,13 @@
using SukiUI.Controls;
using FluentAvalonia.UI.Windowing;
namespace Needlework.Net.Desktop.Views;
public partial class OopsiesWindow : SukiWindow
public partial class OopsiesWindow : AppWindow
{
public OopsiesWindow()
{
InitializeComponent();
TitleBar.ExtendsContentIntoTitleBar = true;
}
}

View File

@@ -3,59 +3,51 @@
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">
<Grid RowDefinitions="*,auto,*" 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"
<Button Margin="0 0 8 0"
Grid.Row="0"
Grid.Column="0"
Command="{Binding ClearCommand}"
Margin="0 0 8 0">Clear</Button>
Command="{Binding ClearCommand}">Clear</Button>
<TextBox Grid.Row="0"
Grid.Column="1"
Text="{Binding Search}"
MaxLines="1"
Margin="0 0 8 0"/>
<CheckBox
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"
Content="Attach"
IsChecked="{Binding IsAttach}"/>
<TextBlock Margin="0 6 0 0"
FontSize="18">Attach</TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal"
<CheckBox
Grid.Row="0"
Grid.Column="3">
<ToggleSwitch Margin="0 0 0 8"
Grid.Column="3"
Content="Tail"
IsChecked="{Binding IsTail}"/>
<TextBlock Margin="0 6 0 0"
FontSize="18">Tail</TextBlock>
</StackPanel>
</Grid>
<ListBox Grid.Row="1"
Grid.Column="0"
Name="EventViewer"
Margin="0 8 0 0"
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"
ShowLineNumbers="True"
@@ -63,7 +55,6 @@
VerticalScrollBarVisibility="Visible"
Text=""
FontSize="12"/>
</suki:GlassCard>
</Border>
</Grid>
</UserControl>

View File

@@ -3,12 +3,10 @@ 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;
@@ -41,7 +39,6 @@ public partial class WebsocketView : UserControl, IRecipient<ResponseUpdatedMess
WeakReferenceMessenger.Default.Register(this, nameof(WebsocketViewModel));
OnBaseThemeChanged(Application.Current!.ActualThemeVariant);
SukiTheme.GetInstance().OnBaseThemeChanged += OnBaseThemeChanged;
}
private void OnBaseThemeChanged(ThemeVariant currentTheme)
@@ -49,9 +46,5 @@ public partial class WebsocketView : UserControl, IRecipient<ResponseUpdatedMess
var registryOptions = new RegistryOptions(
currentTheme == ThemeVariant.Dark ? ThemeName.DarkPlus : ThemeName.LightPlus);
var responseTmi = _responseEditor.InstallTextMate(registryOptions);
responseTmi.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions
.GetLanguageByExtension(".json").Id));
}
}