diff --git a/Needlework.Net/ViewModels/MainWindow/MainWindowViewModel.cs b/Needlework.Net/ViewModels/MainWindow/MainWindowViewModel.cs index caba15d..90592ca 100644 --- a/Needlework.Net/ViewModels/MainWindow/MainWindowViewModel.cs +++ b/Needlework.Net/ViewModels/MainWindow/MainWindowViewModel.cs @@ -47,21 +47,31 @@ public partial class MainWindowViewModel _schemaPaneService.SchemaPaneItems.Subscribe(async item => { - var document = item.Tab switch + try { - Pages.Endpoints.Tab.LCU => await documentService.GetLcuSchemaDocumentAsync(), - Pages.Endpoints.Tab.GameClient => await documentService.GetLolClientDocumentAsync(), - _ => throw new NotImplementedException() - }; - var propertyClassViewModel = OpenApiHelpers.WalkSchema(document.OpenApiDocument.Components.Schemas[item.Key], document.OpenApiDocument); - var schemaViewModel = new SchemaViewModel(propertyClassViewModel); - if (Schemas.ToList().Find(schema => schema.Id == schemaViewModel.Id) == null) - { - Schemas.Add(schemaViewModel); - IsPaneOpen = true; + var document = item.Tab switch + { + Pages.Endpoints.Tab.LCU => await documentService.GetLcuSchemaDocumentAsync(), + Pages.Endpoints.Tab.GameClient => await documentService.GetLolClientDocumentAsync(), + _ => throw new NotImplementedException() + }; + var propertyClassViewModel = OpenApiHelpers.WalkSchema(document.OpenApiDocument.Components.Schemas[item.Key], document.OpenApiDocument); + var schemaViewModel = new SchemaViewModel(propertyClassViewModel); + if (Schemas.ToList().Find(schema => schema.Id == schemaViewModel.Id) == null) + { + Schemas.Add(schemaViewModel); + IsPaneOpen = true; - OpenSchemaPaneCommand.NotifyCanExecuteChanged(); - CloseSchemaAllCommand.NotifyCanExecuteChanged(); + OpenSchemaPaneCommand.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; } }); @@ -92,25 +102,35 @@ public partial class MainWindowViewModel if (value == null) return; Task.Run(async () => { - var document = value.Tab switch + try { - Pages.Endpoints.Tab.LCU => await _documentService.GetLcuSchemaDocumentAsync(), - Pages.Endpoints.Tab.GameClient => await _documentService.GetLolClientDocumentAsync(), - _ => throw new NotImplementedException() - }; - var propertyClassViewModel = OpenApiHelpers.WalkSchema(document.OpenApiDocument.Components.Schemas[value.Key], document.OpenApiDocument); - var schemaViewModel = new SchemaViewModel(propertyClassViewModel); - Dispatcher.UIThread.Post(() => - { - if (Schemas.ToList().Find(schema => schema.Id == schemaViewModel.Id) == null) + var document = value.Tab switch { - Schemas.Add(schemaViewModel); - IsPaneOpen = true; + Pages.Endpoints.Tab.LCU => await _documentService.GetLcuSchemaDocumentAsync(), + Pages.Endpoints.Tab.GameClient => await _documentService.GetLolClientDocumentAsync(), + _ => throw new NotImplementedException() + }; + var propertyClassViewModel = OpenApiHelpers.WalkSchema(document.OpenApiDocument.Components.Schemas[value.Key], document.OpenApiDocument); + var schemaViewModel = new SchemaViewModel(propertyClassViewModel); + Dispatcher.UIThread.Post(() => + { + if (Schemas.ToList().Find(schema => schema.Id == schemaViewModel.Id) == null) + { + Schemas.Add(schemaViewModel); + IsPaneOpen = true; - OpenSchemaPaneCommand.NotifyCanExecuteChanged(); - CloseSchemaAllCommand.NotifyCanExecuteChanged(); - } - }); + OpenSchemaPaneCommand.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,14 +151,23 @@ public partial class MainWindowViewModel { if (searchText == null) return []; - var lcuSchemaDocument = await _documentService.GetLcuSchemaDocumentAsync(cancellationToken); - var gameClientDocument = await _documentService.GetLolClientDocumentAsync(cancellationToken); - var lcuResults = lcuSchemaDocument.OpenApiDocument.Components.Schemas.Keys.Where(key => key.Contains(searchText, StringComparison.OrdinalIgnoreCase)) - .Select(key => new SchemaSearchDetailsViewModel(key, Pages.Endpoints.Tab.LCU)); - var gameClientResults = gameClientDocument.OpenApiDocument.Components.Schemas.Keys.Where(key => key.Contains(searchText, StringComparison.OrdinalIgnoreCase)) - .Select(key => new SchemaSearchDetailsViewModel(key, Pages.Endpoints.Tab.GameClient)); - - return Enumerable.Concat(lcuResults, gameClientResults); + try + { + var lcuSchemaDocument = await _documentService.GetLcuSchemaDocumentAsync(cancellationToken); + var gameClientDocument = await _documentService.GetLolClientDocumentAsync(cancellationToken); + var lcuResults = lcuSchemaDocument.OpenApiDocument.Components.Schemas.Keys.Where(key => key.Contains(searchText, StringComparison.OrdinalIgnoreCase)) + .Select(key => new SchemaSearchDetailsViewModel(key, Pages.Endpoints.Tab.LCU)); + var gameClientResults = gameClientDocument.OpenApiDocument.Components.Schemas.Keys.Where(key => key.Contains(searchText, StringComparison.OrdinalIgnoreCase)) + .Select(key => new SchemaSearchDetailsViewModel(key, Pages.Endpoints.Tab.GameClient)); + 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))] diff --git a/Needlework.Net/ViewModels/Pages/Console/ConsoleViewModel.cs b/Needlework.Net/ViewModels/Pages/Console/ConsoleViewModel.cs index 9d5c571..120a4c9 100644 --- a/Needlework.Net/ViewModels/Pages/Console/ConsoleViewModel.cs +++ b/Needlework.Net/ViewModels/Pages/Console/ConsoleViewModel.cs @@ -1,21 +1,26 @@ using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using Needlework.Net.Extensions; using Needlework.Net.Services; using Needlework.Net.ViewModels.Shared; +using System; using System.Collections.Generic; using System.Threading.Tasks; namespace Needlework.Net.ViewModels.Pages.Console; -public partial class ConsoleViewModel : PageBase +public partial class ConsoleViewModel : PageBase, IEnableLogger { private readonly DocumentService _documentService; + private readonly NotificationService _notificationService; + public ConsoleViewModel(DocumentService documentService, NotificationService notificationService) : base("Console", "fa-solid fa-terminal") { _request = new(notificationService, Endpoints.Tab.LCU); _documentService = documentService; + _notificationService = notificationService; } public List RequestMethods { get; } = ["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS", "TRACE"]; @@ -28,13 +33,22 @@ public partial class ConsoleViewModel : PageBase public override async Task InitializeAsync() { - var document = await _documentService.GetLcuSchemaDocumentAsync(); - Dispatcher.UIThread.Invoke(() => + try { - RequestPaths.Clear(); - RequestPaths.AddRange(document.Paths); - }); - IsBusy = false; + var document = await _documentService.GetLcuSchemaDocumentAsync(); + Dispatcher.UIThread.Invoke(() => + { + RequestPaths.Clear(); + RequestPaths.AddRange(document.Paths); + }); + IsBusy = false; + } + catch (Exception ex) + { + this.Log() + .Error(ex, "Failed to load console."); + _notificationService.Notify("Console", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error); + } } [RelayCommand] diff --git a/Needlework.Net/ViewModels/Pages/Endpoints/EndpointsViewModel.cs b/Needlework.Net/ViewModels/Pages/Endpoints/EndpointsViewModel.cs index b1a297b..1025107 100644 --- a/Needlework.Net/ViewModels/Pages/Endpoints/EndpointsViewModel.cs +++ b/Needlework.Net/ViewModels/Pages/Endpoints/EndpointsViewModel.cs @@ -2,6 +2,7 @@ using AvaloniaEdit.Utils; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using Needlework.Net.Extensions; using Needlework.Net.Models; using Needlework.Net.Services; using System; @@ -16,7 +17,7 @@ public enum Tab GameClient } -public partial class EndpointsViewModel : PageBase +public partial class EndpointsViewModel : PageBase, IEnableLogger { private readonly DocumentService _documentService; @@ -36,32 +37,50 @@ public partial class EndpointsViewModel : PageBase public override async Task InitializeAsync() { - await AddEndpoint(Tab.LCU); - IsBusy = false; + try + { + await AddEndpoint(Tab.LCU); + IsBusy = false; + } + catch (Exception ex) + { + this.Log() + .Error(ex, "Failed to load endpoints."); + _notificationService.Notify("Endpoints", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error); + } } [RelayCommand] private async Task AddEndpoint(Tab tab) { - Document document = tab switch + try { - Tab.LCU => await _documentService.GetLcuSchemaDocumentAsync(), - Tab.GameClient => await _documentService.GetLolClientDocumentAsync(), - _ => throw new NotImplementedException(), - }; - - await Dispatcher.UIThread.InvokeAsync(() => - { - Plugins.Clear(); - Plugins.AddRange(document.Plugins.Keys); - var vm = new EndpointTabItemContentViewModel(_notificationService, Plugins, OnEndpointNavigation, AddEndpointCommand, document, tab); - Endpoints.Add(new() + Document document = tab switch { - Content = vm, - Header = vm.Title, - Selected = true + Tab.LCU => await _documentService.GetLcuSchemaDocumentAsync(), + Tab.GameClient => await _documentService.GetLolClientDocumentAsync(), + _ => throw new NotImplementedException(), + }; + + await Dispatcher.UIThread.InvokeAsync(() => + { + Plugins.Clear(); + Plugins.AddRange(document.Plugins.Keys); + var vm = new EndpointTabItemContentViewModel(_notificationService, Plugins, OnEndpointNavigation, AddEndpointCommand, document, tab); + Endpoints.Add(new() + { + Content = vm, + Header = vm.Title, + Selected = true + }); }); - }); + } + 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) diff --git a/Needlework.Net/ViewModels/Pages/Home/HomeViewModel.cs b/Needlework.Net/ViewModels/Pages/Home/HomeViewModel.cs index 34b767c..699d893 100644 --- a/Needlework.Net/ViewModels/Pages/Home/HomeViewModel.cs +++ b/Needlework.Net/ViewModels/Pages/Home/HomeViewModel.cs @@ -19,11 +19,14 @@ public partial class HomeViewModel : PageBase, IEnableLogger { private readonly HextechDocsService _hextechDocsService; + private readonly NotificationService _notificationService; + 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; + _notificationService = notificationService; _carouselNextDisposable = Observable.Timer(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5)) .Select(time => Unit.Default) @@ -75,6 +78,7 @@ public partial class HomeViewModel : PageBase, IEnableLogger { this.Log() .Error(ex, "Failed to get posts from HextechDocs."); + _notificationService.Notify("Home", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error); } } } diff --git a/Needlework.Net/ViewModels/Pages/Schemas/SchemasViewModel.cs b/Needlework.Net/ViewModels/Pages/Schemas/SchemasViewModel.cs index e07e7e8..a37c3de 100644 --- a/Needlework.Net/ViewModels/Pages/Schemas/SchemasViewModel.cs +++ b/Needlework.Net/ViewModels/Pages/Schemas/SchemasViewModel.cs @@ -2,6 +2,7 @@ using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; using DebounceThrottle; +using Needlework.Net.Extensions; using Needlework.Net.Helpers; using Needlework.Net.Services; using Needlework.Net.ViewModels.Pages.Endpoints; @@ -12,7 +13,7 @@ using System.Threading.Tasks; 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)); @@ -20,12 +21,15 @@ namespace Needlework.Net.ViewModels.Pages.Schemas private readonly SchemaPaneService _schemaPaneService; + private readonly NotificationService _notificationService; + private List _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; _schemaPaneService = schemaPaneService; + _notificationService = notificationService; } [ObservableProperty] @@ -60,18 +64,27 @@ namespace Needlework.Net.ViewModels.Pages.Schemas public override async Task InitializeAsync() { - var lcuSchemaDocument = await _documentService.GetLcuSchemaDocumentAsync(); - var lolClientDocument = await _documentService.GetLolClientDocumentAsync(); - Dispatcher.UIThread.Invoke(() => + try { - var schemas = Enumerable.Concat( - lcuSchemaDocument.OpenApiDocument.Components.Schemas.Values.Select(schema => new SchemaSearchDetailsViewModel(Tab.LCU, OpenApiHelpers.WalkSchema(schema, lcuSchemaDocument.OpenApiDocument), _schemaPaneService)), - lolClientDocument.OpenApiDocument.Components.Schemas.Values.Select(schema => new SchemaSearchDetailsViewModel(Tab.GameClient, OpenApiHelpers.WalkSchema(schema, lolClientDocument.OpenApiDocument), _schemaPaneService)) - ).ToList(); - _schemas = schemas; - SchemaItems = schemas.ToList(); - IsBusy = false; - }); + var lcuSchemaDocument = await _documentService.GetLcuSchemaDocumentAsync(); + var lolClientDocument = await _documentService.GetLolClientDocumentAsync(); + Dispatcher.UIThread.Invoke(() => + { + var schemas = Enumerable.Concat( + lcuSchemaDocument.OpenApiDocument.Components.Schemas.Values.Select(schema => new SchemaSearchDetailsViewModel(Tab.LCU, OpenApiHelpers.WalkSchema(schema, lcuSchemaDocument.OpenApiDocument), _schemaPaneService)), + lolClientDocument.OpenApiDocument.Components.Schemas.Values.Select(schema => new SchemaSearchDetailsViewModel(Tab.GameClient, OpenApiHelpers.WalkSchema(schema, lolClientDocument.OpenApiDocument), _schemaPaneService)) + ).ToList(); + _schemas = schemas; + SchemaItems = schemas.ToList(); + IsBusy = false; + }); + } + catch (Exception ex) + { + this.Log() + .Error(ex, "Failed to load schemas."); + _notificationService.Notify("Schemas", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error); + } } } } diff --git a/Needlework.Net/ViewModels/Pages/Websocket/WebsocketViewModel.cs b/Needlework.Net/ViewModels/Pages/Websocket/WebsocketViewModel.cs index e550986..8e091b7 100644 --- a/Needlework.Net/ViewModels/Pages/Websocket/WebsocketViewModel.cs +++ b/Needlework.Net/ViewModels/Pages/Websocket/WebsocketViewModel.cs @@ -103,7 +103,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."; this.Log() .Error(ex, message); - _notificationService.Notify(AppInfo.Name, message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error); + _notificationService.Notify("WebSocket", message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error); } }