mirror of
https://github.com/BlossomiShymae/Needlework.Net.git
synced 2025-12-06 18:20:47 +01:00
refactor: use data source, remove data loading in ctor of view models
This commit is contained in:
@@ -40,8 +40,6 @@ public partial class App(IServiceProvider serviceProvider) : Application
|
|||||||
MainWindow = desktop.MainWindow;
|
MainWindow = desktop.MainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
base.OnFrameworkInitializationCompleted();
|
base.OnFrameworkInitializationCompleted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
60
Needlework.Net/DataSource.cs
Normal file
60
Needlework.Net/DataSource.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.OpenApi.Readers;
|
||||||
|
using Needlework.Net.Models;
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Needlework.Net
|
||||||
|
{
|
||||||
|
public class DataSource
|
||||||
|
{
|
||||||
|
private readonly ILogger<DataSource> _logger;
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
private Document? _lcuSchemaDocument;
|
||||||
|
private Document? _lolClientDocument;
|
||||||
|
private readonly TaskCompletionSource<bool> _taskCompletionSource = new();
|
||||||
|
|
||||||
|
|
||||||
|
public DataSource(HttpClient httpClient, ILogger<DataSource> logger)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Document> GetLcuSchemaDocumentAsync()
|
||||||
|
{
|
||||||
|
await _taskCompletionSource.Task;
|
||||||
|
return _lcuSchemaDocument ?? throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Document> GetLolClientDocumentAsync()
|
||||||
|
{
|
||||||
|
await _taskCompletionSource.Task;
|
||||||
|
return _lolClientDocument ?? throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var reader = new OpenApiStreamReader();
|
||||||
|
var lcuSchemaStream = await _httpClient.GetStreamAsync("https://raw.githubusercontent.com/dysolix/hasagi-types/main/swagger.json");
|
||||||
|
var lcuSchemaRaw = reader.Read(lcuSchemaStream, out var _);
|
||||||
|
_lcuSchemaDocument = new Document(lcuSchemaRaw);
|
||||||
|
|
||||||
|
var lolClientStream = await _httpClient.GetStreamAsync("https://raw.githubusercontent.com/BlossomiShymae/poroschema/refs/heads/main/schemas/lolclient.json");
|
||||||
|
var lolClientRaw = reader.Read(lolClientStream, out var _);
|
||||||
|
_lolClientDocument = new Document(lolClientRaw);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Failed to initialize DataSource");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_taskCompletionSource.SetResult(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,8 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Needlework.Net
|
namespace Needlework.Net
|
||||||
{
|
{
|
||||||
@@ -16,7 +12,7 @@ namespace Needlework.Net
|
|||||||
{
|
{
|
||||||
var logger = new LoggerConfiguration()
|
var logger = new LoggerConfiguration()
|
||||||
.MinimumLevel.Debug()
|
.MinimumLevel.Debug()
|
||||||
.WriteTo.File("Logs/debug-.log", rollingInterval: RollingInterval.Day, shared: true)
|
.WriteTo.File("Logs/debug-", rollingInterval: RollingInterval.Day, shared: true)
|
||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
logger.Debug("NeedleworkDotNet version: {Version}", Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0.0.0.0");
|
logger.Debug("NeedleworkDotNet version: {Version}", Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0.0.0.0");
|
||||||
logger.Debug("OS description: {Description}", System.Runtime.InteropServices.RuntimeInformation.OSDescription);
|
logger.Debug("OS description: {Description}", System.Runtime.InteropServices.RuntimeInformation.OSDescription);
|
||||||
@@ -25,7 +21,7 @@ namespace Needlework.Net
|
|||||||
|
|
||||||
public static void LogFatal(UnhandledExceptionEventArgs e)
|
public static void LogFatal(UnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
File.WriteAllText($"Logs/fatal-{DateTime.Now:HHmmssfff}.log", e.ExceptionObject.ToString());
|
File.WriteAllText($"Logs/fatal-{DateTime.Now:HHmmssfff}", e.ExceptionObject.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
|
||||||
using Needlework.Net.Models;
|
|
||||||
|
|
||||||
namespace Needlework.Net.Messages
|
|
||||||
{
|
|
||||||
public class DataReadyMessage(OpenApiDocumentWrapper wrapper) : ValueChangedMessage<OpenApiDocumentWrapper>(wrapper)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
|
||||||
using Needlework.Net.Models;
|
|
||||||
|
|
||||||
namespace Needlework.Net.Messages
|
|
||||||
{
|
|
||||||
public class DataRequestMessage : RequestMessage<OpenApiDocumentWrapper>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
|
|
||||||
namespace Needlework.Net.Messages
|
|
||||||
{
|
|
||||||
public class HostDocumentRequestMessage : RequestMessage<OpenApiDocument>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ using Microsoft.OpenApi.Models;
|
|||||||
|
|
||||||
namespace Needlework.Net.Models;
|
namespace Needlework.Net.Models;
|
||||||
|
|
||||||
public class OpenApiDocumentWrapper
|
public class Document
|
||||||
{
|
{
|
||||||
internal OpenApiDocument OpenApiDocument { get; }
|
internal OpenApiDocument OpenApiDocument { get; }
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ public class OpenApiDocumentWrapper
|
|||||||
|
|
||||||
public List<string> Paths => [.. OpenApiDocument.Paths.Keys];
|
public List<string> Paths => [.. OpenApiDocument.Paths.Keys];
|
||||||
|
|
||||||
public OpenApiDocumentWrapper(OpenApiDocument openApiDocument)
|
public Document(OpenApiDocument openApiDocument)
|
||||||
{
|
{
|
||||||
OpenApiDocument = openApiDocument;
|
OpenApiDocument = openApiDocument;
|
||||||
var plugins = new SortedDictionary<string, List<PathOperation>>();
|
var plugins = new SortedDictionary<string, List<PathOperation>>();
|
||||||
@@ -6,10 +6,8 @@ using Needlework.Net.ViewModels.MainWindow;
|
|||||||
using Needlework.Net.ViewModels.Pages;
|
using Needlework.Net.ViewModels.Pages;
|
||||||
using Projektanker.Icons.Avalonia;
|
using Projektanker.Icons.Avalonia;
|
||||||
using Projektanker.Icons.Avalonia.FontAwesome;
|
using Projektanker.Icons.Avalonia.FontAwesome;
|
||||||
using Serilog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.Threading.Tasks;
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Needlework.Net;
|
namespace Needlework.Net;
|
||||||
|
|
||||||
@@ -32,23 +30,32 @@ class Program
|
|||||||
{
|
{
|
||||||
IconProvider.Current
|
IconProvider.Current
|
||||||
.Register<FontAwesomeIconProvider>();
|
.Register<FontAwesomeIconProvider>();
|
||||||
|
var services = BuildServices();
|
||||||
|
Task.Run(async () => await InitializeDataSourceAsync(services));
|
||||||
|
|
||||||
return AppBuilder.Configure(() => new App(BuildServices()))
|
return AppBuilder.Configure(() => new App(services))
|
||||||
.UsePlatformDetect()
|
.UsePlatformDetect()
|
||||||
.WithInterFont()
|
.WithInterFont()
|
||||||
.LogToTrace()
|
.LogToTrace()
|
||||||
.With(new Win32PlatformOptions
|
.With(new Win32PlatformOptions
|
||||||
{
|
{
|
||||||
CompositionMode = [ Win32CompositionMode.WinUIComposition, Win32CompositionMode.DirectComposition ]
|
CompositionMode = [Win32CompositionMode.WinUIComposition, Win32CompositionMode.DirectComposition]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task InitializeDataSourceAsync(IServiceProvider services)
|
||||||
|
{
|
||||||
|
var dataSource = services.GetRequiredService<DataSource>();
|
||||||
|
await dataSource.InitializeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private static IServiceProvider BuildServices()
|
private static IServiceProvider BuildServices()
|
||||||
{
|
{
|
||||||
var builder = new ServiceCollection();
|
var builder = new ServiceCollection();
|
||||||
|
|
||||||
builder.AddSingleton<MainWindowViewModel>();
|
builder.AddSingleton<MainWindowViewModel>();
|
||||||
builder.AddSingleton<DialogService>();
|
builder.AddSingleton<DialogService>();
|
||||||
|
builder.AddSingleton<DataSource>();
|
||||||
builder.AddSingletonsFromAssemblies<PageBase>();
|
builder.AddSingletonsFromAssemblies<PageBase>();
|
||||||
builder.AddHttpClient();
|
builder.AddHttpClient();
|
||||||
builder.AddLogging(Logger.Setup);
|
builder.AddLogging(Logger.Setup);
|
||||||
|
|||||||
@@ -19,20 +19,17 @@ using System.Linq;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
|
||||||
namespace Needlework.Net.ViewModels.MainWindow;
|
namespace Needlework.Net.ViewModels.MainWindow;
|
||||||
|
|
||||||
public partial class MainWindowViewModel
|
public partial class MainWindowViewModel
|
||||||
: ObservableObject, IRecipient<DataRequestMessage>, IRecipient<HostDocumentRequestMessage>, IRecipient<InfoBarUpdateMessage>, IRecipient<OopsiesDialogRequestedMessage>
|
: ObservableObject, IRecipient<InfoBarUpdateMessage>, IRecipient<OopsiesDialogRequestedMessage>
|
||||||
{
|
{
|
||||||
public IAvaloniaReadOnlyList<NavigationViewItem> MenuItems { get; }
|
public IAvaloniaReadOnlyList<NavigationViewItem> MenuItems { get; }
|
||||||
[NotifyPropertyChangedFor(nameof(CurrentPage))]
|
|
||||||
[ObservableProperty] private NavigationViewItem _selectedMenuItem;
|
[ObservableProperty] private NavigationViewItem _selectedMenuItem;
|
||||||
public PageBase CurrentPage => (PageBase)SelectedMenuItem.Tag!;
|
[ObservableProperty] private PageBase _currentPage;
|
||||||
|
|
||||||
public string Version { get; } = Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0.0.0.0";
|
public string Version { get; } = Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0.0.0.0";
|
||||||
[ObservableProperty] private bool _isUpdateShown = false;
|
[ObservableProperty] private bool _isUpdateShown = false;
|
||||||
@@ -42,7 +39,7 @@ public partial class MainWindowViewModel
|
|||||||
|
|
||||||
public HttpClient HttpClient { get; }
|
public HttpClient HttpClient { get; }
|
||||||
public DialogService DialogService { get; }
|
public DialogService DialogService { get; }
|
||||||
public OpenApiDocumentWrapper? OpenApiDocumentWrapper { get; set; }
|
public Document? OpenApiDocumentWrapper { get; set; }
|
||||||
public OpenApiDocument? HostDocument { get; set; }
|
public OpenApiDocument? HostDocument { get; set; }
|
||||||
|
|
||||||
[ObservableProperty] private bool _isBusy = true;
|
[ObservableProperty] private bool _isBusy = true;
|
||||||
@@ -78,14 +75,13 @@ public partial class MainWindowViewModel
|
|||||||
IconSource = new BitmapIconSource() { UriSource = new Uri($"avares://NeedleworkDotNet/Assets/Icons/{p.Icon}.png") }
|
IconSource = new BitmapIconSource() { UriSource = new Uri($"avares://NeedleworkDotNet/Assets/Icons/{p.Icon}.png") }
|
||||||
}));
|
}));
|
||||||
SelectedMenuItem = MenuItems[0];
|
SelectedMenuItem = MenuItems[0];
|
||||||
|
CurrentPage = (PageBase)MenuItems[0].Tag!;
|
||||||
|
|
||||||
HttpClient = httpClient;
|
HttpClient = httpClient;
|
||||||
DialogService = dialogService;
|
DialogService = dialogService;
|
||||||
|
|
||||||
WeakReferenceMessenger.Default.RegisterAll(this);
|
WeakReferenceMessenger.Default.RegisterAll(this);
|
||||||
|
|
||||||
Task.Run(FetchDataAsync);
|
|
||||||
|
|
||||||
_latestUpdateTimer.Elapsed += OnLatestUpdateTimerElapsed;
|
_latestUpdateTimer.Elapsed += OnLatestUpdateTimerElapsed;
|
||||||
_schemaVersionTimer.Elapsed += OnSchemaVersionTimerElapsed;
|
_schemaVersionTimer.Elapsed += OnSchemaVersionTimerElapsed;
|
||||||
_latestUpdateTimer.Start();
|
_latestUpdateTimer.Start();
|
||||||
@@ -95,6 +91,18 @@ public partial class MainWindowViewModel
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedMenuItemChanged(NavigationViewItem value)
|
||||||
|
{
|
||||||
|
if (value.Tag is PageBase page)
|
||||||
|
{
|
||||||
|
CurrentPage = page;
|
||||||
|
if (!page.IsInitialized)
|
||||||
|
{
|
||||||
|
Task.Run(page.InitializeAsync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void OnSchemaVersionTimerElapsed(object? sender, ElapsedEventArgs? e)
|
private async void OnSchemaVersionTimerElapsed(object? sender, ElapsedEventArgs? e)
|
||||||
{
|
{
|
||||||
if (OpenApiDocumentWrapper == null) return;
|
if (OpenApiDocumentWrapper == null) return;
|
||||||
@@ -177,34 +185,6 @@ public partial class MainWindowViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task FetchDataAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var document = await Resources.GetOpenApiDocumentAsync(HttpClient);
|
|
||||||
HostDocument = document;
|
|
||||||
var handler = new OpenApiDocumentWrapper(document);
|
|
||||||
OpenApiDocumentWrapper = handler;
|
|
||||||
|
|
||||||
WeakReferenceMessenger.Default.Send(new DataReadyMessage(handler));
|
|
||||||
IsBusy = false;
|
|
||||||
}
|
|
||||||
catch (HttpRequestException ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Failed to fetch OpenAPI data");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Receive(DataRequestMessage message)
|
|
||||||
{
|
|
||||||
message.Reply(OpenApiDocumentWrapper!);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Receive(HostDocumentRequestMessage message)
|
|
||||||
{
|
|
||||||
message.Reply(HostDocument!);
|
|
||||||
}
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void OpenUrl(string url)
|
private void OpenUrl(string url)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Needlework.Net.ViewModels.Pages;
|
namespace Needlework.Net.ViewModels.Pages;
|
||||||
|
|
||||||
@@ -13,6 +14,12 @@ public partial class AboutViewModel : PageBase
|
|||||||
HttpClient = httpClient;
|
HttpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Task InitializeAsync()
|
||||||
|
{
|
||||||
|
IsInitialized = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void OpenUrl(string url)
|
private void OpenUrl(string url)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
|
using Avalonia.Threading;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Needlework.Net.Messages;
|
|
||||||
using Needlework.Net.ViewModels.Shared;
|
using Needlework.Net.ViewModels.Shared;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Needlework.Net.ViewModels.Pages;
|
namespace Needlework.Net.ViewModels.Pages;
|
||||||
|
|
||||||
public partial class ConsoleViewModel : PageBase, IRecipient<DataReadyMessage>
|
public partial class ConsoleViewModel : PageBase
|
||||||
{
|
{
|
||||||
public IAvaloniaReadOnlyList<string> RequestMethods { get; } = new AvaloniaList<string>(["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS", "TRACE"]);
|
public IAvaloniaReadOnlyList<string> RequestMethods { get; } = new AvaloniaList<string>(["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS", "TRACE"]);
|
||||||
public IAvaloniaList<string> RequestPaths { get; } = new AvaloniaList<string>();
|
public IAvaloniaList<string> RequestPaths { get; } = new AvaloniaList<string>();
|
||||||
@@ -17,10 +16,24 @@ public partial class ConsoleViewModel : PageBase, IRecipient<DataReadyMessage>
|
|||||||
[ObservableProperty] private bool _isBusy = true;
|
[ObservableProperty] private bool _isBusy = true;
|
||||||
[ObservableProperty] private LcuRequestViewModel _lcuRequest;
|
[ObservableProperty] private LcuRequestViewModel _lcuRequest;
|
||||||
|
|
||||||
public ConsoleViewModel(ILogger<LcuRequestViewModel> lcuRequestViewModelLogger) : base("Console", "terminal", -200)
|
private readonly DataSource _dataSource;
|
||||||
|
|
||||||
|
public ConsoleViewModel(ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, DataSource dataSource) : base("Console", "terminal", -200)
|
||||||
{
|
{
|
||||||
_lcuRequest = new(lcuRequestViewModelLogger);
|
_lcuRequest = new(lcuRequestViewModelLogger);
|
||||||
WeakReferenceMessenger.Default.Register<DataReadyMessage>(this);
|
_dataSource = dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
var document = await _dataSource.GetLolClientDocumentAsync();
|
||||||
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
|
{
|
||||||
|
RequestPaths.Clear();
|
||||||
|
RequestPaths.AddRange(document.Paths);
|
||||||
|
});
|
||||||
|
IsBusy = false;
|
||||||
|
IsInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
@@ -28,14 +41,4 @@ public partial class ConsoleViewModel : PageBase, IRecipient<DataReadyMessage>
|
|||||||
{
|
{
|
||||||
await LcuRequest.ExecuteAsync();
|
await LcuRequest.ExecuteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Receive(DataReadyMessage message)
|
|
||||||
{
|
|
||||||
Avalonia.Threading.Dispatcher.UIThread.Invoke(() =>
|
|
||||||
{
|
|
||||||
RequestPaths.Clear();
|
|
||||||
RequestPaths.AddRange(message.Value.Paths);
|
|
||||||
IsBusy = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Needlework.Net.Messages;
|
|
||||||
using Needlework.Net.ViewModels.Shared;
|
using Needlework.Net.ViewModels.Shared;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -23,12 +21,10 @@ public partial class EndpointViewModel : ObservableObject
|
|||||||
|
|
||||||
public event EventHandler<string>? PathOperationSelected;
|
public event EventHandler<string>? PathOperationSelected;
|
||||||
|
|
||||||
public EndpointViewModel(string endpoint, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger)
|
public EndpointViewModel(string endpoint, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, Models.Document lcuSchemaDocument)
|
||||||
{
|
{
|
||||||
Endpoint = endpoint;
|
Endpoint = endpoint;
|
||||||
|
PathOperations = new AvaloniaList<PathOperationViewModel>(lcuSchemaDocument.Plugins[endpoint].Select(x => new PathOperationViewModel(x, lcuRequestViewModelLogger, lcuSchemaDocument)));
|
||||||
var handler = WeakReferenceMessenger.Default.Send<DataRequestMessage>().Response;
|
|
||||||
PathOperations = new AvaloniaList<PathOperationViewModel>(handler.Plugins[endpoint].Select(x => new PathOperationViewModel(x, lcuRequestViewModelLogger)));
|
|
||||||
FilteredPathOperations = new AvaloniaList<PathOperationViewModel>(PathOperations);
|
FilteredPathOperations = new AvaloniaList<PathOperationViewModel>(PathOperations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ public partial class EndpointsNavigationViewModel : ObservableObject
|
|||||||
|
|
||||||
private readonly Action<string?, Guid> _onEndpointNavigation;
|
private readonly Action<string?, Guid> _onEndpointNavigation;
|
||||||
|
|
||||||
public EndpointsNavigationViewModel(IAvaloniaList<string> plugins, Action<string?, Guid> onEndpointNavigation, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger)
|
public EndpointsNavigationViewModel(IAvaloniaList<string> plugins, Action<string?, Guid> onEndpointNavigation, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, Models.Document lcuSchemaDocument)
|
||||||
{
|
{
|
||||||
_activeViewModel = _endpointsViewModel = new EndpointsViewModel(plugins, OnClicked, lcuRequestViewModelLogger);
|
_activeViewModel = _endpointsViewModel = new EndpointsViewModel(plugins, OnClicked, lcuRequestViewModelLogger, lcuSchemaDocument);
|
||||||
_onEndpointNavigation = onEndpointNavigation;
|
_onEndpointNavigation = onEndpointNavigation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ using CommunityToolkit.Mvvm.Input;
|
|||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Needlework.Net.Messages;
|
|
||||||
using Needlework.Net.ViewModels.Shared;
|
using Needlework.Net.ViewModels.Shared;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Needlework.Net.ViewModels.Pages.Endpoints;
|
namespace Needlework.Net.ViewModels.Pages.Endpoints;
|
||||||
|
|
||||||
public partial class EndpointsTabViewModel : PageBase, IRecipient<DataReadyMessage>
|
public partial class EndpointsTabViewModel : PageBase
|
||||||
{
|
{
|
||||||
public IAvaloniaList<string> Plugins { get; } = new AvaloniaList<string>();
|
public IAvaloniaList<string> Plugins { get; } = new AvaloniaList<string>();
|
||||||
public IAvaloniaList<EndpointItem> Endpoints { get; } = new AvaloniaList<EndpointItem>();
|
public IAvaloniaList<EndpointItem> Endpoints { get; } = new AvaloniaList<EndpointItem>();
|
||||||
@@ -19,28 +19,31 @@ public partial class EndpointsTabViewModel : PageBase, IRecipient<DataReadyMessa
|
|||||||
[ObservableProperty] private bool _isBusy = true;
|
[ObservableProperty] private bool _isBusy = true;
|
||||||
|
|
||||||
private readonly ILogger<LcuRequestViewModel> _lcuRequestViewModelLogger;
|
private readonly ILogger<LcuRequestViewModel> _lcuRequestViewModelLogger;
|
||||||
|
private readonly DataSource _dataSource;
|
||||||
|
|
||||||
public EndpointsTabViewModel(ILogger<LcuRequestViewModel> lcuRequestViewModelLogger) : base("Endpoints", "list-alt", -500)
|
public EndpointsTabViewModel(ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, DataSource dataSource) : base("Endpoints", "list-alt", -500)
|
||||||
{
|
{
|
||||||
_lcuRequestViewModelLogger = lcuRequestViewModelLogger;
|
_lcuRequestViewModelLogger = lcuRequestViewModelLogger;
|
||||||
|
_dataSource = dataSource;
|
||||||
WeakReferenceMessenger.Default.RegisterAll(this);
|
WeakReferenceMessenger.Default.RegisterAll(this);
|
||||||
}
|
}
|
||||||
|
public override async Task InitializeAsync()
|
||||||
public void Receive(DataReadyMessage message)
|
|
||||||
{
|
{
|
||||||
IsBusy = false;
|
var document = await _dataSource.GetLcuSchemaDocumentAsync();
|
||||||
Plugins.Clear();
|
Plugins.Clear();
|
||||||
Plugins.AddRange(message.Value.Plugins.Keys);
|
Plugins.AddRange(document.Plugins.Keys);
|
||||||
|
await Dispatcher.UIThread.Invoke(AddEndpoint);
|
||||||
Dispatcher.UIThread.Post(AddEndpoint);
|
IsBusy = false;
|
||||||
|
IsInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void AddEndpoint()
|
private async Task AddEndpoint()
|
||||||
{
|
{
|
||||||
|
var lcuSchemaDocument = await _dataSource.GetLcuSchemaDocumentAsync();
|
||||||
Endpoints.Add(new()
|
Endpoints.Add(new()
|
||||||
{
|
{
|
||||||
Content = new EndpointsNavigationViewModel(Plugins, OnEndpointNavigation, _lcuRequestViewModelLogger),
|
Content = new EndpointsNavigationViewModel(Plugins, OnEndpointNavigation, _lcuRequestViewModelLogger, lcuSchemaDocument),
|
||||||
Selected = true
|
Selected = true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Needlework.Net.Models;
|
||||||
using Needlework.Net.ViewModels.Shared;
|
using Needlework.Net.ViewModels.Shared;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -19,13 +20,15 @@ public partial class EndpointsViewModel : ObservableObject
|
|||||||
public Action<ObservableObject> OnClicked { get; }
|
public Action<ObservableObject> OnClicked { get; }
|
||||||
|
|
||||||
private readonly ILogger<LcuRequestViewModel> _lcuRequestViewModelLogger;
|
private readonly ILogger<LcuRequestViewModel> _lcuRequestViewModelLogger;
|
||||||
|
private readonly Document _lcuSchemaDocument;
|
||||||
|
|
||||||
public EndpointsViewModel(IAvaloniaList<string> plugins, Action<ObservableObject> onClicked, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger)
|
public EndpointsViewModel(IAvaloniaList<string> plugins, Action<ObservableObject> onClicked, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, Models.Document lcuSchemaDocument)
|
||||||
{
|
{
|
||||||
Plugins = new AvaloniaList<string>(plugins);
|
Plugins = new AvaloniaList<string>(plugins);
|
||||||
Query = new AvaloniaList<string>(plugins);
|
Query = new AvaloniaList<string>(plugins);
|
||||||
OnClicked = onClicked;
|
OnClicked = onClicked;
|
||||||
_lcuRequestViewModelLogger = lcuRequestViewModelLogger;
|
_lcuRequestViewModelLogger = lcuRequestViewModelLogger;
|
||||||
|
_lcuSchemaDocument = lcuSchemaDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnSearchChanged(string value)
|
partial void OnSearchChanged(string value)
|
||||||
@@ -42,6 +45,6 @@ public partial class EndpointsViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(value)) return;
|
if (string.IsNullOrEmpty(value)) return;
|
||||||
|
|
||||||
OnClicked.Invoke(new EndpointViewModel(value, _lcuRequestViewModelLogger));
|
OnClicked.Invoke(new EndpointViewModel(value, _lcuRequestViewModelLogger, _lcuSchemaDocument));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Needlework.Net.Messages;
|
using Needlework.Net.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@@ -22,23 +21,23 @@ public partial class OperationViewModel : ObservableObject
|
|||||||
public IAvaloniaReadOnlyList<ParameterViewModel> QueryParameters { get; }
|
public IAvaloniaReadOnlyList<ParameterViewModel> QueryParameters { get; }
|
||||||
public string? RequestTemplate { get; }
|
public string? RequestTemplate { get; }
|
||||||
|
|
||||||
public OperationViewModel(OpenApiOperation operation)
|
public OperationViewModel(OpenApiOperation operation, Models.Document lcuSchemaDocument)
|
||||||
{
|
{
|
||||||
Summary = operation.Summary ?? string.Empty;
|
Summary = operation.Summary ?? string.Empty;
|
||||||
Description = operation.Description ?? string.Empty;
|
Description = operation.Description ?? string.Empty;
|
||||||
IsRequestBody = operation.RequestBody != null;
|
IsRequestBody = operation.RequestBody != null;
|
||||||
ReturnType = GetReturnType(operation.Responses);
|
ReturnType = GetReturnType(operation.Responses);
|
||||||
RequestClasses = GetRequestClasses(operation.RequestBody);
|
RequestClasses = GetRequestClasses(operation.RequestBody, lcuSchemaDocument);
|
||||||
ResponseClasses = GetResponseClasses(operation.Responses);
|
ResponseClasses = GetResponseClasses(operation.Responses, lcuSchemaDocument);
|
||||||
PathParameters = GetParameters(operation.Parameters, ParameterLocation.Path);
|
PathParameters = GetParameters(operation.Parameters, ParameterLocation.Path);
|
||||||
QueryParameters = GetParameters(operation.Parameters, ParameterLocation.Query);
|
QueryParameters = GetParameters(operation.Parameters, ParameterLocation.Query);
|
||||||
RequestBodyType = GetRequestBodyType(operation.RequestBody);
|
RequestBodyType = GetRequestBodyType(operation.RequestBody);
|
||||||
RequestTemplate = GetRequestTemplate(operation.RequestBody);
|
RequestTemplate = GetRequestTemplate(operation.RequestBody, lcuSchemaDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string? GetRequestTemplate(OpenApiRequestBody? requestBody)
|
private string? GetRequestTemplate(OpenApiRequestBody? requestBody, Document lcuSchemaDocument)
|
||||||
{
|
{
|
||||||
var requestClasses = GetRequestClasses(requestBody);
|
var requestClasses = GetRequestClasses(requestBody, lcuSchemaDocument);
|
||||||
if (requestClasses.Count == 0)
|
if (requestClasses.Count == 0)
|
||||||
{
|
{
|
||||||
var type = GetRequestBodyType(requestBody);
|
var type = GetRequestBodyType(requestBody);
|
||||||
@@ -133,12 +132,12 @@ public partial class OperationViewModel : ObservableObject
|
|||||||
return pathParameters;
|
return pathParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AvaloniaList<PropertyClassViewModel> GetResponseClasses(OpenApiResponses responses)
|
private AvaloniaList<PropertyClassViewModel> GetResponseClasses(OpenApiResponses responses, Document lcuSchemaDocument)
|
||||||
{
|
{
|
||||||
if (responses.TryGetValue("2XX", out var response)
|
if (responses.TryGetValue("2XX", out var response)
|
||||||
&& response.Content.TryGetValue("application/json", out var media))
|
&& response.Content.TryGetValue("application/json", out var media))
|
||||||
{
|
{
|
||||||
var document = WeakReferenceMessenger.Default.Send(new HostDocumentRequestMessage()).Response;
|
var document = lcuSchemaDocument.OpenApiDocument;
|
||||||
var schema = media.Schema;
|
var schema = media.Schema;
|
||||||
AvaloniaList<PropertyClassViewModel> propertyClasses = [];
|
AvaloniaList<PropertyClassViewModel> propertyClasses = [];
|
||||||
WalkSchema(schema, propertyClasses, document);
|
WalkSchema(schema, propertyClasses, document);
|
||||||
@@ -186,12 +185,12 @@ public partial class OperationViewModel : ObservableObject
|
|||||||
|| type.Contains("number"));
|
|| type.Contains("number"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private AvaloniaList<PropertyClassViewModel> GetRequestClasses(OpenApiRequestBody? requestBody)
|
private AvaloniaList<PropertyClassViewModel> GetRequestClasses(OpenApiRequestBody? requestBody, Document lcuSchemaDocument)
|
||||||
{
|
{
|
||||||
if (requestBody == null) return [];
|
if (requestBody == null) return [];
|
||||||
if (requestBody.Content.TryGetValue("application/json", out var media))
|
if (requestBody.Content.TryGetValue("application/json", out var media))
|
||||||
{
|
{
|
||||||
var document = WeakReferenceMessenger.Default.Send(new HostDocumentRequestMessage()).Response;
|
var document = lcuSchemaDocument.OpenApiDocument;
|
||||||
var schema = media.Schema;
|
var schema = media.Schema;
|
||||||
if (schema == null) return [];
|
if (schema == null) return [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Avalonia.Controls;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Needlework.Net.Models;
|
using Needlework.Net.Models;
|
||||||
@@ -20,10 +19,10 @@ public partial class PathOperationViewModel : ObservableObject
|
|||||||
[ObservableProperty] private bool _isBusy;
|
[ObservableProperty] private bool _isBusy;
|
||||||
[ObservableProperty] private Lazy<LcuRequestViewModel> _lcuRequest;
|
[ObservableProperty] private Lazy<LcuRequestViewModel> _lcuRequest;
|
||||||
|
|
||||||
public PathOperationViewModel(PathOperation pathOperation, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger)
|
public PathOperationViewModel(PathOperation pathOperation, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, Document lcuSchemaDocument)
|
||||||
{
|
{
|
||||||
Path = pathOperation.Path;
|
Path = pathOperation.Path;
|
||||||
Operation = new OperationViewModel(pathOperation.Operation);
|
Operation = new OperationViewModel(pathOperation.Operation, lcuSchemaDocument);
|
||||||
LcuRequest = new(() => new LcuRequestViewModel(lcuRequestViewModelLogger)
|
LcuRequest = new(() => new LcuRequestViewModel(lcuRequestViewModelLogger)
|
||||||
{
|
{
|
||||||
Method = pathOperation.Method.ToUpper()
|
Method = pathOperation.Method.ToUpper()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Needlework.Net.ViewModels.Pages;
|
namespace Needlework.Net.ViewModels.Pages;
|
||||||
|
|
||||||
@@ -14,6 +15,12 @@ public partial class HomeViewModel : PageBase
|
|||||||
|
|
||||||
public HomeViewModel() : base("Home", "home", int.MinValue) { }
|
public HomeViewModel() : base("Home", "home", int.MinValue) { }
|
||||||
|
|
||||||
|
public override Task InitializeAsync()
|
||||||
|
{
|
||||||
|
IsInitialized = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void OpenUrl(string url)
|
private void OpenUrl(string url)
|
||||||
{
|
{
|
||||||
@@ -23,4 +30,5 @@ public partial class HomeViewModel : PageBase
|
|||||||
};
|
};
|
||||||
process.Start();
|
process.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Needlework.Net.ViewModels.Pages;
|
namespace Needlework.Net.ViewModels.Pages;
|
||||||
|
|
||||||
@@ -8,4 +9,7 @@ public abstract partial class PageBase(string displayName, string icon, int inde
|
|||||||
[ObservableProperty] private string _displayName = displayName;
|
[ObservableProperty] private string _displayName = displayName;
|
||||||
[ObservableProperty] private string _icon = icon;
|
[ObservableProperty] private string _icon = icon;
|
||||||
[ObservableProperty] private int _index = index;
|
[ObservableProperty] private int _index = index;
|
||||||
|
[ObservableProperty] private bool _isInitialized;
|
||||||
|
|
||||||
|
public abstract Task InitializeAsync();
|
||||||
}
|
}
|
||||||
@@ -59,6 +59,12 @@ public partial class WebsocketViewModel : PageBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Task InitializeAsync()
|
||||||
|
{
|
||||||
|
IsInitialized = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task InitializeEventTypes()
|
private async Task InitializeEventTypes()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
Reference in New Issue
Block a user