diff --git a/Needlework.Net.Desktop/App.axaml b/Needlework.Net.Desktop/App.axaml index 14ba17e..55e49e6 100644 --- a/Needlework.Net.Desktop/App.axaml +++ b/Needlework.Net.Desktop/App.axaml @@ -1,20 +1,20 @@ + xmlns:sty="using:FluentAvalonia.Styling" + xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" + RequestedThemeVariant="Dark"> - - + + diff --git a/Needlework.Net.Desktop/Assets/Icons/home.png b/Needlework.Net.Desktop/Assets/Icons/home.png new file mode 100644 index 0000000..76b1031 Binary files /dev/null and b/Needlework.Net.Desktop/Assets/Icons/home.png differ diff --git a/Needlework.Net.Desktop/Assets/Icons/info-circle.png b/Needlework.Net.Desktop/Assets/Icons/info-circle.png new file mode 100644 index 0000000..53ab7e7 Binary files /dev/null and b/Needlework.Net.Desktop/Assets/Icons/info-circle.png differ diff --git a/Needlework.Net.Desktop/Assets/Icons/list-alt.png b/Needlework.Net.Desktop/Assets/Icons/list-alt.png new file mode 100644 index 0000000..60c71be Binary files /dev/null and b/Needlework.Net.Desktop/Assets/Icons/list-alt.png differ diff --git a/Needlework.Net.Desktop/Assets/Icons/plug.png b/Needlework.Net.Desktop/Assets/Icons/plug.png new file mode 100644 index 0000000..e0f566a Binary files /dev/null and b/Needlework.Net.Desktop/Assets/Icons/plug.png differ diff --git a/Needlework.Net.Desktop/Assets/Icons/terminal.png b/Needlework.Net.Desktop/Assets/Icons/terminal.png new file mode 100644 index 0000000..2d12d6d Binary files /dev/null and b/Needlework.Net.Desktop/Assets/Icons/terminal.png differ diff --git a/Needlework.Net.Desktop/Controls/BusyArea.axaml b/Needlework.Net.Desktop/Controls/BusyArea.axaml new file mode 100644 index 0000000..51056a7 --- /dev/null +++ b/Needlework.Net.Desktop/Controls/BusyArea.axaml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + diff --git a/Needlework.Net.Desktop/Controls/BusyArea.axaml.cs b/Needlework.Net.Desktop/Controls/BusyArea.axaml.cs new file mode 100644 index 0000000..e6696b8 --- /dev/null +++ b/Needlework.Net.Desktop/Controls/BusyArea.axaml.cs @@ -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 IsBusyProperty = + AvaloniaProperty.Register(nameof(IsBusy), defaultValue: false); + + public bool IsBusy + { + get { return GetValue(IsBusyProperty); } + set { SetValue(IsBusyProperty, value); } + } + + public static readonly StyledProperty BusyTextProperty = + AvaloniaProperty.Register(nameof(BusyText), defaultValue: null); + + public string? BusyText + { + get => GetValue(BusyTextProperty); + set => SetValue(BusyTextProperty, value); + } +} \ No newline at end of file diff --git a/Needlework.Net.Desktop/Controls/Card.axaml b/Needlework.Net.Desktop/Controls/Card.axaml new file mode 100644 index 0000000..48a01eb --- /dev/null +++ b/Needlework.Net.Desktop/Controls/Card.axaml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/Needlework.Net.Desktop/Controls/Card.axaml.cs b/Needlework.Net.Desktop/Controls/Card.axaml.cs new file mode 100644 index 0000000..3c106bb --- /dev/null +++ b/Needlework.Net.Desktop/Controls/Card.axaml.cs @@ -0,0 +1,10 @@ +using Avalonia.Controls; + +namespace Needlework.Net.Desktop.Controls; + +public class Card : ContentControl +{ + public Card() + { + } +} \ No newline at end of file diff --git a/Needlework.Net.Desktop/Messages/InfoBarUpdateMessage.cs b/Needlework.Net.Desktop/Messages/InfoBarUpdateMessage.cs new file mode 100644 index 0000000..cd99847 --- /dev/null +++ b/Needlework.Net.Desktop/Messages/InfoBarUpdateMessage.cs @@ -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(vm) + { + } +} diff --git a/Needlework.Net.Desktop/Needlework.Net.Desktop.csproj b/Needlework.Net.Desktop/Needlework.Net.Desktop.csproj index b3f2808..06b739c 100644 --- a/Needlework.Net.Desktop/Needlework.Net.Desktop.csproj +++ b/Needlework.Net.Desktop/Needlework.Net.Desktop.csproj @@ -11,8 +11,8 @@ False app.ico NeedleworkDotNet - 0.3.2.0 - 0.3.2.0 + 0.4.0.0 + 0.4.0.0 False @@ -35,12 +35,11 @@ - - + @@ -52,6 +51,9 @@ + + BusyArea.axaml + EndpointView.axaml diff --git a/Needlework.Net.Desktop/Services/WindowService.cs b/Needlework.Net.Desktop/Services/WindowService.cs index a177ac6..0d331e4 100644 --- a/Needlework.Net.Desktop/Services/WindowService.cs +++ b/Needlework.Net.Desktop/Services/WindowService.cs @@ -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 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) diff --git a/Needlework.Net.Desktop/ViewModels/AboutViewModel.cs b/Needlework.Net.Desktop/ViewModels/AboutViewModel.cs index 26d7951..d9f09a0 100644 --- a/Needlework.Net.Desktop/ViewModels/AboutViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/AboutViewModel.cs @@ -2,7 +2,7 @@ { public class AboutViewModel : PageBase { - public AboutViewModel() : base("About", Material.Icons.MaterialIconKind.InfoCircle) + public AboutViewModel() : base("About", "info-circle") { } } diff --git a/Needlework.Net.Desktop/ViewModels/ConsoleViewModel.cs b/Needlework.Net.Desktop/ViewModels/ConsoleViewModel.cs index a9400cc..ada8b48 100644 --- a/Needlework.Net.Desktop/ViewModels/ConsoleViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/ConsoleViewModel.cs @@ -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; diff --git a/Needlework.Net.Desktop/ViewModels/EndpointViewModel.cs b/Needlework.Net.Desktop/ViewModels/EndpointViewModel.cs index f50d4e3..e202243 100644 --- a/Needlework.Net.Desktop/ViewModels/EndpointViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/EndpointViewModel.cs @@ -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(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"))); + } } } diff --git a/Needlework.Net.Desktop/ViewModels/EndpointsContainerViewModel.cs b/Needlework.Net.Desktop/ViewModels/EndpointsContainerViewModel.cs index a7e1791..c5a8b01 100644 --- a/Needlework.Net.Desktop/ViewModels/EndpointsContainerViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/EndpointsContainerViewModel.cs @@ -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; } } } diff --git a/Needlework.Net.Desktop/ViewModels/EndpointsViewModel.cs b/Needlework.Net.Desktop/ViewModels/EndpointsViewModel.cs index f23971f..4e8a5ef 100644 --- a/Needlework.Net.Desktop/ViewModels/EndpointsViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/EndpointsViewModel.cs @@ -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, ISukiStackPageTitleProvider + public partial class EndpointsViewModel : ObservableObject, IRecipient { public HttpClient HttpClient { get; } public string Title => "Endpoints"; - public Action OnClicked; + public Action OnClicked; [ObservableProperty] private IAvaloniaReadOnlyList _plugins = new AvaloniaList(); [ObservableProperty] private bool _isBusy = true; @@ -22,7 +22,7 @@ namespace Needlework.Net.Desktop.ViewModels [ObservableProperty] private IAvaloniaReadOnlyList _query = new AvaloniaList(); [ObservableProperty] private string? _selectedQuery = string.Empty; - public EndpointsViewModel(HttpClient httpClient, Action onClicked) + public EndpointsViewModel(HttpClient httpClient, Action 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; diff --git a/Needlework.Net.Desktop/ViewModels/HomeViewModel.cs b/Needlework.Net.Desktop/ViewModels/HomeViewModel.cs index fe34432..d305639 100644 --- a/Needlework.Net.Desktop/ViewModels/HomeViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/HomeViewModel.cs @@ -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(); } diff --git a/Needlework.Net.Desktop/ViewModels/InfoBarViewModel.cs b/Needlework.Net.Desktop/ViewModels/InfoBarViewModel.cs new file mode 100644 index 0000000..585f6e5 --- /dev/null +++ b/Needlework.Net.Desktop/ViewModels/InfoBarViewModel.cs @@ -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; + } + } +} diff --git a/Needlework.Net.Desktop/ViewModels/MainWindowViewModel.cs b/Needlework.Net.Desktop/ViewModels/MainWindowViewModel.cs index fed6304..a7d50b3 100644 --- a/Needlework.Net.Desktop/ViewModels/MainWindowViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/MainWindowViewModel.cs @@ -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, IRecipient, IRecipient + public partial class MainWindowViewModel : ObservableObject, IRecipient, IRecipient, IRecipient, IRecipient { - public IAvaloniaReadOnlyList Pages { get; } + public IAvaloniaReadOnlyList 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 _infoBarItems = []; public MainWindowViewModel(IEnumerable pages, HttpClient httpClient, WindowService windowService) { - Pages = new AvaloniaList(pages.OrderBy(x => x.Index).ThenBy(x => x.DisplayName)); + MenuItems = new AvaloniaList(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); + } } } diff --git a/Needlework.Net.Desktop/ViewModels/OperationViewModel.cs b/Needlework.Net.Desktop/ViewModels/OperationViewModel.cs index 0434085..0d298a6 100644 --- a/Needlework.Net.Desktop/ViewModels/OperationViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/OperationViewModel.cs @@ -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 ResponseClasses { get; } public IAvaloniaReadOnlyList PathParameters { get; } public IAvaloniaReadOnlyList 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(string.Join(string.Empty, template)), App.JsonSerializerOptions); + } + + private List CreateTemplate(AvaloniaList requestClasses) + { + if (requestClasses.Count == 0) return []; + List 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 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) diff --git a/Needlework.Net.Desktop/ViewModels/PageBase.cs b/Needlework.Net.Desktop/ViewModels/PageBase.cs index 5e0e9f0..3bf4a4d 100644 --- a/Needlework.Net.Desktop/ViewModels/PageBase.cs +++ b/Needlework.Net.Desktop/ViewModels/PageBase.cs @@ -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; } } \ No newline at end of file diff --git a/Needlework.Net.Desktop/ViewModels/PathOperationViewModel.cs b/Needlework.Net.Desktop/ViewModels/PathOperationViewModel.cs index 3705075..fa4c053 100644 --- a/Needlework.Net.Desktop/ViewModels/PathOperationViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/PathOperationViewModel.cs @@ -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 diff --git a/Needlework.Net.Desktop/ViewModels/PropertyEnumViewModel.cs b/Needlework.Net.Desktop/ViewModels/PropertyEnumViewModel.cs index 5b08cf2..c7be32a 100644 --- a/Needlework.Net.Desktop/ViewModels/PropertyEnumViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/PropertyEnumViewModel.cs @@ -11,7 +11,7 @@ namespace Needlework.Net.Desktop.ViewModels public PropertyEnumViewModel(IList enumValue) { - Values = $"[{string.Join(", ", enumValue.Select(x => ((OpenApiString)x).Value).ToList())}]"; + Values = $"[{string.Join(", ", enumValue.Select(x => $"\"{((OpenApiString)x).Value}\"").ToList())}]"; } } } \ No newline at end of file diff --git a/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs b/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs index 1be6d1f..27584a3 100644 --- a/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs @@ -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 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; diff --git a/Needlework.Net.Desktop/Views/AboutView.axaml b/Needlework.Net.Desktop/Views/AboutView.axaml index 5b1712d..37a811f 100644 --- a/Needlework.Net.Desktop/Views/AboutView.axaml +++ b/Needlework.Net.Desktop/Views/AboutView.axaml @@ -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"> - - + + - - - + + + - Blossomi Shymae + Blossomi Shymae - - - + + + + About - 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. 💜 - - + + + diff --git a/Needlework.Net.Desktop/Views/ConsoleView.axaml b/Needlework.Net.Desktop/Views/ConsoleView.axaml index b56ba6f..76f5097 100644 --- a/Needlework.Net.Desktop/Views/ConsoleView.axaml +++ b/Needlework.Net.Desktop/Views/ConsoleView.axaml @@ -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"> - + - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + diff --git a/Needlework.Net.Desktop/Views/EndpointsView.axaml b/Needlework.Net.Desktop/Views/EndpointsView.axaml index f346af8..17feecd 100644 --- a/Needlework.Net.Desktop/Views/EndpointsView.axaml +++ b/Needlework.Net.Desktop/Views/EndpointsView.axaml @@ -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"> - - - - - - - - - - - - - - + + + + + + + + - - + + + + + © 2024 - Blossomi Shymae + MIT License + + + + + 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. + diff --git a/Needlework.Net.Desktop/Views/MainWindow.axaml b/Needlework.Net.Desktop/Views/MainWindow.axaml index 2379f4c..3e881c8 100644 --- a/Needlework.Net.Desktop/Views/MainWindow.axaml +++ b/Needlework.Net.Desktop/Views/MainWindow.axaml @@ -1,9 +1,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Needlework.Net + + + + + + + + + + + + + + + + + - + Grid.ColumnSpan="2"> + This response is too large for Needlework.Net to handle for performance reasons. + + + It can be viewed in an external editor or viewer. + + + + - + diff --git a/Needlework.Net.Desktop/Views/OopsiesWindow.axaml.cs b/Needlework.Net.Desktop/Views/OopsiesWindow.axaml.cs index 6f5802b..e77695e 100644 --- a/Needlework.Net.Desktop/Views/OopsiesWindow.axaml.cs +++ b/Needlework.Net.Desktop/Views/OopsiesWindow.axaml.cs @@ -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; } } \ No newline at end of file diff --git a/Needlework.Net.Desktop/Views/WebsocketView.axaml b/Needlework.Net.Desktop/Views/WebsocketView.axaml index 75351bd..3203036 100644 --- a/Needlework.Net.Desktop/Views/WebsocketView.axaml +++ b/Needlework.Net.Desktop/Views/WebsocketView.axaml @@ -3,67 +3,58 @@ 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"> - + - - - - - - - - Attach - - - - Tail - - - + + + + + + - + + - - - + diff --git a/Needlework.Net.Desktop/Views/WebsocketView.axaml.cs b/Needlework.Net.Desktop/Views/WebsocketView.axaml.cs index 3821c10..de22c6d 100644 --- a/Needlework.Net.Desktop/Views/WebsocketView.axaml.cs +++ b/Needlework.Net.Desktop/Views/WebsocketView.axaml.cs @@ -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