mirror of
https://github.com/BlossomiShymae/Needlework.Net.git
synced 2025-12-06 18:20:47 +01:00
WIP
This commit is contained in:
27
Needlework.Net.Core.Tests/LcuSchemaHandlerTest.cs
Normal file
27
Needlework.Net.Core.Tests/LcuSchemaHandlerTest.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Needlework.Net.Core.Tests;
|
||||
|
||||
public class LcuSchemaHandlerTest
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
internal HttpClient HttpClient { get; } = new();
|
||||
|
||||
public LcuSchemaHandlerTest(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PluginsTestAsync()
|
||||
{
|
||||
var reader = new LcuSchemaHandler(await Resources.GetOpenApiDocumentAsync(HttpClient));
|
||||
|
||||
var plugins = reader.Plugins.Keys.ToList();
|
||||
foreach (var plugin in plugins)
|
||||
_output.WriteLine($"Plugin: {plugin}");
|
||||
|
||||
Assert.True(plugins.Count > 0);
|
||||
}
|
||||
}
|
||||
25
Needlework.Net.Core.Tests/ResourcesTest.cs
Normal file
25
Needlework.Net.Core.Tests/ResourcesTest.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Needlework.Net.Core.Tests;
|
||||
|
||||
public class ResourcesTest
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
internal HttpClient HttpClient { get; } = new();
|
||||
|
||||
public ResourcesTest(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DocumentTestAsync()
|
||||
{
|
||||
var document = await Resources.GetOpenApiDocumentAsync(HttpClient);
|
||||
|
||||
Assert.True(document.Info.Title == "LCU SCHEMA");
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Needlework.Net.Core.Tests;
|
||||
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Needlework.Net.Core;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
10
Needlework.Net.Core/LcuConnector.cs
Normal file
10
Needlework.Net.Core/LcuConnector.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using BlossomiShymae.GrrrLCU;
|
||||
|
||||
namespace Needlework.Net.Core;
|
||||
|
||||
public static class LcuConnector
|
||||
{
|
||||
public static Func<ProcessInfo> GetProcessInfo { get; } = Connector.GetProcessInfo;
|
||||
public static Func<int, string, Uri> GetLeagueClientUri { get; } = Connector.GetLeagueClientUri;
|
||||
public static Func<HttpMethod, string, CancellationToken, Task<HttpResponseMessage>> SendAsync { get; } = Connector.SendAsync;
|
||||
}
|
||||
49
Needlework.Net.Core/LcuSchemaHandler.cs
Normal file
49
Needlework.Net.Core/LcuSchemaHandler.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace Needlework.Net.Core;
|
||||
|
||||
public class LcuSchemaHandler
|
||||
{
|
||||
internal OpenApiDocument OpenApiDocument { get; }
|
||||
|
||||
public SortedDictionary<string, OpenApiPathItem> Plugins { get; } = [];
|
||||
|
||||
public OpenApiInfo Info => OpenApiDocument.Info;
|
||||
|
||||
public LcuSchemaHandler(OpenApiDocument openApiDocument)
|
||||
{
|
||||
OpenApiDocument = openApiDocument;
|
||||
|
||||
// Group paths by plugins
|
||||
foreach (var tag in OpenApiDocument.Tags)
|
||||
{
|
||||
foreach (var path in OpenApiDocument.Paths)
|
||||
{
|
||||
var containsTag = false;
|
||||
var sentinelTag = string.Empty;
|
||||
|
||||
foreach (var operation in path.Value.Operations)
|
||||
{
|
||||
foreach (var operationTag in operation.Value.Tags)
|
||||
{
|
||||
var lhs = tag.Name.Replace("Plugin ", string.Empty);
|
||||
var rhs = operationTag.Name.Replace("Plugin ", string.Empty);
|
||||
|
||||
if (lhs.Equals(rhs, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
containsTag = true;
|
||||
sentinelTag = lhs.ToLower();
|
||||
break; // Break early since all operations in a path share the same tags
|
||||
}
|
||||
}
|
||||
|
||||
if (containsTag)
|
||||
break; // Ditto
|
||||
}
|
||||
|
||||
if (containsTag)
|
||||
Plugins[sentinelTag] = path.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,4 +6,10 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BlossomiShymae.GrrrLCU" Version="0.4.0" />
|
||||
<PackageReference Include="Microsoft.OpenApi" Version="1.6.16" />
|
||||
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.6.16" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
21
Needlework.Net.Core/Resources.cs
Normal file
21
Needlework.Net.Core/Resources.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi.Readers;
|
||||
|
||||
namespace Needlework.Net.Core;
|
||||
|
||||
public static class Resources
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the OpenApi document of the LCU schema. Provided by dysolix.
|
||||
/// </summary>
|
||||
/// <param name="httpClient"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<OpenApiDocument> GetOpenApiDocumentAsync(HttpClient httpClient)
|
||||
{
|
||||
var stream = await httpClient.GetStreamAsync("https://raw.githubusercontent.com/dysolix/hasagi-types/main/swagger.json");
|
||||
|
||||
var document = new OpenApiStreamReader().Read(stream, out var _);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,19 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="Needlework.Net.Desktop.App"
|
||||
RequestedThemeVariant="Default">
|
||||
RequestedThemeVariant="Dark"
|
||||
xmlns:local="using:Needlework.Net.Desktop"
|
||||
xmlns:sukiUi="clr-namespace:SukiUI;assembly=SukiUI"
|
||||
xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia">
|
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
|
||||
<Application.DataTemplates>
|
||||
<local:ViewLocator/>
|
||||
</Application.DataTemplates>
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
<FluentTheme></FluentTheme>
|
||||
<sukiUi:SukiTheme ThemeColor="Blue" />
|
||||
<materialIcons:MaterialIconStyles />
|
||||
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml" />
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
@@ -1,11 +1,23 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Needlework.Net.Desktop.ViewModels;
|
||||
using Needlework.Net.Desktop.Views;
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Needlework.Net.Desktop;
|
||||
|
||||
public partial class App : Application
|
||||
public partial class App(IServiceProvider serviceProvider) : Application
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider = serviceProvider;
|
||||
|
||||
public static JsonSerializerOptions JsonSerializerOptions { get; } = new()
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
@@ -15,7 +27,10 @@ public partial class App : Application
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow = new MainWindow();
|
||||
desktop.MainWindow = new MainWindow()
|
||||
{
|
||||
DataContext = _serviceProvider.GetRequiredService<MainWindowViewModel>()
|
||||
};
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
|
||||
BIN
Needlework.Net.Desktop/Assets/about.png
Normal file
BIN
Needlework.Net.Desktop/Assets/about.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 147 KiB |
@@ -1,9 +0,0 @@
|
||||
<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"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Needlework.Net.Desktop.MainWindow"
|
||||
Title="Needlework.Net.Desktop">
|
||||
Welcome to Avalonia!
|
||||
</Window>
|
||||
@@ -1,11 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Needlework.Net.Desktop;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,48 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net8.0-windows10.0.17763.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Avalonia">
|
||||
<AvaloniaXamlIlDebuggerLaunch>False</AvaloniaXamlIlDebuggerLaunch>
|
||||
<SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion>
|
||||
<AssemblyVersion>0.1.0.0</AssemblyVersion>
|
||||
<FileVersion>0.1.0.0</FileVersion>
|
||||
<AvaloniaXamlVerboseExceptions>False</AvaloniaXamlVerboseExceptions>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.1.0" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.1.0" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.0" />
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.1.0" />
|
||||
<PackageReference Include="Avalonia" Version="11.1.0-beta2" />
|
||||
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.0.6" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.1.0-beta2" />
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.1.0-beta2" />
|
||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.0" />
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.0-beta2" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.0-beta2" />
|
||||
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.0.6" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||
<PackageReference Include="Material.Icons.Avalonia" Version="2.1.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<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.60" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Needlework.Net.Core\Needlework.Net.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<UpToDateCheckInput Remove="Views\AboutView.axaml" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
using Avalonia;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Needlework.Net.Desktop.Services;
|
||||
using Needlework.Net.Desktop.ViewModels;
|
||||
using Projektanker.Icons.Avalonia;
|
||||
using Projektanker.Icons.Avalonia.FontAwesome;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Needlework.Net.Desktop;
|
||||
|
||||
@@ -14,8 +20,32 @@ class Program
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
{
|
||||
IconProvider.Current
|
||||
.Register<FontAwesomeIconProvider>();
|
||||
|
||||
return AppBuilder.Configure(() => new App(BuildServices()))
|
||||
.UsePlatformDetect()
|
||||
.WithInterFont()
|
||||
.LogToTrace();
|
||||
}
|
||||
|
||||
private static IServiceProvider BuildServices()
|
||||
{
|
||||
var builder = new ServiceCollection();
|
||||
|
||||
builder.AddSingleton<MainWindowViewModel>();
|
||||
builder.AddSingleton<DialogService>();
|
||||
// Dynamically add ViewModels
|
||||
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(s => s.GetTypes())
|
||||
.Where(p => !p.IsAbstract && typeof(PageBase).IsAssignableFrom(p));
|
||||
foreach (var type in types)
|
||||
builder.AddSingleton(typeof(PageBase), type);
|
||||
|
||||
builder.AddHttpClient();
|
||||
|
||||
var services = builder.BuildServiceProvider();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
47
Needlework.Net.Desktop/Services/DialogService.cs
Normal file
47
Needlework.Net.Desktop/Services/DialogService.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Needlework.Net.Desktop.ViewModels;
|
||||
using Needlework.Net.Desktop.Views;
|
||||
using SukiUI.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Needlework.Net.Desktop.Services
|
||||
{
|
||||
public class DialogService
|
||||
{
|
||||
public IServiceProvider ServiceProvider { get; }
|
||||
|
||||
public Dictionary<string, SukiWindow> Dialogs { get; } = [];
|
||||
|
||||
public DialogService(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public void ShowEndpoint(string endpoint)
|
||||
{
|
||||
if (!Dialogs.TryGetValue(endpoint, out var _))
|
||||
{
|
||||
var dialog = new EndpointView();
|
||||
dialog.DataContext = new EndpointViewModel(endpoint);
|
||||
dialog.Show();
|
||||
dialog.Closed += OnDialogClosed;
|
||||
Dialogs[endpoint] = dialog;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDialogClosed(object? sender, EventArgs e)
|
||||
{
|
||||
if (sender == null)
|
||||
return;
|
||||
|
||||
var dialog = (SukiWindow)sender;
|
||||
if (dialog.DataContext is EndpointViewModel vm)
|
||||
{
|
||||
Dialogs.Remove(vm.Endpoint);
|
||||
dialog.DataContext = null;
|
||||
}
|
||||
|
||||
dialog.Closed -= OnDialogClosed;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Needlework.Net.Desktop/Services/LcuService.cs
Normal file
31
Needlework.Net.Desktop/Services/LcuService.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Avalonia.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Needlework.Net.Core;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Needlework.Net.Desktop.Services
|
||||
{
|
||||
public partial class LcuService : ObservableObject
|
||||
{
|
||||
public HttpClient HttpClient { get; }
|
||||
|
||||
public LcuSchemaHandler LcuSchemaHandler { get; }
|
||||
|
||||
[ObservableProperty] private string _statusText = "Offline";
|
||||
[ObservableProperty] private IBrush _statusColor = new SolidColorBrush(Colors.Red.ToUInt32());
|
||||
[ObservableProperty] private string _statusAddress = "N/A";
|
||||
|
||||
public LcuService(HttpClient httpClient)
|
||||
{
|
||||
HttpClient = httpClient;
|
||||
|
||||
Task.Run(ProcessBackground);
|
||||
}
|
||||
|
||||
private void ProcessBackground()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Needlework.Net.Desktop/TextUpdatedEventArgs.cs
Normal file
9
Needlework.Net.Desktop/TextUpdatedEventArgs.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace Needlework.Net.Desktop
|
||||
{
|
||||
public class TextUpdatedEventArgs(string text) : EventArgs
|
||||
{
|
||||
public string Text { get; } = text;
|
||||
}
|
||||
}
|
||||
35
Needlework.Net.Desktop/ViewLocator.cs
Normal file
35
Needlework.Net.Desktop/ViewLocator.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Needlework.Net.Desktop.ViewModels;
|
||||
using System;
|
||||
|
||||
namespace Needlework.Net.Desktop
|
||||
{
|
||||
public class ViewLocator : IDataTemplate
|
||||
{
|
||||
public Control? Build(object? param)
|
||||
{
|
||||
if (param is null)
|
||||
return new TextBlock { Text = "data was null" };
|
||||
|
||||
var name = param.GetType().FullName!.Replace("ViewModels", "Views")
|
||||
.Replace("ViewModel", "View");
|
||||
var type = Type.GetType(name);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return (Control)Activator.CreateInstance(type)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TextBlock { Text = "Not Found: " + name };
|
||||
}
|
||||
}
|
||||
|
||||
public bool Match(object? data)
|
||||
{
|
||||
if (data is PageBase) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Needlework.Net.Desktop/ViewModels/AboutViewModel.cs
Normal file
9
Needlework.Net.Desktop/ViewModels/AboutViewModel.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Needlework.Net.Desktop.ViewModels
|
||||
{
|
||||
public class AboutViewModel : PageBase
|
||||
{
|
||||
public AboutViewModel() : base("About", Material.Icons.MaterialIconKind.InfoCircle)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
75
Needlework.Net.Desktop/ViewModels/ConsoleViewModel.cs
Normal file
75
Needlework.Net.Desktop/ViewModels/ConsoleViewModel.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using Avalonia.Collections;
|
||||
using BlossomiShymae.GrrrLCU;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using SukiUI.Controls;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Needlework.Net.Desktop.ViewModels
|
||||
{
|
||||
public partial class ConsoleViewModel : PageBase
|
||||
{
|
||||
public IAvaloniaReadOnlyList<string> RequestMethods { get; } = new AvaloniaList<string>(["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS", "TRACE"]);
|
||||
|
||||
[ObservableProperty] private string? _requestMethodSelected = "GET";
|
||||
[ObservableProperty] private string? _requestPath = null;
|
||||
[ObservableProperty] private string? _requestBody = null;
|
||||
[ObservableProperty] private string? _responsePath = null;
|
||||
[ObservableProperty] private string? _responseStatus = null;
|
||||
[ObservableProperty] private string? _responseAuthentication = null;
|
||||
|
||||
public event EventHandler<TextUpdatedEventArgs>? ResponseBodyUpdated;
|
||||
|
||||
public ConsoleViewModel() : base("Console", Material.Icons.MaterialIconKind.Console, -100)
|
||||
{
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task SendRequest()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(RequestPath)) throw new Exception("Path is empty.");
|
||||
|
||||
var method = RequestMethodSelected switch
|
||||
{
|
||||
"GET" => HttpMethod.Get,
|
||||
"POST" => HttpMethod.Post,
|
||||
"PUT" => HttpMethod.Put,
|
||||
"DELETE" => HttpMethod.Delete,
|
||||
"HEAD" => HttpMethod.Head,
|
||||
"PATCH" => HttpMethod.Patch,
|
||||
"OPTIONS" => HttpMethod.Options,
|
||||
"TRACE" => HttpMethod.Trace,
|
||||
_ => throw new Exception("Method is not selected."),
|
||||
};
|
||||
|
||||
var processInfo = Connector.GetProcessInfo();
|
||||
var response = await Connector.SendAsync(method, RequestPath) ?? throw new Exception("Response is null.");
|
||||
var riotAuthentication = new RiotAuthentication(processInfo.RemotingAuthToken);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
|
||||
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
ResponseStatus = response.StatusCode.ToString();
|
||||
ResponsePath = $"https://127.0.0.1/{processInfo.AppPort}{RequestPath}";
|
||||
ResponseAuthentication = riotAuthentication.Value;
|
||||
ResponseBodyUpdated?.Invoke(this, new(body));
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await SukiHost.ShowToast("Request Failed", ex.Message, SukiUI.Enums.NotificationType.Error);
|
||||
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
ResponseStatus = null;
|
||||
ResponsePath = null;
|
||||
ResponseAuthentication = null;
|
||||
ResponseBodyUpdated?.Invoke(this, new(string.Empty));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Needlework.Net.Desktop/ViewModels/EndpointViewModel.cs
Normal file
10
Needlework.Net.Desktop/ViewModels/EndpointViewModel.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Needlework.Net.Desktop.ViewModels
|
||||
{
|
||||
public partial class EndpointViewModel(string endpoint) : ObservableObject
|
||||
{
|
||||
public string Endpoint { get; } = endpoint;
|
||||
public string Title => $"Needlework.Net - {Endpoint}";
|
||||
}
|
||||
}
|
||||
57
Needlework.Net.Desktop/ViewModels/EndpointsViewModel.cs
Normal file
57
Needlework.Net.Desktop/ViewModels/EndpointsViewModel.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Needlework.Net.Core;
|
||||
using Needlework.Net.Desktop.Services;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Needlework.Net.Desktop.ViewModels
|
||||
{
|
||||
public partial class EndpointsViewModel : PageBase
|
||||
{
|
||||
public HttpClient HttpClient { get; }
|
||||
|
||||
public DialogService DialogService { get; }
|
||||
|
||||
[ObservableProperty] private List<string> _plugins = [];
|
||||
[ObservableProperty] private bool _isBusy = true;
|
||||
[ObservableProperty] private string _search = string.Empty;
|
||||
[ObservableProperty] private List<string> _query = [];
|
||||
[ObservableProperty] private string? _selectedQuery = string.Empty;
|
||||
|
||||
public EndpointsViewModel(HttpClient httpClient, DialogService dialogService) : base("Endpoints", Material.Icons.MaterialIconKind.Hub, -500)
|
||||
{
|
||||
HttpClient = httpClient;
|
||||
DialogService = dialogService;
|
||||
|
||||
Task.Run(InitializeAsync);
|
||||
}
|
||||
|
||||
private async Task InitializeAsync()
|
||||
{
|
||||
var handler = new LcuSchemaHandler(await Resources.GetOpenApiDocumentAsync(HttpClient));
|
||||
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
Plugins = [.. handler.Plugins.Keys];
|
||||
Query = [.. Plugins];
|
||||
IsBusy = false;
|
||||
});
|
||||
}
|
||||
|
||||
partial void OnSearchChanged(string value)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Search))
|
||||
Query = Plugins.Where(x => x.Contains(value)).ToList();
|
||||
else
|
||||
Query = Plugins;
|
||||
}
|
||||
|
||||
partial void OnSelectedQueryChanged(string? value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return;
|
||||
DialogService.ShowEndpoint(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Needlework.Net.Desktop/ViewModels/HomeViewModel.cs
Normal file
55
Needlework.Net.Desktop/ViewModels/HomeViewModel.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Avalonia.Media;
|
||||
using BlossomiShymae.GrrrLCU;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
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)
|
||||
{
|
||||
Task.Run(async () => { while (true) { SetStatus(); await Task.Delay(TimeSpan.FromSeconds(5)); } });
|
||||
}
|
||||
|
||||
private void SetStatus()
|
||||
{
|
||||
void Set(string text, Color color, string address)
|
||||
{
|
||||
StatusText = text;
|
||||
StatusForeground = new SolidColorBrush(color.ToUInt32());
|
||||
StatusAddress = address;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var processInfo = Connector.GetProcessInfo();
|
||||
Avalonia.Threading.Dispatcher.UIThread.Post(() => Set("Online", Colors.Green, $"https://127.0.0.1:{processInfo.AppPort}/"));
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
Avalonia.Threading.Dispatcher.UIThread.Post(() => Set("Offline", Colors.Red, "N/A"));
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenUrl(string url)
|
||||
{
|
||||
var process = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo(url)
|
||||
{
|
||||
UseShellExecute = true
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
41
Needlework.Net.Desktop/ViewModels/MainWindowViewModel.cs
Normal file
41
Needlework.Net.Desktop/ViewModels/MainWindowViewModel.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Avalonia.Collections;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Needlework.Net.Desktop.ViewModels
|
||||
{
|
||||
public partial class MainWindowViewModel : ObservableObject
|
||||
{
|
||||
public IAvaloniaReadOnlyList<PageBase> Pages { get; }
|
||||
|
||||
public string Version { get; } = Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0.0.0.0";
|
||||
|
||||
public MainWindowViewModel(IEnumerable<PageBase> pages)
|
||||
{
|
||||
Pages = new AvaloniaList<PageBase>(pages.OrderBy(x => x.Index).ThenBy(x => x.DisplayName));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenUrl(string url)
|
||||
{
|
||||
var process = new Process()
|
||||
{
|
||||
StartInfo = new ProcessStartInfo(url)
|
||||
{
|
||||
UseShellExecute = true
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenConsole()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Needlework.Net.Desktop/ViewModels/PageBase.cs
Normal file
13
Needlework.Net.Desktop/ViewModels/PageBase.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
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
|
||||
{
|
||||
[ObservableProperty] private string _displayName = displayName;
|
||||
[ObservableProperty] private MaterialIconKind _icon = icon;
|
||||
[ObservableProperty] private int _index = index;
|
||||
}
|
||||
}
|
||||
7
Needlework.Net.Desktop/ViewModels/PluginViewModel.cs
Normal file
7
Needlework.Net.Desktop/ViewModels/PluginViewModel.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Needlework.Net.Desktop.ViewModels
|
||||
{
|
||||
public class PluginViewModel
|
||||
{
|
||||
public PluginViewModel() { }
|
||||
}
|
||||
}
|
||||
39
Needlework.Net.Desktop/Views/AboutView.axaml
Normal file
39
Needlework.Net.Desktop/Views/AboutView.axaml
Normal file
@@ -0,0 +1,39 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
|
||||
xmlns:theme="clr-namespace:SukiUI.Theme;assembly=SukiUI"
|
||||
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Needlework.Net.Desktop.Views.AboutView"
|
||||
x:DataType="vm:AboutViewModel">
|
||||
<ScrollViewer>
|
||||
<WrapPanel Margin="8"
|
||||
theme:WrapPanelExtensions.AnimatedScroll="true"
|
||||
Orientation="Horizontal">
|
||||
<suki:GlassCard Margin="8">
|
||||
<Image Source="/Assets/about.png"
|
||||
RenderOptions.BitmapInterpolationMode="MediumQuality"
|
||||
Width="200"
|
||||
Height="200"/>
|
||||
</suki:GlassCard>
|
||||
<StackPanel>
|
||||
<suki:GlassCard Width="400" Margin="8">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="h3">Blossomi Shymae</TextBlock>
|
||||
</StackPanel>
|
||||
</suki:GlassCard>
|
||||
<suki:GlassCard Width="400" Margin="8">
|
||||
<suki:GroupBox Header="About">
|
||||
<TextBlock TextWrapping="Wrap">
|
||||
Needlework.Net is the sister project of Needlework. Like Needlework, this project is inspired by
|
||||
LCU Explorer. This tool was made to help others with LCU development. Feel free to ask any questions
|
||||
or help contribute to the project! 💜
|
||||
</TextBlock>
|
||||
</suki:GroupBox>
|
||||
</suki:GlassCard>
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
11
Needlework.Net.Desktop/Views/AboutView.axaml.cs
Normal file
11
Needlework.Net.Desktop/Views/AboutView.axaml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Needlework.Net.Desktop.Views;
|
||||
|
||||
public partial class AboutView : UserControl
|
||||
{
|
||||
public AboutView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
65
Needlework.Net.Desktop/Views/ConsoleView.axaml
Normal file
65
Needlework.Net.Desktop/Views/ConsoleView.axaml
Normal file
@@ -0,0 +1,65 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
|
||||
xmlns:avaloniaEdit="https://github.com/avaloniaui/avaloniaedit"
|
||||
xmlns:theme="clr-namespace:SukiUI.Theme;assembly=SukiUI"
|
||||
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Needlework.Net.Desktop.Views.ConsoleView"
|
||||
x:DataType="vm:ConsoleViewModel">
|
||||
<Grid Margin="16" RowDefinitions="auto,*" ColumnDefinitions="*,*">
|
||||
<Grid Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2">
|
||||
<suki:GlassCard Margin="0 0 0 16">
|
||||
<suki:GroupBox Header="Console">
|
||||
<Grid RowDefinitions="auto,auto" ColumnDefinitions="auto,*">
|
||||
<ComboBox ItemsSource="{Binding RequestMethods}" SelectedItem="{Binding RequestMethodSelected}"
|
||||
Grid.Row="0" Grid.Column="0"/>
|
||||
<TextBox Text="{Binding RequestPath}"
|
||||
Grid.Row="0" Grid.Column="1"
|
||||
Watermark="E.g. /lol-summoner/v1/current-summoner"/>
|
||||
<TextBox Text="{Binding RequestBody}" Height="200" AcceptsReturn="True" TextWrapping="Wrap"
|
||||
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
</Grid>
|
||||
</suki:GroupBox>
|
||||
</suki:GlassCard>
|
||||
<Button Classes="Flat Rounded"
|
||||
Margin="0 0 0 0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Bottom"
|
||||
FontWeight="DemiBold"
|
||||
Command="{Binding SendRequestCommand}">
|
||||
Send
|
||||
</Button>
|
||||
</Grid>
|
||||
<StackPanel
|
||||
Margin="0 0 8 0"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0">
|
||||
<suki:GlassCard Margin="0 4">
|
||||
<TextBlock Text="{Binding ResponsePath}"/>
|
||||
</suki:GlassCard>
|
||||
<suki:GlassCard Margin="0 4">
|
||||
<TextBlock Text="{Binding ResponseStatus}"/>
|
||||
</suki:GlassCard>
|
||||
<suki:GlassCard Margin="0 4">
|
||||
<TextBlock Text="{Binding ResponseAuthentication}" />
|
||||
</suki:GlassCard>
|
||||
</StackPanel>
|
||||
<suki:GlassCard
|
||||
Margin="0 8"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1">
|
||||
<avaloniaEdit:TextEditor Name="ResponseEditor"
|
||||
Text=""
|
||||
FontFamily="Cascadia Code,Consolas,Menlo,Monospace"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Visible"
|
||||
FontWeight="Light"
|
||||
FontSize="14"/>
|
||||
</suki:GlassCard>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
56
Needlework.Net.Desktop/Views/ConsoleView.axaml.cs
Normal file
56
Needlework.Net.Desktop/Views/ConsoleView.axaml.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Styling;
|
||||
using AvaloniaEdit;
|
||||
using AvaloniaEdit.Highlighting;
|
||||
using AvaloniaEdit.Indentation.CSharp;
|
||||
using AvaloniaEdit.TextMate;
|
||||
using Needlework.Net.Desktop.ViewModels;
|
||||
using SukiUI;
|
||||
using System.Text.Json;
|
||||
using TextMateSharp.Grammars;
|
||||
|
||||
namespace Needlework.Net.Desktop.Views;
|
||||
|
||||
public partial class ConsoleView : UserControl
|
||||
{
|
||||
private TextEditor? _responseEditor;
|
||||
|
||||
public ConsoleView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
|
||||
_responseEditor = this.FindControl<TextEditor>("ResponseEditor");
|
||||
_responseEditor!.TextArea.IndentationStrategy = new CSharpIndentationStrategy(_responseEditor.Options);
|
||||
_responseEditor!.TextArea.RightClickMovesCaret = true;
|
||||
_responseEditor!.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("JavaScript");
|
||||
|
||||
((ConsoleViewModel)DataContext!)!.ResponseBodyUpdated += ConsoleView_ResponseBodyUpdated;
|
||||
|
||||
OnBaseThemeChanged(Application.Current!.ActualThemeVariant);
|
||||
SukiTheme.GetInstance().OnBaseThemeChanged += OnBaseThemeChanged;
|
||||
}
|
||||
|
||||
private void ConsoleView_ResponseBodyUpdated(object? sender, TextUpdatedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Text))
|
||||
_responseEditor!.Text = JsonSerializer.Serialize(JsonSerializer.Deserialize<object>(e.Text), App.JsonSerializerOptions);
|
||||
else _responseEditor!.Text = e.Text;
|
||||
}
|
||||
|
||||
private void OnBaseThemeChanged(ThemeVariant currentTheme)
|
||||
{
|
||||
var registryOptions = new RegistryOptions(
|
||||
currentTheme == ThemeVariant.Dark ? ThemeName.DarkPlus : ThemeName.LightPlus);
|
||||
|
||||
var textMateInstallation = _responseEditor.InstallTextMate(registryOptions);
|
||||
textMateInstallation.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions
|
||||
.GetLanguageByExtension(".json").Id));
|
||||
}
|
||||
}
|
||||
19
Needlework.Net.Desktop/Views/EndpointView.axaml
Normal file
19
Needlework.Net.Desktop/Views/EndpointView.axaml
Normal file
@@ -0,0 +1,19 @@
|
||||
<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.EndpointView"
|
||||
x:DataType="vm:EndpointViewModel"
|
||||
Title="{Binding Title}"
|
||||
Width="1280"
|
||||
Height="720">
|
||||
<Grid Margin="8" RowDefinitions="auto,*" ColumnDefinitions="*">
|
||||
<TextBlock Classes="h3" Grid.Row="0" Grid.Column="0" Text="{Binding Endpoint}"/>
|
||||
<ScrollViewer Grid.Row="1" Grid.Column="0">
|
||||
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Window>
|
||||
11
Needlework.Net.Desktop/Views/EndpointView.axaml.cs
Normal file
11
Needlework.Net.Desktop/Views/EndpointView.axaml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using SukiUI.Controls;
|
||||
|
||||
namespace Needlework.Net.Desktop.Views;
|
||||
|
||||
public partial class EndpointView : SukiWindow
|
||||
{
|
||||
public EndpointView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
27
Needlework.Net.Desktop/Views/EndpointsView.axaml
Normal file
27
Needlework.Net.Desktop/Views/EndpointsView.axaml
Normal file
@@ -0,0 +1,27 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
|
||||
xmlns:theme="clr-namespace:SukiUI.Theme;assembly=SukiUI"
|
||||
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Needlework.Net.Desktop.Views.EndpointsView"
|
||||
x:DataType="vm:EndpointsViewModel">
|
||||
<!-- TOP LEVEL -->
|
||||
<suki:BusyArea IsBusy="{Binding IsBusy}" BusyText="Loading...">
|
||||
<Grid Margin="16" RowDefinitions="auto,auto,*" ColumnDefinitions="*">
|
||||
<TextBlock Classes="h3" Margin="0 4" Grid.Row="0" Grid.Column="0">Endpoints</TextBlock>
|
||||
<TextBox Watermark="Search" Margin="0 4" Text="{Binding Search}" Grid.Row="1" Grid.Column="0"/>
|
||||
<ScrollViewer Grid.Row="2" Grid.Column="0">
|
||||
<ListBox ItemsSource="{Binding Query}" SelectedItem="{Binding SelectedQuery}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" Foreground="White" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</suki:BusyArea>
|
||||
</UserControl>
|
||||
12
Needlework.Net.Desktop/Views/EndpointsView.axaml.cs
Normal file
12
Needlework.Net.Desktop/Views/EndpointsView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Needlework.Net.Desktop.Views
|
||||
{
|
||||
public partial class EndpointsView : UserControl
|
||||
{
|
||||
public EndpointsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
75
Needlework.Net.Desktop/Views/HomeView.axaml
Normal file
75
Needlework.Net.Desktop/Views/HomeView.axaml
Normal file
@@ -0,0 +1,75 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
|
||||
xmlns:theme="clr-namespace:SukiUI.Theme;assembly=SukiUI"
|
||||
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
|
||||
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">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="h3">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">
|
||||
<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>
|
||||
</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">
|
||||
<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">
|
||||
<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">
|
||||
Hextech Docs
|
||||
</Button>
|
||||
<Button CommandParameter="https://hextechdocs.dev/getting-started-with-the-lcu-api/">
|
||||
Getting Started
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</suki:GroupBox>
|
||||
</suki:GlassCard>
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
12
Needlework.Net.Desktop/Views/HomeView.axaml.cs
Normal file
12
Needlework.Net.Desktop/Views/HomeView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Needlework.Net.Desktop.Views
|
||||
{
|
||||
public partial class HomeView : UserControl
|
||||
{
|
||||
public HomeView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Needlework.Net.Desktop/Views/MainWindow.axaml
Normal file
57
Needlework.Net.Desktop/Views/MainWindow.axaml
Normal file
@@ -0,0 +1,57 @@
|
||||
<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: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"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Needlework.Net.Desktop.Views.MainWindow"
|
||||
x:DataType="vm:MainWindowViewModel"
|
||||
Title="Needlework.Net"
|
||||
Width="1280"
|
||||
Height="720">
|
||||
<!-- 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">
|
||||
<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" />
|
||||
</Style>
|
||||
<Style Selector="i|Icon">
|
||||
<Setter Property="FontSize" Value="25" />
|
||||
</Style>
|
||||
</StackPanel.Styles>
|
||||
<Button Classes="Flat"
|
||||
Content="{Binding Version}" />
|
||||
<Button Classes="Basic"
|
||||
CommandParameter="https://github.com/BlossomiShymae/Needlework.Net"
|
||||
ToolTip.Tip="Open on GitHub.">
|
||||
<materialIcons:MaterialIcon Kind="Github" />
|
||||
</Button>
|
||||
<Button Classes="Basic"
|
||||
CommandParameter="https://discord.gg/chEvEX5J4E"
|
||||
ToolTip.Tip="Open Discord server.">
|
||||
<i:Icon Value="fa-brand fa-discord" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</suki:SukiSideMenu.FooterContent>
|
||||
</suki:SukiSideMenu>
|
||||
</Window>
|
||||
12
Needlework.Net.Desktop/Views/MainWindow.axaml.cs
Normal file
12
Needlework.Net.Desktop/Views/MainWindow.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Avalonia.Controls;
|
||||
using SukiUI.Controls;
|
||||
|
||||
namespace Needlework.Net.Desktop.Views;
|
||||
|
||||
public partial class MainWindow : SukiWindow
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
20
Needlework.Net.Desktop/Views/PluginView.axaml
Normal file
20
Needlework.Net.Desktop/Views/PluginView.axaml
Normal file
@@ -0,0 +1,20 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:suki="clr-namespace:SukiUI.Controls;assembly=SukiUI"
|
||||
xmlns:vm="using:Needlework.Net.Desktop.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Needlework.Net.Desktop.Views.PluginView"
|
||||
x:DataType="vm:PluginViewModel">
|
||||
<!-- TOP LEVEL -->
|
||||
<ScrollViewer>
|
||||
<StackPanel Margin="8">
|
||||
<suki:GlassCard>
|
||||
<StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</suki:GlassCard>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
12
Needlework.Net.Desktop/Views/PluginView.axaml.cs
Normal file
12
Needlework.Net.Desktop/Views/PluginView.axaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Needlework.Net.Desktop.Views
|
||||
{
|
||||
public partial class PluginView : UserControl
|
||||
{
|
||||
public PluginView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user