Compare commits

..

17 Commits

Author SHA1 Message Date
estrogen elf c93093c0ea chore: increment version 2026-05-25 13:32:11 -05:00
estrogen elf cc14d4ee04 fix: trim titles of Hextech Docs posts 2026-05-25 13:31:04 -05:00
estrogen elf f3cf177409 Merge pull request #10 from DarkIntaqt/ft/hextechdocs-fix
Fix: Object reference not set to an instance of an object
2026-05-19 16:27:45 -05:00
DarkIntaqt 226eb6ccb3 fix: change hextechdocs html parsing to adapt for new format
It works on my machine
2026-05-19 23:21:42 +02:00
estrogen elf 94902c635e Increment version 2025-12-18 08:35:12 -06:00
estrogen elf d005e5ac56 Update thingies in about page 2025-12-18 08:34:32 -06:00
estrogen elf 221f21caa9 Merge pull request #9 from AoshiW/fix-Oopsies-Dialog-Spam 2025-12-18 08:26:01 -06:00
AoshiW b9f1b5a51e fix Oopsies Dialog Spam 2025-12-18 00:09:48 +01:00
estrogen elf 019d70df53 Merge branch 'main' of https://github.com/BlossomiShymae/Needlework.Net 2025-08-09 08:53:42 -05:00
estrogen elf c0eeef8658 chore: increment version 2025-08-09 08:53:37 -05:00
estrogen elf 347dd8da68 feat: add bug report button 2025-08-09 08:53:05 -05:00
estrogen elf 7a7c8e479c chore: increment version 2025-08-09 08:49:00 -05:00
estrogen elf 0ea0538873 fix: broken game client document URL 2025-08-09 08:48:42 -05:00
estrogen elf 09cc3320e5 refactor: logging for exceptions 2025-08-09 08:47:17 -05:00
estrogen elf 47d02a61fb feat: update README.md 2025-07-05 14:25:43 -05:00
estrogen elf fd57aad4dd chore: increment version 2025-07-05 14:16:43 -05:00
estrogen elf 560a9622ef fix: missing params bug 2025-07-05 14:16:31 -05:00
13 changed files with 191 additions and 88 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 72 KiB

+2 -2
View File
@@ -11,7 +11,7 @@
<AvaloniaXamlIlDebuggerLaunch>False</AvaloniaXamlIlDebuggerLaunch> <AvaloniaXamlIlDebuggerLaunch>False</AvaloniaXamlIlDebuggerLaunch>
<ApplicationIcon>app.ico</ApplicationIcon> <ApplicationIcon>app.ico</ApplicationIcon>
<AssemblyName>NeedleworkDotNet</AssemblyName> <AssemblyName>NeedleworkDotNet</AssemblyName>
<AssemblyVersion>0.13.0.0</AssemblyVersion> <AssemblyVersion>0.14.2.0</AssemblyVersion>
<FileVersion>$(AssemblyVersion)</FileVersion> <FileVersion>$(AssemblyVersion)</FileVersion>
<AvaloniaXamlVerboseExceptions>False</AvaloniaXamlVerboseExceptions> <AvaloniaXamlVerboseExceptions>False</AvaloniaXamlVerboseExceptions>
</PropertyGroup> </PropertyGroup>
@@ -29,7 +29,7 @@
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.8" /> <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.8" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.8" /> <PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.8" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.3.0" /> <PackageReference Include="AvaloniaEdit.TextMate" Version="11.3.0" />
<PackageReference Include="BlossomiShymae.Briar" Version="0.2.2" /> <PackageReference Include="BlossomiShymae.Briar" Version="0.2.3" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="DebounceThrottle" Version="3.0.1" /> <PackageReference Include="DebounceThrottle" Version="3.0.1" />
<PackageReference Include="FastCache.Cached" Version="1.8.2" /> <PackageReference Include="FastCache.Cached" Version="1.8.2" />
+1 -1
View File
@@ -49,7 +49,7 @@ namespace Needlework.Net
return cached; return cached;
} }
var lolClientStream = await _githubUserContentClient.Request("/AlsoSylv/Irelia/refs/heads/master/schemas/game_schema.json") var lolClientStream = await _githubUserContentClient.Request("/AlsoSylv/Irelia/refs/heads/master/schemas/game.json")
.GetStreamAsync(cancellationToken: cancellationToken); .GetStreamAsync(cancellationToken: cancellationToken);
var lolClientRaw = _reader.Read(lolClientStream, out var diagnostic); var lolClientRaw = _reader.Read(lolClientStream, out var diagnostic);
foreach (var error in diagnostic.Errors) foreach (var error in diagnostic.Errors)
@@ -32,8 +32,8 @@ namespace Needlework.Net.Services
foreach (var element in elements) foreach (var element in elements)
{ {
var path = element.QuerySelector("a.post-card-content-link")!.GetAttribute("href")!; var path = element.QuerySelector("a.post-card-content-link")!.GetAttribute("href")!;
var title = element.QuerySelector(".post-card-title")!.TextContent; var title = element.QuerySelector(".post-card-title")!.TextContent.Trim();
var excerpt = element.QuerySelector(".post-card-excerpt > p")!.TextContent; var excerpt = element.QuerySelector(".post-card-excerpt")!.TextContent;
var post = new HextechDocsPost() var post = new HextechDocsPost()
{ {
Path = path, Path = path,
@@ -46,6 +46,8 @@ public partial class MainWindowViewModel
}); });
_schemaPaneService.SchemaPaneItems.Subscribe(async item => _schemaPaneService.SchemaPaneItems.Subscribe(async item =>
{
try
{ {
var document = item.Tab switch var document = item.Tab switch
{ {
@@ -63,6 +65,14 @@ public partial class MainWindowViewModel
OpenSchemaPaneCommand.NotifyCanExecuteChanged(); OpenSchemaPaneCommand.NotifyCanExecuteChanged();
CloseSchemaAllCommand.NotifyCanExecuteChanged(); CloseSchemaAllCommand.NotifyCanExecuteChanged();
} }
}
catch (Exception ex)
{
this.Log()
.Error(ex, "Failed to load schema pane item.");
_notificationService.Notify("Schema pane", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
throw;
}
}); });
WeakReferenceMessenger.Default.RegisterAll(this); WeakReferenceMessenger.Default.RegisterAll(this);
@@ -91,6 +101,8 @@ public partial class MainWindowViewModel
{ {
if (value == null) return; if (value == null) return;
Task.Run(async () => Task.Run(async () =>
{
try
{ {
var document = value.Tab switch var document = value.Tab switch
{ {
@@ -111,6 +123,14 @@ public partial class MainWindowViewModel
CloseSchemaAllCommand.NotifyCanExecuteChanged(); CloseSchemaAllCommand.NotifyCanExecuteChanged();
} }
}); });
}
catch (Exception ex)
{
this.Log()
.Error(ex, "Failed to load schema search details.");
_notificationService.Notify("Schema search", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
throw;
}
}); });
} }
@@ -131,15 +151,24 @@ public partial class MainWindowViewModel
{ {
if (searchText == null) return []; if (searchText == null) return [];
try
{
var lcuSchemaDocument = await _documentService.GetLcuSchemaDocumentAsync(cancellationToken); var lcuSchemaDocument = await _documentService.GetLcuSchemaDocumentAsync(cancellationToken);
var gameClientDocument = await _documentService.GetLolClientDocumentAsync(cancellationToken); var gameClientDocument = await _documentService.GetLolClientDocumentAsync(cancellationToken);
var lcuResults = lcuSchemaDocument.OpenApiDocument.Components.Schemas.Keys.Where(key => key.Contains(searchText, StringComparison.OrdinalIgnoreCase)) var lcuResults = lcuSchemaDocument.OpenApiDocument.Components.Schemas.Keys.Where(key => key.Contains(searchText, StringComparison.OrdinalIgnoreCase))
.Select(key => new SchemaSearchDetailsViewModel(key, Pages.Endpoints.Tab.LCU)); .Select(key => new SchemaSearchDetailsViewModel(key, Pages.Endpoints.Tab.LCU));
var gameClientResults = gameClientDocument.OpenApiDocument.Components.Schemas.Keys.Where(key => key.Contains(searchText, StringComparison.OrdinalIgnoreCase)) var gameClientResults = gameClientDocument.OpenApiDocument.Components.Schemas.Keys.Where(key => key.Contains(searchText, StringComparison.OrdinalIgnoreCase))
.Select(key => new SchemaSearchDetailsViewModel(key, Pages.Endpoints.Tab.GameClient)); .Select(key => new SchemaSearchDetailsViewModel(key, Pages.Endpoints.Tab.GameClient));
return Enumerable.Concat(lcuResults, gameClientResults); return Enumerable.Concat(lcuResults, gameClientResults);
} }
catch (Exception ex)
{
this.Log()
.Error(ex, "Failed to load populate.");
_notificationService.Notify("Schema search", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
throw;
}
}
[RelayCommand(CanExecute = nameof(CanOpenSchemaPane))] [RelayCommand(CanExecute = nameof(CanOpenSchemaPane))]
private void OpenSchemaPane() private void OpenSchemaPane()
@@ -1,21 +1,26 @@
using Avalonia.Threading; using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Needlework.Net.Extensions;
using Needlework.Net.Services; using Needlework.Net.Services;
using Needlework.Net.ViewModels.Shared; using Needlework.Net.ViewModels.Shared;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Needlework.Net.ViewModels.Pages.Console; namespace Needlework.Net.ViewModels.Pages.Console;
public partial class ConsoleViewModel : PageBase public partial class ConsoleViewModel : PageBase, IEnableLogger
{ {
private readonly DocumentService _documentService; private readonly DocumentService _documentService;
private readonly NotificationService _notificationService;
public ConsoleViewModel(DocumentService documentService, NotificationService notificationService) : base("Console", "fa-solid fa-terminal") public ConsoleViewModel(DocumentService documentService, NotificationService notificationService) : base("Console", "fa-solid fa-terminal")
{ {
_request = new(notificationService, Endpoints.Tab.LCU); _request = new(notificationService, Endpoints.Tab.LCU);
_documentService = documentService; _documentService = documentService;
_notificationService = notificationService;
} }
public List<string> RequestMethods { get; } = ["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS", "TRACE"]; public List<string> RequestMethods { get; } = ["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS", "TRACE"];
@@ -27,6 +32,8 @@ public partial class ConsoleViewModel : PageBase
[ObservableProperty] private RequestViewModel _request; [ObservableProperty] private RequestViewModel _request;
public override async Task InitializeAsync() public override async Task InitializeAsync()
{
try
{ {
var document = await _documentService.GetLcuSchemaDocumentAsync(); var document = await _documentService.GetLcuSchemaDocumentAsync();
Dispatcher.UIThread.Invoke(() => Dispatcher.UIThread.Invoke(() =>
@@ -36,6 +43,13 @@ public partial class ConsoleViewModel : PageBase
}); });
IsBusy = false; IsBusy = false;
} }
catch (Exception ex)
{
this.Log()
.Error(ex, "Failed to load console.");
_notificationService.Notify("Console", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
}
}
[RelayCommand] [RelayCommand]
private async Task SendRequest() private async Task SendRequest()
@@ -2,6 +2,7 @@
using AvaloniaEdit.Utils; using AvaloniaEdit.Utils;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Needlework.Net.Extensions;
using Needlework.Net.Models; using Needlework.Net.Models;
using Needlework.Net.Services; using Needlework.Net.Services;
using System; using System;
@@ -16,7 +17,7 @@ public enum Tab
GameClient GameClient
} }
public partial class EndpointsViewModel : PageBase public partial class EndpointsViewModel : PageBase, IEnableLogger
{ {
private readonly DocumentService _documentService; private readonly DocumentService _documentService;
@@ -35,13 +36,24 @@ public partial class EndpointsViewModel : PageBase
[ObservableProperty] private bool _isBusy = true; [ObservableProperty] private bool _isBusy = true;
public override async Task InitializeAsync() public override async Task InitializeAsync()
{
try
{ {
await AddEndpoint(Tab.LCU); await AddEndpoint(Tab.LCU);
IsBusy = false; IsBusy = false;
} }
catch (Exception ex)
{
this.Log()
.Error(ex, "Failed to load endpoints.");
_notificationService.Notify("Endpoints", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
}
}
[RelayCommand] [RelayCommand]
private async Task AddEndpoint(Tab tab) private async Task AddEndpoint(Tab tab)
{
try
{ {
Document document = tab switch Document document = tab switch
{ {
@@ -63,6 +75,13 @@ public partial class EndpointsViewModel : PageBase
}); });
}); });
} }
catch (Exception ex)
{
this.Log()
.Error(ex, "Failed to add endpoint.");
_notificationService.Notify("Endpoints", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
}
}
private void OnEndpointNavigation(string? title, Guid guid) private void OnEndpointNavigation(string? title, Guid guid)
{ {
@@ -19,11 +19,14 @@ public partial class HomeViewModel : PageBase, IEnableLogger
{ {
private readonly HextechDocsService _hextechDocsService; private readonly HextechDocsService _hextechDocsService;
private readonly NotificationService _notificationService;
private readonly IDisposable _carouselNextDisposable; private readonly IDisposable _carouselNextDisposable;
public HomeViewModel(HextechDocsService hextechDocsService) : base("Home", "fa-solid fa-house") public HomeViewModel(HextechDocsService hextechDocsService, NotificationService notificationService) : base("Home", "fa-solid fa-house")
{ {
_hextechDocsService = hextechDocsService; _hextechDocsService = hextechDocsService;
_notificationService = notificationService;
_carouselNextDisposable = Observable.Timer(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5)) _carouselNextDisposable = Observable.Timer(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5))
.Select(time => Unit.Default) .Select(time => Unit.Default)
@@ -75,6 +78,7 @@ public partial class HomeViewModel : PageBase, IEnableLogger
{ {
this.Log() this.Log()
.Error(ex, "Failed to get posts from HextechDocs."); .Error(ex, "Failed to get posts from HextechDocs.");
_notificationService.Notify("Home", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
} }
} }
} }
@@ -2,6 +2,7 @@
using Avalonia.Threading; using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using DebounceThrottle; using DebounceThrottle;
using Needlework.Net.Extensions;
using Needlework.Net.Helpers; using Needlework.Net.Helpers;
using Needlework.Net.Services; using Needlework.Net.Services;
using Needlework.Net.ViewModels.Pages.Endpoints; using Needlework.Net.ViewModels.Pages.Endpoints;
@@ -12,7 +13,7 @@ using System.Threading.Tasks;
namespace Needlework.Net.ViewModels.Pages.Schemas namespace Needlework.Net.ViewModels.Pages.Schemas
{ {
public partial class SchemasViewModel : PageBase public partial class SchemasViewModel : PageBase, IEnableLogger
{ {
private readonly DebounceDispatcher _debounceDispatcher = new(TimeSpan.FromMilliseconds(500)); private readonly DebounceDispatcher _debounceDispatcher = new(TimeSpan.FromMilliseconds(500));
@@ -20,12 +21,15 @@ namespace Needlework.Net.ViewModels.Pages.Schemas
private readonly SchemaPaneService _schemaPaneService; private readonly SchemaPaneService _schemaPaneService;
private readonly NotificationService _notificationService;
private List<SchemaSearchDetailsViewModel> _schemas = []; private List<SchemaSearchDetailsViewModel> _schemas = [];
public SchemasViewModel(DocumentService documentService, SchemaPaneService schemaPaneService) : base("Schemas", "fa-solid fa-file-lines") public SchemasViewModel(DocumentService documentService, SchemaPaneService schemaPaneService, NotificationService notificationService) : base("Schemas", "fa-solid fa-file-lines")
{ {
_documentService = documentService; _documentService = documentService;
_schemaPaneService = schemaPaneService; _schemaPaneService = schemaPaneService;
_notificationService = notificationService;
} }
[ObservableProperty] [ObservableProperty]
@@ -59,6 +63,8 @@ namespace Needlework.Net.ViewModels.Pages.Schemas
} }
public override async Task InitializeAsync() public override async Task InitializeAsync()
{
try
{ {
var lcuSchemaDocument = await _documentService.GetLcuSchemaDocumentAsync(); var lcuSchemaDocument = await _documentService.GetLcuSchemaDocumentAsync();
var lolClientDocument = await _documentService.GetLolClientDocumentAsync(); var lolClientDocument = await _documentService.GetLolClientDocumentAsync();
@@ -73,5 +79,12 @@ namespace Needlework.Net.ViewModels.Pages.Schemas
IsBusy = false; IsBusy = false;
}); });
} }
catch (Exception ex)
{
this.Log()
.Error(ex, "Failed to load schemas.");
_notificationService.Notify("Schemas", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
}
}
} }
} }
@@ -29,6 +29,8 @@ public partial class WebSocketViewModel : PageBase, IEnableLogger
{ {
private Dictionary<string, EventMessage> _events = []; private Dictionary<string, EventMessage> _events = [];
private readonly AvaloniaList<EventViewModel> _filteredEventLog = new();
private readonly IFlurlClient _githubUserContentClient; private readonly IFlurlClient _githubUserContentClient;
private readonly NotificationService _notificationService; private readonly NotificationService _notificationService;
@@ -53,7 +55,20 @@ public partial class WebSocketViewModel : PageBase, IEnableLogger
public CancellationTokenSource TokenSource { get; set; } = new(); public CancellationTokenSource TokenSource { get; set; } = new();
public IReadOnlyList<EventViewModel> FilteredEventLog => string.IsNullOrWhiteSpace(Search) ? EventLog : [.. EventLog.Where(x => x.Key.Contains(Search, StringComparison.InvariantCultureIgnoreCase))]; public IReadOnlyList<EventViewModel> FilteredEventLog
{
get
{
IEnumerable<EventViewModel> events = EventLog;
if (!string.IsNullOrWhiteSpace(Search))
{
events = events.Where(x => x.Key.Contains(Search, StringComparison.InvariantCultureIgnoreCase));
}
_filteredEventLog.Clear();
_filteredEventLog.AddRange(events);
return _filteredEventLog;
}
}
[ObservableProperty] [ObservableProperty]
private Vector _eventLogOffset = new(); private Vector _eventLogOffset = new();
@@ -103,7 +118,7 @@ public partial class WebSocketViewModel : PageBase, IEnableLogger
var message = "Failed to get event types from GitHub. Please check your internet connection or try again later."; var message = "Failed to get event types from GitHub. Please check your internet connection or try again later.";
this.Log() this.Log()
.Error(ex, message); .Error(ex, message);
_notificationService.Notify(AppInfo.Name, message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error); _notificationService.Notify("WebSocket", message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
} }
} }
@@ -92,6 +92,15 @@
Margin="4"> Margin="4">
<materialIcons:MaterialIcon Kind="Github" /> <materialIcons:MaterialIcon Kind="Github" />
</Button> </Button>
<Button
Theme="{StaticResource TransparentButton}"
VerticalAlignment="Center"
Command="{Binding OpenUrlCommand}"
CommandParameter="https://github.com/BlossomiShymae/Needlework.Net/issues/new"
ToolTip.Tip="Submit bug report."
Margin="4">
<i:Icon Value="fa-solid fa-bug" />
</Button>
<Button <Button
Theme="{StaticResource TransparentButton}" Theme="{StaticResource TransparentButton}"
VerticalAlignment="Center" VerticalAlignment="Center"
@@ -46,7 +46,7 @@
<controls:UserCard UserImage="/Assets/Users/aoshiw.png" <controls:UserCard UserImage="/Assets/Users/aoshiw.png"
UserName="AoshiW" UserName="AoshiW"
UserGithub="AoshiW"> UserGithub="AoshiW">
For PR. For PRs that we needed the most.
</controls:UserCard> </controls:UserCard>
</WrapPanel> </WrapPanel>
</ScrollViewer> </ScrollViewer>
+3 -3
View File
@@ -27,10 +27,10 @@ Needlework.Net is an open-source helper tool for the LCU and Game Client that pr
## Credits ## Credits
### GrrrLCU ### Briar
A simple wrapper for the LCU. A simple wrapper for the League Client and Game Client APIs.
- [Repository](https://github.com/BlossomiShymae/GrrrLCU) - [Repository](https://github.com/BlossomiShymae/Briar)
### LCU Explorer ### LCU Explorer