From bd8e50718d91c0ce8f3ce4cd5fe566f486e9c187 Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 14 Oct 2023 17:33:56 +0200 Subject: [PATCH 01/26] Update sonar-code-analysis.yml replace sonar.login with sonar.token due to the old version being deprecated --- .github/workflows/sonar-code-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonar-code-analysis.yml b/.github/workflows/sonar-code-analysis.yml index 8289ab882..1d798be35 100644 --- a/.github/workflows/sonar-code-analysis.yml +++ b/.github/workflows/sonar-code-analysis.yml @@ -47,7 +47,7 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} shell: pwsh run: | - ./.sonar/scanner/dotnet-sonarscanner begin /k:"WoWs-Builder-Team_WoWs-ShipBuilder" /o:"wows-builder-team" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="TestResults/*/*.xml" + ./.sonar/scanner/dotnet-sonarscanner begin /k:"WoWs-Builder-Team_WoWs-ShipBuilder" /o:"wows-builder-team" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="TestResults/*/*.xml" dotnet build dirs.proj -c Release --no-restore dotnet test dirs.proj -c Release --no-build --collect:"XPlat Code Coverage;Format=opencover" --results-directory TestResults ./.sonar/scanner/dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" From aa083c9e323f1d9fc60cadf0090fd43cf98576d9 Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 14 Oct 2023 22:02:43 +0200 Subject: [PATCH 02/26] fix application crash when message box is opened fixes #269 --- WoWsShipBuilder.Desktop/App.axaml.cs | 243 +++++++++--------- .../Common/AppHeader.axaml | 11 +- .../Common/AppHeader.axaml.cs | 202 +++++++-------- .../Features/MessageBox/MessageBox.axaml | 30 ++- .../Features/MessageBox/MessageBox.axaml.cs | 5 +- WoWsShipBuilder.Desktop/Program.cs | 23 +- 6 files changed, 256 insertions(+), 258 deletions(-) diff --git a/WoWsShipBuilder.Desktop/App.axaml.cs b/WoWsShipBuilder.Desktop/App.axaml.cs index ee3314c10..d1bde2160 100644 --- a/WoWsShipBuilder.Desktop/App.axaml.cs +++ b/WoWsShipBuilder.Desktop/App.axaml.cs @@ -25,164 +25,163 @@ using WoWsShipBuilder.Infrastructure.Localization.Resources; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.Desktop +namespace WoWsShipBuilder.Desktop; + +[SuppressMessage("System.IO.Abstractions", "IO0003", Justification = "This class is never tested.")] +[SuppressMessage("System.IO.Abstractions", "IO0006", Justification = "This class is never tested.")] +public class App : Application { - [SuppressMessage("System.IO.Abstractions", "IO0003", Justification = "This class is never tested.")] - [SuppressMessage("System.IO.Abstractions", "IO0006", Justification = "This class is never tested.")] - public class App : Application - { - private readonly ILogger logger = NullLogger.Instance; - private readonly IServiceProvider services = default!; + private readonly ILogger logger = NullLogger.Instance; + private readonly IServiceProvider services = default!; - public App() - { - ModeDetector.OverrideModeDetector(new CustomModeDetector()); - } + public App() + { + ModeDetector.OverrideModeDetector(new CustomModeDetector()); + } - public IServiceProvider Services + public IServiceProvider Services + { + get => services; + init { - get => services; - init - { - services = value; - logger = services.GetRequiredService>(); - } + services = value; + logger = services.GetRequiredService>(); } + } - public static async Task ShowUpdateRestartDialog(Window? parent, ILocalizer localizer) - { - return await Dispatcher.UIThread.InvokeAsync(async () => await MessageBox.Show( - parent, - localizer.GetAppLocalization(nameof(Translation.UpdateMessageBox_Description)).Localization, - localizer.GetAppLocalization(nameof(Translation.UpdateMessageBox_Title)).Localization, - MessageBox.MessageBoxButtons.YesNo, - MessageBox.MessageBoxIcon.Question)); - } + public static async Task ShowUpdateRestartDialog(Window? parent, ILocalizer localizer) + { + return await Dispatcher.UIThread.InvokeAsync(async () => await MessageBox.Show( + parent, + localizer.GetAppLocalization(nameof(Translation.UpdateMessageBox_Description)).Localization, + localizer.GetAppLocalization(nameof(Translation.UpdateMessageBox_Title)).Localization, + MessageBox.MessageBoxButtons.YesNo, + MessageBox.MessageBoxIcon.Question)); + } - public override void Initialize() - { - AvaloniaXamlLoader.Load(this); - } + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } - public override void OnFrameworkInitializationCompleted() + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - Logging.Initialize(Services.GetRequiredService()); - InitializeSettings(); - var settings = Services.GetRequiredService(); + Logging.Initialize(Services.GetRequiredService()); + InitializeSettings(); + var settings = Services.GetRequiredService(); - LogManager.ReconfigExistingLoggers(); + LogManager.ReconfigExistingLoggers(); - desktop.Exit += OnExit; - desktop.MainWindow = new SplashScreen(Services); - logger.LogInformation("AutoUpdate Enabled: {SettingsAutoUpdateEnabled}", settings.AutoUpdateEnabled); + desktop.Exit += OnExit; + desktop.MainWindow = new SplashScreen(Services); + logger.LogInformation("AutoUpdate Enabled: {SettingsAutoUpdateEnabled}", settings.AutoUpdateEnabled); - if (settings.AutoUpdateEnabled) + if (settings.AutoUpdateEnabled) + { + Task.Run(async () => { - Task.Run(async () => + if (OperatingSystem.IsWindows()) { - if (OperatingSystem.IsWindows()) - { - await UpdateCheck(Services.GetRequiredService()); - logger.LogInformation("Finished updatecheck"); - } - else - { - logger.LogInformation("Skipped updatecheck"); - } - }); - } + await UpdateCheck(Services.GetRequiredService()); + logger.LogInformation("Finished updatecheck"); + } + else + { + logger.LogInformation("Skipped updatecheck"); + } + }); } - - base.OnFrameworkInitializationCompleted(); } - private void InitializeSettings() - { - var settingsAccessor = (DesktopSettingsAccessor)services.GetRequiredService(); - var settings = settingsAccessor.LoadSettingsSync(); - settings ??= new(); - - logger.LogDebug("Updating app settings with settings read from file..."); - var appSettings = services.GetRequiredService(); - appSettings.UpdateFromSettings(settings); - AppData.IsInitialized = true; - Thread.CurrentThread.CurrentCulture = appSettings.SelectedLanguage.CultureInfo; - Thread.CurrentThread.CurrentUICulture = appSettings.SelectedLanguage.CultureInfo; - logger.LogDebug("Settings initialization complete"); - } + base.OnFrameworkInitializationCompleted(); + } + + private void InitializeSettings() + { + var settingsAccessor = (DesktopSettingsAccessor)services.GetRequiredService(); + var settings = settingsAccessor.LoadSettingsSync(); + settings ??= new(); + + logger.LogDebug("Updating app settings with settings read from file..."); + var appSettings = services.GetRequiredService(); + appSettings.UpdateFromSettings(settings); + AppData.IsInitialized = true; + Thread.CurrentThread.CurrentCulture = appSettings.SelectedLanguage.CultureInfo; + Thread.CurrentThread.CurrentUICulture = appSettings.SelectedLanguage.CultureInfo; + logger.LogDebug("Settings initialization complete"); + } + + private void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs e) + { + logger.LogInformation("Closing app, saving setting and builds"); + var settingsAccessor = (DesktopSettingsAccessor)Services.GetRequiredService(); + settingsAccessor.SaveSettingsSync(Services.GetRequiredService()); + logger.LogInformation("Exiting..."); + logger.LogInformation("------------------------------"); + } + + [SupportedOSPlatform("windows")] + private async Task UpdateCheck(AppNotificationService notificationService) + { + logger.LogInformation("Current version: {Version}", Assembly.GetExecutingAssembly().GetName().Version); - private void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs e) + using UpdateManager updateManager = new GithubUpdateManager("https://github.com/WoWs-Builder-Team/WoWs-ShipBuilder"); + if (!updateManager.IsInstalledApp) { - logger.LogInformation("Closing app, saving setting and builds"); - var settingsAccessor = (DesktopSettingsAccessor)Services.GetRequiredService(); - settingsAccessor.SaveSettingsSync(Services.GetRequiredService()); - logger.LogInformation("Exiting..."); - logger.LogInformation("------------------------------"); + logger.LogInformation("No update.exe found, aborting update check"); + return; } - [SupportedOSPlatform("windows")] - private async Task UpdateCheck(AppNotificationService notificationService) + logger.LogInformation("Update manager initialized"); + try { - logger.LogInformation("Current version: {Version}", Assembly.GetExecutingAssembly().GetName().Version); - - using UpdateManager updateManager = new GithubUpdateManager("https://github.com/WoWs-Builder-Team/WoWs-ShipBuilder"); - if (!updateManager.IsInstalledApp) + // Can throw a null-reference-exception, no idea why. + var updateInfo = await updateManager.CheckForUpdate(); + if (!updateInfo.ReleasesToApply.Any()) { - logger.LogInformation("No update.exe found, aborting update check"); + logger.LogInformation("No app update found"); return; } - logger.LogInformation("Update manager initialized"); - try + await notificationService.NotifyAppUpdateStart(); + var release = await updateManager.UpdateApp(); + if (release == null) { - // Can throw a null-reference-exception, no idea why. - var updateInfo = await updateManager.CheckForUpdate(); - if (!updateInfo.ReleasesToApply.Any()) - { - logger.LogInformation("No app update found"); - return; - } + logger.LogInformation("No app update found"); + return; + } - await notificationService.NotifyAppUpdateStart(); - var release = await updateManager.UpdateApp(); - if (release == null) + logger.LogInformation("App updated to version {ReleaseVersion}", release.Version); + await notificationService.NotifyAppUpdateComplete(); + var result = await ShowUpdateRestartDialog((ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow, Services.GetRequiredService()); + if (result.Equals(MessageBox.MessageBoxResult.Yes)) + { + logger.LogInformation("User decided to restart after update"); + if (OperatingSystem.IsWindows()) { - logger.LogInformation("No app update found"); - return; + UpdateManager.RestartApp(); } - - logger.LogInformation("App updated to version {ReleaseVersion}", release.Version); - await notificationService.NotifyAppUpdateComplete(); - var result = await ShowUpdateRestartDialog((ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow, Services.GetRequiredService()); - if (result.Equals(MessageBox.MessageBoxResult.Yes)) - { - logger.LogInformation("User decided to restart after update"); - if (OperatingSystem.IsWindows()) - { - UpdateManager.RestartApp(); - } - } - } - catch (NullReferenceException) - { - logger.LogDebug("NullReferenceException during app update"); } - catch (Exception e) - { + } + catch (NullReferenceException) + { + logger.LogDebug("NullReferenceException during app update"); + } + catch (Exception e) + { #if DEBUG - logger.LogWarning(e, "Exception during app update"); + logger.LogWarning(e, "Exception during app update"); #else logger.LogError(e, "Exception during app update"); #endif - await notificationService.NotifyAppUpdateError(nameof(Translation.NotificationService_ErrorMessage)); - } + await notificationService.NotifyAppUpdateError(nameof(Translation.NotificationService_ErrorMessage)); } + } - private sealed class CustomModeDetector : IModeDetector - { - public bool? InUnitTestRunner() => false; - } + private sealed class CustomModeDetector : IModeDetector + { + public bool? InUnitTestRunner() => false; } } diff --git a/WoWsShipBuilder.Desktop/Common/AppHeader.axaml b/WoWsShipBuilder.Desktop/Common/AppHeader.axaml index d4e5d37e1..939408fe6 100644 --- a/WoWsShipBuilder.Desktop/Common/AppHeader.axaml +++ b/WoWsShipBuilder.Desktop/Common/AppHeader.axaml @@ -28,7 +28,7 @@ @@ -52,7 +52,7 @@ @@ -70,11 +70,8 @@ - - ShowTitleProperty = + AvaloniaProperty.Register(nameof(ShowTitle), true); + + public static readonly StyledProperty TitleProperty = + AvaloniaProperty.Register(nameof(Title), "WoWs Ship Builder"); + + public static readonly StyledProperty ShowMinimizeButtonProperty = + AvaloniaProperty.Register(nameof(ShowMinimizeButton), true); + + public static readonly StyledProperty ShowMaximizeButtonProperty = + AvaloniaProperty.Register(nameof(ShowMaximizeButton), false); + + public static readonly StyledProperty ShowCloseButtonProperty = + AvaloniaProperty.Register(nameof(ShowCloseButton), true); + + public AppHeader() { - public static readonly StyledProperty ShowTitleProperty = - AvaloniaProperty.Register(nameof(ShowTitle), true); + InitializeComponent(); + } - public static readonly StyledProperty TitleProperty = - AvaloniaProperty.Register(nameof(Title), "WoWs Ship Builder"); + public bool ShowTitle + { + get => GetValue(ShowTitleProperty); + set => SetValue(ShowTitleProperty, value); + } - public static readonly StyledProperty ShowMinimizeButtonProperty = - AvaloniaProperty.Register(nameof(ShowMinimizeButton), true); + public string Title + { + get => GetValue(TitleProperty); + set => SetValue(TitleProperty, value); + } - public static readonly StyledProperty ShowMaximizeButtonProperty = - AvaloniaProperty.Register(nameof(ShowMaximizeButton), false); + public bool ShowMinimizeButton + { + get => GetValue(ShowMinimizeButtonProperty); + set => SetValue(ShowMinimizeButtonProperty, value); + } - public static readonly StyledProperty ShowCloseButtonProperty = - AvaloniaProperty.Register(nameof(ShowCloseButton), true); + public bool ShowMaximizeButton + { + get => GetValue(ShowMaximizeButtonProperty); + set => SetValue(ShowMaximizeButtonProperty, value); + } - public AppHeader() - { - InitializeComponent(); + public bool ShowCloseButton + { + get => GetValue(ShowCloseButtonProperty); + set => SetValue(ShowCloseButtonProperty, value); + } - MinimizeButton.Click += MinimizeWindow; - MaximizeButton.Click += MaximizeWindow; - CloseButton.Click += CloseWindow; + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + MinimizeButton.Click += MinimizeWindow; + MaximizeButton.Click += MaximizeWindow; + CloseButton.Click += CloseWindow; - SubscribeToWindowState(); - } + SubscribeToWindowState(); + } - public bool ShowTitle + private void CloseWindow(object? sender, RoutedEventArgs e) + { + if (Design.IsDesignMode) { - get => GetValue(ShowTitleProperty); - set => SetValue(ShowTitleProperty, value); + return; } - public string Title - { - get => GetValue(TitleProperty); - set => SetValue(TitleProperty, value); - } + Window hostWindow = (Window)VisualRoot!; + hostWindow.Close(); + } - public bool ShowMinimizeButton + private void MaximizeWindow(object? sender, RoutedEventArgs e) + { + if (Design.IsDesignMode) { - get => GetValue(ShowMinimizeButtonProperty); - set => SetValue(ShowMinimizeButtonProperty, value); + return; } - public bool ShowMaximizeButton - { - get => GetValue(ShowMaximizeButtonProperty); - set => SetValue(ShowMaximizeButtonProperty, value); - } + Window hostWindow = (Window)VisualRoot!; - public bool ShowCloseButton + if (hostWindow.WindowState == WindowState.Normal) { - get => GetValue(ShowCloseButtonProperty); - set => SetValue(ShowCloseButtonProperty, value); + hostWindow.WindowState = WindowState.Maximized; } - - private void InitializeComponent() + else { - AvaloniaXamlLoader.Load(this); + hostWindow.WindowState = WindowState.Normal; } + } - private void CloseWindow(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + private void MinimizeWindow(object? sender, RoutedEventArgs e) + { + if (Design.IsDesignMode) { - if (Design.IsDesignMode) - { - return; - } - - Window hostWindow = (Window)VisualRoot!; - hostWindow.Close(); + return; } - private void MaximizeWindow(object? sender, Avalonia.Interactivity.RoutedEventArgs e) - { - if (Design.IsDesignMode) - { - return; - } - - Window hostWindow = (Window)VisualRoot!; + Window hostWindow = (Window)VisualRoot!; + hostWindow.WindowState = WindowState.Minimized; + } - if (hostWindow.WindowState == WindowState.Normal) - { - hostWindow.WindowState = WindowState.Maximized; - } - else - { - hostWindow.WindowState = WindowState.Normal; - } - } + private async void SubscribeToWindowState() + { + var hostWindow = (Window?)VisualRoot; - private void MinimizeWindow(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + while (hostWindow == null) { - if (Design.IsDesignMode) - { - return; - } - - Window hostWindow = (Window)VisualRoot!; - hostWindow.WindowState = WindowState.Minimized; + hostWindow = (Window)VisualRoot!; + await Task.Delay(50); } - private async void SubscribeToWindowState() + hostWindow.GetObservable(Window.WindowStateProperty).Subscribe(s => { - Window hostWindow = (Window)VisualRoot!; - - while (hostWindow == null) + if (s != WindowState.Maximized) { - hostWindow = (Window)VisualRoot!; - await Task.Delay(50); + MaximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 2048v-2048h-2048v2048h2048zM1843 1843h-1638v-1638h1638v1638z"); + hostWindow.Padding = new Thickness(0, 0, 0, 0); } - hostWindow.GetObservable(Window.WindowStateProperty).Subscribe(s => + if (s == WindowState.Maximized) { - if (s != WindowState.Maximized) - { - MaximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 2048v-2048h-2048v2048h2048zM1843 1843h-1638v-1638h1638v1638z"); - hostWindow.Padding = new Thickness(0, 0, 0, 0); - } - - if (s == WindowState.Maximized) - { - MaximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 1638h-410v410h-1638v-1638h410v-410h1638v1638zm-614-1024h-1229v1229h1229v-1229zm409-409h-1229v205h1024v1024h205v-1229z"); - - // This should be a more universal approach in both cases, but I found it to be less reliable, when for example double-clicking the title bar. - hostWindow.Padding = new Thickness( - hostWindow.OffScreenMargin.Left, - hostWindow.OffScreenMargin.Top, - hostWindow.OffScreenMargin.Right, - hostWindow.OffScreenMargin.Bottom); - } - }); - } + MaximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 1638h-410v410h-1638v-1638h410v-410h1638v1638zm-614-1024h-1229v1229h1229v-1229zm409-409h-1229v205h1024v1024h205v-1229z"); + + // This should be a more universal approach in both cases, but I found it to be less reliable, when for example double-clicking the title bar. + hostWindow.Padding = new Thickness( + hostWindow.OffScreenMargin.Left, + hostWindow.OffScreenMargin.Top, + hostWindow.OffScreenMargin.Right, + hostWindow.OffScreenMargin.Bottom); + } + }); } } diff --git a/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml b/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml index 2f0fb6e9e..8265872bb 100644 --- a/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml +++ b/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml @@ -2,25 +2,27 @@ 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:infrastructure="clr-namespace:WoWsShipBuilder.Desktop.Infrastructure" xmlns:common="clr-namespace:WoWsShipBuilder.Desktop.Common" mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="150" x:Class="WoWsShipBuilder.Desktop.Features.MessageBox.MessageBox" WindowStartupLocation="CenterOwner" ExtendClientAreaChromeHints="NoChrome"> - - - - - - - - - - + + + + + + + + + + + + - + diff --git a/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml.cs b/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml.cs index 43fcdd0b9..00a0a5e9d 100644 --- a/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml.cs +++ b/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml.cs @@ -1,11 +1,8 @@ using System; using System.Threading.Tasks; -using Avalonia; using Avalonia.Controls; -using Avalonia.Markup.Xaml; using Avalonia.Media.Imaging; using Avalonia.Platform; -using WoWsShipBuilder.Desktop.Infrastructure; using WoWsShipBuilder.Infrastructure.Localization.Resources; namespace WoWsShipBuilder.Desktop.Features.MessageBox; @@ -14,7 +11,7 @@ public partial class MessageBox : Window { public MessageBox() { - AvaloniaXamlLoader.Load(this); + InitializeComponent(); } public enum MessageBoxButtons diff --git a/WoWsShipBuilder.Desktop/Program.cs b/WoWsShipBuilder.Desktop/Program.cs index f6de95ee1..0fb444666 100644 --- a/WoWsShipBuilder.Desktop/Program.cs +++ b/WoWsShipBuilder.Desktop/Program.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using NLog; +using Microsoft.Extensions.Logging.Abstractions; using NLog.Extensions.Logging; using Sentry; using Squirrel; @@ -15,12 +15,13 @@ using WoWsShipBuilder.Desktop.Infrastructure.StaticConfiguration; using WoWsShipBuilder.Infrastructure.ApplicationData; using WoWsShipBuilder.Infrastructure.Localization; -using LogLevel = Microsoft.Extensions.Logging.LogLevel; namespace WoWsShipBuilder.Desktop; internal sealed class Program { + private static ILogger logger = NullLogger.Instance; + [STAThread] public static void Main(string[] args) => RunProgram(args).GetAwaiter().GetResult(); @@ -39,7 +40,7 @@ private static async Task RunProgram(string[] args) AppData.WebMode = false; await app.StartAsync(); - var logger = app.Services.GetRequiredService>(); + logger = app.Services.GetRequiredService>(); LocalizeConverter.InitializeLocalizer(app.Services.GetRequiredService()); var avaloniaApp = BuildAvaloniaApp(app.Services); @@ -88,29 +89,33 @@ public static AppBuilder BuildAvaloniaApp(IServiceProvider services) .UseSkia() .UseReactiveUI(); - public static AppBuilder BuildAvaloniaApp() => BuildAvaloniaApp(null!); + public static AppBuilder BuildAvaloniaApp() => BuildAvaloniaApp(CreatePreviewServiceProvider()); [SupportedOSPlatform("windows")] private static void OnAppUninstall(SemanticVersion version, IAppTools tools) { - LogManager.GetCurrentClassLogger().Info("App is uninstalling..."); + logger.LogInformation("App is uninstalling..."); tools.RemoveShortcutForThisExe(); } [SupportedOSPlatform("windows")] private static void OnInitialInstall(SemanticVersion version, IAppTools tools) { - var logger = LogManager.GetCurrentClassLogger(); - logger.Info("App has been installed, creating shortcuts..."); + logger.LogInformation("App has been installed, creating shortcuts..."); try { tools.CreateShortcutForThisExe(); - logger.Info("Shortcuts have been created."); + logger.LogInformation("Shortcuts have been created."); } catch (Exception e) { - logger.Error(e); + logger.LogError(e, "Error during installation"); throw; } } + + private static IServiceProvider CreatePreviewServiceProvider() + { + return new ServiceCollection().AddLogging(builder => builder.ClearProviders()).BuildServiceProvider(); + } } From 5311fe7d51b7045cdf987e26955ad0c06565ef78 Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 14 Oct 2023 22:04:35 +0200 Subject: [PATCH 03/26] Improved source generators (#268) * initial draft for improved source gen * add tests for new generator and restructure generator project * keep ordering of data container properties in generated code * add data element analyzer and unittests, refactor data element generator * add new DataContainer attribute to data containers to enable new generator * update PropertyChangedSourceGenerator to use FAWMN * code cleanup for generators and analyzer * add TextKind type to better specify how a type should be treated * move data elements to reduce unnecessary namespace nesting * fix unittests after moving data elements to new namespace * fix tests for PropertyChangedGenerator * fix sonarlint warnings and issues from review --- .editorconfig | 11 +- .../Aircraft/AirstrikeDataContainer.cs | 5 +- .../Aircraft/CvAircraftDataContainer.cs | 608 +++++++++--------- .../DepthChargesLauncherDataContainer.cs | 3 +- .../Armament/MainBatteryDataContainer.cs | 5 +- .../Armament/PingerGunDataContainer.cs | 168 ++--- .../Armament/SecondaryBatteryDataContainer.cs | 5 +- .../Armament/TorpedoArmamentDataContainer.cs | 9 +- .../Projectiles/BombDataContainer.cs | 5 +- .../Projectiles/DepthChargeDataContainer.cs | 1 + .../Projectiles/ProjectileDataContainer.cs | 2 +- .../Projectiles/RocketDataContainer.cs | 176 ++--- .../Projectiles/ShellDataContainer.cs | 5 +- .../Projectiles/TorpedoDataContainer.cs | 49 +- .../Ship/AuraDataDataContainer.cs | 7 +- .../Ship/ConcealmentDataContainer.cs | 174 ++--- .../Ship/ConsumableDataContainer.cs | 3 +- .../Ship/ManeuverabilityDataContainer.cs | 11 +- .../Ship/SpecialAbilityDataContainer.cs | 176 ++--- .../Ship/SurvivabilityDataContainer.cs | 292 ++++----- .../Components/ConsumableSelector.razor | 2 +- .../Components/SharedFragments.razor | 18 +- .../ShipStats/Components/ShipStatsPanel.razor | 3 +- .../Features/ShipStats/FormattedTextHelper.cs | 22 +- .../AssertionMethodAttribute.cs | 8 + .../DataElementAnalyzerTest.cs | 79 +++ .../DataElementAnalyzerTests/FormattedText.cs | 144 +++++ .../DataElementAnalyzerTests/Grouped.cs | 84 +++ .../DataElementAnalyzerTests/KeyValue.cs | 144 +++++ .../DataElementAnalyzerTests/KeyValueUnit.cs | 184 ++++++ .../DataElementAnalyzerTests/Tooltip.cs | 184 ++++++ .../DataElementAnalyzerTests/Value.cs | 144 +++++ .../DataElementGeneratorTest.cs | 58 ++ .../FormattedText.cs | 319 +++++++++ .../DataElementGeneratorTests/Grouped.cs | 136 ++++ .../DataElementGeneratorTests/KeyValue.cs | 127 ++++ .../DataElementGeneratorTests/KeyValueUnit.cs | 45 ++ .../DataElementGeneratorTests/Mixed.cs | 152 +++++ .../DataElementGeneratorTests/Tooltip.cs | 86 +++ .../DataElementGeneratorTests/Value.cs | 127 ++++ .../PropertyChangedGeneratorTest.cs | 224 +++++++ .../SourceGeneratorResultTest.cs | 43 -- .../SourceGeneratorTest.cs | 327 ---------- .../TestStructures/DataElements.cs | 5 - .../TestStructures/TestDataUi1.cs | 39 -- ...WoWsShipBuilder.Data.Generator.Test.csproj | 10 +- .../Attributes/AttributeGenerator.cs | 62 -- .../DataElementGenerator/AttributeHelper.cs | 169 +++++ .../DataElementAnalyzer.cs | 256 ++++++++ .../DataElementGenerator.cs | 190 ++++++ .../DataElementTypes.cs | 2 +- .../Model/ContainerData.cs | 5 + .../Model/FormattedTextData.cs | 3 + .../Model/GroupPropertyData.cs | 6 + .../Model/PropertyData.cs | 3 + .../Model/PropertyDisplayOptions.cs | 3 + .../Model/PropertyFilter.cs | 3 + .../Model/RawContainerData.cs | 5 + .../Model/SinglePropertyData.cs | 3 + .../DataElementGenerator/PropertyHelper.cs | 41 ++ .../DataElementGenerator/Rules.cs | 58 ++ .../DataElementGenerator/TextKind.cs | 8 + .../DataElementSourceGenerator.cs | 445 ------------- .../PropertyChangedGenerator/FieldData.cs | 3 + .../PropertyChangedSourceGenerator.cs | 66 ++ .../Visibility.cs | 2 +- .../PropertyChangedSourceGenerator.cs | 103 --- .../Utilities/EquatableArray.cs | 196 ++++++ .../Utilities/HashCode.cs | 180 ++++++ .../Utilities/SourceBuilder.cs | 201 ++++++ .../Utilities/SymbolExtensions.cs | 40 ++ .../WoWsShipBuilder.Data.Generator.csproj | 6 +- .../{DataElements => }/DataContainerBase.cs | 2 +- .../DataElementFilteringAttribute.cs | 17 - .../DataElementTypeAttribute.cs | 72 --- .../DataElementAttributes/DataElementTypes.cs | 14 - .../DataElementTextKind.cs | 8 + .../DataElements/FormattedTextDataElement.cs | 12 - .../DataElements/KeyValueDataElement.cs | 10 - .../DataElements/ValueDataElement.cs | 9 - .../FormattedTextDataElement.cs | 12 + .../{DataElements => }/GroupedDataElement.cs | 2 +- .../{DataElements => }/IDataElement.cs | 2 +- .../KeyValueDataElement.cs | 9 + .../KeyValueUnitDataElement.cs | 2 +- .../{DataElements => }/TooltipDataElement.cs | 2 +- .../ValueDataElement.cs | 8 + nuget.config | 9 + 88 files changed, 4640 insertions(+), 2038 deletions(-) create mode 100644 WoWsShipBuilder.Data.Generator.Test/AssertionMethodAttribute.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/DataElementAnalyzerTest.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/FormattedText.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Grouped.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/KeyValue.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/KeyValueUnit.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Tooltip.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Value.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/DataElementGeneratorTest.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/FormattedText.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Grouped.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/KeyValue.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/KeyValueUnit.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Mixed.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Tooltip.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Value.cs create mode 100644 WoWsShipBuilder.Data.Generator.Test/PropertyChangedGeneratorTests/PropertyChangedGeneratorTest.cs delete mode 100644 WoWsShipBuilder.Data.Generator.Test/SourceGeneratorResultTest.cs delete mode 100644 WoWsShipBuilder.Data.Generator.Test/SourceGeneratorTest.cs delete mode 100644 WoWsShipBuilder.Data.Generator.Test/TestStructures/DataElements.cs delete mode 100644 WoWsShipBuilder.Data.Generator.Test/TestStructures/TestDataUi1.cs delete mode 100644 WoWsShipBuilder.Data.Generator/Attributes/AttributeGenerator.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/AttributeHelper.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementAnalyzer.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementGenerator.cs rename WoWsShipBuilder.Data.Generator/{Internals => DataElementGenerator}/DataElementTypes.cs (73%) create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/ContainerData.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/FormattedTextData.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/GroupPropertyData.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyData.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyDisplayOptions.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyFilter.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/RawContainerData.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/SinglePropertyData.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/PropertyHelper.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/Rules.cs create mode 100644 WoWsShipBuilder.Data.Generator/DataElementGenerator/TextKind.cs delete mode 100644 WoWsShipBuilder.Data.Generator/DataElementSourceGenerator.cs create mode 100644 WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/FieldData.cs create mode 100644 WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/PropertyChangedSourceGenerator.cs rename WoWsShipBuilder.Data.Generator/{Internals => PropertyChangedGenerator}/Visibility.cs (50%) delete mode 100644 WoWsShipBuilder.Data.Generator/PropertyChangedSourceGenerator.cs create mode 100644 WoWsShipBuilder.Data.Generator/Utilities/EquatableArray.cs create mode 100644 WoWsShipBuilder.Data.Generator/Utilities/HashCode.cs create mode 100644 WoWsShipBuilder.Data.Generator/Utilities/SourceBuilder.cs create mode 100644 WoWsShipBuilder.Data.Generator/Utilities/SymbolExtensions.cs rename WoWsShipBuilder.DataElements/{DataElements => }/DataContainerBase.cs (90%) delete mode 100644 WoWsShipBuilder.DataElements/DataElementAttributes/DataElementFilteringAttribute.cs delete mode 100644 WoWsShipBuilder.DataElements/DataElementAttributes/DataElementTypeAttribute.cs delete mode 100644 WoWsShipBuilder.DataElements/DataElementAttributes/DataElementTypes.cs create mode 100644 WoWsShipBuilder.DataElements/DataElementTextKind.cs delete mode 100644 WoWsShipBuilder.DataElements/DataElements/FormattedTextDataElement.cs delete mode 100644 WoWsShipBuilder.DataElements/DataElements/KeyValueDataElement.cs delete mode 100644 WoWsShipBuilder.DataElements/DataElements/ValueDataElement.cs create mode 100644 WoWsShipBuilder.DataElements/FormattedTextDataElement.cs rename WoWsShipBuilder.DataElements/{DataElements => }/GroupedDataElement.cs (88%) rename WoWsShipBuilder.DataElements/{DataElements => }/IDataElement.cs (76%) create mode 100644 WoWsShipBuilder.DataElements/KeyValueDataElement.cs rename WoWsShipBuilder.DataElements/{DataElements => }/KeyValueUnitDataElement.cs (87%) rename WoWsShipBuilder.DataElements/{DataElements => }/TooltipDataElement.cs (89%) create mode 100644 WoWsShipBuilder.DataElements/ValueDataElement.cs create mode 100644 nuget.config diff --git a/.editorconfig b/.editorconfig index 1faf532e4..c707c9c26 100644 --- a/.editorconfig +++ b/.editorconfig @@ -51,10 +51,10 @@ dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggesti dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:suggestion dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion dotnet_style_predefined_type_for_member_access = true:suggestion -dotnet_style_qualification_for_event = false:suggestion -dotnet_style_qualification_for_field = false:suggestion -dotnet_style_qualification_for_method = false:suggestion -dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_event = true:suggestion +dotnet_style_qualification_for_field = true:suggestion +dotnet_style_qualification_for_method = true:suggestion +dotnet_style_qualification_for_property = true:suggestion dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion # ReSharper properties @@ -112,9 +112,8 @@ dotnet_diagnostic.rs2008.severity = none # Ignore analyzer release tracking dotnet_diagnostic.sa0001.severity = none # Ignore disabled xml documentation dotnet_diagnostic.sa1000.severity = none # Ignore missing space after "new" dotnet_diagnostic.sa1009.severity = none # Ignore missing space after closing parenthesis -dotnet_diagnostic.sa1028.severity = none # Ignore trailing whitespace dotnet_diagnostic.sa1100.severity = none # Ignore base. prefix if there is no local override -dotnet_diagnostic.sa1101.severity = none # Ignore missing this prefix for local calls +dotnet_diagnostic.sa1101.severity = suggestion # Ignore missing this prefix for local calls dotnet_diagnostic.sa1122.severity = none # Don't force the use of string.Empty dotnet_diagnostic.sa1124.severity = none # Allow the use of regions dotnet_diagnostic.sa1127.severity = none # Generic constraints may share a line with other declarations diff --git a/WoWsShipBuilder.Common/DataContainers/Aircraft/AirstrikeDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Aircraft/AirstrikeDataContainer.cs index ee0fd14dc..646c8bfd1 100644 --- a/WoWsShipBuilder.Common/DataContainers/Aircraft/AirstrikeDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Aircraft/AirstrikeDataContainer.cs @@ -1,5 +1,5 @@ +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.ApplicationData; @@ -7,11 +7,12 @@ namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record AirstrikeDataContainer : DataContainerBase { public string Header { get; set; } = default!; - [DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true)] + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.LocalizationKey)] public string Name { get; set; } = default!; [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "HP")] diff --git a/WoWsShipBuilder.Common/DataContainers/Aircraft/CvAircraftDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Aircraft/CvAircraftDataContainer.cs index 28b957236..7dca33344 100644 --- a/WoWsShipBuilder.Common/DataContainers/Aircraft/CvAircraftDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Aircraft/CvAircraftDataContainer.cs @@ -1,6 +1,6 @@ using System.Globalization; +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Aircraft; using WoWsShipBuilder.DataStructures.Ship; @@ -8,351 +8,351 @@ using WoWsShipBuilder.Infrastructure.GameData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers +namespace WoWsShipBuilder.DataContainers; + +[DataContainer] +public partial record CvAircraftDataContainer : DataContainerBase { - public partial record CvAircraftDataContainer : DataContainerBase - { - public string Name { get; set; } = default!; + public string Name { get; set; } = default!; + + public string PlaneVariant { get; set; } = default!; + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "AircraftAmount")] + public int NumberInSquad { get; set; } + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "AircraftAmount")] + public int NumberDuringAttack { get; set; } + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "AircraftAmount")] + public int MaxNumberOnDeck { get; set; } + + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] + public decimal RestorationTime { get; set; } + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Speed", UnitKey = "Knots")] + public decimal CruisingSpeed { get; set; } + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Speed", UnitKey = "Knots")] + public decimal MaxSpeed { get; set; } + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Speed", UnitKey = "Knots")] + public decimal MinSpeed { get; set; } + + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] + public decimal MaxEngineBoostDuration { get; set; } + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "InitialBoost", UnitKey = "S")] + public decimal JatoDuration { get; set; } + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "InitialBoost", UnitKey = "PerCent")] + public decimal JatoSpeedMultiplier { get; set; } + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "HP", UnitKey = "HP")] + public int PlaneHp { get; set; } + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "HP", UnitKey = "HP")] + public int SquadronHp { get; set; } - public string PlaneVariant { get; set; } = default!; + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "HP", UnitKey = "HP")] + public int AttackGroupHp { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "AircraftAmount")] - public int NumberInSquad { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "PerCent")] + public int DamageTakenDuringAttack { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "AircraftAmount")] - public int NumberDuringAttack { get; set; } + [DataElementType(DataElementTypes.KeyValue)] + public int AmmoPerAttack { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "AircraftAmount")] - public int MaxNumberOnDeck { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AttackTimings", UnitKey = "S")] + public decimal PreparationTime { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal RestorationTime { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AttackTimings", UnitKey = "S")] + public decimal AimingTime { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Speed", UnitKey = "Knots")] - public decimal CruisingSpeed { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AttackTimings", UnitKey = "S")] + public decimal TimeToFullyAimed { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Speed", UnitKey = "Knots")] - public decimal MaxSpeed { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AttackTimings", UnitKey = "S")] + public decimal PostAttackInvulnerabilityDuration { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Speed", UnitKey = "Knots")] - public decimal MinSpeed { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AttackTimings", UnitKey = "S")] + public decimal AttackCd { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal MaxEngineBoostDuration { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Concealment", UnitKey = "KM")] + public decimal ConcealmentFromShips { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "InitialBoost", UnitKey = "S")] - public decimal JatoDuration { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Concealment", UnitKey = "KM")] + public decimal ConcealmentFromPlanes { get; set; } + + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "KM")] + public decimal MaxViewDistance { get; set; } + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AimPenaltyPlanes", UnitKey = "PerCent")] + public string AimingRateMoving { get; set; } = default!; + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AimPenaltyPlanes", UnitKey = "PerCent")] + public string AimingPreparationRateMoving { get; set; } = default!; + + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "PerCent")] + public int InnerBombPercentage { get; set; } + + public string WeaponType { get; set; } = default!; + + public bool IsLast { get; set; } + + public ProjectileDataContainer? Weapon { get; set; } + + public List PlaneConsumables { get; set; } = default!; + + // TODO + public decimal ArmamentReloadTime { get; set; } + + public decimal BoostDurationTime { get; set; } + + public decimal BoostReloadTime { get; set; } + + public static List? FromShip(Ship ship, List shipConfiguration, List<(string name, float value)> modifiers) + { + if (!ship.CvPlanes.Any()) + { + return null; + } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "InitialBoost", UnitKey = "PerCent")] - public decimal JatoSpeedMultiplier { get; set; } + var list = new List(); + var planes = new List(); - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "HP", UnitKey = "HP")] - public int PlaneHp { get; set; } + var rocketConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Fighter); + if (rocketConfiguration != null) + { + List skipModule = ship.CvPlanes[rocketConfiguration.Components[ComponentType.Fighter].First()]; + planes.AddRange(skipModule); + } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "HP", UnitKey = "HP")] - public int SquadronHp { get; set; } + var torpConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.TorpedoBomber); + if (torpConfiguration != null) + { + List skipModule = ship.CvPlanes[torpConfiguration.Components[ComponentType.TorpedoBomber].First()]; + planes.AddRange(skipModule); + } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "HP", UnitKey = "HP")] - public int AttackGroupHp { get; set; } + var diveConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.DiveBomber); + if (diveConfiguration != null) + { + List diveModule = ship.CvPlanes[diveConfiguration.Components[ComponentType.DiveBomber].First()]; + planes.AddRange(diveModule); + } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "PerCent")] - public int DamageTakenDuringAttack { get; set; } + var skipConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.SkipBomber); + if (skipConfiguration != null) + { + List skipModule = ship.CvPlanes[skipConfiguration.Components[ComponentType.SkipBomber].First()]; + planes.AddRange(skipModule); + } - [DataElementType(DataElementTypes.KeyValue)] - public int AmmoPerAttack { get; set; } + foreach (var value in planes) + { + int index = value.IndexOf("_", StringComparison.InvariantCultureIgnoreCase); + string name = value.Substring(0, index); + var plane = AppData.FindAircraft(name); + var planeDataContainer = ProcessCvPlane(plane, ship.Tier, modifiers); + list.Add(planeDataContainer); + } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AttackTimings", UnitKey = "S")] - public decimal PreparationTime { get; set; } + list.Last().IsLast = true; + return list; + } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AttackTimings", UnitKey = "S")] - public decimal AimingTime { get; set; } + private static CvAircraftDataContainer ProcessCvPlane(Aircraft plane, int shipTier, List<(string name, float value)> modifiers) + { + var maxOnDeckModifiers = modifiers.FindModifiers("planeExtraHangarSize"); + int maxOnDeck = maxOnDeckModifiers.Aggregate(plane.MaxPlaneInHangar, (current, modifier) => (int)(current + modifier)); + + var restorationTimeModifiers = modifiers.FindModifiers("planeSpawnTime"); + decimal restorationTime = (decimal)restorationTimeModifiers.Aggregate(plane.RestorationTime, (current, modifier) => current * modifier); + + var talentRestorationModifiers = modifiers.FindModifiers("airplaneReloadCoeff"); + restorationTime = talentRestorationModifiers.Aggregate(restorationTime, (current, modifier) => current * (decimal)modifier); + + float planeHp = 0; + float cruisingSpeed = plane.Speed; + float minSpeedMultiplier = plane.SpeedMinModifier; + float maxSpeedMultiplier = plane.SpeedMaxModifier; + var planesConcealmentFromShips = (float)plane.ConcealmentFromShips; + var planesConcealmentFromPlanes = (float)plane.ConcealmentFromPlanes; + decimal aimRateModifier = 1; + decimal aimingTime = 0; + switch (plane.PlaneType) + { + case PlaneType.TacticalFighter: + case PlaneType.Fighter: + var rocketPlaneHpModifiers = modifiers.FindModifiers("fighterHealth"); + planeHp = rocketPlaneHpModifiers.Aggregate(plane.MaxHealth, (current, modifier) => current * modifier); - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AttackTimings", UnitKey = "S")] - public decimal TimeToFullyAimed { get; set; } + var rocketAimingTimeModifiers = modifiers.FindModifiers("fighterAimingTime"); + aimingTime = rocketAimingTimeModifiers.Aggregate(plane.AimingTime, (current, modifier) => current + (decimal)modifier); - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AttackTimings", UnitKey = "S")] - public decimal PostAttackInvulnerabilityDuration { get; set; } + var aimModifiersRocket = modifiers.FindModifiers("fighterAccuracyIncRateCoeff"); + aimRateModifier = aimModifiersRocket.Aggregate(aimRateModifier, (current, modifier) => current * (decimal)modifier); - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AttackTimings", UnitKey = "S")] - public decimal AttackCd { get; set; } + break; + case PlaneType.TacticalDiveBomber: + case PlaneType.DiveBomber: + var divePlaneHpModifiers = modifiers.FindModifiers("diveBomberHealth"); + planeHp = divePlaneHpModifiers.Aggregate(plane.MaxHealth, (current, modifier) => current * modifier); - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Concealment", UnitKey = "KM")] - public decimal ConcealmentFromShips { get; set; } + var divePlaneSpeedModifiers = modifiers.FindModifiers("diveBomberSpeedMultiplier"); + cruisingSpeed = divePlaneSpeedModifiers.Aggregate(cruisingSpeed, (current, modifier) => current * modifier); - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Concealment", UnitKey = "KM")] - public decimal ConcealmentFromPlanes { get; set; } + var minSpeedMultiplierModifiers = modifiers.FindModifiers("diveBomberMinSpeedMultiplier"); + minSpeedMultiplier = minSpeedMultiplierModifiers.Aggregate(minSpeedMultiplier, (current, modifier) => current * modifier); - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "KM")] - public decimal MaxViewDistance { get; set; } + var maxSpeedMultiplierModifiers = modifiers.FindModifiers("diveBomberMaxSpeedMultiplier"); + maxSpeedMultiplier = maxSpeedMultiplierModifiers.Aggregate(maxSpeedMultiplier, (current, modifier) => current * modifier); - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AimPenaltyPlanes", UnitKey = "PerCent")] - public string AimingRateMoving { get; set; } = default!; + var aimModifiersBomber = modifiers.FindModifiers("diveBomberAccuracyIncRateCoeff"); + aimRateModifier = aimModifiersBomber.Aggregate(aimRateModifier, (current, modifier) => current * (decimal)modifier); - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AimPenaltyPlanes", UnitKey = "PerCent")] - public string AimingPreparationRateMoving { get; set; } = default!; + break; + case PlaneType.TacticalTorpedoBomber: + case PlaneType.TorpedoBomber: + var torpPlaneHpModifiers = modifiers.FindModifiers("torpedoBomberHealth"); + planeHp = torpPlaneHpModifiers.Aggregate(plane.MaxHealth, (current, modifier) => current * modifier); - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "PerCent")] - public int InnerBombPercentage { get; set; } + var torpAimingTimeModifiers = modifiers.FindModifiers("torpedoBomberAimingTime"); + aimingTime = torpAimingTimeModifiers.Aggregate(plane.AimingTime, (current, modifier) => current + (decimal)modifier); - public string WeaponType { get; set; } = default!; + var aimModifiersTorpedo = modifiers.FindModifiers("torpedoBomberAccuracyIncRateCoeff"); + aimRateModifier = aimModifiersTorpedo.Aggregate(aimRateModifier, (current, modifier) => current * (decimal)modifier); - public bool IsLast { get; set; } + break; + case PlaneType.TacticalSkipBomber: + case PlaneType.SkipBomber: + var skipPlaneHpModifiers = modifiers.FindModifiers("skipBomberHealth"); + planeHp = skipPlaneHpModifiers.Aggregate(plane.MaxHealth, (current, modifier) => current * modifier); - public ProjectileDataContainer? Weapon { get; set; } + var skipPlaneSpeedModifiers = modifiers.FindModifiers("skipBomberSpeedMultiplier"); + cruisingSpeed = skipPlaneSpeedModifiers.Aggregate(cruisingSpeed, (current, modifier) => current * modifier); - public List PlaneConsumables { get; set; } = default!; + var skipAimingTimeModifiers = modifiers.FindModifiers("skipBomberAimingTime"); + aimingTime = skipAimingTimeModifiers.Aggregate(plane.AimingTime, (current, modifier) => current * (decimal)modifier); - // TODO - public decimal ArmamentReloadTime { get; set; } + var aimModifiersSkip = modifiers.FindModifiers("skipBomberAccuracyIncRateCoeff"); + aimRateModifier = aimModifiersSkip.Aggregate(aimRateModifier, (current, modifier) => current * (decimal)modifier); - public decimal BoostDurationTime { get; set; } + break; + } - public decimal BoostReloadTime { get; set; } + var allPlaneHpModifiers = modifiers.FindModifiers("planeHealthCoeff", true); + var finalPlaneHp = (int)Math.Round(allPlaneHpModifiers.Aggregate(planeHp, (current, modifier) => current * modifier), 0); - public static List? FromShip(Ship ship, List shipConfiguration, List<(string name, float value)> modifiers) + int planeHpPerTierIndex = modifiers.FindModifierIndex("planeHealthPerLevel"); + if (planeHpPerTierIndex > 0) { - if (!ship.CvPlanes.Any()) - { - return null; - } - - var list = new List(); - var planes = new List(); - - var rocketConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Fighter); - if (rocketConfiguration != null) - { - List skipModule = ship.CvPlanes[rocketConfiguration.Components[ComponentType.Fighter].First()]; - planes.AddRange(skipModule); - } - - var torpConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.TorpedoBomber); - if (torpConfiguration != null) - { - List skipModule = ship.CvPlanes[torpConfiguration.Components[ComponentType.TorpedoBomber].First()]; - planes.AddRange(skipModule); - } - - var diveConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.DiveBomber); - if (diveConfiguration != null) - { - List diveModule = ship.CvPlanes[diveConfiguration.Components[ComponentType.DiveBomber].First()]; - planes.AddRange(diveModule); - } - - var skipConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.SkipBomber); - if (skipConfiguration != null) - { - List skipModule = ship.CvPlanes[skipConfiguration.Components[ComponentType.SkipBomber].First()]; - planes.AddRange(skipModule); - } - - foreach (var value in planes) - { - int index = value.IndexOf("_", StringComparison.InvariantCultureIgnoreCase); - string name = value.Substring(0, index); - var plane = AppData.FindAircraft(name); - var planeDataContainer = ProcessCvPlane(plane, ship.Tier, modifiers); - list.Add(planeDataContainer); - } - - list.Last().IsLast = true; - return list; + int additionalHp = (int)modifiers[planeHpPerTierIndex].value * shipTier; + finalPlaneHp += additionalHp; } - private static CvAircraftDataContainer ProcessCvPlane(Aircraft plane, int shipTier, List<(string name, float value)> modifiers) + var cruisingSpeedModifiers = modifiers.FindModifiers("planeSpeed"); + decimal finalCruisingSpeed = (decimal)cruisingSpeedModifiers.Aggregate(cruisingSpeed, (current, modifier) => current * modifier); + + var talentCruisingSpeedModifiers = modifiers.FindModifiers("squadronSpeedCoeff"); + finalCruisingSpeed = talentCruisingSpeedModifiers.Aggregate(finalCruisingSpeed, (current, modifier) => current * (decimal)modifier); + + var maxSpeedModifiers = modifiers.FindModifiers("planeMaxSpeedMultiplier"); + maxSpeedMultiplier = maxSpeedModifiers.Aggregate(maxSpeedMultiplier, (current, modifier) => current * modifier); + + var maxEngineBoostDurationModifiers = modifiers.FindModifiers("planeForsageTimeCoeff"); + var maxEngineBoostDuration = maxEngineBoostDurationModifiers.Aggregate(plane.MaxEngineBoostDuration, (current, modifier) => current * modifier); + + var planesConcealmentModifiers = modifiers.FindModifiers("planeVisibilityFactor").ToList(); + planesConcealmentFromShips = planesConcealmentModifiers.Aggregate(planesConcealmentFromShips, (current, modifier) => current * modifier); + planesConcealmentFromPlanes = planesConcealmentModifiers.Aggregate(planesConcealmentFromPlanes, (current, modifier) => current * modifier); + + var jatoDuration = (decimal)plane.JatoData.JatoDuration; + var jatoMultiplier = (decimal)plane.JatoData.JatoSpeedMultiplier; + if (jatoDuration == 0) { - var maxOnDeckModifiers = modifiers.FindModifiers("planeExtraHangarSize"); - int maxOnDeck = maxOnDeckModifiers.Aggregate(plane.MaxPlaneInHangar, (current, modifier) => (int)(current + modifier)); + jatoMultiplier = 0; + } - var restorationTimeModifiers = modifiers.FindModifiers("planeSpawnTime"); - decimal restorationTime = (decimal)restorationTimeModifiers.Aggregate(plane.RestorationTime, (current, modifier) => current * modifier); + var weaponType = AppData.FindProjectile(plane.BombName).ProjectileType; + var bombInnerEllipse = 0; + ProjectileDataContainer weapon = null!; + switch (weaponType) + { + case ProjectileType.Bomb: + weapon = BombDataContainer.FromBombName(plane.BombName, modifiers); + bombInnerEllipse = (int)plane.InnerBombsPercentage; + break; + case ProjectileType.SkipBomb: + weapon = BombDataContainer.FromBombName(plane.BombName, modifiers); + break; + case ProjectileType.Torpedo: + var torpList = new List + { + plane.BombName, + }; + weapon = TorpedoDataContainer.FromTorpedoName(torpList, modifiers, true).First(); + break; + case ProjectileType.Rocket: + weapon = RocketDataContainer.FromRocketName(plane.BombName, modifiers); + break; + } - var talentRestorationModifiers = modifiers.FindModifiers("airplaneReloadCoeff"); - restorationTime = talentRestorationModifiers.Aggregate(restorationTime, (current, modifier) => current * (decimal)modifier); - - float planeHp = 0; - float cruisingSpeed = plane.Speed; - float minSpeedMultiplier = plane.SpeedMinModifier; - float maxSpeedMultiplier = plane.SpeedMaxModifier; - var planesConcealmentFromShips = (float)plane.ConcealmentFromShips; - var planesConcealmentFromPlanes = (float)plane.ConcealmentFromPlanes; - decimal aimRateModifier = 1; - decimal aimingTime = 0; - switch (plane.PlaneType) - { - case PlaneType.TacticalFighter: - case PlaneType.Fighter: - var rocketPlaneHpModifiers = modifiers.FindModifiers("fighterHealth"); - planeHp = rocketPlaneHpModifiers.Aggregate(plane.MaxHealth, (current, modifier) => current * modifier); - - var rocketAimingTimeModifiers = modifiers.FindModifiers("fighterAimingTime"); - aimingTime = rocketAimingTimeModifiers.Aggregate(plane.AimingTime, (current, modifier) => current + (decimal)modifier); - - var aimModifiersRocket = modifiers.FindModifiers("fighterAccuracyIncRateCoeff"); - aimRateModifier = aimModifiersRocket.Aggregate(aimRateModifier, (current, modifier) => current * (decimal)modifier); - - break; - case PlaneType.TacticalDiveBomber: - case PlaneType.DiveBomber: - var divePlaneHpModifiers = modifiers.FindModifiers("diveBomberHealth"); - planeHp = divePlaneHpModifiers.Aggregate(plane.MaxHealth, (current, modifier) => current * modifier); - - var divePlaneSpeedModifiers = modifiers.FindModifiers("diveBomberSpeedMultiplier"); - cruisingSpeed = divePlaneSpeedModifiers.Aggregate(cruisingSpeed, (current, modifier) => current * modifier); - - var minSpeedMultiplierModifiers = modifiers.FindModifiers("diveBomberMinSpeedMultiplier"); - minSpeedMultiplier = minSpeedMultiplierModifiers.Aggregate(minSpeedMultiplier, (current, modifier) => current * modifier); - - var maxSpeedMultiplierModifiers = modifiers.FindModifiers("diveBomberMaxSpeedMultiplier"); - maxSpeedMultiplier = maxSpeedMultiplierModifiers.Aggregate(maxSpeedMultiplier, (current, modifier) => current * modifier); - - var aimModifiersBomber = modifiers.FindModifiers("diveBomberAccuracyIncRateCoeff"); - aimRateModifier = aimModifiersBomber.Aggregate(aimRateModifier, (current, modifier) => current * (decimal)modifier); - - break; - case PlaneType.TacticalTorpedoBomber: - case PlaneType.TorpedoBomber: - var torpPlaneHpModifiers = modifiers.FindModifiers("torpedoBomberHealth"); - planeHp = torpPlaneHpModifiers.Aggregate(plane.MaxHealth, (current, modifier) => current * modifier); - - var torpAimingTimeModifiers = modifiers.FindModifiers("torpedoBomberAimingTime"); - aimingTime = torpAimingTimeModifiers.Aggregate(plane.AimingTime, (current, modifier) => current + (decimal)modifier); - - var aimModifiersTorpedo = modifiers.FindModifiers("torpedoBomberAccuracyIncRateCoeff"); - aimRateModifier = aimModifiersTorpedo.Aggregate(aimRateModifier, (current, modifier) => current * (decimal)modifier); - - break; - case PlaneType.TacticalSkipBomber: - case PlaneType.SkipBomber: - var skipPlaneHpModifiers = modifiers.FindModifiers("skipBomberHealth"); - planeHp = skipPlaneHpModifiers.Aggregate(plane.MaxHealth, (current, modifier) => current * modifier); - - var skipPlaneSpeedModifiers = modifiers.FindModifiers("skipBomberSpeedMultiplier"); - cruisingSpeed = skipPlaneSpeedModifiers.Aggregate(cruisingSpeed, (current, modifier) => current * modifier); - - var skipAimingTimeModifiers = modifiers.FindModifiers("skipBomberAimingTime"); - aimingTime = skipAimingTimeModifiers.Aggregate(plane.AimingTime, (current, modifier) => current * (decimal)modifier); - - var aimModifiersSkip = modifiers.FindModifiers("skipBomberAccuracyIncRateCoeff"); - aimRateModifier = aimModifiersSkip.Aggregate(aimRateModifier, (current, modifier) => current * (decimal)modifier); - - break; - } - - var allPlaneHpModifiers = modifiers.FindModifiers("planeHealthCoeff", true); - var finalPlaneHp = (int)Math.Round(allPlaneHpModifiers.Aggregate(planeHp, (current, modifier) => current * modifier), 0); - - int planeHpPerTierIndex = modifiers.FindModifierIndex("planeHealthPerLevel"); - if (planeHpPerTierIndex > 0) - { - int additionalHp = (int)modifiers[planeHpPerTierIndex].value * shipTier; - finalPlaneHp += additionalHp; - } - - var cruisingSpeedModifiers = modifiers.FindModifiers("planeSpeed"); - decimal finalCruisingSpeed = (decimal)cruisingSpeedModifiers.Aggregate(cruisingSpeed, (current, modifier) => current * modifier); - - var talentCruisingSpeedModifiers = modifiers.FindModifiers("squadronSpeedCoeff"); - finalCruisingSpeed = talentCruisingSpeedModifiers.Aggregate(finalCruisingSpeed, (current, modifier) => current * (decimal)modifier); - - var maxSpeedModifiers = modifiers.FindModifiers("planeMaxSpeedMultiplier"); - maxSpeedMultiplier = maxSpeedModifiers.Aggregate(maxSpeedMultiplier, (current, modifier) => current * modifier); - - var maxEngineBoostDurationModifiers = modifiers.FindModifiers("planeForsageTimeCoeff"); - var maxEngineBoostDuration = maxEngineBoostDurationModifiers.Aggregate(plane.MaxEngineBoostDuration, (current, modifier) => current * modifier); - - var planesConcealmentModifiers = modifiers.FindModifiers("planeVisibilityFactor").ToList(); - planesConcealmentFromShips = planesConcealmentModifiers.Aggregate(planesConcealmentFromShips, (current, modifier) => current * modifier); - planesConcealmentFromPlanes = planesConcealmentModifiers.Aggregate(planesConcealmentFromPlanes, (current, modifier) => current * modifier); - - var jatoDuration = (decimal)plane.JatoData.JatoDuration; - var jatoMultiplier = (decimal)plane.JatoData.JatoSpeedMultiplier; - if (jatoDuration == 0) - { - jatoMultiplier = 0; - } - - var weaponType = AppData.FindProjectile(plane.BombName).ProjectileType; - var bombInnerEllipse = 0; - ProjectileDataContainer weapon = null!; - switch (weaponType) - { - case ProjectileType.Bomb: - weapon = BombDataContainer.FromBombName(plane.BombName, modifiers); - bombInnerEllipse = (int)plane.InnerBombsPercentage; - break; - case ProjectileType.SkipBomb: - weapon = BombDataContainer.FromBombName(plane.BombName, modifiers); - break; - case ProjectileType.Torpedo: - var torpList = new List - { - plane.BombName, - }; - weapon = TorpedoDataContainer.FromTorpedoName(torpList, modifiers, true).First(); - break; - case ProjectileType.Rocket: - weapon = RocketDataContainer.FromRocketName(plane.BombName, modifiers); - break; - } - - List consumables = new(); - foreach (var consumable in plane.AircraftConsumable) - { - var consumableDataContainer = ConsumableDataContainer.FromTypeAndVariant(consumable, modifiers, true, 0, ShipClass.AirCarrier); - consumables.Add(consumableDataContainer); - } - - consumables = consumables.OrderBy(x => x.Slot).ToList(); - - var aimingRateMoving = plane.AimingAccuracyIncreaseRate + plane.AimingAccuracyDecreaseRate; - var preparationAimingRateMoving = plane.PreparationAccuracyIncreaseRate + plane.PreparationAccuracyDecreaseRate; - - var fullAimTime = plane.PreparationTime + ((1 - (plane.PreparationTime * plane.PreparationAccuracyIncreaseRate * aimRateModifier)) / (plane.AimingAccuracyIncreaseRate * aimRateModifier)); - - var jatoSpeedMultiplier = jatoMultiplier > 1 ? (jatoMultiplier - 1) * 100 : 0; - - const string stringFormat = "+#0.0;-#0.0;0"; - - var cvAircraft = new CvAircraftDataContainer - { - Name = plane.Name, - PlaneVariant = plane.PlaneType.PlaneTypeToString(), - PlaneHp = finalPlaneHp, - SquadronHp = finalPlaneHp * plane.NumPlanesInSquadron, - AttackGroupHp = finalPlaneHp * plane.AttackData.AttackerSize, - NumberInSquad = plane.NumPlanesInSquadron, - MaxNumberOnDeck = maxOnDeck, - RestorationTime = Math.Round(restorationTime, 2), - CruisingSpeed = finalCruisingSpeed, - MaxSpeed = Math.Round(finalCruisingSpeed * (decimal)maxSpeedMultiplier, 0), - MinSpeed = Math.Round(finalCruisingSpeed * (decimal)minSpeedMultiplier, 0), - MaxEngineBoostDuration = (decimal)maxEngineBoostDuration, - InnerBombPercentage = bombInnerEllipse, - NumberDuringAttack = plane.AttackData.AttackerSize, - AmmoPerAttack = plane.AttackData.AttackCount, - AttackCd = Math.Round((decimal)plane.AttackData.AttackCooldown, 1), - JatoDuration = jatoDuration, - JatoSpeedMultiplier = Math.Round(jatoSpeedMultiplier, 0), - WeaponType = weaponType.ProjectileTypeToString(), - Weapon = weapon, - PlaneConsumables = consumables, - AimingTime = Math.Round(aimingTime, 1), - PreparationTime = plane.PreparationTime, - PostAttackInvulnerabilityDuration = plane.PostAttackInvulnerabilityDuration, - DamageTakenDuringAttack = (int)Math.Round(plane.DamageTakenMultiplier * 100), - AimingRateMoving = (aimingRateMoving * 100).ToString(stringFormat, CultureInfo.InvariantCulture), - AimingPreparationRateMoving = (preparationAimingRateMoving * 100).ToString(stringFormat, CultureInfo.InvariantCulture), - TimeToFullyAimed = Math.Round(fullAimTime, 1), - ConcealmentFromShips = (decimal)planesConcealmentFromShips, - ConcealmentFromPlanes = (decimal)planesConcealmentFromPlanes, - MaxViewDistance = (decimal)plane.SpottingOnShips, - }; - - cvAircraft.UpdateDataElements(); - - return cvAircraft; + List consumables = new(); + foreach (var consumable in plane.AircraftConsumable) + { + var consumableDataContainer = ConsumableDataContainer.FromTypeAndVariant(consumable, modifiers, true, 0, ShipClass.AirCarrier); + consumables.Add(consumableDataContainer); } + + consumables = consumables.OrderBy(x => x.Slot).ToList(); + + var aimingRateMoving = plane.AimingAccuracyIncreaseRate + plane.AimingAccuracyDecreaseRate; + var preparationAimingRateMoving = plane.PreparationAccuracyIncreaseRate + plane.PreparationAccuracyDecreaseRate; + + var fullAimTime = plane.PreparationTime + ((1 - (plane.PreparationTime * plane.PreparationAccuracyIncreaseRate * aimRateModifier)) / (plane.AimingAccuracyIncreaseRate * aimRateModifier)); + + var jatoSpeedMultiplier = jatoMultiplier > 1 ? (jatoMultiplier - 1) * 100 : 0; + + const string stringFormat = "+#0.0;-#0.0;0"; + + var cvAircraft = new CvAircraftDataContainer + { + Name = plane.Name, + PlaneVariant = plane.PlaneType.PlaneTypeToString(), + PlaneHp = finalPlaneHp, + SquadronHp = finalPlaneHp * plane.NumPlanesInSquadron, + AttackGroupHp = finalPlaneHp * plane.AttackData.AttackerSize, + NumberInSquad = plane.NumPlanesInSquadron, + MaxNumberOnDeck = maxOnDeck, + RestorationTime = Math.Round(restorationTime, 2), + CruisingSpeed = finalCruisingSpeed, + MaxSpeed = Math.Round(finalCruisingSpeed * (decimal)maxSpeedMultiplier, 0), + MinSpeed = Math.Round(finalCruisingSpeed * (decimal)minSpeedMultiplier, 0), + MaxEngineBoostDuration = (decimal)maxEngineBoostDuration, + InnerBombPercentage = bombInnerEllipse, + NumberDuringAttack = plane.AttackData.AttackerSize, + AmmoPerAttack = plane.AttackData.AttackCount, + AttackCd = Math.Round((decimal)plane.AttackData.AttackCooldown, 1), + JatoDuration = jatoDuration, + JatoSpeedMultiplier = Math.Round(jatoSpeedMultiplier, 0), + WeaponType = weaponType.ProjectileTypeToString(), + Weapon = weapon, + PlaneConsumables = consumables, + AimingTime = Math.Round(aimingTime, 1), + PreparationTime = plane.PreparationTime, + PostAttackInvulnerabilityDuration = plane.PostAttackInvulnerabilityDuration, + DamageTakenDuringAttack = (int)Math.Round(plane.DamageTakenMultiplier * 100), + AimingRateMoving = (aimingRateMoving * 100).ToString(stringFormat, CultureInfo.InvariantCulture), + AimingPreparationRateMoving = (preparationAimingRateMoving * 100).ToString(stringFormat, CultureInfo.InvariantCulture), + TimeToFullyAimed = Math.Round(fullAimTime, 1), + ConcealmentFromShips = (decimal)planesConcealmentFromShips, + ConcealmentFromPlanes = (decimal)planesConcealmentFromPlanes, + MaxViewDistance = (decimal)plane.SpottingOnShips, + }; + + cvAircraft.UpdateDataElements(); + + return cvAircraft; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/DepthChargesLauncherDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Armament/DepthChargesLauncherDataContainer.cs index 75c72d99d..17d36e9ef 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/DepthChargesLauncherDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Armament/DepthChargesLauncherDataContainer.cs @@ -1,11 +1,12 @@ +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record DepthChargesLauncherDataContainer : DataContainerBase { [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/MainBatteryDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Armament/MainBatteryDataContainer.cs index ea15bdb30..d5d3dbe3e 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/MainBatteryDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Armament/MainBatteryDataContainer.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Text; +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.GameData; @@ -10,9 +10,10 @@ // ReSharper disable UnusedAutoPropertyAccessor.Global namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record MainBatteryDataContainer : DataContainerBase { - [DataElementType(DataElementTypes.FormattedText, ValuesPropertyName = "TurretNames", ArePropertyNameValuesKeys = true)] + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = "TurretNames", ArgumentsTextKind = TextKind.LocalizationKey)] public string Name { get; set; } = default!; public List TurretNames { get; set; } = new(); diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/PingerGunDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Armament/PingerGunDataContainer.cs index eabd36ce2..540be959f 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/PingerGunDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Armament/PingerGunDataContainer.cs @@ -1,103 +1,103 @@ using Microsoft.Extensions.Logging; +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers +namespace WoWsShipBuilder.DataContainers; + +[DataContainer] +public partial record PingerGunDataContainer : DataContainerBase { - public partial record PingerGunDataContainer : DataContainerBase - { - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal Reload { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] + public decimal Reload { get; set; } + + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "DegreePerSecond")] + public decimal TraverseSpeed { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "DegreePerSecond")] - public decimal TraverseSpeed { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] + public decimal TurnTime { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal TurnTime { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "KM")] + public decimal Range { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "KM")] - public decimal Range { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "PingDuration", UnitKey = "S", LocalizationKeyOverride = "First")] + public decimal FirstPingDuration { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "PingDuration", UnitKey = "S", NameLocalizationKey = "First")] - public decimal FirstPingDuration { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "PingDuration", UnitKey = "S", LocalizationKeyOverride = "Second")] + public decimal SecondPingDuration { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "PingDuration", UnitKey = "S", NameLocalizationKey = "Second")] - public decimal SecondPingDuration { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "M")] + public decimal PingWidth { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "M")] - public decimal PingWidth { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MPS")] + public decimal PingSpeed { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MPS")] - public decimal PingSpeed { get; set; } + public static PingerGunDataContainer? FromShip(Ship ship, IEnumerable shipConfiguration, List<(string name, float value)> modifiers) + { + if (!ship.PingerGunList.Any()) + { + return null; + } - public static PingerGunDataContainer? FromShip(Ship ship, IEnumerable shipConfiguration, List<(string name, float value)> modifiers) + PingerGun pingerGun; + var pingerUpgrade = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Sonar); + if (pingerUpgrade is null && ship.PingerGunList.Count is 1) { - if (!ship.PingerGunList.Any()) - { - return null; - } - - PingerGun pingerGun; - var pingerUpgrade = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Sonar); - if (pingerUpgrade is null && ship.PingerGunList.Count is 1) - { - Logging.Logger.LogWarning("No sonar upgrade information found for ship {ShipName} even though there is one sonar module available", ship.Name); - return null; - } - - if (pingerUpgrade is null) - { - throw new InvalidOperationException($"No sonar upgrade information found for ship {ship.Name} but there is more than one sonar module."); - } - - // Safe approach is necessary because data up until 0.11.9#1 does not include this data due to an issue in the data converter - if (pingerUpgrade.Components.TryGetValue(ComponentType.Sonar, out string[]? pingerGunInfo)) - { - pingerGun = ship.PingerGunList[pingerGunInfo.First()]; - } - else - { - Logging.Logger.LogWarning("Unable to retrieve sonar component from upgrade info for ship {} and ship upgrade {}", ship.Index, pingerUpgrade.Name); - pingerGun = ship.PingerGunList.First().Value; - } - - var pingSpeed = pingerGun.WaveParams.First().WaveSpeed.First(); - var pingSpeedModifiers = modifiers.FindModifiers("pingerWaveSpeedCoeff"); - pingSpeed = pingSpeedModifiers.Aggregate(pingSpeed, (current, pingSpeedModifier) => current * (decimal)pingSpeedModifier); - - var firstPingDuration = pingerGun.SectorParams[0].Lifetime; - var firstPingDurationModifiers = modifiers.FindModifiers("firstSectorTimeCoeff"); - firstPingDuration = firstPingDurationModifiers.Aggregate(firstPingDuration, (current, firstPingDurationModifier) => current * (decimal)firstPingDurationModifier); - - var secondPingDuration = pingerGun.SectorParams[1].Lifetime; - var secondPingDurationModifiers = modifiers.FindModifiers("secondSectorTimeCoeff"); - secondPingDuration = secondPingDurationModifiers.Aggregate(secondPingDuration, (current, secondPingDurationModifiersModifier) => current * (decimal)secondPingDurationModifiersModifier); - - var traverseSpeed = pingerGun.RotationSpeed[0]; - - var arModifiers = modifiers.FindModifiers("lastChanceReloadCoefficient"); - var reload = arModifiers.Aggregate(pingerGun.WaveReloadTime, (current, arModifier) => current * (1 - ((decimal)arModifier / 100))); - var pingReloadModifiers = modifiers.FindModifiers("pingerReloadCoeff"); - reload = pingReloadModifiers.Aggregate(reload, (current, pingReloadModifier) => current * (decimal)pingReloadModifier); - - var pingerGunDataContainer = new PingerGunDataContainer - { - TurnTime = Math.Round(180 / traverseSpeed, 1), - TraverseSpeed = traverseSpeed, - Reload = Math.Round(reload, 2), - Range = pingerGun.WaveDistance / 1000, - FirstPingDuration = Math.Round(firstPingDuration, 1), - SecondPingDuration = Math.Round(secondPingDuration, 1), - PingWidth = pingerGun.WaveParams.First().StartWaveWidth, - PingSpeed = Math.Round(pingSpeed, 0), - }; - - pingerGunDataContainer.UpdateDataElements(); - - return pingerGunDataContainer; + Logging.Logger.LogWarning("No sonar upgrade information found for ship {ShipName} even though there is one sonar module available", ship.Name); + return null; } + + if (pingerUpgrade is null) + { + throw new InvalidOperationException($"No sonar upgrade information found for ship {ship.Name} but there is more than one sonar module."); + } + + // Safe approach is necessary because data up until 0.11.9#1 does not include this data due to an issue in the data converter + if (pingerUpgrade.Components.TryGetValue(ComponentType.Sonar, out string[]? pingerGunInfo)) + { + pingerGun = ship.PingerGunList[pingerGunInfo.First()]; + } + else + { + Logging.Logger.LogWarning("Unable to retrieve sonar component from upgrade info for ship {} and ship upgrade {}", ship.Index, pingerUpgrade.Name); + pingerGun = ship.PingerGunList.First().Value; + } + + var pingSpeed = pingerGun.WaveParams.First().WaveSpeed.First(); + var pingSpeedModifiers = modifiers.FindModifiers("pingerWaveSpeedCoeff"); + pingSpeed = pingSpeedModifiers.Aggregate(pingSpeed, (current, pingSpeedModifier) => current * (decimal)pingSpeedModifier); + + var firstPingDuration = pingerGun.SectorParams[0].Lifetime; + var firstPingDurationModifiers = modifiers.FindModifiers("firstSectorTimeCoeff"); + firstPingDuration = firstPingDurationModifiers.Aggregate(firstPingDuration, (current, firstPingDurationModifier) => current * (decimal)firstPingDurationModifier); + + var secondPingDuration = pingerGun.SectorParams[1].Lifetime; + var secondPingDurationModifiers = modifiers.FindModifiers("secondSectorTimeCoeff"); + secondPingDuration = secondPingDurationModifiers.Aggregate(secondPingDuration, (current, secondPingDurationModifiersModifier) => current * (decimal)secondPingDurationModifiersModifier); + + var traverseSpeed = pingerGun.RotationSpeed[0]; + + var arModifiers = modifiers.FindModifiers("lastChanceReloadCoefficient"); + var reload = arModifiers.Aggregate(pingerGun.WaveReloadTime, (current, arModifier) => current * (1 - ((decimal)arModifier / 100))); + var pingReloadModifiers = modifiers.FindModifiers("pingerReloadCoeff"); + reload = pingReloadModifiers.Aggregate(reload, (current, pingReloadModifier) => current * (decimal)pingReloadModifier); + + var pingerGunDataContainer = new PingerGunDataContainer + { + TurnTime = Math.Round(180 / traverseSpeed, 1), + TraverseSpeed = traverseSpeed, + Reload = Math.Round(reload, 2), + Range = pingerGun.WaveDistance / 1000, + FirstPingDuration = Math.Round(firstPingDuration, 1), + SecondPingDuration = Math.Round(secondPingDuration, 1), + PingWidth = pingerGun.WaveParams.First().StartWaveWidth, + PingSpeed = Math.Round(pingSpeed, 0), + }; + + pingerGunDataContainer.UpdateDataElements(); + + return pingerGunDataContainer; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/SecondaryBatteryDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Armament/SecondaryBatteryDataContainer.cs index ef10cb9c3..4939a0a93 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/SecondaryBatteryDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Armament/SecondaryBatteryDataContainer.cs @@ -1,7 +1,7 @@ using System.Globalization; using Microsoft.Extensions.Logging; +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.GameData; @@ -9,6 +9,7 @@ namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record SecondaryBatteryDataContainer : DataContainerBase { public string Name { get; set; } = default!; @@ -92,7 +93,7 @@ public partial record SecondaryBatteryDataContainer : DataContainerBase { Name = arrangementString, TurretName = turretName, - TurretSetup = new(arrangementString, turretName, AreValuesKeys: true), + TurretSetup = new(arrangementString, turretName, ArgumentsTextKind: DataElementTextKind.LocalizationKey), BarrelsLayout = $"{secondaryGroup.Count} x {secondaryGun.NumBarrels}", BarrelsCount = secondaryGroup.Count * secondaryGun.NumBarrels, GunCaliber = Math.Round(secondaryGun.BarrelDiameter * 1000), diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/TorpedoArmamentDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Armament/TorpedoArmamentDataContainer.cs index 0617fbb60..bc9990430 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/TorpedoArmamentDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Armament/TorpedoArmamentDataContainer.cs @@ -1,16 +1,17 @@ using System.Globalization; using System.Text; +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record TorpedoArmamentDataContainer : DataContainerBase { - [DataElementType(DataElementTypes.FormattedText, ValuesPropertyName = "LauncherNames", ArePropertyNameValuesKeys = true)] + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = "LauncherNames", ArgumentsTextKind = TextKind.LocalizationKey)] public string Name { get; set; } = default!; public List LauncherNames { get; set; } = new(); @@ -39,10 +40,10 @@ public partial record TorpedoArmamentDataContainer : DataContainerBase [DataElementType(DataElementTypes.KeyValue)] public string FullSalvoDamage { get; set; } = default!; - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "FullSalvoDamage", NameLocalizationKey = "FirstOption")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "FullSalvoDamage", LocalizationKeyOverride = "FirstOption")] public string TorpFullSalvoDmg { get; set; } = default!; - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "FullSalvoDamage", NameLocalizationKey = "SecondOption")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "FullSalvoDamage", LocalizationKeyOverride = "SecondOption")] public string AltTorpFullSalvoDmg { get; set; } = default!; public int LoadersCount { get; set; } diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/BombDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Projectiles/BombDataContainer.cs index b8898ad76..5ff69265f 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/BombDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Projectiles/BombDataContainer.cs @@ -7,12 +7,13 @@ namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record BombDataContainer : ProjectileDataContainer { - [DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true, IsValueAppLocalization = true)] + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.AppLocalizationKey)] public string BombType { get; set; } = default!; - [DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true)] + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.LocalizationKey)] public string Name { get; set; } = default!; [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MM")] diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/DepthChargeDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Projectiles/DepthChargeDataContainer.cs index d73c1e699..027b37542 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/DepthChargeDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Projectiles/DepthChargeDataContainer.cs @@ -5,6 +5,7 @@ namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record DepthChargeDataContainer : ProjectileDataContainer { [DataElementType(DataElementTypes.KeyValue)] diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/ProjectileDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Projectiles/ProjectileDataContainer.cs index 0696e8c69..fe19a2a02 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/ProjectileDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Projectiles/ProjectileDataContainer.cs @@ -1,4 +1,4 @@ -using WoWsShipBuilder.DataElements.DataElements; +using WoWsShipBuilder.DataElements; namespace WoWsShipBuilder.DataContainers; diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/RocketDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Projectiles/RocketDataContainer.cs index 69140fbf6..e432d1a77 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/RocketDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Projectiles/RocketDataContainer.cs @@ -5,113 +5,113 @@ using WoWsShipBuilder.Infrastructure.GameData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers +namespace WoWsShipBuilder.DataContainers; + +[DataContainer] +public partial record RocketDataContainer : ProjectileDataContainer { - public partial record RocketDataContainer : ProjectileDataContainer - { - [DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true, IsValueAppLocalization = true)] - public string RocketType { get; set; } = default!; + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.AppLocalizationKey)] + public string RocketType { get; set; } = default!; - [DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true)] - public string Name { get; set; } = default!; + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.LocalizationKey)] + public string Name { get; set; } = default!; - [DataElementType(DataElementTypes.KeyValue)] - public decimal Damage { get; set; } + [DataElementType(DataElementTypes.KeyValue)] + public decimal Damage { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.Tooltip, GroupKey = "Splash", TooltipKey = "SplashExplanation", UnitKey = "M")] - public decimal SplashRadius { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.Tooltip, GroupKey = "Splash", TooltipKey = "SplashExplanation", UnitKey = "M")] + public decimal SplashRadius { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.Tooltip, GroupKey = "Splash", TooltipKey = "SplashExplanation")] - public decimal SplashDmg { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.Tooltip, GroupKey = "Splash", TooltipKey = "SplashExplanation")] + public decimal SplashDmg { get; set; } - [DataElementType(DataElementTypes.Tooltip, TooltipKey = "KruppExplanation")] - public decimal Krupp { get; set; } + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "KruppExplanation")] + public decimal Krupp { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MM")] - public int Penetration { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MM")] + public int Penetration { get; set; } - [DataElementType(DataElementTypes.Tooltip, TooltipKey = "ApPenetrationFormula", UnitKey = "MM")] - public int PenetrationAp { get; set; } + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "ApPenetrationFormula", UnitKey = "MM")] + public int PenetrationAp { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal FuseTimer { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] + public decimal FuseTimer { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MM")] - public int ArmingThreshold { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MM")] + public int ArmingThreshold { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Degree")] - public string RicochetAngles { get; set; } = default!; + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Degree")] + public string RicochetAngles { get; set; } = default!; - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "PerCent")] - public decimal FireChance { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "PerCent")] + public decimal FireChance { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Blast", UnitKey = "M")] - public decimal ExplosionRadius { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Blast", UnitKey = "M")] + public decimal ExplosionRadius { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.Tooltip, GroupKey = "Blast", TooltipKey = "BlastExplanation")] - [DataElementFiltering(true, "ShouldDisplayBlastPenetration")] - public decimal SplashCoeff { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.Tooltip, GroupKey = "Blast", TooltipKey = "BlastExplanation")] + [DataElementFiltering(true, "ShouldDisplayBlastPenetration")] + public decimal SplashCoeff { get; set; } - public bool ShowBlastPenetration { get; private set; } + public bool ShowBlastPenetration { get; private set; } - public static RocketDataContainer FromRocketName(string name, List<(string name, float value)> modifiers) + public static RocketDataContainer FromRocketName(string name, List<(string name, float value)> modifiers) + { + var rocket = AppData.FindProjectile(name); + + var rocketDamage = (decimal)rocket.Damage; + var showBlastPenetration = true; + var ricochetAngle = ""; + decimal fuseTimer = 0; + var armingThreshold = 0; + decimal fireChance = 0; + int penetrationHe = 0; + int penetrationAp = 0; + if (rocket.RocketType.Equals(DataStructures.RocketType.AP)) { - var rocket = AppData.FindProjectile(name); - - var rocketDamage = (decimal)rocket.Damage; - var showBlastPenetration = true; - var ricochetAngle = ""; - decimal fuseTimer = 0; - var armingThreshold = 0; - decimal fireChance = 0; - int penetrationHe = 0; - int penetrationAp = 0; - if (rocket.RocketType.Equals(DataStructures.RocketType.AP)) - { - List rocketDamageModifiers = modifiers.FindModifiers("rocketApAlphaDamageMultiplier").ToList(); - rocketDamage = rocketDamageModifiers.Aggregate(rocketDamage, (current, modifier) => current * (decimal)modifier); - ricochetAngle = $"{rocket.RicochetAngle}-{rocket.AlwaysRicochetAngle}"; - fuseTimer = (decimal)rocket.FuseTimer; - armingThreshold = (int)rocket.ArmingThreshold; - showBlastPenetration = false; - penetrationAp = (int)Math.Round(BallisticHelper.CalculatePen(rocket.MuzzleVelocity, rocket.Caliber, rocket.Mass, rocket.Krupp)); - } - else - { - var fireChanceModifiers = modifiers.FindModifiers("rocketBurnChanceBonus"); - fireChance = (decimal)fireChanceModifiers.Aggregate(rocket.FireChance, (current, modifier) => current + modifier); - var fireChanceModifiersRockets = modifiers.FindModifiers("burnChanceFactorSmall"); - fireChance = fireChanceModifiersRockets.Aggregate(fireChance, (current, modifier) => current + (decimal)modifier); - penetrationHe = (int)Math.Truncate(rocket.Penetration); - } - - var rocketDataContainer = new RocketDataContainer - { - Name = rocket.Name, - RocketType = $"ArmamentType_{rocket.RocketType.RocketTypeToString()}", - Damage = Math.Round(rocketDamage, 2), - Penetration = penetrationHe, - PenetrationAp = penetrationAp, - FuseTimer = fuseTimer, - ArmingThreshold = armingThreshold, - RicochetAngles = ricochetAngle, - FireChance = Math.Round(fireChance * 100, 1), - ExplosionRadius = (decimal)rocket.ExplosionRadius, - SplashCoeff = (decimal)rocket.SplashCoeff, - ShowBlastPenetration = showBlastPenetration, - SplashRadius = Math.Round((decimal)rocket.DepthSplashRadius, 1), - SplashDmg = Math.Round(rocketDamage * (decimal)rocket.SplashDamageCoefficient), - Krupp = (decimal)rocket.Krupp, - }; - - rocketDataContainer.UpdateDataElements(); - - return rocketDataContainer; + List rocketDamageModifiers = modifiers.FindModifiers("rocketApAlphaDamageMultiplier").ToList(); + rocketDamage = rocketDamageModifiers.Aggregate(rocketDamage, (current, modifier) => current * (decimal)modifier); + ricochetAngle = $"{rocket.RicochetAngle}-{rocket.AlwaysRicochetAngle}"; + fuseTimer = (decimal)rocket.FuseTimer; + armingThreshold = (int)rocket.ArmingThreshold; + showBlastPenetration = false; + penetrationAp = (int)Math.Round(BallisticHelper.CalculatePen(rocket.MuzzleVelocity, rocket.Caliber, rocket.Mass, rocket.Krupp)); } - - private bool ShouldDisplayBlastPenetration(object obj) + else { - return ShowBlastPenetration; + var fireChanceModifiers = modifiers.FindModifiers("rocketBurnChanceBonus"); + fireChance = (decimal)fireChanceModifiers.Aggregate(rocket.FireChance, (current, modifier) => current + modifier); + var fireChanceModifiersRockets = modifiers.FindModifiers("burnChanceFactorSmall"); + fireChance = fireChanceModifiersRockets.Aggregate(fireChance, (current, modifier) => current + (decimal)modifier); + penetrationHe = (int)Math.Truncate(rocket.Penetration); } + + var rocketDataContainer = new RocketDataContainer + { + Name = rocket.Name, + RocketType = $"ArmamentType_{rocket.RocketType.RocketTypeToString()}", + Damage = Math.Round(rocketDamage, 2), + Penetration = penetrationHe, + PenetrationAp = penetrationAp, + FuseTimer = fuseTimer, + ArmingThreshold = armingThreshold, + RicochetAngles = ricochetAngle, + FireChance = Math.Round(fireChance * 100, 1), + ExplosionRadius = (decimal)rocket.ExplosionRadius, + SplashCoeff = (decimal)rocket.SplashCoeff, + ShowBlastPenetration = showBlastPenetration, + SplashRadius = Math.Round((decimal)rocket.DepthSplashRadius, 1), + SplashDmg = Math.Round(rocketDamage * (decimal)rocket.SplashDamageCoefficient), + Krupp = (decimal)rocket.Krupp, + }; + + rocketDataContainer.UpdateDataElements(); + + return rocketDataContainer; + } + + private bool ShouldDisplayBlastPenetration(object obj) + { + return ShowBlastPenetration; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/ShellDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Projectiles/ShellDataContainer.cs index 837116d77..65d4b55f5 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/ShellDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Projectiles/ShellDataContainer.cs @@ -1,7 +1,7 @@ // ReSharper disable UnusedAutoPropertyAccessor.Global +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Projectile; using WoWsShipBuilder.Infrastructure.ApplicationData; @@ -10,11 +10,12 @@ namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record ShellDataContainer : DataContainerBase { public string Name { get; set; } = default!; - [DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true, IsValueAppLocalization = true)] + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.AppLocalizationKey)] public string Type { get; set; } = default!; [DataElementType(DataElementTypes.KeyValue)] diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/TorpedoDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Projectiles/TorpedoDataContainer.cs index d6b68cf3c..1753f4ab1 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/TorpedoDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Projectiles/TorpedoDataContainer.cs @@ -7,12 +7,13 @@ namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record TorpedoDataContainer : ProjectileDataContainer { - [DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true, IsValueAppLocalization = true)] + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.AppLocalizationKey)] public string TorpedoType { get; set; } = default!; - [DataElementType(DataElementTypes.KeyValue, IsValueLocalizationKey = true)] + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.LocalizationKey)] [DataElementFiltering(true, "ShouldDisplayName")] public string Name { get; set; } = default!; @@ -44,70 +45,70 @@ public partial record TorpedoDataContainer : ProjectileDataContainer [DataElementFiltering(false)] public decimal SplashCoeff { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxTurningSpeed", UnitKey = "DegreePerSecond", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxTurningSpeed", UnitKey = "DegreePerSecond", LocalizationKeyOverride = "FirstPing")] public decimal MaxTurningSpeedFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxTurningSpeed", UnitKey = "DegreePerSecond", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxTurningSpeed", UnitKey = "DegreePerSecond", LocalizationKeyOverride = "SecondPing")] public decimal MaxTurningSpeedSecondPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "TurningAcceleration", UnitKey = "DegreePerSecond2", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "TurningAcceleration", UnitKey = "DegreePerSecond2", LocalizationKeyOverride = "FirstPing")] public decimal TurningAccelerationFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "TurningAcceleration", UnitKey = "DegreePerSecond2", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "TurningAcceleration", UnitKey = "DegreePerSecond2", LocalizationKeyOverride = "SecondPing")] public decimal TurningAccelerationSecondPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxVerticalSpeed", UnitKey = "MPS", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxVerticalSpeed", UnitKey = "MPS", LocalizationKeyOverride = "FirstPing")] public decimal MaxVerticalSpeedFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxVerticalSpeed", UnitKey = "MPS", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxVerticalSpeed", UnitKey = "MPS", LocalizationKeyOverride = "SecondPing")] public decimal MaxVerticalSpeedSecondPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "VerticalAcceleration", UnitKey = "MPS2", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "VerticalAcceleration", UnitKey = "MPS2", LocalizationKeyOverride = "FirstPing")] public decimal VerticalAccelerationFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "VerticalAcceleration", UnitKey = "MPS2", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "VerticalAcceleration", UnitKey = "MPS2", LocalizationKeyOverride = "SecondPing")] public decimal VerticalAccelerationSecondPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "SearchRadius", UnitKey = "KM", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "SearchRadius", UnitKey = "KM", LocalizationKeyOverride = "FirstPing")] public decimal SearchRadiusFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "SearchRadius", UnitKey = "KM", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "SearchRadius", UnitKey = "KM", LocalizationKeyOverride = "SecondPing")] public decimal SearchRadiusSecondPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "SearchAngle", UnitKey = "Degree", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "SearchAngle", UnitKey = "Degree", LocalizationKeyOverride = "FirstPing")] public decimal SearchAngleFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "SearchAngle", UnitKey = "Degree", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "SearchAngle", UnitKey = "Degree", LocalizationKeyOverride = "SecondPing")] public decimal SearchAngleSecondPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Destroyer", UnitKey = "M", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Destroyer", UnitKey = "M", LocalizationKeyOverride = "FirstPing")] public decimal DestroyerCutOffFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Destroyer", UnitKey = "M", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Destroyer", UnitKey = "M", LocalizationKeyOverride = "SecondPing")] public decimal DestroyerCutOffSecondPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Battleship", UnitKey = "M", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Battleship", UnitKey = "M", LocalizationKeyOverride = "FirstPing")] public decimal BattleshipCutOffFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Battleship", UnitKey = "M", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Battleship", UnitKey = "M", LocalizationKeyOverride = "SecondPing")] public decimal BattleshipCutOffSecondPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Cruiser", UnitKey = "M", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Cruiser", UnitKey = "M", LocalizationKeyOverride = "FirstPing")] public decimal CruiserCutOffFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Cruiser", UnitKey = "M", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Cruiser", UnitKey = "M", LocalizationKeyOverride = "SecondPing")] public decimal CruiserCutOffSecondPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Submarine", UnitKey = "M", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Submarine", UnitKey = "M", LocalizationKeyOverride = "FirstPing")] public decimal SubCutOffFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Submarine", UnitKey = "M", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Submarine", UnitKey = "M", LocalizationKeyOverride = "SecondPing")] public decimal SubCutOffSecondPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AirCarrier", UnitKey = "M", NameLocalizationKey = "FirstPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AirCarrier", UnitKey = "M", LocalizationKeyOverride = "FirstPing")] public decimal CvCutOffFirstPing { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AirCarrier", UnitKey = "M", NameLocalizationKey = "SecondPing")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AirCarrier", UnitKey = "M", LocalizationKeyOverride = "SecondPing")] public decimal CvCutOffSecondPing { get; set; } public List? CanHitClasses { get; set; } diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/AuraDataDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Ship/AuraDataDataContainer.cs index c8d002729..5cc0e0d54 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/AuraDataDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Ship/AuraDataDataContainer.cs @@ -1,8 +1,9 @@ -using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; +using WoWsShipBuilder.DataElements; +using WoWsShipBuilder.DataElements.DataElementAttributes; namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record AuraDataDataContainer : DataContainerBase { [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "KM")] @@ -22,6 +23,6 @@ public partial record AuraDataDataContainer : DataContainerBase public void UpdateData() { - UpdateDataElements(); + this.UpdateDataElements(); } } diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/ConcealmentDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Ship/ConcealmentDataContainer.cs index 75428aef2..67f40078d 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/ConcealmentDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Ship/ConcealmentDataContainer.cs @@ -1,119 +1,119 @@ +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers +namespace WoWsShipBuilder.DataContainers; + +[DataContainer] +public partial record ConcealmentDataContainer : DataContainerBase { - public partial record ConcealmentDataContainer : DataContainerBase - { - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Sea", UnitKey = "KM")] - public decimal ConcealmentBySea { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Sea", UnitKey = "KM")] + public decimal ConcealmentBySea { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Sea", UnitKey = "KM")] - public decimal ConcealmentBySeaFire { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Sea", UnitKey = "KM")] + public decimal ConcealmentBySeaFire { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Sea", UnitKey = "KM")] - public decimal ConcealmentBySeaFiringSmoke { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Sea", UnitKey = "KM")] + public decimal ConcealmentBySeaFiringSmoke { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Air", UnitKey = "KM")] - public decimal ConcealmentByAir { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Air", UnitKey = "KM")] + public decimal ConcealmentByAir { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Air", UnitKey = "KM")] - public decimal ConcealmentByAirFire { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Air", UnitKey = "KM")] + public decimal ConcealmentByAirFire { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "FromSubs", UnitKey = "KM")] - public decimal ConcealmentBySubPeriscope { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "FromSubs", UnitKey = "KM")] + public decimal ConcealmentBySubPeriscope { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "FromSubs", UnitKey = "KM")] - [DataElementFiltering(false)] - public decimal ConcealmentBySubOperating { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "FromSubs", UnitKey = "KM")] + [DataElementFiltering(false)] + public decimal ConcealmentBySubOperating { get; set; } - public static ConcealmentDataContainer FromShip(Ship ship, List shipConfiguration, List<(string Key, float Value)> modifiers) - { - var hull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull].First()]; + public static ConcealmentDataContainer FromShip(Ship ship, List shipConfiguration, List<(string Key, float Value)> modifiers) + { + var hull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull].First()]; - // Sea Detection - decimal concealmentBySea = hull.SurfaceDetection; - decimal concealmentBySeaFiringSmoke = hull.SmokeFiringDetection; + // Sea Detection + decimal concealmentBySea = hull.SurfaceDetection; + decimal concealmentBySeaFiringSmoke = hull.SmokeFiringDetection; - // AA Detection - decimal concealmentByAir = hull.AirDetection; + // AA Detection + decimal concealmentByAir = hull.AirDetection; - decimal concealmentBySubPeriscope = hull.DetectionBySubPeriscope; - decimal concealmentBySubOperating = hull.DetectionBySubOperating; + decimal concealmentBySubPeriscope = hull.DetectionBySubPeriscope; + decimal concealmentBySubOperating = hull.DetectionBySubOperating; - int concealmentExpertIndex = modifiers.FindModifierIndex("visibilityDistCoeff"); - if (concealmentExpertIndex > -1) + int concealmentExpertIndex = modifiers.FindModifierIndex("visibilityDistCoeff"); + if (concealmentExpertIndex > -1) + { + List modifiersValues = modifiers.FindModifiers("visibilityDistCoeff").ToList(); + foreach (decimal value in modifiersValues.Select(f => (decimal)f)) { - List modifiersValues = modifiers.FindModifiers("visibilityDistCoeff").ToList(); - foreach (decimal value in modifiersValues.Select(f => (decimal)f)) - { - concealmentBySea *= value; - concealmentByAir *= value; - concealmentBySubPeriscope *= value; - concealmentBySubOperating *= value; - } + concealmentBySea *= value; + concealmentByAir *= value; + concealmentBySubPeriscope *= value; + concealmentBySubOperating *= value; } + } + + int visibilityFactorIndex = modifiers.FindModifierIndex("visibilityFactor", true); + if (visibilityFactorIndex > -1) + { + var visibilityFactorModifier = (decimal)modifiers[visibilityFactorIndex].Value; + concealmentBySea *= visibilityFactorModifier; + } - int visibilityFactorIndex = modifiers.FindModifierIndex("visibilityFactor", true); - if (visibilityFactorIndex > -1) + // Checks for Heavy He + var artilleryConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Artillery); + if (artilleryConfiguration != null) + { + string[]? artilleryOptions = artilleryConfiguration.Components[ComponentType.Artillery]; + TurretModule? mainBattery; + if (artilleryOptions.Length == 1) { - var visibilityFactorModifier = (decimal)modifiers[visibilityFactorIndex].Value; - concealmentBySea *= visibilityFactorModifier; + mainBattery = ship.MainBatteryModuleList[artilleryConfiguration.Components[ComponentType.Artillery].First()]; } - - // Checks for Heavy He - var artilleryConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Artillery); - if (artilleryConfiguration != null) + else { - string[]? artilleryOptions = artilleryConfiguration.Components[ComponentType.Artillery]; - TurretModule? mainBattery; - if (artilleryOptions.Length == 1) - { - mainBattery = ship.MainBatteryModuleList[artilleryConfiguration.Components[ComponentType.Artillery].First()]; - } - else - { - string? hullArtilleryName = shipConfiguration.First(c => c.UcType == ComponentType.Hull).Components[ComponentType.Artillery].First(); - mainBattery = ship.MainBatteryModuleList[hullArtilleryName]; - } + string? hullArtilleryName = shipConfiguration.First(c => c.UcType == ComponentType.Hull).Components[ComponentType.Artillery].First(); + mainBattery = ship.MainBatteryModuleList[hullArtilleryName]; + } - var gun = mainBattery.Guns.First(); + var gun = mainBattery.Guns.First(); - // GMBigGunVisibilityCoeff - if (gun.BarrelDiameter >= 0.149M) + // GMBigGunVisibilityCoeff + if (gun.BarrelDiameter >= 0.149M) + { + int bigGunVisibilityFactorIndex = modifiers.FindModifierIndex("GMBigGunVisibilityCoeff", true); + if (bigGunVisibilityFactorIndex > -1) { - int bigGunVisibilityFactorIndex = modifiers.FindModifierIndex("GMBigGunVisibilityCoeff", true); - if (bigGunVisibilityFactorIndex > -1) - { - var bigGunVisibilityFactorModifier = (decimal)modifiers[bigGunVisibilityFactorIndex].Value; - concealmentBySea *= bigGunVisibilityFactorModifier; - concealmentByAir *= bigGunVisibilityFactorModifier; - concealmentBySubOperating *= bigGunVisibilityFactorModifier; - concealmentBySubPeriscope *= bigGunVisibilityFactorModifier; - } + var bigGunVisibilityFactorModifier = (decimal)modifiers[bigGunVisibilityFactorIndex].Value; + concealmentBySea *= bigGunVisibilityFactorModifier; + concealmentByAir *= bigGunVisibilityFactorModifier; + concealmentBySubOperating *= bigGunVisibilityFactorModifier; + concealmentBySubPeriscope *= bigGunVisibilityFactorModifier; } } + } - decimal concealmentBySeaFire = concealmentBySea + 2.0m; - decimal concealmentByAirFire = concealmentByAir + 3.0m; + decimal concealmentBySeaFire = concealmentBySea + 2.0m; + decimal concealmentByAirFire = concealmentByAir + 3.0m; - var concealment = new ConcealmentDataContainer - { - ConcealmentBySea = Math.Round(concealmentBySea, 2), - ConcealmentBySeaFiringSmoke = Math.Round(concealmentBySeaFiringSmoke, 2), - ConcealmentBySeaFire = Math.Round(concealmentBySeaFire, 2), - ConcealmentByAir = Math.Round(concealmentByAir, 2), - ConcealmentByAirFire = Math.Round(concealmentByAirFire, 2), - ConcealmentBySubOperating = Math.Round(concealmentBySubOperating, 2), - ConcealmentBySubPeriscope = Math.Round(concealmentBySubPeriscope, 2), - }; - - concealment.UpdateDataElements(); - - return concealment; - } + var concealment = new ConcealmentDataContainer + { + ConcealmentBySea = Math.Round(concealmentBySea, 2), + ConcealmentBySeaFiringSmoke = Math.Round(concealmentBySeaFiringSmoke, 2), + ConcealmentBySeaFire = Math.Round(concealmentBySeaFire, 2), + ConcealmentByAir = Math.Round(concealmentByAir, 2), + ConcealmentByAirFire = Math.Round(concealmentByAirFire, 2), + ConcealmentBySubOperating = Math.Round(concealmentBySubOperating, 2), + ConcealmentBySubPeriscope = Math.Round(concealmentBySubPeriscope, 2), + }; + + concealment.UpdateDataElements(); + + return concealment; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/ConsumableDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Ship/ConsumableDataContainer.cs index 8d0406405..60f0a156b 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/ConsumableDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Ship/ConsumableDataContainer.cs @@ -1,7 +1,7 @@ using System.Globalization; using Microsoft.Extensions.Logging; +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Aircraft; using WoWsShipBuilder.DataStructures.Ship; @@ -11,6 +11,7 @@ namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record ConsumableDataContainer : DataContainerBase { public string Name { get; set; } = default!; diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/ManeuverabilityDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Ship/ManeuverabilityDataContainer.cs index 45420638e..42ce84f70 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/ManeuverabilityDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Ship/ManeuverabilityDataContainer.cs @@ -1,17 +1,18 @@ +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; namespace WoWsShipBuilder.DataContainers; +[DataContainer] public partial record ManeuverabilityDataContainer : DataContainerBase { [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Knots")] public decimal ManeuverabilityMaxSpeed { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Knots", NameLocalizationKey = "MaxReverseSpeed")] + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Knots", LocalizationKeyOverride = "MaxReverseSpeed")] public decimal ManeuverabilityMaxReverseSpeed { get; set; } [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxSpeed", UnitKey = "Knots")] @@ -23,13 +24,13 @@ public partial record ManeuverabilityDataContainer : DataContainerBase [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxSpeed", UnitKey = "Knots")] public decimal ManeuverabilitySubsMaxSpeedAtMaxDepth { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxReverseSpeed", UnitKey = "Knots", NameLocalizationKey = "ManeuverabilitySubsMaxSpeedOnSurface")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxReverseSpeed", UnitKey = "Knots", LocalizationKeyOverride = "ManeuverabilitySubsMaxSpeedOnSurface")] public decimal ManeuverabilitySubsMaxReverseSpeedOnSurface { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxReverseSpeed", UnitKey = "Knots", NameLocalizationKey = "ManeuverabilitySubsMaxSpeedAtPeriscope")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxReverseSpeed", UnitKey = "Knots", LocalizationKeyOverride = "ManeuverabilitySubsMaxSpeedAtPeriscope")] public decimal ManeuverabilitySubsMaxReverseSpeedAtPeriscope { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxReverseSpeed", UnitKey = "Knots", NameLocalizationKey = "ManeuverabilitySubsMaxSpeedAtMaxDepth")] + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxReverseSpeed", UnitKey = "Knots", LocalizationKeyOverride = "ManeuverabilitySubsMaxSpeedAtMaxDepth")] public decimal ManeuverabilitySubsMaxReverseSpeedAtMaxDepth { get; set; } [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MPS")] diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/SpecialAbilityDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Ship/SpecialAbilityDataContainer.cs index ee9b2f062..2ae848071 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/SpecialAbilityDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Ship/SpecialAbilityDataContainer.cs @@ -1,119 +1,119 @@ using System.Text.Json.Serialization; +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; // ReSharper disable InconsistentNaming -namespace WoWsShipBuilder.DataContainers +namespace WoWsShipBuilder.DataContainers; + +[DataContainer] +public partial record SpecialAbilityDataContainer : DataContainerBase { - public partial record SpecialAbilityDataContainer : DataContainerBase - { - public string Name { get; set; } = default!; + public string Name { get; set; } = default!; - public string Description { get; set; } = default!; + public string Description { get; set; } = default!; - // These are for the special ability of ships like satsuma etc. - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal Duration { get; set; } + // These are for the special ability of ships like satsuma etc. + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] + public decimal Duration { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "KM")] - public decimal TargetAreaRadius { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "KM")] + public decimal TargetAreaRadius { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "PerCent")] - public decimal ProgressPerAction { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "PerCent")] + public decimal ProgressPerAction { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal InactivityDelay { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] + public decimal InactivityDelay { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal ProgressLossInterval { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] + public decimal ProgressLossInterval { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "PerCent")] - public decimal ProgressLossPerInterval { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "PerCent")] + public decimal ProgressLossPerInterval { get; set; } - // These are for Burst mode - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal ReloadDuringBurst { get; set; } + // These are for Burst mode + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] + public decimal ReloadDuringBurst { get; set; } - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal ReloadAfterBurst { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] + public decimal ReloadAfterBurst { get; set; } - [DataElementType(DataElementTypes.KeyValue)] - public int ShotInBurst { get; set; } + [DataElementType(DataElementTypes.KeyValue)] + public int ShotInBurst { get; set; } - // This is in common - [JsonIgnore] - public Dictionary Modifiers { get; set; } = null!; + // This is in common + [JsonIgnore] + public Dictionary Modifiers { get; set; } = null!; - public bool IsBurstMode { get; set; } + public bool IsBurstMode { get; set; } - public static SpecialAbilityDataContainer? FromShip(Ship ship, List shipConfiguration, List<(string name, float value)> modifiers) + public static SpecialAbilityDataContainer? FromShip(Ship ship, List shipConfiguration, List<(string name, float value)> modifiers) + { + SpecialAbilityDataContainer specialDataContainer; + + if (ship.SpecialAbility is not null) { - SpecialAbilityDataContainer specialDataContainer; + var specialAbility = ship.SpecialAbility; - if (ship.SpecialAbility is not null) + specialDataContainer = new() { - var specialAbility = ship.SpecialAbility; - - specialDataContainer = new() - { - Name = $"DOCK_RAGE_MODE_TITLE_{specialAbility.Name}", - Description = specialAbility.ActivatorName.Equals("RibbonActivator") ? $"RAGE_MODE_TRIGGER_DESCRIPTION_{specialAbility.ActivatorName}" : $"RAGE_MODE_DESCRIPTION_{specialAbility.ActivatorName}", - Duration = Math.Round((decimal)specialAbility.Duration, 1), - TargetAreaRadius = Math.Round((decimal)(specialAbility.ActivatorRadius / 1000), 1), - ProgressPerAction = (decimal)specialAbility.ProgressPerAction, - InactivityDelay = (decimal)specialAbility.DecrementDelay, - ProgressLossInterval = (decimal)specialAbility.DecrementPeriod, - ProgressLossPerInterval = (decimal)specialAbility.DecrementCount, - Modifiers = specialAbility.Modifiers, - }; - - specialDataContainer.UpdateDataElements(); + Name = $"DOCK_RAGE_MODE_TITLE_{specialAbility.Name}", + Description = specialAbility.ActivatorName.Equals("RibbonActivator") ? $"RAGE_MODE_TRIGGER_DESCRIPTION_{specialAbility.ActivatorName}" : $"RAGE_MODE_DESCRIPTION_{specialAbility.ActivatorName}", + Duration = Math.Round((decimal)specialAbility.Duration, 1), + TargetAreaRadius = Math.Round((decimal)(specialAbility.ActivatorRadius / 1000), 1), + ProgressPerAction = (decimal)specialAbility.ProgressPerAction, + InactivityDelay = (decimal)specialAbility.DecrementDelay, + ProgressLossInterval = (decimal)specialAbility.DecrementPeriod, + ProgressLossPerInterval = (decimal)specialAbility.DecrementCount, + Modifiers = specialAbility.Modifiers, + }; + + specialDataContainer.UpdateDataElements(); + } + else + { + var artilleryConfiguration = shipConfiguration.Find(c => c.UcType == ComponentType.Artillery); + if (artilleryConfiguration == null) + { + return null; + } + + string[] artilleryOptions = artilleryConfiguration.Components[ComponentType.Artillery]; + string[] supportedModules = artilleryConfiguration.Components[ComponentType.Artillery]; + + TurretModule? mainBattery; + if (artilleryOptions.Length == 1) + { + mainBattery = ship.MainBatteryModuleList[supportedModules[0]]; } else { - var artilleryConfiguration = shipConfiguration.Find(c => c.UcType == ComponentType.Artillery); - if (artilleryConfiguration == null) - { - return null; - } - - string[] artilleryOptions = artilleryConfiguration.Components[ComponentType.Artillery]; - string[] supportedModules = artilleryConfiguration.Components[ComponentType.Artillery]; - - TurretModule? mainBattery; - if (artilleryOptions.Length == 1) - { - mainBattery = ship.MainBatteryModuleList[supportedModules[0]]; - } - else - { - string hullArtilleryName = shipConfiguration.First(c => c.UcType == ComponentType.Hull).Components[ComponentType.Artillery].First(artilleryName => supportedModules.Contains(artilleryName)); - mainBattery = ship.MainBatteryModuleList[hullArtilleryName]; - } - - var burstMode = mainBattery.BurstModeAbility; - - if (burstMode is null) - { - return null; - } - - specialDataContainer = new() - { - Name = "ShipStats_BurstMode", - ReloadDuringBurst = burstMode.ReloadDuringBurst, - ReloadAfterBurst = burstMode.ReloadAfterBurst, - ShotInBurst = burstMode.ShotInBurst, - Modifiers = burstMode.Modifiers, - IsBurstMode = true, - }; - - specialDataContainer.UpdateDataElements(); + string hullArtilleryName = shipConfiguration.First(c => c.UcType == ComponentType.Hull).Components[ComponentType.Artillery].First(artilleryName => supportedModules.Contains(artilleryName)); + mainBattery = ship.MainBatteryModuleList[hullArtilleryName]; + } + + var burstMode = mainBattery.BurstModeAbility; + + if (burstMode is null) + { + return null; } - return specialDataContainer; + specialDataContainer = new() + { + Name = "ShipStats_BurstMode", + ReloadDuringBurst = burstMode.ReloadDuringBurst, + ReloadAfterBurst = burstMode.ReloadAfterBurst, + ShotInBurst = burstMode.ShotInBurst, + Modifiers = burstMode.Modifiers, + IsBurstMode = true, + }; + + specialDataContainer.UpdateDataElements(); } + + return specialDataContainer; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/SurvivabilityDataContainer.cs b/WoWsShipBuilder.Common/DataContainers/Ship/SurvivabilityDataContainer.cs index 009a2534c..9127b08fc 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/SurvivabilityDataContainer.cs +++ b/WoWsShipBuilder.Common/DataContainers/Ship/SurvivabilityDataContainer.cs @@ -1,198 +1,198 @@ // ReSharper disable InconsistentNaming +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers +namespace WoWsShipBuilder.DataContainers; + +[DataContainer] +public partial record SurvivabilityDataContainer : DataContainerBase { - public partial record SurvivabilityDataContainer : DataContainerBase - { - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "HP", NameLocalizationKey = "ShipHp")] - public int HitPoints { get; set; } + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "HP", LocalizationKeyOverride = "ShipHp")] + public int HitPoints { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Citadel", UnitKey = "HP", NameLocalizationKey = "HitPoints")] - public int CitadelHp { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Citadel", UnitKey = "HP", LocalizationKeyOverride = "HitPoints")] + public int CitadelHp { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Citadel", UnitKey = "PerCent", NameLocalizationKey = "RegenRatio")] - public decimal CitadelRegenRatio { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Citadel", UnitKey = "PerCent", LocalizationKeyOverride = "RegenRatio")] + public decimal CitadelRegenRatio { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Casemate", UnitKey = "HP", NameLocalizationKey = "HitPoints")] - public int CasemateHp { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Casemate", UnitKey = "HP", LocalizationKeyOverride = "HitPoints")] + public int CasemateHp { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Casemate", UnitKey = "PerCent", NameLocalizationKey = "RegenRatio")] - public decimal CasemateRegenRatio { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Casemate", UnitKey = "PerCent", LocalizationKeyOverride = "RegenRatio")] + public decimal CasemateRegenRatio { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Bow", UnitKey = "HP", NameLocalizationKey = "HitPoints")] - public int BowHp { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Bow", UnitKey = "HP", LocalizationKeyOverride = "HitPoints")] + public int BowHp { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Bow", UnitKey = "PerCent", NameLocalizationKey = "RegenRatio")] - public decimal BowRegenRatio { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Bow", UnitKey = "PerCent", LocalizationKeyOverride = "RegenRatio")] + public decimal BowRegenRatio { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Stern", UnitKey = "HP", NameLocalizationKey = "HitPoints")] - public int SternHp { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Stern", UnitKey = "HP", LocalizationKeyOverride = "HitPoints")] + public int SternHp { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Stern", UnitKey = "PerCent", NameLocalizationKey = "RegenRatio")] - public decimal SternRegenRatio { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Stern", UnitKey = "PerCent", LocalizationKeyOverride = "RegenRatio")] + public decimal SternRegenRatio { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Superstructure", UnitKey = "HP", NameLocalizationKey = "HitPoints")] - public int SuperstructureHp { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Superstructure", UnitKey = "HP", LocalizationKeyOverride = "HitPoints")] + public int SuperstructureHp { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Superstructure", UnitKey = "PerCent", NameLocalizationKey = "RegenRatio")] - public decimal SuperstructureRegenRatio { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Superstructure", UnitKey = "PerCent", LocalizationKeyOverride = "RegenRatio")] + public decimal SuperstructureRegenRatio { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AuxiliaryRooms", UnitKey = "HP", NameLocalizationKey = "HitPoints")] - public int AuxiliaryRoomsHp { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AuxiliaryRooms", UnitKey = "HP", LocalizationKeyOverride = "HitPoints")] + public int AuxiliaryRoomsHp { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AuxiliaryRooms", UnitKey = "PerCent", NameLocalizationKey = "RegenRatio")] - public decimal AuxiliaryRoomsRegenRatio { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "AuxiliaryRooms", UnitKey = "PerCent", LocalizationKeyOverride = "RegenRatio")] + public decimal AuxiliaryRoomsRegenRatio { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Hull", UnitKey = "HP", NameLocalizationKey = "HitPoints")] - public int HullHp { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Hull", UnitKey = "HP", LocalizationKeyOverride = "HitPoints")] + public int HullHp { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Hull", UnitKey = "PerCent", NameLocalizationKey = "RegenRatio")] - public decimal HullRegenRatio { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Hull", UnitKey = "PerCent", LocalizationKeyOverride = "RegenRatio")] + public decimal HullRegenRatio { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Battery", UnitKey = "U")] - public decimal DiveCapacity { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Battery", UnitKey = "U")] + public decimal DiveCapacity { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Battery", UnitKey = "UPS")] - public decimal DiveCapacityRechargeRate { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Battery", UnitKey = "UPS")] + public decimal DiveCapacityRechargeRate { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Fire")] - public decimal FireAmount { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Fire")] + public decimal FireAmount { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Fire", UnitKey = "S")] - public decimal FireDuration { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Fire", UnitKey = "S")] + public decimal FireDuration { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Fire", UnitKey = "DPS")] - public decimal FireDPS { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Fire", UnitKey = "DPS")] + public decimal FireDPS { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Fire", UnitKey = "HP")] - public decimal FireTotalDamage { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Fire", UnitKey = "HP")] + public decimal FireTotalDamage { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Fire", UnitKey = "PerCent")] - public decimal FireReduction { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Fire", UnitKey = "PerCent")] + public decimal FireReduction { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Flooding")] - public decimal FloodAmount { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Flooding")] + public decimal FloodAmount { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Flooding", UnitKey = "S")] - public decimal FloodDuration { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Flooding", UnitKey = "S")] + public decimal FloodDuration { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Flooding", UnitKey = "DPS")] - public decimal FloodDPS { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Flooding", UnitKey = "DPS")] + public decimal FloodDPS { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Flooding", UnitKey = "HP")] - public decimal FloodTotalDamage { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Flooding", UnitKey = "HP")] + public decimal FloodTotalDamage { get; set; } - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Flooding", UnitKey = "PerCent")] - public decimal FloodTorpedoProtection { get; set; } + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "Flooding", UnitKey = "PerCent")] + public decimal FloodTorpedoProtection { get; set; } - public static SurvivabilityDataContainer FromShip(Ship ship, List shipConfiguration, List<(string Key, float Value)> modifiers) - { - Hull shipHull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull].First()]; + public static SurvivabilityDataContainer FromShip(Ship ship, List shipConfiguration, List<(string Key, float Value)> modifiers) + { + Hull shipHull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull].First()]; - // Survivability expert - decimal hitPoints = shipHull.Health; - int survivabilityExpertIndex = modifiers.FindModifierIndex("healthPerLevel"); - if (survivabilityExpertIndex > -1) - { - hitPoints += (decimal)modifiers[survivabilityExpertIndex].Value * ship.Tier; - } + // Survivability expert + decimal hitPoints = shipHull.Health; + int survivabilityExpertIndex = modifiers.FindModifierIndex("healthPerLevel"); + if (survivabilityExpertIndex > -1) + { + hitPoints += (decimal)modifiers[survivabilityExpertIndex].Value * ship.Tier; + } - int fireSpots = shipHull.FireSpots; - if (modifiers.FindModifierIndex("fireResistanceEnabled") > -1) - { - fireSpots--; - } + int fireSpots = shipHull.FireSpots; + if (modifiers.FindModifierIndex("fireResistanceEnabled") > -1) + { + fireSpots--; + } - decimal fireDuration = shipHull.FireDuration; - decimal floodDuration = shipHull.FloodingDuration; - foreach (float modifier in modifiers.FindModifiers("hlCritTimeCoeff")) - { - fireDuration *= (decimal)modifier; - floodDuration *= (decimal)modifier; - } + decimal fireDuration = shipHull.FireDuration; + decimal floodDuration = shipHull.FloodingDuration; + foreach (float modifier in modifiers.FindModifiers("hlCritTimeCoeff")) + { + fireDuration *= (decimal)modifier; + floodDuration *= (decimal)modifier; + } - fireDuration = modifiers.FindModifiers("burnTime").Aggregate(fireDuration, (current, modifier) => current * (decimal)modifier); + fireDuration = modifiers.FindModifiers("burnTime").Aggregate(fireDuration, (current, modifier) => current * (decimal)modifier); - floodDuration = modifiers.FindModifiers("floodTime").Aggregate(floodDuration, (current, modifier) => current * (decimal)modifier); + floodDuration = modifiers.FindModifiers("floodTime").Aggregate(floodDuration, (current, modifier) => current * (decimal)modifier); - // fire chance reduction = base fire resistance +(100 - base fire resistance) *(1 - burnProb) - decimal baseFireResistance = 1 - shipHull.FireResistance; - decimal fireResistanceModifiers = modifiers.FindModifiers("burnProb").Aggregate(1M, (current, modifier) => current * (decimal)modifier); - decimal fireResistance = baseFireResistance + ((1 - baseFireResistance) * (1 - fireResistanceModifiers)); + // fire chance reduction = base fire resistance +(100 - base fire resistance) *(1 - burnProb) + decimal baseFireResistance = 1 - shipHull.FireResistance; + decimal fireResistanceModifiers = modifiers.FindModifiers("burnProb").Aggregate(1M, (current, modifier) => current * (decimal)modifier); + decimal fireResistance = baseFireResistance + ((1 - baseFireResistance) * (1 - fireResistanceModifiers)); - decimal modifiedFloodingCoeff = modifiers.FindModifiers("uwCoeffBonus").Aggregate(shipHull.FloodingResistance * 3, (current, modifier) => current - ((decimal)modifier / 100)) * 100; - decimal fireDps = hitPoints * shipHull.FireTickDamage / 100; - decimal fireTotalDamage = fireDuration * fireDps; + decimal modifiedFloodingCoeff = modifiers.FindModifiers("uwCoeffBonus").Aggregate(shipHull.FloodingResistance * 3, (current, modifier) => current - ((decimal)modifier / 100)) * 100; + decimal fireDps = hitPoints * shipHull.FireTickDamage / 100; + decimal fireTotalDamage = fireDuration * fireDps; - decimal floodDps = hitPoints * shipHull.FloodingTickDamage / 100; - decimal floodTotalDamage = floodDuration * floodDps; + decimal floodDps = hitPoints * shipHull.FloodingTickDamage / 100; + decimal floodTotalDamage = floodDuration * floodDps; - decimal diveCapacityRechargeRateModifier = modifiers.FindModifiers("batteryRegenCoeff").Aggregate(1M, (current, modifier) => current * (decimal)modifier); - decimal diveCapacityModifier = modifiers.FindModifiers("batteryCapacityCoeff").Aggregate(1M, (current, modifier) => current * (decimal)modifier); + decimal diveCapacityRechargeRateModifier = modifiers.FindModifiers("batteryRegenCoeff").Aggregate(1M, (current, modifier) => current * (decimal)modifier); + decimal diveCapacityModifier = modifiers.FindModifiers("batteryCapacityCoeff").Aggregate(1M, (current, modifier) => current * (decimal)modifier); - float repairableDamageModifier = modifiers.FindModifiers("regeneratedHPPartCoef", true).Aggregate(0f, (current, modifier) => current + modifier); + float repairableDamageModifier = modifiers.FindModifiers("regeneratedHPPartCoef", true).Aggregate(0f, (current, modifier) => current + modifier); - var survivability = new SurvivabilityDataContainer - { - HitPoints = (int)hitPoints, - FireDuration = Math.Round(fireDuration, 1), - FireAmount = fireSpots, - FireReduction = Math.Round(fireResistance * 100, 1), - FireDPS = Math.Round(fireDps), - FireTotalDamage = Math.Round(fireTotalDamage), - FloodDuration = Math.Round(floodDuration, 1), - FloodAmount = shipHull.FloodingSpots, - FloodTorpedoProtection = Math.Round(100 - modifiedFloodingCoeff, 1), - FloodDPS = Math.Round(floodDps), - FloodTotalDamage = Math.Round(floodTotalDamage), - DiveCapacity = Math.Round(shipHull.SubBatteryCapacity * diveCapacityModifier, 1), - DiveCapacityRechargeRate = Math.Round(shipHull.SubBatteryRegenRate * diveCapacityRechargeRateModifier, 1), - }; - - foreach (var location in shipHull.HitLocations) + var survivability = new SurvivabilityDataContainer + { + HitPoints = (int)hitPoints, + FireDuration = Math.Round(fireDuration, 1), + FireAmount = fireSpots, + FireReduction = Math.Round(fireResistance * 100, 1), + FireDPS = Math.Round(fireDps), + FireTotalDamage = Math.Round(fireTotalDamage), + FloodDuration = Math.Round(floodDuration, 1), + FloodAmount = shipHull.FloodingSpots, + FloodTorpedoProtection = Math.Round(100 - modifiedFloodingCoeff, 1), + FloodDPS = Math.Round(floodDps), + FloodTotalDamage = Math.Round(floodTotalDamage), + DiveCapacity = Math.Round(shipHull.SubBatteryCapacity * diveCapacityModifier, 1), + DiveCapacityRechargeRate = Math.Round(shipHull.SubBatteryRegenRate * diveCapacityRechargeRateModifier, 1), + }; + + foreach (var location in shipHull.HitLocations) + { + switch (location.Name) { - switch (location.Name) - { - case ShipHitLocation.Citadel: - survivability.CitadelHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; - survivability.CitadelRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); - break; - case ShipHitLocation.Bow: - survivability.BowHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; - survivability.BowRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); - break; - case ShipHitLocation.Stern: - survivability.SternHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; - survivability.SternRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); - break; - case ShipHitLocation.Superstructure: - survivability.SuperstructureHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; - survivability.SuperstructureRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); - break; - case ShipHitLocation.AuxiliaryRooms: - survivability.AuxiliaryRoomsHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; - survivability.AuxiliaryRoomsRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); - break; - case ShipHitLocation.Casemate: - survivability.CasemateHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; - survivability.CasemateRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); - break; - default: - survivability.HullHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; - survivability.HullRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); - break; - } + case ShipHitLocation.Citadel: + survivability.CitadelHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; + survivability.CitadelRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); + break; + case ShipHitLocation.Bow: + survivability.BowHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; + survivability.BowRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); + break; + case ShipHitLocation.Stern: + survivability.SternHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; + survivability.SternRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); + break; + case ShipHitLocation.Superstructure: + survivability.SuperstructureHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; + survivability.SuperstructureRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); + break; + case ShipHitLocation.AuxiliaryRooms: + survivability.AuxiliaryRoomsHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; + survivability.AuxiliaryRoomsRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); + break; + case ShipHitLocation.Casemate: + survivability.CasemateHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; + survivability.CasemateRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); + break; + default: + survivability.HullHp = (int)Math.Ceiling(location.Hp * (survivability.HitPoints / shipHull.Health) / 50) * 50; + survivability.HullRegenRatio = Math.Round((decimal)(location.RepairableDamage + repairableDamageModifier) * 100); + break; } + } - survivability.UpdateDataElements(); + survivability.UpdateDataElements(); - return survivability; - } + return survivability; } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/ConsumableSelector.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/ConsumableSelector.razor index 2557340c3..fe33ce149 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/ConsumableSelector.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/ConsumableSelector.razor @@ -1,6 +1,6 @@ @using WoWsShipBuilder.DataStructures -@using WoWsShipBuilder.DataElements.DataElements @using WoWsShipBuilder.DataContainers +@using WoWsShipBuilder.DataElements @using WoWsShipBuilder.Features.ShipStats.ViewModels @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Metrics diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/SharedFragments.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/SharedFragments.razor index 3a5e69e9b..00d8beeac 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/SharedFragments.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/SharedFragments.razor @@ -1,5 +1,4 @@ -@using WoWsShipBuilder.DataElements.DataElements - +@using WoWsShipBuilder.DataElements @code { // Parameter needs to be named __builder, otherwise compilation will fail. @@ -22,7 +21,7 @@ case KeyValueDataElement element:
@group.localizer.GetAppLocalization(element.Key).Localization - @ConvertValue(element.Value, element.IsValueKey, element.IsValueAppLocalization, group.localizer) + @ConvertValue(element.Value, element.ValueTextKind, group.localizer)
break; case KeyValueUnitDataElement element: @@ -52,7 +51,7 @@ break; case ValueDataElement element: - @ConvertValue(element.Value, element.IsValueKey, element.IsValueAppLocalization, group.localizer) + @ConvertValue(element.Value, element.ValueTextKind, group.localizer) break; case FormattedTextDataElement element: @@ -74,9 +73,14 @@ } } - private static string ConvertValue(string value, bool isValueKey, bool isAppLocalizationKey, ILocalizer localizer) + private static string ConvertValue(string value, DataElementTextKind valueTextKind, ILocalizer localizer) { - return !isValueKey ? value : (isAppLocalizationKey ? localizer.GetAppLocalization(value) : localizer.GetGameLocalization(value)).Localization; + return valueTextKind switch { + DataElementTextKind.Plain => value, + DataElementTextKind.LocalizationKey => localizer.SimpleGameLocalization(value), + DataElementTextKind.AppLocalizationKey => localizer.SimpleAppLocalization(value), + _ => throw new ArgumentOutOfRangeException(nameof(valueTextKind), valueTextKind, "Unknown DataElementTextKind"), + }; } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor index 7ea600172..9eea18651 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor @@ -1,5 +1,4 @@ -@using WoWsShipBuilder.DataElements.DataElements -@using WoWsShipBuilder.DataStructures +@using WoWsShipBuilder.DataStructures @using static WoWsShipBuilder.Features.ShipStats.Components.SharedFragments @using Microsoft.Extensions.Logging.Console @using System.Text diff --git a/WoWsShipBuilder.Common/Features/ShipStats/FormattedTextHelper.cs b/WoWsShipBuilder.Common/Features/ShipStats/FormattedTextHelper.cs index 6ae93b43b..2a3960796 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/FormattedTextHelper.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/FormattedTextHelper.cs @@ -1,5 +1,5 @@ using System.Globalization; -using WoWsShipBuilder.DataElements.DataElements; +using WoWsShipBuilder.DataElements; using WoWsShipBuilder.Infrastructure.Localization; namespace WoWsShipBuilder.Features.ShipStats; @@ -8,17 +8,21 @@ public static class FormattedTextHelper { public static string ConvertFormattedText(FormattedTextDataElement formattedTextDataElement, ILocalizer localizer) { - string text = formattedTextDataElement.Text; - if (formattedTextDataElement.IsTextKey) + string text = formattedTextDataElement.ValueTextKind switch { - text = formattedTextDataElement.IsTextAppLocalization ? localizer.GetAppLocalization(text).Localization : localizer.GetGameLocalization(text).Localization; - } + DataElementTextKind.Plain => formattedTextDataElement.Text, + DataElementTextKind.LocalizationKey => localizer.SimpleGameLocalization(formattedTextDataElement.Text), + DataElementTextKind.AppLocalizationKey => localizer.SimpleAppLocalization(formattedTextDataElement.Text), + _ => throw new NotSupportedException("Invalid value for ValueTextKind"), + }; - IEnumerable values = formattedTextDataElement.Values; - if (formattedTextDataElement.AreValuesKeys) + IEnumerable values = formattedTextDataElement.ArgumentsTextKind switch { - values = formattedTextDataElement.AreValuesAppLocalization ? values.Select(x => localizer.GetAppLocalization(x).Localization) : values.Select(x => localizer.GetGameLocalization(x).Localization); - } + DataElementTextKind.Plain => formattedTextDataElement.Arguments, + DataElementTextKind.LocalizationKey => formattedTextDataElement.Arguments.Select(localizer.SimpleGameLocalization), + DataElementTextKind.AppLocalizationKey => formattedTextDataElement.Arguments.Select(localizer.SimpleAppLocalization), + _ => throw new NotSupportedException("Invalid value for ArgumentsTextKind"), + }; return string.Format(CultureInfo.InvariantCulture, text, values.Cast().ToArray()); } diff --git a/WoWsShipBuilder.Data.Generator.Test/AssertionMethodAttribute.cs b/WoWsShipBuilder.Data.Generator.Test/AssertionMethodAttribute.cs new file mode 100644 index 000000000..c3e23e5dc --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/AssertionMethodAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace WoWsShipBuilder.Data.Generator.Test; + +[AttributeUsage(AttributeTargets.Method)] +public class AssertionMethodAttribute : Attribute +{ +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/DataElementAnalyzerTest.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/DataElementAnalyzerTest.cs new file mode 100644 index 000000000..6ca8d4bd4 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/DataElementAnalyzerTest.cs @@ -0,0 +1,79 @@ +using System.Reflection; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.CSharp.Testing.NUnit; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using WoWsShipBuilder.Data.Generator.DataElementGenerator; +using WoWsShipBuilder.DataElements; + +namespace WoWsShipBuilder.Data.Generator.Test.DataElementAnalyzerTests; + +using Verify = AnalyzerVerifier; + +[TestFixture] +public partial class DataElementAnalyzerTest +{ + [Test] + public async Task Analyze_InvalidDataElementType_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType((DataElementTypes)128)] + public decimal {|SB0001:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [AssertionMethod] + private static CSharpAnalyzerTest CreateTest(string source) + { + const string baseClass = """ + namespace WoWsShipBuilder.DataElements; + + public abstract record DataContainerBase + { + public global::System.Collections.Generic.List DataElements { get; } = new(); + + protected static bool ShouldAdd(object? value) + { + return value switch + { + string strValue => !string.IsNullOrEmpty(strValue), + decimal decValue => decValue != 0, + (decimal min, decimal max) => min > 0 || max > 0, + int intValue => intValue != 0, + _ => false, + }; + } + } + """; + return new() + { + TestCode = source, + TestState = + { + Sources = + { + AttributeHelper.DataElementTypesEnum, + AttributeHelper.DataElementTextKindEnum, + AttributeHelper.DataContainerAttribute, + AttributeHelper.DataElementTypeAttribute, + AttributeHelper.DataElementFilteringAttribute, + baseClass, + }, + ReferenceAssemblies = ReferenceAssemblies.Net.Net70, + AdditionalReferences = { MetadataReference.CreateFromFile(typeof(IDataElement).GetTypeInfo().Assembly.Location) }, + }, + }; + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/FormattedText.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/FormattedText.cs new file mode 100644 index 000000000..72162ebf1 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/FormattedText.cs @@ -0,0 +1,144 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementAnalyzerTests; + +public partial class DataElementAnalyzerTest +{ + [Test] + public async Task AnalyzeFormattedText_AllRequiredParams_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName="Test")] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeFormattedText_ArgumentCollectionNameMissing_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText)] + public decimal {|SB1002:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeFormattedText_TreatArgumentsAsLocalizationSpecified_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = "Test", ArgumentsTextKind = TextKind.LocalizationKey)] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeFormattedText_TreatArgumentsAsAppLocalizationSpecified_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = "Test", ArgumentsTextKind = TextKind.AppLocalizationKey)] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeFormattedText_LocalizationKeyOverrideSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = "Test", LocalizationKeyOverride = "Test")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeFormattedText_UnitKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = "Test", UnitKey = "Test")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeFormattedText_TooltipKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = "Test", TooltipKey = "Test")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Grouped.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Grouped.cs new file mode 100644 index 000000000..bdb277cae --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Grouped.cs @@ -0,0 +1,84 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementAnalyzerTests; + +public partial class DataElementAnalyzerTest +{ + [Test] + public async Task AnalyzeGrouped_SecondaryTypeSpecified_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord: DataContainerBase + { + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Loaders")] + public string Prop1 { get; set; } = default!; + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeGrouped_SecondaryTypeMissing_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord: DataContainerBase + { + [DataElementType(DataElementTypes.Grouped, GroupKey = "Loaders")] + public string {|SB0002:Prop1|} { get; set; } = default!; + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeGrouped_GroupKeyMissing_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord: DataContainerBase + { + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue)] + public string {|SB1001:Prop1|} { get; set; } = default!; + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeGrouped_NoGroupGroupKeyExists_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord: DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue, GroupKey="Test")] + public string {|SB1003:Prop1|} { get; set; } = default!; + } + """; + + await CreateTest(source).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/KeyValue.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/KeyValue.cs new file mode 100644 index 000000000..972720cf7 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/KeyValue.cs @@ -0,0 +1,144 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementAnalyzerTests; + +public partial class DataElementAnalyzerTest +{ + [Test] + public async Task AnalyzeKeyValue_AllRequiredParams_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue)] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValue_LocalizationKeyOverrideSpecified_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue, LocalizationKeyOverride = "Test")] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValue_CollectionNameSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue, ArgumentsCollectionName = "Values")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValue_TreatArgumentsAsLocalizationSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue, ArgumentsTextKind = TextKind.LocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValue_TreatArgumentsAsAppLocalizationSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue, ArgumentsTextKind = TextKind.AppLocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValue_UnitKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue, UnitKey="Test")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValue_TooltipKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue, TooltipKey="Test")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/KeyValueUnit.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/KeyValueUnit.cs new file mode 100644 index 000000000..76fc965fc --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/KeyValueUnit.cs @@ -0,0 +1,184 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementAnalyzerTests; + +public partial class DataElementAnalyzerTest +{ + [Test] + public async Task AnalyzeKeyValueUnit_AllRequiredParams_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Test")] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValueUnit_LocalizationKeyOverrideSpecified_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Test", LocalizationKeyOverride = "Test")] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValueUnit_UnitKeyMissing_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit)] + public decimal {|SB1002:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValueUnit_CollectionNameSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Test", ArgumentsCollectionName = "Values")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValueUnit_TreatArgumentsAsLocalizationSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Test", ArgumentsTextKind = TextKind.LocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValueUnit_TreatArgumentsAsAppLocalizationSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Test", ArgumentsTextKind = TextKind.AppLocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValueUnit_TooltipKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Test", TooltipKey = "Test")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValueUnit_TreatValueAsLocalizationKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Test", ValueTextKind = TextKind.LocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeKeyValueUnit_TreatValueAsAppLocalizationKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Test", ValueTextKind = TextKind.AppLocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Tooltip.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Tooltip.cs new file mode 100644 index 000000000..de80eff14 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Tooltip.cs @@ -0,0 +1,184 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementAnalyzerTests; + +public partial class DataElementAnalyzerTest +{ + [Test] + public async Task AnalyzeTooltip_AllRequiredParams_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "Test")] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeTooltip_TooltipKeyMissing_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip)] + public decimal {|SB1002:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeTooltip_UnitKeySpecified_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "Test", UnitKey = "Test")] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeTooltip_LocalizationKeySpecified_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "Test", LocalizationKeyOverride = "Test")] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeTooltip_CollectionNameSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "Test", ArgumentsCollectionName = "Values")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeTooltip_TreatArgumentsAsLocalizationSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "Test", ArgumentsTextKind = TextKind.LocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeTooltip_TreatArgumentsAsAppLocalizationSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "Test", ArgumentsTextKind = TextKind.AppLocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeTooltip_TreatValueAsLocalizationKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "Test", ValueTextKind = TextKind.LocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeTooltip_TreatValueAsAppLocalizationKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "Test", ValueTextKind = TextKind.AppLocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Value.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Value.cs new file mode 100644 index 000000000..f6c5d1a13 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementAnalyzerTests/Value.cs @@ -0,0 +1,144 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementAnalyzerTests; + +public partial class DataElementAnalyzerTest +{ + [Test] + public async Task AnalyzeValue_AllRequiredParams_NoDiagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Value)] + public decimal Prop1 { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeValue_CollectionNameSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Value, ArgumentsCollectionName = "Values")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeValue_TreatArgumentsAsLocalizationSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Value, ArgumentsTextKind = TextKind.LocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeValue_TreatArgumentsAsAppLocalizationSpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Value, ArgumentsTextKind = TextKind.AppLocalizationKey)] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeValue_UnitKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Value, UnitKey = "Test")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeValue_TooltipKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Value, TooltipKey = "Test")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } + + [Test] + public async Task AnalyzeValue_LocalizationKeySpecified_Diagnostics() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Value, LocalizationKeyOverride = "Test")] + public decimal {|SB1003:Prop1|} { get; set; } + } + """; + + await CreateTest(source).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/DataElementGeneratorTest.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/DataElementGeneratorTest.cs new file mode 100644 index 000000000..45f6ae3c7 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/DataElementGeneratorTest.cs @@ -0,0 +1,58 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using WoWsShipBuilder.Data.Generator.DataElementGenerator; +using WoWsShipBuilder.DataElements; + +namespace WoWsShipBuilder.Data.Generator.Test.DataElementGeneratorTests; + +[TestFixture] +[SuppressMessage("Maintainability", "S2699", Justification = "false-positive since sonarlint does not recognize custom CreateTest method")] +public partial class DataElementGeneratorTest +{ + [AssertionMethod] + private static CSharpSourceGeneratorTest CreateTest(string source, string expected) + { + const string baseClass = """ + namespace WoWsShipBuilder.DataElements; + + public abstract record DataContainerBase + { + public global::System.Collections.Generic.List DataElements { get; } = new(); + + protected static bool ShouldAdd(object? value) + { + return value switch + { + string strValue => !string.IsNullOrEmpty(strValue), + decimal decValue => decValue != 0, + (decimal min, decimal max) => min > 0 || max > 0, + int intValue => intValue != 0, + _ => false, + }; + } + } + """; + return new() + { + TestState = + { + Sources = { baseClass, source }, + GeneratedSources = + { + (typeof(DataElementGenerator.DataElementGenerator), "DataElementTypes.g.cs", AttributeHelper.DataElementTypesEnum), + (typeof(DataElementGenerator.DataElementGenerator), "TextKind.g.cs", AttributeHelper.DataElementTextKindEnum), + (typeof(DataElementGenerator.DataElementGenerator), "DataContainerAttribute.g.cs", AttributeHelper.DataContainerAttribute), + (typeof(DataElementGenerator.DataElementGenerator), "DataElementTypeAttribute.g.cs", AttributeHelper.DataElementTypeAttribute), + (typeof(DataElementGenerator.DataElementGenerator), "DataElementFilteringAttribute.g.cs", AttributeHelper.DataElementFilteringAttribute), + (typeof(DataElementGenerator.DataElementGenerator), "TestRecord.g.cs", expected), + }, + ReferenceAssemblies = ReferenceAssemblies.Net.Net70, + AdditionalReferences = { MetadataReference.CreateFromFile(typeof(IDataElement).GetTypeInfo().Assembly.Location) }, + }, + }; + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/FormattedText.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/FormattedText.cs new file mode 100644 index 000000000..5b538c2a6 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/FormattedText.cs @@ -0,0 +1,319 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementGeneratorTests; + +public partial class DataElementGeneratorTest +{ + [Test] + [Category("FormattedText")] + public async Task GenerateCode_FormattedTextNoLocalization_Success() + { + var source = """ + using System.Collections.Generic; + + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = nameof(TestValues))] + public string Test { get; set; } = default!; + + public List TestValues { get; set; } = new(); + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Test)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.FormattedTextDataElement(this.Test, this.TestValues, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("FormattedText")] + public async Task GenerateCode_FormattedTextValuesLocalization_Success() + { + var source = """ + using System.Collections.Generic; + + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = nameof(TestValues), ArgumentsTextKind = TextKind.LocalizationKey)] + public string Test { get; set; } = default!; + + public List TestValues { get; set; } = new(); + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Test)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.FormattedTextDataElement(this.Test, this.TestValues, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain, global::WoWsShipBuilder.DataElements.DataElementTextKind.LocalizationKey)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("FormattedText")] + public async Task GenerateCode_FormattedTextKeyLocalization_Success() + { + var source = """ + using System.Collections.Generic; + + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = nameof(TestValues), ValueTextKind = TextKind.LocalizationKey)] + public string Test { get; set; } = default!; + + public List TestValues { get; set; } = new(); + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Test)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.FormattedTextDataElement(this.Test, this.TestValues, global::WoWsShipBuilder.DataElements.DataElementTextKind.LocalizationKey, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("FormattedText")] + public async Task GenerateCode_FormattedTextKeyAndValueLocalization_Success() + { + var source = """ + using System.Collections.Generic; + + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = nameof(TestValues), ValueTextKind = TextKind.LocalizationKey, ArgumentsTextKind = TextKind.LocalizationKey)] + public string Test { get; set; } = default!; + + public List TestValues { get; set; } = new(); + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Test)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.FormattedTextDataElement(this.Test, this.TestValues, global::WoWsShipBuilder.DataElements.DataElementTextKind.LocalizationKey, global::WoWsShipBuilder.DataElements.DataElementTextKind.LocalizationKey)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("FormattedText")] + public async Task GenerateCode_FormattedTextValuesAppLocalization_Success() + { + var source = """ + using System.Collections.Generic; + + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = nameof(TestValues), ArgumentsTextKind = TextKind.AppLocalizationKey)] + public string Test { get; set; } = default!; + + public List TestValues { get; set; } = new(); + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Test)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.FormattedTextDataElement(this.Test, this.TestValues, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain, global::WoWsShipBuilder.DataElements.DataElementTextKind.AppLocalizationKey)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("FormattedText")] + public async Task GenerateCode_FormattedTextKeyAppLocalization_Success() + { + var source = """ + using System.Collections.Generic; + + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = nameof(TestValues), ValueTextKind = TextKind.AppLocalizationKey)] + public string Test { get; set; } = default!; + + public List TestValues { get; set; } = new(); + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Test)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.FormattedTextDataElement(this.Test, this.TestValues, global::WoWsShipBuilder.DataElements.DataElementTextKind.AppLocalizationKey, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("FormattedText")] + public async Task GenerateCode_FormattedTextKeyAndValueAppLocalization_Success() + { + var source = """ + using System.Collections.Generic; + + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = nameof(TestValues), ValueTextKind = TextKind.AppLocalizationKey, ArgumentsTextKind = TextKind.AppLocalizationKey)] + public string Test { get; set; } = default!; + + public List TestValues { get; set; } = new(); + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Test)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.FormattedTextDataElement(this.Test, this.TestValues, global::WoWsShipBuilder.DataElements.DataElementTextKind.AppLocalizationKey, global::WoWsShipBuilder.DataElements.DataElementTextKind.AppLocalizationKey)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Grouped.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Grouped.cs new file mode 100644 index 000000000..a81aed6a1 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Grouped.cs @@ -0,0 +1,136 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementGeneratorTests; + +public partial class DataElementGeneratorTest +{ + [Test] + [Category("Grouped")] + public async Task GenerateCode_OneGroupTwoElements_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Loaders")] + public string BowLoaders { get; set; } = default!; + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Loaders")] + public string SternLoaders { get; set; } = default!; + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + var LoadersList = new global::System.Collections.Generic.List(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.BowLoaders)) + { + LoadersList.Add(new global::WoWsShipBuilder.DataElements.KeyValueDataElement("ShipStats_BowLoaders", this.BowLoaders, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.SternLoaders)) + { + LoadersList.Add(new global::WoWsShipBuilder.DataElements.KeyValueDataElement("ShipStats_SternLoaders", this.SternLoaders, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + + if (LoadersList.Count > 0) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.GroupedDataElement("ShipStats_Loaders", LoadersList)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("Grouped")] + public async Task GenerateCode_TwoGroupsMixedOrder_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Group1")] + public string Prop1 { get; set; } = default!; + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Group2")] + public string Prop2 { get; set; } = default!; + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Group1")] + public string Prop3 { get; set; } = default!; + + [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "Group2")] + public string Prop4 { get; set; } = default!; + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + var Group1List = new global::System.Collections.Generic.List(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + Group1List.Add(new global::WoWsShipBuilder.DataElements.KeyValueDataElement("ShipStats_Prop1", this.Prop1, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop3)) + { + Group1List.Add(new global::WoWsShipBuilder.DataElements.KeyValueDataElement("ShipStats_Prop3", this.Prop3, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + + if (Group1List.Count > 0) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.GroupedDataElement("ShipStats_Group1", Group1List)); + } + + var Group2List = new global::System.Collections.Generic.List(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop2)) + { + Group2List.Add(new global::WoWsShipBuilder.DataElements.KeyValueDataElement("ShipStats_Prop2", this.Prop2, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop4)) + { + Group2List.Add(new global::WoWsShipBuilder.DataElements.KeyValueDataElement("ShipStats_Prop4", this.Prop4, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + + if (Group2List.Count > 0) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.GroupedDataElement("ShipStats_Group2", Group2List)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/KeyValue.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/KeyValue.cs new file mode 100644 index 000000000..c5fd55bcb --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/KeyValue.cs @@ -0,0 +1,127 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementGeneratorTests; + +public partial class DataElementGeneratorTest +{ + [Test] + [Category("KeyValue")] + public async Task GenerateCode_KeyValueNoLocalization_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue)] + public decimal Prop1 { get; set; } + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.KeyValueDataElement("ShipStats_Prop1", this.Prop1.ToString(), global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("KeyValue")] + public async Task GenerateCode_KeyValueGameLocalization_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.LocalizationKey)] + public decimal Prop1 { get; set; } + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.KeyValueDataElement("ShipStats_Prop1", this.Prop1.ToString(), global::WoWsShipBuilder.DataElements.DataElementTextKind.LocalizationKey)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("KeyValue")] + public async Task GenerateCode_KeyValueAppLocalization_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.AppLocalizationKey)] + public decimal Prop1 { get; set; } + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.KeyValueDataElement("ShipStats_Prop1", this.Prop1.ToString(), global::WoWsShipBuilder.DataElements.DataElementTextKind.AppLocalizationKey)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/KeyValueUnit.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/KeyValueUnit.cs new file mode 100644 index 000000000..7c1210bce --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/KeyValueUnit.cs @@ -0,0 +1,45 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementGeneratorTests; + +public partial class DataElementGeneratorTest +{ + [Test] + [Category("KeyValueUnit")] + public async Task GenerateCode_SingleKeyValueUnit_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Knots")] + public decimal Prop1 { get; set; } + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.KeyValueUnitDataElement("ShipStats_Prop1", this.Prop1.ToString(), "Unit_Knots")); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Mixed.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Mixed.cs new file mode 100644 index 000000000..8b32892a7 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Mixed.cs @@ -0,0 +1,152 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementGeneratorTests; + +public partial class DataElementGeneratorTest +{ + [Test] + public async Task GenerateCode_EmptyRecord_EmptyMethod() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + public async Task GenerateCode_ElementWithCustomFilter_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "FPM")] + [DataElementFiltering(true, nameof(this.ShouldDisplayTest))] + public decimal TestProperty { get; set; } + + private bool ShouldDisplayTest(object obj) + { + return true; + } + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (ShouldDisplayTest(this.TestProperty)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.KeyValueUnitDataElement("ShipStats_TestProperty", this.TestProperty.ToString(), "Unit_FPM")); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + public async Task GenerateCode_MixedElements_Success() + { + var source = """ + using System.Collections.Generic; + + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.KeyValue, ValueTextKind = TextKind.LocalizationKey)] + public string Prop1 { get; set; } = default!; + + [DataElementType(DataElementTypes.KeyValueUnit, UnitKey="Knots")] + public decimal Prop2 { get; set; } = default!; + + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "TestTooltip")] + public string Prop3 { get; set; } = default!; + + [DataElementType(DataElementTypes.FormattedText, ArgumentsCollectionName = nameof(TestValues))] + public string Prop4 { get; set; } = default!; + + public List TestValues { get; set; } = new(); + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.KeyValueDataElement("ShipStats_Prop1", this.Prop1, global::WoWsShipBuilder.DataElements.DataElementTextKind.LocalizationKey)); + } + + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop2)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.KeyValueUnitDataElement("ShipStats_Prop2", this.Prop2.ToString(), "Unit_Knots")); + } + + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop3)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.TooltipDataElement("ShipStats_Prop3", this.Prop3, "ShipStats_TestTooltip", "")); + } + + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop4)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.FormattedTextDataElement(this.Prop4, this.TestValues, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain, global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Tooltip.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Tooltip.cs new file mode 100644 index 000000000..e101fd47c --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Tooltip.cs @@ -0,0 +1,86 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementGeneratorTests; + +public partial class DataElementGeneratorTest +{ + [Test] + [Category("KeyValueUnit")] + public async Task GenerateCode_Tooltip_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "TestTooltip")] + public decimal Prop1 { get; set; } + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.TooltipDataElement("ShipStats_Prop1", this.Prop1.ToString(), "ShipStats_TestTooltip", "")); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("KeyValueUnit")] + public async Task GenerateCode_TooltipWithUnit_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Tooltip, TooltipKey = "TestTooltip", UnitKey="Knots")] + public decimal Prop1 { get; set; } + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.TooltipDataElement("ShipStats_Prop1", this.Prop1.ToString(), "ShipStats_TestTooltip", "Unit_Knots")); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Value.cs b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Value.cs new file mode 100644 index 000000000..70ef9f202 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/DataElementGeneratorTests/Value.cs @@ -0,0 +1,127 @@ +namespace WoWsShipBuilder.Data.Generator.Test.DataElementGeneratorTests; + +public partial class DataElementGeneratorTest +{ + [Test] + [Category("Value")] + public async Task GenerateCode_ValueNoLocalization_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Value)] + public decimal Prop1 { get; set; } + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.ValueDataElement(this.Prop1.ToString(), global::WoWsShipBuilder.DataElements.DataElementTextKind.Plain)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("Value")] + public async Task GenerateCode_ValueGameLocalization_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Value, ValueTextKind = TextKind.LocalizationKey)] + public decimal Prop1 { get; set; } + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.ValueDataElement(this.Prop1.ToString(), global::WoWsShipBuilder.DataElements.DataElementTextKind.LocalizationKey)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } + + [Test] + [Category("Value")] + public async Task GenerateCode_ValueAppLocalization_Success() + { + var source = """ + using WoWsShipBuilder.DataElements.DataElementAttributes; + using WoWsShipBuilder.DataElements; + + namespace Test; + + [DataContainer] + public partial record TestRecord : DataContainerBase + { + [DataElementType(DataElementTypes.Value, ValueTextKind = TextKind.AppLocalizationKey)] + public decimal Prop1 { get; set; } + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial record TestRecord + { + private void UpdateDataElements() + { + this.DataElements.Clear(); + if (global::WoWsShipBuilder.DataElements.DataContainerBase.ShouldAdd(this.Prop1)) + { + this.DataElements.Add(new global::WoWsShipBuilder.DataElements.ValueDataElement(this.Prop1.ToString(), global::WoWsShipBuilder.DataElements.DataElementTextKind.AppLocalizationKey)); + } + } + } + } + + """; + + await CreateTest(source, expected).RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/PropertyChangedGeneratorTests/PropertyChangedGeneratorTest.cs b/WoWsShipBuilder.Data.Generator.Test/PropertyChangedGeneratorTests/PropertyChangedGeneratorTest.cs new file mode 100644 index 000000000..d802ddf98 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator.Test/PropertyChangedGeneratorTests/PropertyChangedGeneratorTest.cs @@ -0,0 +1,224 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using WoWsShipBuilder.Data.Generator.PropertyChangedGenerator; + +namespace WoWsShipBuilder.Data.Generator.Test.PropertyChangedGeneratorTests; + +[TestFixture] +[SuppressMessage("Maintainability", "S2699", Justification = "false-positive since sonarlint does not recognize RunAsync method from generator test framework")] +public class PropertyChangedGeneratorTest +{ + private const string AttributeClass = """ + namespace WoWsShipBuilder.Infrastructure.Utility; + + [global::System.AttributeUsage(global::System.AttributeTargets.Field)] + public class ObservableAttribute : global::System.Attribute + { + public enum Visibility + { + Private, Protected, Internal, Public, + } + + public Visibility SetterVisibility { get; set; } = Visibility.Public; + + public string[]? Dependants { get; set; } + } + """; + + [Test] + public async Task GenerateCode_NoFields_NoCode() + { + var source = """ + using WoWsShipBuilder.Infrastructure.Utility; + + namespace Test; + + public partial class TestViewModel + { + } + + """; + + await new CSharpSourceGeneratorTest + { + TestState = + { + Sources = { source, AttributeClass }, + }, + }.RunAsync(); + } + + [Test] + public async Task GenerateCode_OneField_Success() + { + var source = """ + #nullable enable + using WoWsShipBuilder.Infrastructure.Utility; + + namespace Test; + + public partial class TestViewModel + { + [Observable] + private string test = default!; + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial class TestViewModel + { + public string Test + { + get => this.test; + set => global::{|CS0400:ReactiveUI|}.IReactiveObjectExtensions.RaiseAndSetIfChanged(this, ref this.test, value); + } + } + } + + """; + + await new CSharpSourceGeneratorTest + { + TestState = + { + Sources = { source, AttributeClass }, + GeneratedSources = { (typeof(PropertyChangedSourceGenerator), "Test.TestViewModel_test.g.cs", expected) }, + }, + }.RunAsync(); + } + + [Test] + public async Task GenerateCode_OneNullableField_Success() + { + var source = """ + #nullable enable + using WoWsShipBuilder.Infrastructure.Utility; + + namespace Test; + + public partial class TestViewModel + { + [Observable] + private string? test; + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial class TestViewModel + { + public string? Test + { + get => this.test; + set => global::{|CS0400:ReactiveUI|}.IReactiveObjectExtensions.RaiseAndSetIfChanged(this, ref this.test, value); + } + } + } + + """; + + await new CSharpSourceGeneratorTest + { + TestState = + { + Sources = { source, AttributeClass }, + GeneratedSources = { (typeof(PropertyChangedSourceGenerator), "Test.TestViewModel_test.g.cs", expected) }, + }, + }.RunAsync(); + } + + [Test] + public async Task GenerateCode_OneNullableFieldValueType_Success() + { + var source = """ + #nullable enable + using WoWsShipBuilder.Infrastructure.Utility; + + namespace Test; + + public partial class TestViewModel + { + [Observable] + private int? test; + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial class TestViewModel + { + public int? Test + { + get => this.test; + set => global::{|CS0400:ReactiveUI|}.IReactiveObjectExtensions.RaiseAndSetIfChanged(this, ref this.test, value); + } + } + } + + """; + + await new CSharpSourceGeneratorTest + { + TestState = + { + Sources = { source, AttributeClass }, + GeneratedSources = { (typeof(PropertyChangedSourceGenerator), "Test.TestViewModel_test.g.cs", expected) }, + }, + }.RunAsync(); + } + + [Test] + public async Task GenerateCode_ListWithNullableReferenceType_Success() + { + var source = """ + #nullable enable + using System.Collections.Generic; + using WoWsShipBuilder.Infrastructure.Utility; + + namespace Test; + + public partial class TestViewModel + { + [Observable] + private List test = default!; + } + """; + + var expected = """ + // + #nullable enable + namespace Test + { + public partial class TestViewModel + { + public global::System.Collections.Generic.List Test + { + get => this.test; + set => global::{|CS0400:ReactiveUI|}.IReactiveObjectExtensions.RaiseAndSetIfChanged(this, ref this.test, value); + } + } + } + + """; + + await new CSharpSourceGeneratorTest + { + TestState = + { + Sources = { source, AttributeClass }, + GeneratedSources = { (typeof(PropertyChangedSourceGenerator), "Test.TestViewModel_test.g.cs", expected) }, + }, + }.RunAsync(); + } +} diff --git a/WoWsShipBuilder.Data.Generator.Test/SourceGeneratorResultTest.cs b/WoWsShipBuilder.Data.Generator.Test/SourceGeneratorResultTest.cs deleted file mode 100644 index 6a2aa998f..000000000 --- a/WoWsShipBuilder.Data.Generator.Test/SourceGeneratorResultTest.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Linq; -using FluentAssertions; -using NUnit.Framework; -using WoWsShipBuilder.Data.Generator.Test.TestStructures; -using WoWsShipBuilder.DataElements.DataElements; - -namespace WoWsShipBuilder.Data.Generator.Test; - -public class SourceGeneratorResultTest -{ - [Test] - public void SingleDataValue_DataElementsNotEmpty() - { - const string testString = "1234test"; - var testRecord = new TestDataUi1 - { - TestValue = testString, - }; - - testRecord.UpdateData(); - - testRecord.DataElements.Should().NotBeEmpty(); - } - - [Test] - public void GroupedValuesSet_DataElementHasGroup() - { - const string testString = "1234test"; - var testRecord = new TestDataUi1 - { - TestGroup1 = testString, - Test2Group1 = testString, - }; - - testRecord.UpdateData(); - - testRecord.DataElements.Should().NotBeEmpty(); - testRecord.DataElements.OfType().Should().HaveCount(1); - var groupedData = testRecord.DataElements.OfType().Single(); - groupedData.Key.Should().BeEquivalentTo("ShipStats_test1"); - groupedData.Children.Should().HaveCount(2); - } -} diff --git a/WoWsShipBuilder.Data.Generator.Test/SourceGeneratorTest.cs b/WoWsShipBuilder.Data.Generator.Test/SourceGeneratorTest.cs deleted file mode 100644 index dc4e36000..000000000 --- a/WoWsShipBuilder.Data.Generator.Test/SourceGeneratorTest.cs +++ /dev/null @@ -1,327 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.IO; -using System.Linq; -using System.Reflection; -using FluentAssertions; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using NUnit.Framework; -using WoWsShipBuilder.DataElements.DataElementAttributes; -using Binder = Microsoft.CSharp.RuntimeBinder.Binder; - -namespace WoWsShipBuilder.Data.Generator.Test; - -[TestFixture] -public class SourceGeneratorTest -{ - [Test] - public void AllTest() - { - var code = @"using WoWsShipBuilder.DataElements.DataElements; -using WoWsShipBuilder.DataElements.DataElementAttributes; - -namespace WoWsShipBuilder.Data.Generator.Test.TestStructures; - -public partial record TestDataUi1 : ProjectileDataContainer -{ - [DataElementType(DataElementTypes.Value)] - public string TestValue { get; init; } = default!; - - [DataElementType(DataElementTypes.KeyValue)] - [DataElementVisibility(false)] - public decimal TestKeyValue { get; init; } - - [DataElementType(DataElementTypes.KeyValue)] - [DataElementVisibility(true, ""TestVisibility"")] - public decimal TestVisibilityCustom { get; init; } - - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = ""mm"")] - public string TestKeyUnitValue { get; init; } = default!; - - [DataElementType(DataElementTypes.Tooltip, TooltipKey = ""testTooltip"")] - public decimal TestTooltipValue { get; init; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = ""test1"")] - public string TestGroup1 { get; init; } = default!; - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = ""test1"")] - public string Test2Group1 { get; init; } = default!; - - public bool TestVisibility(object value) - { - return true; - } -} -"; - _ = VerifyGenerator(code); - } - - [Test] - public void ManeuverabilityDataContainer_NoErrors() - { - var code = """ -using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; -using WoWsShipBuilder.DataStructures; -using WoWsShipBuilder.DataStructures.Ship; -using WoWsShipBuilder.Infrastructure.Utility; - -namespace WoWsShipBuilder.DataContainers; - -public partial record ManeuverabilityDataContainer : DataContainerBase -{ - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Knots")] - public decimal ManeuverabilityMaxSpeed { get; set; } - - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Knots", NameLocalizationKey = "MaxReverseSpeed")] - public decimal ManeuverabilityMaxReverseSpeed { get; set; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxSpeed", UnitKey = "Knots")] - public decimal ManeuverabilitySubsMaxSpeedOnSurface { get; set; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxSpeed", UnitKey = "Knots")] - public decimal ManeuverabilitySubsMaxSpeedAtPeriscope { get; set; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxSpeed", UnitKey = "Knots")] - public decimal ManeuverabilitySubsMaxSpeedAtMaxDepth { get; set; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxReverseSpeed", UnitKey = "Knots", NameLocalizationKey = "ManeuverabilitySubsMaxSpeedOnSurface")] - public decimal ManeuverabilitySubsMaxReverseSpeedOnSurface { get; set; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxReverseSpeed", UnitKey = "Knots", NameLocalizationKey = "ManeuverabilitySubsMaxSpeedAtPeriscope")] - public decimal ManeuverabilitySubsMaxReverseSpeedAtPeriscope { get; set; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxReverseSpeed", UnitKey = "Knots", NameLocalizationKey = "ManeuverabilitySubsMaxSpeedAtMaxDepth")] - public decimal ManeuverabilitySubsMaxReverseSpeedAtMaxDepth { get; set; } - - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "MPS")] - public decimal ManeuverabilitySubsMaxDiveSpeed { get; set; } - - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal ManeuverabilitySubsDivingPlaneShiftTime { get; set; } - - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "S")] - public decimal ManeuverabilityRudderShiftTime { get; set; } - - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "M")] - public decimal ManeuverabilityTurningCircle { get; set; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxSpeedTime", UnitKey = "S")] - public decimal ForwardMaxSpeedTime { get; set; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "MaxSpeedTime", UnitKey = "S")] - public decimal ReverseMaxSpeedTime { get; set; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.Tooltip, GroupKey = "BlastProtection", TooltipKey = "BlastExplanation")] - [DataElementFiltering(false)] - public decimal RudderBlastProtection { get; set; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.Tooltip, GroupKey = "BlastProtection", TooltipKey = "BlastExplanation")] - [DataElementFiltering(false)] - public decimal EngineBlastProtection { get; set; } -} -"""; - var expected = """ -using System; -using System.Collections.Generic; -using WoWsShipBuilder.DataElements.DataElements; - -namespace WoWsShipBuilder.DataContainers; - -#nullable enable -public partial record ManeuverabilityDataContainer -{ - private void UpdateDataElements() - { - DataElements.Clear(); - if (DataContainerBase.ShouldAdd(ManeuverabilityMaxSpeed)) - DataElements.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilityMaxSpeed", ManeuverabilityMaxSpeed.ToString(), "Unit_Knots")); - - if (DataContainerBase.ShouldAdd(ManeuverabilityMaxReverseSpeed)) - DataElements.Add(new KeyValueUnitDataElement("ShipStats_MaxReverseSpeed", ManeuverabilityMaxReverseSpeed.ToString(), "Unit_Knots")); - - var MaxSpeedList = new List(); - if (DataContainerBase.ShouldAdd(ManeuverabilitySubsMaxSpeedOnSurface)) - MaxSpeedList.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilitySubsMaxSpeedOnSurface", ManeuverabilitySubsMaxSpeedOnSurface.ToString(), "Unit_Knots")); - if (DataContainerBase.ShouldAdd(ManeuverabilitySubsMaxSpeedAtPeriscope)) - MaxSpeedList.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilitySubsMaxSpeedAtPeriscope", ManeuverabilitySubsMaxSpeedAtPeriscope.ToString(), "Unit_Knots")); - if (DataContainerBase.ShouldAdd(ManeuverabilitySubsMaxSpeedAtMaxDepth)) - MaxSpeedList.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilitySubsMaxSpeedAtMaxDepth", ManeuverabilitySubsMaxSpeedAtMaxDepth.ToString(), "Unit_Knots")); - if (MaxSpeedList.Count > 0) - DataElements.Add(new GroupedDataElement("ShipStats_MaxSpeed", MaxSpeedList)); - - var MaxReverseSpeedList = new List(); - if (DataContainerBase.ShouldAdd(ManeuverabilitySubsMaxReverseSpeedOnSurface)) - MaxReverseSpeedList.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilitySubsMaxSpeedOnSurface", ManeuverabilitySubsMaxReverseSpeedOnSurface.ToString(), "Unit_Knots")); - if (DataContainerBase.ShouldAdd(ManeuverabilitySubsMaxReverseSpeedAtPeriscope)) - MaxReverseSpeedList.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilitySubsMaxSpeedAtPeriscope", ManeuverabilitySubsMaxReverseSpeedAtPeriscope.ToString(), "Unit_Knots")); - if (DataContainerBase.ShouldAdd(ManeuverabilitySubsMaxReverseSpeedAtMaxDepth)) - MaxReverseSpeedList.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilitySubsMaxSpeedAtMaxDepth", ManeuverabilitySubsMaxReverseSpeedAtMaxDepth.ToString(), "Unit_Knots")); - if (MaxReverseSpeedList.Count > 0) - DataElements.Add(new GroupedDataElement("ShipStats_MaxReverseSpeed", MaxReverseSpeedList)); - - if (DataContainerBase.ShouldAdd(ManeuverabilitySubsMaxDiveSpeed)) - DataElements.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilitySubsMaxDiveSpeed", ManeuverabilitySubsMaxDiveSpeed.ToString(), "Unit_MPS")); - - if (DataContainerBase.ShouldAdd(ManeuverabilitySubsDivingPlaneShiftTime)) - DataElements.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilitySubsDivingPlaneShiftTime", ManeuverabilitySubsDivingPlaneShiftTime.ToString(), "Unit_S")); - - if (DataContainerBase.ShouldAdd(ManeuverabilityRudderShiftTime)) - DataElements.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilityRudderShiftTime", ManeuverabilityRudderShiftTime.ToString(), "Unit_S")); - - if (DataContainerBase.ShouldAdd(ManeuverabilityTurningCircle)) - DataElements.Add(new KeyValueUnitDataElement("ShipStats_ManeuverabilityTurningCircle", ManeuverabilityTurningCircle.ToString(), "Unit_M")); - - var MaxSpeedTimeList = new List(); - if (DataContainerBase.ShouldAdd(ForwardMaxSpeedTime)) - MaxSpeedTimeList.Add(new KeyValueUnitDataElement("ShipStats_ForwardMaxSpeedTime", ForwardMaxSpeedTime.ToString(), "Unit_S")); - if (DataContainerBase.ShouldAdd(ReverseMaxSpeedTime)) - MaxSpeedTimeList.Add(new KeyValueUnitDataElement("ShipStats_ReverseMaxSpeedTime", ReverseMaxSpeedTime.ToString(), "Unit_S")); - if (MaxSpeedTimeList.Count > 0) - DataElements.Add(new GroupedDataElement("ShipStats_MaxSpeedTime", MaxSpeedTimeList)); - - var BlastProtectionList = new List(); - - BlastProtectionList.Add(new TooltipDataElement("ShipStats_RudderBlastProtection", RudderBlastProtection.ToString(), "ShipStats_BlastExplanation", "")); - - BlastProtectionList.Add(new TooltipDataElement("ShipStats_EngineBlastProtection", EngineBlastProtection.ToString(), "ShipStats_BlastExplanation", "")); - if (BlastProtectionList.Count > 0) - DataElements.Add(new GroupedDataElement("ShipStats_BlastProtection", BlastProtectionList)); - } -} -#nullable restore -"""; - - _ = VerifyGenerator(code, expected); - } - - [Test] - public void SingleKeyValueUnitElement_NoErrors() - { - var code = """ -using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; - -namespace WoWsShipBuilder.DataContainers; - -public partial record TestContainer : DataContainerBase -{ - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "Knots")] - public decimal TestProperty { get; set; } -} -"""; - var expected = """ -using System; -using System.Collections.Generic; -using WoWsShipBuilder.DataElements.DataElements; - -namespace WoWsShipBuilder.DataContainers; - -#nullable enable -public partial record TestContainer -{ - private void UpdateDataElements() - { - DataElements.Clear(); - if (DataContainerBase.ShouldAdd(TestProperty)) - DataElements.Add(new KeyValueUnitDataElement("ShipStats_TestProperty", TestProperty.ToString(), "Unit_Knots")); - } -} -#nullable restore -"""; - - _ = VerifyGenerator(code, expected); - } - - [Test] - public void GroupedKeyValueUnitElement_NoErrors() - { - var code = """ -using WoWsShipBuilder.DataElements.DataElementAttributes; -using WoWsShipBuilder.DataElements.DataElements; - -namespace WoWsShipBuilder.DataContainers; - -public partial record TestContainer : DataContainerBase -{ - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValueUnit, GroupKey = "TestGroup", UnitKey = "Knots")] - public decimal TestProperty { get; set; } -} -"""; - var expected = """ -using System; -using System.Collections.Generic; -using WoWsShipBuilder.DataElements.DataElements; - -namespace WoWsShipBuilder.DataContainers; - -#nullable enable -public partial record TestContainer -{ - private void UpdateDataElements() - { - DataElements.Clear(); - - var TestGroupList = new List(); - if (DataContainerBase.ShouldAdd(TestProperty)) - TestGroupList.Add(new KeyValueUnitDataElement("ShipStats_TestProperty", TestProperty.ToString(), "Unit_Knots")); - if (TestGroupList.Count > 0) - DataElements.Add(new GroupedDataElement("ShipStats_TestGroup", TestGroupList)); - - - } -} -#nullable restore -"""; - - _ = VerifyGenerator(code, expected); - } - - private static GeneratorDriverRunResult VerifyGenerator(string source, string generated = "") - { - var baseInput = """ -using WoWsShipBuilder.DataElements.DataElements; - -namespace WoWsShipBuilder.Data.Generator.Test.TestStructures; - -public record ProjectileDataContainer : DataContainerBase; -"""; - - var compilation = CreateCompilation(baseInput, source); - GeneratorDriver driver = CSharpGeneratorDriver.Create(new DataElementSourceGenerator()); - driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out _, out ImmutableArray _); - - var result = driver.GetRunResult(); - result.Diagnostics.Should().BeEmpty(); - - if (!string.IsNullOrEmpty(generated)) - { - var expectedTree = CSharpSyntaxTree.ParseText(generated); - result.GeneratedTrees.Should().Contain(syntaxTree => syntaxTree.IsEquivalentTo(expectedTree, false)); - } - - return result; - } - - private static Compilation CreateCompilation(params string[] source) - { - List syntaxTrees = source.Select(sourceFile => CSharpSyntaxTree.ParseText(sourceFile)).ToList(); - - var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location)!; - return CSharpCompilation.Create("compilation", - syntaxTrees, - new[] - { - MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location), - MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "mscorlib.dll")), - MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.dll")), - MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Core.dll")), - MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Private.CoreLib.dll")), - MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Runtime.dll")), - MetadataReference.CreateFromFile(typeof(DataElementTypeAttribute).GetTypeInfo().Assembly.Location), - }, - new(OutputKind.ConsoleApplication)); - } - -} diff --git a/WoWsShipBuilder.Data.Generator.Test/TestStructures/DataElements.cs b/WoWsShipBuilder.Data.Generator.Test/TestStructures/DataElements.cs deleted file mode 100644 index 1852d99a7..000000000 --- a/WoWsShipBuilder.Data.Generator.Test/TestStructures/DataElements.cs +++ /dev/null @@ -1,5 +0,0 @@ -using WoWsShipBuilder.DataElements.DataElements; - -namespace WoWsShipBuilder.Data.Generator.Test.TestStructures; - -public record ProjectileDataContainer : DataContainerBase; diff --git a/WoWsShipBuilder.Data.Generator.Test/TestStructures/TestDataUi1.cs b/WoWsShipBuilder.Data.Generator.Test/TestStructures/TestDataUi1.cs deleted file mode 100644 index 636b17a96..000000000 --- a/WoWsShipBuilder.Data.Generator.Test/TestStructures/TestDataUi1.cs +++ /dev/null @@ -1,39 +0,0 @@ -using WoWsShipBuilder.DataElements.DataElementAttributes; - -namespace WoWsShipBuilder.Data.Generator.Test.TestStructures; - -public partial record TestDataUi1 : ProjectileDataContainer -{ - [DataElementType(DataElementTypes.Value)] - public string TestValue { get; init; } = default!; - - [DataElementType(DataElementTypes.KeyValue)] - [DataElementFiltering(false)] - public decimal TestKeyValue { get; init; } - - [DataElementType(DataElementTypes.KeyValue)] - [DataElementFiltering(true, "TestVisibility")] - public decimal TestVisibilityCustom { get; init; } - - [DataElementType(DataElementTypes.KeyValueUnit, UnitKey = "mm")] - public string TestKeyUnitValue { get; init; } = default!; - - [DataElementType(DataElementTypes.Tooltip, TooltipKey = "testTooltip")] - public decimal TestTooltipValue { get; init; } - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "test1")] - public string TestGroup1 { get; init; } = default!; - - [DataElementType(DataElementTypes.Grouped | DataElementTypes.KeyValue, GroupKey = "test1")] - public string Test2Group1 { get; init; } = default!; - - public void UpdateData() - { - UpdateDataElements(); - } - - public bool TestVisibility(object value) - { - return true; - } -} diff --git a/WoWsShipBuilder.Data.Generator.Test/WoWsShipBuilder.Data.Generator.Test.csproj b/WoWsShipBuilder.Data.Generator.Test/WoWsShipBuilder.Data.Generator.Test.csproj index 3c170182e..4e9b42c04 100644 --- a/WoWsShipBuilder.Data.Generator.Test/WoWsShipBuilder.Data.Generator.Test.csproj +++ b/WoWsShipBuilder.Data.Generator.Test/WoWsShipBuilder.Data.Generator.Test.csproj @@ -5,13 +5,21 @@ false + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + + + diff --git a/WoWsShipBuilder.Data.Generator/Attributes/AttributeGenerator.cs b/WoWsShipBuilder.Data.Generator/Attributes/AttributeGenerator.cs deleted file mode 100644 index a608d75a3..000000000 --- a/WoWsShipBuilder.Data.Generator/Attributes/AttributeGenerator.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace WoWsShipBuilder.Data.Generator.Attributes; - -public static class AttributeGenerator -{ - - public const string DataElementTypesEnum = @" -namespace WoWsShipBuilder.DataElements.DataElementAttributes; - -[Flags] -public enum DataElementTypes -{ - KeyValue = 1, - KeyValueUnit = 2, - Value = 4, - Grouped = 8, - Tooltip = 16, -} -"; - - public const string DataElementTypeAttribute = @" -using System; - -namespace WoWsShipBuilder.DataElements.DataElementAttributes; - -[AttributeUsage(AttributeTargets.Property)] -public class DataElementTypeAttribute : Attribute -{ - public DataElementTypeAttribute(DataElementTypes type) - { - Type = type; - } - - public DataElementTypes Type { get; } - - public string? UnitKey { get; set; } - - public string? TooltipKey { get; set; } - - public string? GroupKey { get; set; } - - public string[] LocalizationArguments { get; set; } = Array.Empty(); -} -"; - - public const string DataElementVisibilityAttribute = @"using System; - -namespace WoWsShipBuilder.DataElements.DataElementAttributes; - -[AttributeUsage(AttributeTargets.Property)] -public class DataElementVisibilityAttribute : Attribute -{ - public DataElementVisibilityAttribute(bool enableFilterVisibility, string filterMethodName = "") - { - EnableFilterVisibility = enableFilterVisibility; - FilterMethodName = filterMethodName; - } - - public bool EnableFilterVisibility { get; } - - public string FilterMethodName { get; } -}"; -} diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/AttributeHelper.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/AttributeHelper.cs new file mode 100644 index 000000000..1c80e0d8a --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/AttributeHelper.cs @@ -0,0 +1,169 @@ +using Microsoft.CodeAnalysis; + +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator; + +public static class AttributeHelper +{ + public const string AttributeNamespace = "WoWsShipBuilder.DataElements.DataElementAttributes"; + + public const string DataElementTypesEnumName = "DataElementTypes"; + + // language=csharp + public const string DataElementTypesEnum = $$""" + // + #nullable enable + namespace {{AttributeNamespace}}; + + [global::System.Flags] + internal enum {{DataElementTypesEnumName}} + { + KeyValue = 1, + KeyValueUnit = 2, + Value = 4, + Grouped = 8, + Tooltip = 16, + FormattedText = 32, + } + """; + + public const string DataElementTextKindEnumName = "TextKind"; + + // language=csharp + public const string DataElementTextKindEnum = $$""" + // + #nullable enable + namespace {{AttributeNamespace}}; + + /// + /// Specifies how a text value of a property marked by will be interpreted. + /// + internal enum {{DataElementTextKindEnumName}} + { + /// + /// Identifies a plain text value that will be displayed as is. + /// + Plain, + + /// + /// Identifies a text value that will be used as game localization key. + /// + LocalizationKey, + + /// + /// Identifies a text value that will be used as app localization key. + /// + AppLocalizationKey, + } + """; + + public const string DataContainerAttributeName = "DataContainerAttribute"; + + // language=csharp + public const string DataContainerAttribute = $$""" + // + #nullable enable + namespace {{AttributeNamespace}}; + + [global::System.AttributeUsage(global::System.AttributeTargets.Class, Inherited = false)] + internal class {{DataContainerAttributeName}} : global::System.Attribute + { + } + """; + + public const string DataElementTypeAttributeName = "DataElementTypeAttribute"; + + // language=csharp + public const string DataElementTypeAttribute = $$""" + // + #nullable enable + namespace {{AttributeNamespace}}; + + [global::System.AttributeUsage(global::System.AttributeTargets.Property)] + internal class {{DataElementTypeAttributeName}} : global::System.Attribute + { + public {{DataElementTypeAttributeName}}(global::{{AttributeNamespace}}.DataElementTypes type) + { + this.Type = type; + } + + /// + /// Gets the type of the DataElement for the property marked by this attribute. /> + /// + public global::{{AttributeNamespace}}.DataElementTypes Type { get; } + + /// + /// Gets or sets the property name localization key override for the property marked by this attribute.
+ /// Only valid for , , and . + ///
+ public string? LocalizationKeyOverride { get; set; } + + /// + /// Gets or sets the unit localization key for the property marked by this attribute.
+ /// Only valid for and . + ///
+ public string? UnitKey { get; set; } + + /// + /// Gets or sets the tooltip localization key for the property marked by this attribute.
+ /// Only valid for . + ///
+ public string? TooltipKey { get; set; } + + /// + /// Gets or sets the group localization key and identifier for the property marked by this attribute.
+ /// Only valid for . + ///
+ public string? GroupKey { get; set; } + + /// + /// Gets or sets the of the value of the property marked by this attribute.
+ /// Only valid for , and + ///
+ public global::{{AttributeNamespace}}.{{DataElementTextKindEnumName}} ValueTextKind { get; set; } + + /// + /// Gets or set the name of the property containing the list of values that will replace the placeholder. Requires the value of the property marked by this attribute to follow the specifications.
+ /// Only valid for . + ///
+ public string? ArgumentsCollectionName { get; set; } + + /// + /// Gets or sets the of the argument values of the property marked by this attribute.
+ /// Only valid for + ///
+ public global::{{AttributeNamespace}}.{{DataElementTextKindEnumName}} ArgumentsTextKind { get; set; } + } + """; + + public const string DataElementFilteringAttributeName = "DataElementFilteringAttribute"; + + // language=csharp + public const string DataElementFilteringAttribute = $$""" + // + #nullable enable + namespace {{AttributeNamespace}}; + + [global::System.AttributeUsage(global::System.AttributeTargets.Property)] + internal class {{DataElementFilteringAttributeName}} : global::System.Attribute + { + public {{DataElementFilteringAttributeName}}(bool enableFilterVisibility, string filterMethodName = "") + { + this.EnableFilterVisibility = enableFilterVisibility; + this.FilterMethodName = filterMethodName; + } + + public bool EnableFilterVisibility { get; } + + public string FilterMethodName { get; } + } + """; + + public static void GenerateAttributes(IncrementalGeneratorPostInitializationContext context) + { + context.AddSource("DataElementTypes.g.cs", DataElementTypesEnum); + context.AddSource("TextKind.g.cs", DataElementTextKindEnum); + context.AddSource("DataContainerAttribute.g.cs", DataContainerAttribute); + context.AddSource("DataElementTypeAttribute.g.cs", DataElementTypeAttribute); + context.AddSource("DataElementFilteringAttribute.g.cs", DataElementFilteringAttribute); + } +} diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementAnalyzer.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementAnalyzer.cs new file mode 100644 index 000000000..571ac26cb --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementAnalyzer.cs @@ -0,0 +1,256 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; +using WoWsShipBuilder.Data.Generator.Utilities; + +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public class DataElementAnalyzer : DiagnosticAnalyzer +{ + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create( + Rules.InvalidDataElementTypeRule, + Rules.MissingSecondaryDataElementTypeRule, + Rules.GroupKeyMissingRule, + Rules.MissingAttributeParametersRule, + Rules.IncompatibleAttributeParametersRule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterSymbolAction(AnalyzeDataElementProperty, SymbolKind.Property); + } + + private static void AnalyzeDataElementProperty(SymbolAnalysisContext context) + { + var propertySymbol = (IPropertySymbol)context.Symbol; + var dataElementAttribute = propertySymbol.FindAttributeOrDefault($"{AttributeHelper.AttributeNamespace}.{AttributeHelper.DataElementTypeAttributeName}"); + if (dataElementAttribute is null) + { + return; + } + + var dataElementType = (DataElementTypes)dataElementAttribute.ConstructorArguments[0].Value!; + var propertyData = ExtractPropertyData(propertySymbol, dataElementType, dataElementAttribute); + context.CancellationToken.ThrowIfCancellationRequested(); + + if ((dataElementType & DataElementTypes.Grouped) == DataElementTypes.Grouped) + { + CheckGroupedDataElement(context, propertySymbol, dataElementType, dataElementAttribute); + } + else if (propertyData.DisplayOptions.GroupKey is not null) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.IncompatibleAttributeParametersRule, propertySymbol.Locations[0], "GroupKey")); + } + + context.CancellationToken.ThrowIfCancellationRequested(); + switch (dataElementType & ~DataElementTypes.Grouped) + { + case DataElementTypes.KeyValue: + CheckKeyValueDataElement(context, propertySymbol, propertyData); + break; + case DataElementTypes.KeyValueUnit: + CheckKeyValueUnitDataElement(context, propertySymbol, propertyData); + break; + case DataElementTypes.Value: + CheckValueDataElement(context, propertySymbol, propertyData); + break; + case DataElementTypes.Tooltip: + CheckTooltipDataElement(context, propertySymbol, propertyData); + break; + case DataElementTypes.FormattedText: + CheckFormattedTextDataElement(context, propertySymbol, propertyData); + break; + default: + if ((dataElementType & DataElementTypes.Grouped) != DataElementTypes.Grouped) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.InvalidDataElementTypeRule, propertySymbol.Locations[0], dataElementType)); + } + + break; + } + } + + private static void CheckGroupedDataElement(SymbolAnalysisContext context, ISymbol propertySymbol, DataElementTypes dataElementType, AttributeData dataElementAttribute) + { + if ((dataElementType & ~DataElementTypes.Grouped) == 0) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.MissingSecondaryDataElementTypeRule, propertySymbol.Locations[0])); + } + + if (dataElementAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "GroupKey").Value.Value is null) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.GroupKeyMissingRule, propertySymbol.Locations[0])); + } + } + + private static void CheckKeyValueDataElement(SymbolAnalysisContext context, ISymbol propertySymbol, SinglePropertyData propertyData) + { + var incompatibleParameters = new List(); + + if (propertyData.FormattedTextData.ArgumentsCollectionName is not null) + { + incompatibleParameters.Add("ArgumentsCollectionName"); + } + + if (propertyData.FormattedTextData.ArgumentsTextKind != TextKind.Plain) + { + incompatibleParameters.Add("ArgumentsTextKind"); + } + + if (propertyData.DisplayOptions.UnitKey is not null) + { + incompatibleParameters.Add("UnitKey"); + } + + if (propertyData.DisplayOptions.TooltipKey is not null) + { + incompatibleParameters.Add("TooltipKey"); + } + + if (incompatibleParameters.Count > 0) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.IncompatibleAttributeParametersRule, propertySymbol.Locations[0], string.Join(", ", incompatibleParameters))); + } + } + + private static void CheckKeyValueUnitDataElement(SymbolAnalysisContext context, ISymbol propertySymbol, SinglePropertyData propertyData) + { + var errors = new List(); + + if (propertyData.FormattedTextData.ArgumentsCollectionName is not null) + { + errors.Add("ArgumentsCollectionName"); + } + + if (propertyData.FormattedTextData.ArgumentsTextKind != TextKind.Plain) + { + errors.Add("ArgumentsTextKind"); + } + + if (propertyData.DisplayOptions.TooltipKey is not null) + { + errors.Add("TooltipKey"); + } + + if (propertyData.DisplayOptions.ValueTextKind != TextKind.Plain) + { + errors.Add("ValueTextKind"); + } + + if (errors.Count > 0) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.IncompatibleAttributeParametersRule, propertySymbol.Locations[0], string.Join(", ", errors))); + } + + if (string.IsNullOrEmpty(propertyData.DisplayOptions.UnitKey)) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.MissingAttributeParametersRule, propertySymbol.Locations[0], "UnitKey")); + } + } + + private static void CheckValueDataElement(SymbolAnalysisContext context, ISymbol propertySymbol, SinglePropertyData propertyData) + { + var incompatibleParameters = new List(); + + if (propertyData.FormattedTextData.ArgumentsCollectionName is not null) + { + incompatibleParameters.Add("ArgumentsCollectionName"); + } + + if (propertyData.FormattedTextData.ArgumentsTextKind != TextKind.Plain) + { + incompatibleParameters.Add("ArgumentsTextKind"); + } + + if (propertyData.DisplayOptions.UnitKey is not null) + { + incompatibleParameters.Add("UnitKey"); + } + + if (propertyData.DisplayOptions.TooltipKey is not null) + { + incompatibleParameters.Add("TooltipKey"); + } + + if (!propertyData.DisplayOptions.LocalizationKey.Equals(propertySymbol.Name)) + { + incompatibleParameters.Add("LocalizationKeyOverride"); + } + + if (incompatibleParameters.Count > 0) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.IncompatibleAttributeParametersRule, propertySymbol.Locations[0], string.Join(", ", incompatibleParameters))); + } + } + + private static void CheckTooltipDataElement(SymbolAnalysisContext context, ISymbol propertySymbol, SinglePropertyData propertyData) + { + var errors = new List(); + + if (propertyData.FormattedTextData.ArgumentsCollectionName is not null) + { + errors.Add("ArgumentsCollectionName"); + } + + if (propertyData.FormattedTextData.ArgumentsTextKind != TextKind.Plain) + { + errors.Add("ArgumentsTextKind"); + } + + if (propertyData.DisplayOptions.ValueTextKind != TextKind.Plain) + { + errors.Add("ValueTextKind"); + } + + if (errors.Count > 0) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.IncompatibleAttributeParametersRule, propertySymbol.Locations[0], string.Join(", ", errors))); + } + + if (string.IsNullOrEmpty(propertyData.DisplayOptions.TooltipKey)) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.MissingAttributeParametersRule, propertySymbol.Locations[0], "TooltipKey")); + } + } + + private static void CheckFormattedTextDataElement(SymbolAnalysisContext context, ISymbol propertySymbol, SinglePropertyData propertyData) + { + var errors = new List(); + + if (propertyData.DisplayOptions.UnitKey is not null) + { + errors.Add("UnitKey"); + } + + if (propertyData.DisplayOptions.TooltipKey is not null) + { + errors.Add("TooltipKey"); + } + + if (!propertyData.DisplayOptions.LocalizationKey.Equals(propertySymbol.Name)) + { + errors.Add("LocalizationKeyOverride"); + } + + if (errors.Count > 0) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.IncompatibleAttributeParametersRule, propertySymbol.Locations[0], string.Join(", ", errors))); + } + + if (string.IsNullOrEmpty(propertyData.FormattedTextData.ArgumentsCollectionName)) + { + context.ReportDiagnostic(Diagnostic.Create(Rules.MissingAttributeParametersRule, propertySymbol.Locations[0], "ArgumentsCollectionName")); + } + } + + private static SinglePropertyData ExtractPropertyData(IPropertySymbol propertySymbol, DataElementTypes dataElementType, AttributeData dataElementAttribute) + { + return new(propertySymbol.Name, propertySymbol.Type.SpecialType == SpecialType.System_String, propertySymbol.NullableAnnotation == NullableAnnotation.Annotated, dataElementType, PropertyHelper.ExtractDisplayOptions(propertySymbol, dataElementAttribute), PropertyHelper.ExtractFilterOptions(propertySymbol), PropertyHelper.ExtractFormattedTextOptions(dataElementAttribute), 0); + } +} diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementGenerator.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementGenerator.cs new file mode 100644 index 000000000..00c6556a1 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementGenerator.cs @@ -0,0 +1,190 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; +using WoWsShipBuilder.Data.Generator.Utilities; + +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator; + +[Generator(LanguageNames.CSharp)] +public class DataElementGenerator : IIncrementalGenerator +{ + private const string DataContainerAttributeFullName = $"{AttributeHelper.AttributeNamespace}.{AttributeHelper.DataContainerAttributeName}"; + private const string DataElementAttributeFullName = $"{AttributeHelper.AttributeNamespace}.{AttributeHelper.DataElementTypeAttributeName}"; + private const string DataElementNamespace = "global::WoWsShipBuilder.DataElements"; + private const string DataElementsCollectionName = "this.DataElements"; + + public void Initialize(IncrementalGeneratorInitializationContext context) + { + context.RegisterPostInitializationOutput(AttributeHelper.GenerateAttributes); + var model = context.SyntaxProvider + .ForAttributeWithMetadataName(DataContainerAttributeFullName, CouldBeDataContainer, ComputeRawContainerData) + .Select(ExtractPropertyGroups); + + context.RegisterSourceOutput(model, GenerateSourceCode); + } + + private static bool CouldBeDataContainer(SyntaxNode syntaxNode, CancellationToken token) + { + token.ThrowIfCancellationRequested(); + return syntaxNode is RecordDeclarationSyntax typeDeclarationSyntax && typeDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)); + } + + private static RawContainerData ComputeRawContainerData(GeneratorAttributeSyntaxContext context, CancellationToken token) + { + var recordSymbol = (INamedTypeSymbol)context.TargetSymbol; + token.ThrowIfCancellationRequested(); + var name = recordSymbol.Name; + var dataNamespace = recordSymbol.ContainingNamespace.ToDisplayString(); + var properties = recordSymbol.GetMembers() + .OfType() + .Where(prop => prop.HasAttributeWithFullName(DataElementAttributeFullName)) + .Select(RefineProperty) + .ToEquatableArray(); + + token.ThrowIfCancellationRequested(); + return new(name, dataNamespace, properties); + } + + private static SinglePropertyData RefineProperty(IPropertySymbol propertySymbol, int index) + { + var dataElementAttribute = propertySymbol.FindAttribute(DataElementAttributeFullName); + var dataElementType = (DataElementTypes)dataElementAttribute.ConstructorArguments[0].Value!; + + return new(propertySymbol.Name, propertySymbol.Type.SpecialType == SpecialType.System_String, propertySymbol.NullableAnnotation == NullableAnnotation.Annotated, dataElementType, PropertyHelper.ExtractDisplayOptions(propertySymbol, dataElementAttribute), PropertyHelper.ExtractFilterOptions(propertySymbol), PropertyHelper.ExtractFormattedTextOptions(dataElementAttribute), index); + } + + private static ContainerData ExtractPropertyGroups(RawContainerData rawContainerData, CancellationToken token) + { + token.ThrowIfCancellationRequested(); + IEnumerable propertyGroups = rawContainerData.Properties + .Where(prop => (prop.DataElementType & DataElementTypes.Grouped) == DataElementTypes.Grouped) + .GroupBy(prop => prop.DisplayOptions.GroupKey!) + .Select(CreatePropertyGroup) + .Select(groupData => new PropertyData(null, groupData, groupData.DeclarationIndex)); + token.ThrowIfCancellationRequested(); + + var newProperties = rawContainerData.Properties + .Where(prop => prop.DisplayOptions.GroupKey is null) + .Select(p => new PropertyData(p, null, p.DeclarationIndex)) + .Concat(propertyGroups) + .OrderBy(p => p.DeclarationIndex) + .ToEquatableArray(); + + token.ThrowIfCancellationRequested(); + return new(rawContainerData.ContainerName, rawContainerData.Namespace, newProperties.ToEquatableArray()); + } + + private static GroupPropertyData CreatePropertyGroup(IGrouping grouping) + { + var children = grouping.Select(prop => prop with { DataElementType = prop.DataElementType & ~DataElementTypes.Grouped }).ToEquatableArray(); + return new(grouping.Key, children, children[0].DeclarationIndex); + } + + private static void GenerateSourceCode(SourceProductionContext context, ContainerData containerData) + { + var builder = new SourceBuilder(); + builder.Line("// "); + builder.Line("#nullable enable"); + using (builder.Namespace(containerData.Namespace)) + { + using (builder.Record(containerData.ContainerName)) + { + using (builder.Block("private void UpdateDataElements()")) + { + GenerateUpdateMethodContent(builder, containerData); + } + } + } + + context.AddSource($"{containerData.ContainerName}.g.cs", builder.ToString()); + } + + private static void GenerateUpdateMethodContent(SourceBuilder builder, ContainerData containerData) + { + builder.Line("this.DataElements.Clear();"); + + foreach (var property in containerData.Properties) + { + if (property.SinglePropertyData is { } singleProperty) + { + GeneratePropertyCode(builder, singleProperty); + } + else if (property.GroupPropertyData is { } propertyGroup) + { + var listName = $"{propertyGroup.GroupName}List"; + builder.Line($"var {listName} = new global::System.Collections.Generic.List<{DataElementNamespace}.IDataElement>();"); + foreach (var childProperty in propertyGroup.Properties) + { + GenerateGroupedPropertyCode(builder, childProperty, listName); + } + + using (builder.Block($"if ({listName}.Count > 0)")) + { + builder.Line($"{DataElementsCollectionName}.Add(new {DataElementNamespace}.GroupedDataElement(\"ShipStats_{propertyGroup.GroupName}\", {listName}));"); + } + } + } + } + + private static void GenerateGroupedPropertyCode(SourceBuilder builder, SinglePropertyData property, string listName) + { + if (property.PropertyFilter.IsEnabled) + { + var filterMethodName = property.PropertyFilter.FilterMethodName; + using (builder.Block($"if ({filterMethodName}(this.{property.Name}))")) + { + builder.Line($"{listName}.Add({GenerateDataElementCreationCode(property)});"); + } + } + else + { + builder.Line($"{listName}.Add({GenerateDataElementCreationCode(property)});"); + } + } + + private static void GeneratePropertyCode(SourceBuilder builder, SinglePropertyData property) + { + if (property.PropertyFilter.IsEnabled) + { + var filterMethodName = property.PropertyFilter.FilterMethodName; + using (builder.Block($"if ({filterMethodName}(this.{property.Name}))")) + { + builder.Line($"{DataElementsCollectionName}.Add({GenerateDataElementCreationCode(property)});"); + } + } + else + { + builder.Line($"{DataElementsCollectionName}.Add({GenerateDataElementCreationCode(property)});"); + } + } + + private static string GenerateDataElementCreationCode(SinglePropertyData propertyData) + { + return propertyData.DataElementType switch + { + DataElementTypes.Value => $"new {DataElementNamespace}.ValueDataElement({GeneratePropertyAccess(propertyData)}, {DataElementNamespace}.DataElementTextKind.{propertyData.DisplayOptions.ValueTextKind})", + DataElementTypes.KeyValue => $$"""new {{DataElementNamespace}}.KeyValueDataElement("ShipStats_{{propertyData.DisplayOptions.LocalizationKey}}", {{GeneratePropertyAccess(propertyData)}}, {{DataElementNamespace}}.DataElementTextKind.{{propertyData.DisplayOptions.ValueTextKind}})""", + DataElementTypes.KeyValueUnit => $"""new {DataElementNamespace}.KeyValueUnitDataElement("ShipStats_{propertyData.DisplayOptions.LocalizationKey}", {GeneratePropertyAccess(propertyData)}, "Unit_{propertyData.DisplayOptions.UnitKey}")""", + DataElementTypes.FormattedText => $"new {DataElementNamespace}.FormattedTextDataElement({GeneratePropertyAccess(propertyData)}, this.{propertyData.FormattedTextData.ArgumentsCollectionName}, {DataElementNamespace}.DataElementTextKind.{propertyData.DisplayOptions.ValueTextKind}, {DataElementNamespace}.DataElementTextKind.{propertyData.FormattedTextData.ArgumentsTextKind})", + DataElementTypes.Tooltip => $"""new {DataElementNamespace}.TooltipDataElement("ShipStats_{propertyData.DisplayOptions.LocalizationKey}", {GeneratePropertyAccess(propertyData)}, "ShipStats_{propertyData.DisplayOptions.TooltipKey}", "{ComputeNullableUnitValue(propertyData.DisplayOptions)}")""", + _ => string.Empty, + }; + } + + private static string ComputeNullableUnitValue(PropertyDisplayOptions displayOptions) => displayOptions.UnitKey is not null ? $"Unit_{displayOptions.UnitKey}" : string.Empty; + + private static string GeneratePropertyAccess(SinglePropertyData propertyData) + { + return propertyData switch + { + { IsString: true, IsNullable: false } => $"this.{propertyData.Name}", + { IsString: true, IsNullable: true } => $"this.{propertyData.Name} ?? \"null\"", + { IsString: false, IsNullable: false } => $"this.{propertyData.Name}.ToString()", + { IsString: false, IsNullable: true } => $"this.{propertyData.Name}?.ToString() ?? \"null\"", + }; + } +} diff --git a/WoWsShipBuilder.Data.Generator/Internals/DataElementTypes.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementTypes.cs similarity index 73% rename from WoWsShipBuilder.Data.Generator/Internals/DataElementTypes.cs rename to WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementTypes.cs index b9fbd147b..46b15036b 100644 --- a/WoWsShipBuilder.Data.Generator/Internals/DataElementTypes.cs +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/DataElementTypes.cs @@ -1,6 +1,6 @@ using System; -namespace WoWsShipBuilder.Data.Generator.Internals; +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator; [Flags] internal enum DataElementTypes diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/ContainerData.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/ContainerData.cs new file mode 100644 index 000000000..f296d55b5 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/ContainerData.cs @@ -0,0 +1,5 @@ +using WoWsShipBuilder.Data.Generator.Utilities; + +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; + +internal sealed record ContainerData(string ContainerName, string Namespace, EquatableArray Properties); diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/FormattedTextData.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/FormattedTextData.cs new file mode 100644 index 000000000..9d9c804d3 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/FormattedTextData.cs @@ -0,0 +1,3 @@ +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; + +internal sealed record FormattedTextData(string? ArgumentsCollectionName, TextKind ArgumentsTextKind); diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/GroupPropertyData.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/GroupPropertyData.cs new file mode 100644 index 000000000..4c8f596d9 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/GroupPropertyData.cs @@ -0,0 +1,6 @@ +using WoWsShipBuilder.Data.Generator.Utilities; + +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; + +internal sealed record GroupPropertyData(string GroupName, EquatableArray Properties, int DeclarationIndex); + diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyData.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyData.cs new file mode 100644 index 000000000..554d07f42 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyData.cs @@ -0,0 +1,3 @@ +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; + +internal sealed record PropertyData(SinglePropertyData? SinglePropertyData, GroupPropertyData? GroupPropertyData, int DeclarationIndex); diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyDisplayOptions.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyDisplayOptions.cs new file mode 100644 index 000000000..4659f9e49 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyDisplayOptions.cs @@ -0,0 +1,3 @@ +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; + +internal sealed record PropertyDisplayOptions(string? UnitKey, string LocalizationKey, string? TooltipKey, string? GroupKey, TextKind ValueTextKind); diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyFilter.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyFilter.cs new file mode 100644 index 000000000..880ce1c34 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/PropertyFilter.cs @@ -0,0 +1,3 @@ +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; + +internal sealed record PropertyFilter(bool IsEnabled, string FilterMethodName); diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/RawContainerData.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/RawContainerData.cs new file mode 100644 index 000000000..b41a93b6c --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/RawContainerData.cs @@ -0,0 +1,5 @@ +using WoWsShipBuilder.Data.Generator.Utilities; + +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; + +internal sealed record RawContainerData(string ContainerName, string Namespace, EquatableArray Properties); diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/SinglePropertyData.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/SinglePropertyData.cs new file mode 100644 index 000000000..a418b9e28 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Model/SinglePropertyData.cs @@ -0,0 +1,3 @@ +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; + +internal sealed record SinglePropertyData(string Name, bool IsString, bool IsNullable, DataElementTypes DataElementType, PropertyDisplayOptions DisplayOptions, PropertyFilter PropertyFilter, FormattedTextData FormattedTextData, int DeclarationIndex); diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/PropertyHelper.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/PropertyHelper.cs new file mode 100644 index 000000000..d15c2a3dd --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/PropertyHelper.cs @@ -0,0 +1,41 @@ +using System.Linq; +using Microsoft.CodeAnalysis; +using WoWsShipBuilder.Data.Generator.DataElementGenerator.Model; +using WoWsShipBuilder.Data.Generator.Utilities; + +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator; + +internal static class PropertyHelper +{ + private const string DataElementNamespace = "global::WoWsShipBuilder.DataElements"; + + public static FormattedTextData ExtractFormattedTextOptions(AttributeData dataElementAttribute) + { + return new( + dataElementAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "ArgumentsCollectionName").Value.Value?.ToString(), + (TextKind)(dataElementAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "ArgumentsTextKind").Value.Value ?? TextKind.Plain)); + } + + public static PropertyDisplayOptions ExtractDisplayOptions(ISymbol propertySymbol, AttributeData dataElementAttribute) + { + return new( + dataElementAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "UnitKey").Value.Value?.ToString(), + dataElementAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "LocalizationKeyOverride").Value.Value?.ToString() ?? propertySymbol.Name, + dataElementAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "TooltipKey").Value.Value?.ToString(), + dataElementAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "GroupKey").Value.Value?.ToString(), + (TextKind)(dataElementAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "ValueTextKind").Value.Value ?? TextKind.Plain)); + } + + public static PropertyFilter ExtractFilterOptions(IPropertySymbol propertySymbol) + { + var filterAttribute = propertySymbol.FindAttributeOrDefault("WoWsShipBuilder.DataElements.DataElementAttributes.DataElementFilteringAttribute"); + if (filterAttribute is null) + { + return new(true, $"{DataElementNamespace}.DataContainerBase.ShouldAdd"); + } + + var isEnabled = (bool)filterAttribute.ConstructorArguments[0].Value!; + var filterMethodName = filterAttribute.ConstructorArguments[1].Value?.ToString() ?? $"{DataElementNamespace}.DataContainerBase.ShouldAdd"; + return new(isEnabled, filterMethodName); + } +} diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/Rules.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Rules.cs new file mode 100644 index 000000000..e6590f6be --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/Rules.cs @@ -0,0 +1,58 @@ +using Microsoft.CodeAnalysis; + +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator; + +internal static class Rules +{ + public const string DataElementCategory = "DataElement"; + + public const string InvalidDataElementTypeId = "SB0001"; + + public const string MissingSecondaryDataElementTypeId = "SB0002"; + + public const string GroupKeyMissingId = "SB1001"; + + public const string MissingAttributeParametersId = "SB1002"; + + public const string IncompatibleAttributeParametersId = "SB1003"; + + public static readonly DiagnosticDescriptor InvalidDataElementTypeRule = new( + id: InvalidDataElementTypeId, + title: "Invalid DataElementType", + messageFormat: "The specified DataElementType is not valid: {0}", + category: DataElementCategory, + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor MissingSecondaryDataElementTypeRule = new( + id: MissingSecondaryDataElementTypeId, + title: "Missing DataElementType specification", + messageFormat: "When using DataElementTypes.Grouped, a second type must be specified", + category: DataElementCategory, + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor GroupKeyMissingRule = new( + id: GroupKeyMissingId, + title: "Missing GroupKey", + messageFormat: "When using DataElementTypes.Grouped, a GroupKey must be specified", + category: DataElementCategory, + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor MissingAttributeParametersRule = new( + id: MissingAttributeParametersId, + title: "Missing attribute parameters", + messageFormat: "The following attribute parameters are required with the specified DataElementType but not specified: {0}", + category: DataElementCategory, + DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor IncompatibleAttributeParametersRule = new( + id: IncompatibleAttributeParametersId, + title: "Incompatible attribute parameters", + messageFormat: "The following attribute parameters are incompatible with the specified DataElementType: {0}", + category: DataElementCategory, + DiagnosticSeverity.Warning, + isEnabledByDefault: true); +} diff --git a/WoWsShipBuilder.Data.Generator/DataElementGenerator/TextKind.cs b/WoWsShipBuilder.Data.Generator/DataElementGenerator/TextKind.cs new file mode 100644 index 000000000..7433c5d63 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/DataElementGenerator/TextKind.cs @@ -0,0 +1,8 @@ +namespace WoWsShipBuilder.Data.Generator.DataElementGenerator; + +internal enum TextKind +{ + Plain, + LocalizationKey, + AppLocalizationKey, +} diff --git a/WoWsShipBuilder.Data.Generator/DataElementSourceGenerator.cs b/WoWsShipBuilder.Data.Generator/DataElementSourceGenerator.cs deleted file mode 100644 index fbbed4346..000000000 --- a/WoWsShipBuilder.Data.Generator/DataElementSourceGenerator.cs +++ /dev/null @@ -1,445 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Text; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; -using WoWsShipBuilder.Data.Generator.Attributes; -using WoWsShipBuilder.Data.Generator.Internals; - -namespace WoWsShipBuilder.Data.Generator; - -[Generator] -public class DataElementSourceGenerator : IIncrementalGenerator -{ - private const string DataContainerBaseName = "DataContainerBase"; - private const string ProjectileDataContainer = "ProjectileDataContainer"; - private const string GeneratedMethodName = "UpdateDataElements"; - private const string DataElementCollectionName = "DataElements"; - private const string Indentation = " "; - private const string IfIndentation = " "; - - private static readonly DiagnosticDescriptor MissingAttributeError = new(id: "SB001", - title: "A required secondary attribute is missing", - messageFormat: "Couldn't find the required attribute property {0} for the DataElement type {1}", - category: "Generator", - DiagnosticSeverity.Error, - isEnabledByDefault: true); - - private static readonly DiagnosticDescriptor InvalidTypeEnumError = new(id: "SB002", - title: "The enum type is invalid", - messageFormat: "The enum type for the property {0} doesn't exist", - category: "Generator", - DiagnosticSeverity.Error, - isEnabledByDefault: true); - - private static readonly DiagnosticDescriptor GenerationError = new(id: "SB003", - title: "Error during source generation", - messageFormat: "There was an exception during source generation: {0}", - category: "Generator", - DiagnosticSeverity.Error, - isEnabledByDefault: true); - - private static readonly DiagnosticDescriptor TooManyIterationsError = new(id: "SB004", - title: "Too many iterations", - messageFormat: "Too many iteration for the grouped data element", - category: "Generator", - DiagnosticSeverity.Error, - isEnabledByDefault: true); - - private static readonly DiagnosticDescriptor GroupedMissingDefinitionError = new(id: "SB004", - title: "Grouped require secondary type definition", - messageFormat: "The property {0} is missing its own type definition. Add a type definition with the use of |.", - category: "Generator", - DiagnosticSeverity.Error, - isEnabledByDefault: true); - - public void Initialize(IncrementalGeneratorInitializationContext context) - { - var dataClasses = context.SyntaxProvider.CreateSyntaxProvider(IsDataContainerRecord, GetRecordTypeOrNull) - .Where(type => type is not null) - .Select(GetPropertiesWithAttributes) - .Where(x => x.properties.Count > 0) - .Collect(); - - context.RegisterSourceOutput(dataClasses, GenerateCode); - } - - private static bool IsDataContainerRecord(SyntaxNode syntaxNode, CancellationToken token) - { - token.ThrowIfCancellationRequested(); - if (syntaxNode is not RecordDeclarationSyntax recordSyntax) - { - return false; - } - - bool baseName = recordSyntax.BaseList?.Types.ToString().Contains(DataContainerBaseName) ?? false; - bool projectileDataContainerName = recordSyntax.BaseList?.Types.ToString().Contains(ProjectileDataContainer) ?? false; - return recordSyntax.Modifiers.ToString().Contains("partial") && (baseName || projectileDataContainerName); - } - - private static ITypeSymbol? GetRecordTypeOrNull(GeneratorSyntaxContext context, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - var recordSyntax = (RecordDeclarationSyntax)context.Node; - return context.SemanticModel.GetDeclaredSymbol(recordSyntax); - } - - private static (string className, string classNamespace, List properties) GetPropertiesWithAttributes(ITypeSymbol? symbol, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - var name = symbol!.Name; - var dataNamespace = symbol.ContainingNamespace.ToDisplayString(); - var properties = symbol.GetMembers().OfType().Where(prop => prop.GetAttributes().Any(attr => attr.AttributeClass!.Name == nameof(AttributeGenerator.DataElementTypeAttribute))).ToList(); - return (name, dataNamespace, properties); - } - - private static void GenerateCode(SourceProductionContext context, ImmutableArray<(string className, string classNamespace, List properties)> dataRecords) - { - // context.AddSource("test.g.cs", SourceText.From("//" + string.Join(" - ",dataRecords.Select(x => x.Name)), Encoding.UTF8)); - foreach (var dataRecord in dataRecords) - { - var properties = dataRecord.properties; - var classStart = $@" -using System; -using System.Collections.Generic; -using WoWsShipBuilder.DataElements.DataElements; - -namespace {dataRecord.classNamespace}; - -#nullable enable -public partial record {dataRecord.className} -{{ - private void {GeneratedMethodName}() - {{ - {DataElementCollectionName}.Clear(); -"; - const string classEnd = @" - } -} -#nullable restore -"; - var builder = new StringBuilder(classStart); - - while (properties.Any()) - { - var prop = properties.First(); - var propertyAttributes = prop.GetAttributes(); - - var typeAttribute = propertyAttributes.FirstOrDefault(); - if (typeAttribute is not null) - { - if (typeAttribute.ConstructorArguments.IsEmpty) - { - context.ReportDiagnostic(Diagnostic.Create(InvalidTypeEnumError, typeAttribute.ApplicationSyntaxReference!.GetSyntax().GetLocation(), prop.Name)); - properties.RemoveAt(0); - continue; - } - - try - { - var (code, additionalIndexes) = GenerateCode(context, typeAttribute, prop, propertyAttributes, properties, DataElementCollectionName, 0); - builder.Append(code); - builder.AppendLine(); - foreach (var index in additionalIndexes.OrderByDescending(x => x)) - { - properties.RemoveAt(index); - } - } - catch (Exception e) - { - context.ReportDiagnostic(Diagnostic.Create(GenerationError, typeAttribute.ApplicationSyntaxReference!.GetSyntax().GetLocation(), e.Message + " - " + e.TargetSite)); - break; - } - } - } - - builder.Append(classEnd); - context.AddSource($"{dataRecord.className}.g.cs", SourceText.From(builder.ToString(), Encoding.UTF8)); - } - } - - private static (string code, List additionalIndexes) GenerateCode(SourceProductionContext context, AttributeData typeAttribute, IPropertySymbol currentProp, ImmutableArray propertyAttributes, List properties, string collectionName, int iterationCounter, bool isGroup = false) - { - var additionalPropIndexes = new List(); - if (iterationCounter > 10) - { - context.ReportDiagnostic(Diagnostic.Create(TooManyIterationsError, typeAttribute.ApplicationSyntaxReference!.GetSyntax().GetLocation())); - additionalPropIndexes.Add(0); - return("", additionalPropIndexes); - } - - var builder = new StringBuilder(); - - var type = (DataElementTypes)typeAttribute.ConstructorArguments[0].Value!; - - if (isGroup) - { - type &= ~DataElementTypes.Grouped; - // Grouped element is missing the element own type. Return and add error diagnostic - if (type == 0) - { - context.ReportDiagnostic(Diagnostic.Create(GroupedMissingDefinitionError, typeAttribute.ApplicationSyntaxReference!.GetSyntax().GetLocation(), currentProp.Name)); - additionalPropIndexes.Add(0); - return("", additionalPropIndexes); - } - } - - switch (type) - { - case DataElementTypes.Value: - builder.Append(GenerateValueRecord(currentProp, typeAttribute, propertyAttributes, collectionName)); - builder.AppendLine(); - additionalPropIndexes.Add(0); - break; - case DataElementTypes.KeyValue: - builder.Append(GenerateKeyValueRecord(currentProp, typeAttribute, propertyAttributes, collectionName)); - builder.AppendLine(); - additionalPropIndexes.Add(0); - break; - case DataElementTypes.KeyValueUnit: - builder.Append(GenerateKeyValueUnitRecord(context, currentProp, typeAttribute, propertyAttributes, collectionName)); - builder.AppendLine(); - additionalPropIndexes.Add(0); - break; - case DataElementTypes.Tooltip: - builder.Append(GenerateTooltipRecord(context, currentProp, typeAttribute, propertyAttributes, collectionName)); - builder.AppendLine(); - additionalPropIndexes.Add(0); - break; - case DataElementTypes.FormattedText: - builder.Append(GenerateFormattedTextRecord(context, currentProp, typeAttribute, propertyAttributes, collectionName)); - builder.AppendLine(); - additionalPropIndexes.Add(0); - break; - case { } when (type & DataElementTypes.Grouped) == DataElementTypes.Grouped: - var (code, additionalIndexes) = GenerateGroupedRecord(context, typeAttribute, properties, collectionName, iterationCounter); - builder.Append(code); - builder.AppendLine(); - additionalPropIndexes.AddRange(additionalIndexes); - break; - default: - context.ReportDiagnostic(Diagnostic.Create(InvalidTypeEnumError, Location.None, currentProp.Name)); - break; - } - - return (builder.ToString(), additionalPropIndexes); - } - - private static (string code, List additionalIndexes) GenerateGroupedRecord(SourceProductionContext context, AttributeData typeAttr, List properties, string collectionName, int iterationCounter) - { - - var groupName = (string?)typeAttr.NamedArguments.First(arg => arg.Key == "GroupKey").Value.Value; - - if (string.IsNullOrWhiteSpace(groupName)) - { - context.ReportDiagnostic(Diagnostic.Create(MissingAttributeError, typeAttr.ApplicationSyntaxReference!.GetSyntax().GetLocation(), "GroupKey", "GroupedDataElement")); - return (string.Empty, new List() { 0 }); - } - - var builder = new StringBuilder(); - - builder.Append($@"{Indentation}var {groupName}List = new List();"); - builder.AppendLine(); - - var groupProperties = properties.Where(prop => prop.GetAttributes().Any(attribute => attribute.AttributeClass!.Name.Contains("DataElementType") && ((DataElementTypes)attribute.ConstructorArguments[0].Value!).HasFlag(DataElementTypes.Grouped) && attribute.NamedArguments.Any(arg => arg.Key == "GroupKey" && (arg.Value.Value?.Equals(groupName) ?? false)))).ToList(); - - var indexList = groupProperties.Select(singleProperty => properties.IndexOf(singleProperty)).ToList(); - - while (groupProperties.Any()) - { - var currentGroupProp = groupProperties.First(); - var currentGroupPropertyAttributes = currentGroupProp.GetAttributes(); - - //exclude the group attribute, to avoid infinite recursion. Need to find a better way to skip the Group type. - var typeAttribute = currentGroupPropertyAttributes.FirstOrDefault(); - if (typeAttribute is not null) - { - if (typeAttribute.ConstructorArguments.IsEmpty) - { - context.ReportDiagnostic(Diagnostic.Create(InvalidTypeEnumError, Location.None, currentGroupProp.Name)); - groupProperties.RemoveAt(0); - continue; - } - - var (code, additionalIndexes) = GenerateCode(context, typeAttribute, currentGroupProp, currentGroupPropertyAttributes, groupProperties, $"{groupName}List", iterationCounter++, true); - builder.Append(code); - foreach (var index in additionalIndexes.OrderByDescending(x => x)) - { - groupProperties.RemoveAt(index); - } - } - } - - builder.Append($@"{IfIndentation}if ({groupName}List.Count > 0)"); - builder.AppendLine(); - builder.Append(@$"{Indentation}{collectionName}.Add(new GroupedDataElement(""ShipStats_{groupName}"", {groupName}List));"); - - return (builder.ToString(), indexList); - } - - private static string GenerateFormattedTextRecord(SourceProductionContext context, IPropertySymbol property, AttributeData typeAttribute, ImmutableArray propertyAttributes, string collectionName) - { - var name = property.Name; - var valuesProperty = (string?)typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "ValuesPropertyName").Value.Value; - if (string.IsNullOrWhiteSpace(valuesProperty)) - { - context.ReportDiagnostic(Diagnostic.Create(MissingAttributeError, typeAttribute.ApplicationSyntaxReference!.GetSyntax().GetLocation(), "ValuesPropertyName", "TooltipDataElement")); - return string.Empty; - } - var isKeyLocalization = (bool?)typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "IsValueLocalizationKey").Value.Value ?? false; - var isListLocalization = (bool?)typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "ArePropertyNameValuesKeys").Value.Value ?? false; - - var isKeyAppLocalization = (bool?) typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "IsValueAppLocalization").Value.Value ?? false; - var isListAppLocalization = (bool?) typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "IsPropertyNameValuesAppLocalization").Value.Value ?? false; - - - var filter = GetFilterAttributeData(property.Name, propertyAttributes); - var builder = new StringBuilder(); - builder.Append(filter); - builder.AppendLine(); - builder.Append($@"{Indentation}{collectionName}.Add(new FormattedTextDataElement({name}, {valuesProperty}, {isKeyLocalization.ToString().ToLower()}, {isKeyAppLocalization.ToString().ToLower()}, {isListLocalization.ToString().ToLower()}, {isListAppLocalization.ToString().ToLower()}));"); - return builder.ToString(); - } - - private static string GenerateTooltipRecord(SourceProductionContext context, IPropertySymbol property, AttributeData typeAttribute, ImmutableArray propertyAttributes, string collectionName) - { - var name = property.Name; - var propertyProcessingAddition = GetPropertyAddition(property); - - var tooltip = (string?)typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "TooltipKey").Value.Value; - if (string.IsNullOrWhiteSpace(tooltip)) - { - context.ReportDiagnostic(Diagnostic.Create(MissingAttributeError, typeAttribute.ApplicationSyntaxReference!.GetSyntax().GetLocation(), "TooltipKey", "TooltipDataElement")); - return string.Empty; - } - - var unit = (string?)typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "UnitKey").Value.Value ?? ""; - if (!string.IsNullOrWhiteSpace(unit)) - { - unit = "Unit_" + unit; - } - - var localizationKey = (string?)typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "NameLocalizationKey").Value.Value ?? name; - - var filter = GetFilterAttributeData(property.Name, propertyAttributes); - - var builder = new StringBuilder(); - builder.Append(filter); - builder.AppendLine(); - builder.Append($@"{Indentation}{collectionName}.Add(new TooltipDataElement(""ShipStats_{localizationKey}"", {name}{propertyProcessingAddition}, ""ShipStats_{tooltip}"", ""{unit}""));"); - return builder.ToString(); - } - - private static string GenerateKeyValueUnitRecord(SourceProductionContext context, IPropertySymbol property, AttributeData typeAttribute, ImmutableArray propertyAttributes, string collectionName) - { - var name = property.Name; - var propertyProcessingAddition = GetPropertyAddition(property); - - var unit = (string?)typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "UnitKey").Value.Value; - if (string.IsNullOrWhiteSpace(unit)) - { - context.ReportDiagnostic(Diagnostic.Create(MissingAttributeError, typeAttribute.ApplicationSyntaxReference!.GetSyntax().GetLocation(), "UnitKey", "KeyValueUnitDataElement")); - return string.Empty; - } - - var localizationKey = (string?)typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "NameLocalizationKey").Value.Value ?? name; - - var filter = GetFilterAttributeData(property.Name, propertyAttributes); - - var builder = new StringBuilder(); - builder.Append(filter); - builder.AppendLine(); - builder.Append($@"{Indentation}{collectionName}.Add(new KeyValueUnitDataElement(""ShipStats_{localizationKey}"", {name}{propertyProcessingAddition}, ""Unit_{unit}""));"); - return builder.ToString(); - } - - private static string GenerateKeyValueRecord(IPropertySymbol property, AttributeData typeAttribute, ImmutableArray propertyAttributes, string collectionName) - { - var name = property.Name; - var propertyProcessingAddition = GetPropertyAddition(property); - var filter = GetFilterAttributeData(property.Name, propertyAttributes); - - var isKeyLocalization = (bool?)typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "IsValueLocalizationKey").Value.Value ?? false; - var isKeyAppLocalization = (bool?) typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "IsValueAppLocalization").Value.Value ?? false; - - var localizationKey = (string?) typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "NameLocalizationKey").Value.Value ?? name; - - var builder = new StringBuilder(); - builder.Append(filter); - builder.AppendLine(); - builder.Append($@"{Indentation}{collectionName}.Add(new KeyValueDataElement(""ShipStats_{localizationKey}"", {name}{propertyProcessingAddition}, {isKeyLocalization.ToString().ToLower()}, {isKeyAppLocalization.ToString().ToLower()}));"); - return builder.ToString(); - } - - private static string GenerateValueRecord(IPropertySymbol property, AttributeData typeAttribute, ImmutableArray propertyAttributes, string collectionName) - { - var propertyProcessingAddition = GetPropertyAddition(property); - var filter = GetFilterAttributeData(property.Name, propertyAttributes); - - var isKeyLocalization = (bool?)typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "IsValueLocalizationKey").Value.Value ?? false; - var isKeyAppLocalization = (bool?) typeAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "IsValueAppLocalization").Value.Value ?? false; - - var builder = new StringBuilder(); - builder.Append(filter); - builder.AppendLine(); - builder.Append($@"{Indentation}{collectionName}.Add(new ValueDataElement({property.Name}{propertyProcessingAddition}, {isKeyLocalization.ToString().ToLower()}, {isKeyAppLocalization.ToString().ToLower()}));"); - return builder.ToString(); - } - - private static string GetPropertyAddition(IPropertySymbol property) - { - var propertyProcessingAddition = string.Empty; - if (!property.Type.Name.Equals("string", StringComparison.InvariantCultureIgnoreCase)) - { - propertyProcessingAddition = ".ToString()"; - } - else if (property.NullableAnnotation == NullableAnnotation.Annotated) - { - propertyProcessingAddition = " ?? \"null\""; - } - - return propertyProcessingAddition; - } - - private static string GetFilterString(string propertyName, bool filterEnabled, string filterName) - { - var filter = string.Empty; - if (!filterEnabled) - { - return filter; - } - - if (string.IsNullOrWhiteSpace(filterName)) - { - return @$"{IfIndentation}if ({DataContainerBaseName}.ShouldAdd({propertyName}))"; - } - - filter = @$"{IfIndentation}if ({filterName}({propertyName}))"; - return filter; - } - - private static string GetFilterAttributeData(string propertyName, ImmutableArray propertyAttributes) - { - var attribute = propertyAttributes.FirstOrDefault(attribute => attribute.AttributeClass!.Name.Contains("DataElementFilteringAttribute")); - - // if there is no attribute, returns active filter, no name for custom filter. - if (attribute is null) - { - return GetFilterString(propertyName, true, ""); - } - - var filterEnabled = (bool)attribute.ConstructorArguments[0].Value!; - string filterName = string.Empty; - if (attribute.ConstructorArguments.Length > 1) - { - filterName = attribute.ConstructorArguments[1].Value?.ToString() ?? string.Empty; - } - - return GetFilterString(propertyName, filterEnabled, filterName); - } -} diff --git a/WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/FieldData.cs b/WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/FieldData.cs new file mode 100644 index 000000000..a73d71e5c --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/FieldData.cs @@ -0,0 +1,3 @@ +namespace WoWsShipBuilder.Data.Generator.PropertyChangedGenerator; + +internal sealed record FieldData(string FieldName, string PropertyName, string Type, string ClassName, string Namespace, string VisibilityModifier); diff --git a/WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/PropertyChangedSourceGenerator.cs b/WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/PropertyChangedSourceGenerator.cs new file mode 100644 index 000000000..428e32087 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/PropertyChangedSourceGenerator.cs @@ -0,0 +1,66 @@ +using System; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using WoWsShipBuilder.Data.Generator.Utilities; + +namespace WoWsShipBuilder.Data.Generator.PropertyChangedGenerator; + +[Generator(LanguageNames.CSharp)] +public class PropertyChangedSourceGenerator : IIncrementalGenerator +{ + private static readonly SymbolDisplayFormat FullyQualifiedWithNullableFormat = SymbolDisplayFormat.FullyQualifiedFormat.AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier); + + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var properties = context.SyntaxProvider.ForAttributeWithMetadataName("WoWsShipBuilder.Infrastructure.Utility.ObservableAttribute", CouldBeObservableField, ProcessField); + context.RegisterSourceOutput(properties, GeneratePropertyCode); + } + + private static bool CouldBeObservableField(SyntaxNode node, CancellationToken _) + { + return node is VariableDeclaratorSyntax { Parent: VariableDeclarationSyntax { Parent: FieldDeclarationSyntax { Parent: ClassDeclarationSyntax or RecordDeclarationSyntax, AttributeLists.Count: > 0 } } }; + } + + private static FieldData ProcessField(GeneratorAttributeSyntaxContext context, CancellationToken token) + { + token.ThrowIfCancellationRequested(); + var fieldSymbol = (IFieldSymbol)context.TargetSymbol; + var propertyName = char.ToUpper(fieldSymbol.Name[0]) + fieldSymbol.Name[1..]; + var type = fieldSymbol.Type.ToDisplayString(FullyQualifiedWithNullableFormat); + var className = fieldSymbol.ContainingType.Name; + var containingNamespace = fieldSymbol.ContainingType.ContainingNamespace.ToFullyQualifiedMetadataName(); + var visibility = (Visibility)(context.Attributes[0].NamedArguments.FirstOrDefault(arg => arg.Key == "SetterVisibility").Value.Value ?? Visibility.Public); + var visibilityModifier = visibility switch + { + Visibility.Public => string.Empty, + Visibility.Protected => "protected ", + Visibility.Internal => "internal ", + Visibility.Private => "private ", + _ => throw new InvalidOperationException(), + }; + + token.ThrowIfCancellationRequested(); + return new(fieldSymbol.Name, propertyName, type, className, containingNamespace, visibilityModifier); + } + + private static void GeneratePropertyCode(SourceProductionContext context, FieldData fieldData) + { + var builder = new SourceBuilder(); + builder.Line("// ").Line("#nullable enable"); + using (builder.Namespace(fieldData.Namespace)) + { + using (builder.Class(fieldData.ClassName)) + { + using (builder.Block($"public {fieldData.Type} {fieldData.PropertyName}")) + { + builder.Line($"get => this.{fieldData.FieldName};"); + builder.Line($"{fieldData.VisibilityModifier}set => global::ReactiveUI.IReactiveObjectExtensions.RaiseAndSetIfChanged(this, ref this.{fieldData.FieldName}, value);"); + } + } + } + + context.AddSource($"{fieldData.Namespace}.{fieldData.ClassName}_{fieldData.FieldName}.g.cs", builder.ToString()); + } +} diff --git a/WoWsShipBuilder.Data.Generator/Internals/Visibility.cs b/WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/Visibility.cs similarity index 50% rename from WoWsShipBuilder.Data.Generator/Internals/Visibility.cs rename to WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/Visibility.cs index ce0640084..2463334c4 100644 --- a/WoWsShipBuilder.Data.Generator/Internals/Visibility.cs +++ b/WoWsShipBuilder.Data.Generator/PropertyChangedGenerator/Visibility.cs @@ -1,4 +1,4 @@ -namespace WoWsShipBuilder.Data.Generator.Internals; +namespace WoWsShipBuilder.Data.Generator.PropertyChangedGenerator; internal enum Visibility { diff --git a/WoWsShipBuilder.Data.Generator/PropertyChangedSourceGenerator.cs b/WoWsShipBuilder.Data.Generator/PropertyChangedSourceGenerator.cs deleted file mode 100644 index cf8094544..000000000 --- a/WoWsShipBuilder.Data.Generator/PropertyChangedSourceGenerator.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Text; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; -using WoWsShipBuilder.Data.Generator.Internals; - -namespace WoWsShipBuilder.Data.Generator; - -[Generator] -public class PropertyChangedSourceGenerator : IIncrementalGenerator -{ - public void Initialize(IncrementalGeneratorInitializationContext context) - { - var viewModels = context.SyntaxProvider.CreateSyntaxProvider(ViewModelFilter, GetViewModelOrNull) - .Where(type => type is not null) - .Select(GetObservableFields!) - .Where(result => result.Items.Count > 0) - .Collect(); - context.RegisterSourceOutput(viewModels, GenerateCode); - } - - private static bool ViewModelFilter(SyntaxNode syntaxNode, CancellationToken token) - { - token.ThrowIfCancellationRequested(); - if (syntaxNode is not ClassDeclarationSyntax classDeclaration) - { - return false; - } - - return classDeclaration.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.PartialKeyword)); - } - - private static ITypeSymbol? GetViewModelOrNull(GeneratorSyntaxContext context, CancellationToken token) - { - token.ThrowIfCancellationRequested(); - var typeDeclaration = (TypeDeclarationSyntax)context.Node; - return context.SemanticModel.GetDeclaredSymbol(typeDeclaration); - } - - private static SourceGenFilterResult GetObservableFields(ITypeSymbol symbol, CancellationToken token) - { - token.ThrowIfCancellationRequested(); - string className = symbol.Name; - string classNamespace = symbol.ContainingNamespace.ToDisplayString(); - List fields = symbol.GetMembers().OfType().Where(field => field.GetAttributes().Any(attr => attr.AttributeClass!.Name == "ObservableAttribute")).ToList(); - return new(className, classNamespace, fields); - } - - private static void GenerateCode(SourceProductionContext context, ImmutableArray viewmodels) - { - var logMessages = new StringBuilder(); - foreach (var viewmodel in viewmodels) - { - var classStart = $@" -using ReactiveUI; - -namespace {viewmodel.ElementNamespace}; - -#nullable enable -public partial class {viewmodel.ElementName} -{{ -"; - const string classEnd = @" -} -#nullable restore -"; - - var classBuilder = new StringBuilder(classStart); - foreach (var field in viewmodel.Items) - { - var propertyName = char.ToUpper(field.Name.First()) + field.Name.Substring(1); - var fieldAttribute = field.GetAttributes().First(a => a.AttributeClass!.Name == "ObservableAttribute"); - var setterVisibility = (Visibility)(fieldAttribute.NamedArguments.FirstOrDefault(arg => arg.Key == "SetterVisibility").Value.Value ?? Visibility.Public); - var setterVisibilityString = setterVisibility switch - { - Visibility.Public => string.Empty, - Visibility.Protected => "protected ", - Visibility.Internal => "internal ", - Visibility.Private => "private ", - _ => throw new InvalidOperationException(), - }; - logMessages.AppendLine("#4"); - classBuilder.AppendLine($@" - public {field.Type} {propertyName} - {{ - get => this.{field.Name}; - {setterVisibilityString}set => this.RaiseAndSetIfChanged(ref this.{field.Name}, value); - }}"); - } - - classBuilder.AppendLine(classEnd); - context.AddSource($"{viewmodel.ElementName}.g.cs", SourceText.From(classBuilder.ToString(), Encoding.UTF8)); - } - } - - private record struct SourceGenFilterResult(string ElementName, string ElementNamespace, List Items); -} diff --git a/WoWsShipBuilder.Data.Generator/Utilities/EquatableArray.cs b/WoWsShipBuilder.Data.Generator/Utilities/EquatableArray.cs new file mode 100644 index 000000000..b262dcc28 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/Utilities/EquatableArray.cs @@ -0,0 +1,196 @@ +// Based on the EquatableArray{T} implementation from CommunityToolkit/dotnet +// see https://github.com/CommunityToolkit/dotnet/blob/main/src/CommunityToolkit.Mvvm.SourceGenerators/Helpers/EquatableArray%7BT%7D.cs for the original implementation + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace WoWsShipBuilder.Data.Generator.Utilities; + +/// +/// Extensions for . +/// +internal static class EquatableArray +{ + public static EquatableArray ToEquatableArray(this ImmutableArray array) + where T : IEquatable + { + return new(array); + } + + public static EquatableArray ToEquatableArray(this IEnumerable enumerable) + where T : IEquatable + { + return new(enumerable.ToImmutableArray()); + } +} + +/// +/// An immutable, equatable array. This is equivalent to but with value equality support. +/// +/// The type of values in the array. +internal readonly struct EquatableArray : IEquatable>, IEnumerable + where T : IEquatable +{ + /// + /// The underlying array. + /// + private readonly T[]? array; + + public EquatableArray(ImmutableArray array) + { + this.array = Unsafe.As, T[]?>(ref array); + } + + public static readonly EquatableArray Empty = new(); + + /// + /// Gets a reference to an item at a specified position within the array. + /// + /// The index of the item to retrieve a reference to. + /// A reference to an item at a specified position within the array. + public ref readonly T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref this.AsImmutableArray().ItemRef(index); + } + + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => this.AsImmutableArray().IsEmpty; + } + + /// + public bool Equals(EquatableArray array) + { + return this.AsSpan().SequenceEqual(array.AsSpan()); + } + + /// + public override bool Equals([NotNullWhen(true)] object? obj) + { + return obj is EquatableArray array && Equals(this, array); + } + + /// + public override int GetHashCode() + { + if (this.array is not { } array) + { + return 0; + } + + HashCode hashCode = default; + + foreach (var item in array) + { + hashCode.Add(item); + } + + return hashCode.ToHashCode(); + } + + /// + /// Gets an instance from the current . + /// + /// The from the current . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ImmutableArray AsImmutableArray() + { + return Unsafe.As>(ref Unsafe.AsRef(in this.array)); + } + + /// + /// Creates an instance from a given . + /// + /// The input instance. + /// An instance from a given . + public static EquatableArray FromImmutableArray(ImmutableArray array) + { + return new(array); + } + + /// + /// Returns a wrapping the current items. + /// + /// A wrapping the current items. + public ReadOnlySpan AsSpan() + { + return this.AsImmutableArray().AsSpan(); + } + + /// + /// Copies the contents of this instance to a mutable array. + /// + /// The newly instantiated array. + public T[] ToArray() + { + return this.AsImmutableArray().ToArray(); + } + + /// + /// Gets an value to traverse items in the current array. + /// + /// An value to traverse items in the current array. + public ImmutableArray.Enumerator GetEnumerator() + { + return this.AsImmutableArray().GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)this.AsImmutableArray()).GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)this.AsImmutableArray()).GetEnumerator(); + } + + /// + /// Implicitly converts an to . + /// + /// An instance from a given . + public static implicit operator EquatableArray(ImmutableArray array) + { + return FromImmutableArray(array); + } + + /// + /// Implicitly converts an to . + /// + /// An instance from a given . + public static implicit operator ImmutableArray(EquatableArray array) + { + return array.AsImmutableArray(); + } + + /// + /// Checks whether two values are the same. + /// + /// The first value. + /// The second value. + /// Whether and are equal. + public static bool operator ==(EquatableArray left, EquatableArray right) + { + return left.Equals(right); + } + + /// + /// Checks whether two values are not the same. + /// + /// The first value. + /// The second value. + /// Whether and are not equal. + public static bool operator !=(EquatableArray left, EquatableArray right) + { + return !left.Equals(right); + } +} diff --git a/WoWsShipBuilder.Data.Generator/Utilities/HashCode.cs b/WoWsShipBuilder.Data.Generator/Utilities/HashCode.cs new file mode 100644 index 000000000..3169f4b3e --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/Utilities/HashCode.cs @@ -0,0 +1,180 @@ +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; + +#pragma warning disable CS0809 + +namespace WoWsShipBuilder.Data.Generator.Utilities; + +/// +/// A polyfill for the HashCode struct from .NET 6 with the methods required for . +/// +internal struct HashCode +{ + private const uint Prime1 = 2654435761U; + private const uint Prime2 = 2246822519U; + private const uint Prime3 = 3266489917U; + private const uint Prime4 = 668265263U; + private const uint Prime5 = 374761393U; + + private static readonly uint Seed = GenerateGlobalSeed(); + + private uint v1, v2, v3, v4; + private uint queue1, queue2, queue3; + private uint length; + + /// + /// Adds a single value to the current hash. + /// + /// The type of the value to add into the hash code. + /// The value to add into the hash code. + public void Add(T value) + { + this.Add(value?.GetHashCode() ?? 0); + } + + /// + /// Gets the resulting hashcode from the current instance. + /// + /// The resulting hashcode from the current instance. + public int ToHashCode() + { + uint length = this.length; + uint position = length % 4; + uint hash = length < 4 ? MixEmptyState() : MixState(this.v1, this.v2, this.v3, this.v4); + + hash += length * 4; + + if (position > 0) + { + hash = QueueRound(hash, this.queue1); + + if (position > 1) + { + hash = QueueRound(hash, this.queue2); + + if (position > 2) + { + hash = QueueRound(hash, this.queue3); + } + } + } + + hash = MixFinal(hash); + + return (int)hash; + } + + /// + [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes. Use ToHashCode to retrieve the computed hash code.", error: true)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => throw new NotSupportedException(); + + /// + [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes.", error: true)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object? obj) => throw new NotSupportedException(); + + private static uint GenerateGlobalSeed() + { + var bytes = new byte[4]; + using (var generator = RandomNumberGenerator.Create()) + { + generator.GetBytes(bytes); + } + + return BitConverter.ToUInt32(bytes, 0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Initialize(out uint v1, out uint v2, out uint v3, out uint v4) + { + v1 = Seed + Prime1 + Prime2; + v2 = Seed + Prime2; + v3 = Seed; + v4 = Seed - Prime1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Round(uint hash, uint input) + { + return RotateLeft(hash + (input * Prime2), 13) * Prime1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint QueueRound(uint hash, uint queuedValue) + { + return RotateLeft(hash + (queuedValue * Prime3), 17) * Prime4; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint MixState(uint v1, uint v2, uint v3, uint v4) + { + return RotateLeft(v1, 1) + RotateLeft(v2, 7) + RotateLeft(v3, 12) + RotateLeft(v4, 18); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint MixEmptyState() + { + return Seed + Prime5; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint MixFinal(uint hash) + { + hash ^= hash >> 15; + hash *= Prime2; + hash ^= hash >> 13; + hash *= Prime3; + hash ^= hash >> 16; + + return hash; + } + + private void Add(int value) + { + uint val = (uint)value; + uint previousLength = this.length++; + uint position = previousLength % 4; + + if (position == 0) + { + this.queue1 = val; + } + else if (position == 1) + { + this.queue2 = val; + } + else if (position == 2) + { + this.queue3 = val; + } + else + { + if (previousLength == 3) + { + Initialize(out this.v1, out this.v2, out this.v3, out this.v4); + } + + this.v1 = Round(this.v1, this.queue1); + this.v2 = Round(this.v2, this.queue2); + this.v3 = Round(this.v3, this.queue3); + this.v4 = Round(this.v4, val); + } + } + + /// + /// Rotates the specified value left by the specified number of bits. + /// Similar in behavior to the x86 instruction ROL. + /// + /// The value to rotate. + /// The number of bits to rotate by. + /// Any value outside the range [0..31] is treated as congruent mod 32. + /// The rotated value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint RotateLeft(uint value, int offset) + { + return (value << offset) | (value >> (32 - offset)); + } +} diff --git a/WoWsShipBuilder.Data.Generator/Utilities/SourceBuilder.cs b/WoWsShipBuilder.Data.Generator/Utilities/SourceBuilder.cs new file mode 100644 index 000000000..23f400564 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/Utilities/SourceBuilder.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WoWsShipBuilder.Data.Generator.Utilities; + +internal sealed class SourceBuilder +{ + private const int IndentSize = 4; + + private readonly StringBuilder sb; + + private int currentIndent; + + private LastAction lastAction; + + public SourceBuilder(StringBuilder? sb = null) + { + this.sb = sb ?? new StringBuilder(); + } + + private enum LastAction + { + None, + + BlockClose, + } + + public IDisposable Namespace(string ns) + { + return this.Block($"namespace {ns}"); + } + + public IDisposable Class(string className) + { + return this.Block($"public partial class {className}"); + } + + public IDisposable Record(string recordName) + { + return this.Block($"public partial record {recordName}"); + } + + public IDisposable Block(string? line = null) + { + this.BlockOpen(line); + return this.BlockCloseAction(); + } + + public IDisposable PragmaWarning(string warning) + { + this.AddBlankLineIfNeeded(); + this.Append($"#pragma warning disable {warning}").AppendNewLine(); + return new DisposableAction(() => this.Append($"#pragma warning restore {warning}").AppendNewLine()); + } + + public SourceBuilder DelimitedLines(string delimiter, params string[] lines) => this.DelimitedLines(delimiter, lines as IReadOnlyList); + + public SourceBuilder DelimitedLines(string delimiter, IEnumerable lines) => this.DelimitedLines(delimiter, lines.ToList()); + + public SourceBuilder DelimitedLines(string delimiter, IReadOnlyList lines) + { + _ = lines ?? throw new ArgumentNullException(nameof(lines)); + + this.AddBlankLineIfNeeded(); + + for (var i = 0; i < lines.Count; ++i) + { + this.AppendIndented(lines[i]); + + if (i < lines.Count - 1) + { + this.Append(delimiter); + } + + this.AppendNewLine(); + } + + return this; + } + + public SourceBuilder Line() + { + this.AddBlankLineIfNeeded(); + return this.AppendNewLine(); + } + + public SourceBuilder Line(string line) + { + this.AddBlankLineIfNeeded(); + return this.AppendIndentedLine(line); + } + + public SourceBuilder SpacedLine(string line) + { + this.AddBlankLineIfNeeded(); + this.AppendIndentedLine(line); + this.lastAction = LastAction.BlockClose; + return this; + } + + public SourceBuilder Lines(params string[] lines) + { + this.AddBlankLineIfNeeded(); + return this.DelimitedLines("", lines); + } + + public SourceBuilder Lines(IEnumerable lines) + { + this.AddBlankLineIfNeeded(); + return this.DelimitedLines("", lines.ToList()); + } + + public IDisposable Parens(string line, string? postfix = null) + { + this.AddBlankLineIfNeeded(); + this.AppendIndented(line).Append("(").AppendNewLine().IncreaseIndent(); + return new DisposableAction(() => this.DecreaseIndent().AppendIndented(")").Append(postfix).AppendNewLine()); + } + + public override string ToString() => this.sb.ToString(); + + private void BlockClose() + { + this.DecreaseIndent().AppendIndentedLine("}"); + this.lastAction = LastAction.BlockClose; + } + + private void BlockOpen(string? line = null) + { + this.AddBlankLineIfNeeded(); + + if (line is not null) + { + this.AppendIndentedLine(line); + } + + this.AppendIndentedLine("{").IncreaseIndent(); + } + + private SourceBuilder DecreaseIndent() + { + --this.currentIndent; + return this; + } + + private SourceBuilder IncreaseIndent() + { + ++this.currentIndent; + return this; + } + + private void AddBlankLineIfNeeded() + { + if (this.lastAction != LastAction.BlockClose) + { + return; + } + + this.lastAction = LastAction.None; + this.AppendNewLine(); + } + + private SourceBuilder Append(string? text) + { + if (text is not null) + { + this.sb.Append(text); + } + + return this; + } + + private SourceBuilder AppendIndent() + { + this.sb.Append(' ', this.currentIndent * IndentSize); + return this; + } + + private SourceBuilder AppendIndented(string text) => this.AppendIndent().Append(text); + + private SourceBuilder AppendIndentedLine(string text) => this.AppendIndent().Append(text).AppendNewLine(); + + private SourceBuilder AppendNewLine() + { + this.sb.AppendLine(); + return this; + } + + private IDisposable BlockCloseAction() => new DisposableAction(this.BlockClose); + + private sealed class DisposableAction : IDisposable + { + private readonly Action action; + + public DisposableAction(Action action) => this.action = action; + + public void Dispose() => this.action(); + } +} diff --git a/WoWsShipBuilder.Data.Generator/Utilities/SymbolExtensions.cs b/WoWsShipBuilder.Data.Generator/Utilities/SymbolExtensions.cs new file mode 100644 index 000000000..815b1c1d2 --- /dev/null +++ b/WoWsShipBuilder.Data.Generator/Utilities/SymbolExtensions.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; + +namespace WoWsShipBuilder.Data.Generator.Utilities; + +internal static class SymbolExtensions +{ + private static readonly SymbolDisplayFormat FullyQualifiedWithoutGlobalFormat = SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted).AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier); + + public static AttributeData? FindAttributeOrDefault(this ISymbol symbol, string fullAttributeName) + { + return symbol.GetAttributes().FirstOrDefault(attribute => attribute.AttributeClass?.ToDisplayString(FullyQualifiedWithoutGlobalFormat).Equals(fullAttributeName, StringComparison.Ordinal) == true); + } + + public static AttributeData FindAttribute(this ISymbol symbol, string fullAttributeName) + { + return symbol.FindAttributeOrDefault(fullAttributeName) ?? throw new KeyNotFoundException($"No attribute found with name {fullAttributeName}."); + } + + public static bool HasAttributeWithFullName(this ISymbol symbol, string fullAttributeName) + { + return symbol.FindAttributeOrDefault(fullAttributeName) != null; + } + + public static bool HasInterface(this INamedTypeSymbol symbol, INamedTypeSymbol interfaceType) + { + return symbol.AllInterfaces.Contains(interfaceType, SymbolEqualityComparer.Default); + } + + public static bool NamespaceContains(this INamedTypeSymbol symbol, string search) + { + return symbol.ContainingNamespace.ToDisplayString(FullyQualifiedWithoutGlobalFormat).IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0; + } + + public static string ToLowerString(this bool value) => value.ToString().ToLowerInvariant(); + + public static string ToFullyQualifiedMetadataName(this ISymbol symbol) => symbol.ToDisplayString(FullyQualifiedWithoutGlobalFormat); +} diff --git a/WoWsShipBuilder.Data.Generator/WoWsShipBuilder.Data.Generator.csproj b/WoWsShipBuilder.Data.Generator/WoWsShipBuilder.Data.Generator.csproj index 339dbe19a..5d0f90414 100644 --- a/WoWsShipBuilder.Data.Generator/WoWsShipBuilder.Data.Generator.csproj +++ b/WoWsShipBuilder.Data.Generator/WoWsShipBuilder.Data.Generator.csproj @@ -7,11 +7,15 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/WoWsShipBuilder.DataElements/DataElements/DataContainerBase.cs b/WoWsShipBuilder.DataElements/DataContainerBase.cs similarity index 90% rename from WoWsShipBuilder.DataElements/DataElements/DataContainerBase.cs rename to WoWsShipBuilder.DataElements/DataContainerBase.cs index 18b77f1bb..f5248f1c1 100644 --- a/WoWsShipBuilder.DataElements/DataElements/DataContainerBase.cs +++ b/WoWsShipBuilder.DataElements/DataContainerBase.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace WoWsShipBuilder.DataElements.DataElements; +namespace WoWsShipBuilder.DataElements; public abstract record DataContainerBase { diff --git a/WoWsShipBuilder.DataElements/DataElementAttributes/DataElementFilteringAttribute.cs b/WoWsShipBuilder.DataElements/DataElementAttributes/DataElementFilteringAttribute.cs deleted file mode 100644 index a2aefd790..000000000 --- a/WoWsShipBuilder.DataElements/DataElementAttributes/DataElementFilteringAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace WoWsShipBuilder.DataElements.DataElementAttributes; - -[AttributeUsage(AttributeTargets.Property)] -public class DataElementFilteringAttribute : Attribute -{ - public DataElementFilteringAttribute(bool enableFilterVisibility, string filterMethodName = "") - { - EnableFilterVisibility = enableFilterVisibility; - FilterMethodName = filterMethodName; - } - - public bool EnableFilterVisibility { get; } - - public string FilterMethodName { get; } -} diff --git a/WoWsShipBuilder.DataElements/DataElementAttributes/DataElementTypeAttribute.cs b/WoWsShipBuilder.DataElements/DataElementAttributes/DataElementTypeAttribute.cs deleted file mode 100644 index b7a8b5f6c..000000000 --- a/WoWsShipBuilder.DataElements/DataElementAttributes/DataElementTypeAttribute.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; - -namespace WoWsShipBuilder.DataElements.DataElementAttributes; - -[AttributeUsage(AttributeTargets.Property)] -public class DataElementTypeAttribute : Attribute -{ - public DataElementTypeAttribute(DataElementTypes type) - { - Type = type; - } - - /// - /// Gets the type of the DataElement for the property marked by this attribute. /> - /// - public DataElementTypes Type { get; } - - /// - /// Gets or sets the unit localization key for the property marked by this attribute.
- /// Only valid for and . - ///
- public string? UnitKey { get; set; } - - /// - /// Gets or sets the property name localization key for the property marked by this attribute.
- /// Only valid for , , and . - ///
- public string? NameLocalizationKey { get; set; } - - /// - /// Gets or sets the tooltip localization key for the property marked by this attribute.
- /// Only valid for . - ///
- public string? TooltipKey { get; set; } - - /// - /// Gets or sets the group localization key and identifier for the property marked by this attribute.
- /// Only valid for . - ///
- public string? GroupKey { get; set; } - - /// - /// Gets or set the name of the property containing the list of values that will replace the placeholder. Requires the value of the property marked by this attribute to follow the specifications.
- /// Only valid for . - ///
- public string? ValuesPropertyName { get; set; } - - /// - /// Gets or sets if the value of the property marked by this attribute is a localization key.
- /// Only valid for , and - ///
- public bool IsValueLocalizationKey { get; set; } - - /// - /// Gets or sets if the values indicated by are localization keys.
- /// Only valid for - ///
- public bool ArePropertyNameValuesKeys { get; set; } - - /// - /// Gets or sets if the value of the property marked by this attribute is an app localization key.
- /// Only valid for , and - ///
- public bool IsValueAppLocalization { get; set; } - - /// - /// Gets or sets if the values indicated by are app localization keys.
- /// Only valid for - ///
- public bool IsPropertyNameValuesAppLocalization { get; set; } - -} diff --git a/WoWsShipBuilder.DataElements/DataElementAttributes/DataElementTypes.cs b/WoWsShipBuilder.DataElements/DataElementAttributes/DataElementTypes.cs deleted file mode 100644 index a7b83d491..000000000 --- a/WoWsShipBuilder.DataElements/DataElementAttributes/DataElementTypes.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace WoWsShipBuilder.DataElements.DataElementAttributes; - -[Flags] -public enum DataElementTypes -{ - KeyValue = 1, - KeyValueUnit = 2, - Value = 4, - Grouped = 8, - Tooltip = 16, - FormattedText = 32, -} diff --git a/WoWsShipBuilder.DataElements/DataElementTextKind.cs b/WoWsShipBuilder.DataElements/DataElementTextKind.cs new file mode 100644 index 000000000..eec521dc3 --- /dev/null +++ b/WoWsShipBuilder.DataElements/DataElementTextKind.cs @@ -0,0 +1,8 @@ +namespace WoWsShipBuilder.DataElements; + +public enum DataElementTextKind +{ + Plain, + LocalizationKey, + AppLocalizationKey, +} diff --git a/WoWsShipBuilder.DataElements/DataElements/FormattedTextDataElement.cs b/WoWsShipBuilder.DataElements/DataElements/FormattedTextDataElement.cs deleted file mode 100644 index 17ddeba30..000000000 --- a/WoWsShipBuilder.DataElements/DataElements/FormattedTextDataElement.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace WoWsShipBuilder.DataElements.DataElements; - -/// -/// A record that represent a formatted text data element. -/// -/// The text to format. Need to respect specifications. -/// The enumerable that will be used by . -/// If is a localization key and not actual text. -/// If are localization keys and not actual values. -public sealed record FormattedTextDataElement(string Text, IEnumerable Values, bool IsTextKey = false, bool IsTextAppLocalization = false, bool AreValuesKeys = false, bool AreValuesAppLocalization = false) : IDataElement; diff --git a/WoWsShipBuilder.DataElements/DataElements/KeyValueDataElement.cs b/WoWsShipBuilder.DataElements/DataElements/KeyValueDataElement.cs deleted file mode 100644 index 8e7f5eef7..000000000 --- a/WoWsShipBuilder.DataElements/DataElements/KeyValueDataElement.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace WoWsShipBuilder.DataElements.DataElements; - -/// -/// Record that represent a key value pair. Localization is left to the UI. -/// -/// The key of the element. -/// The value of the element. -/// If the value is a localizer key. -/// If the value is an app localization key. -public readonly record struct KeyValueDataElement(string Key, string Value, bool IsValueKey, bool IsValueAppLocalization) : IDataElement; diff --git a/WoWsShipBuilder.DataElements/DataElements/ValueDataElement.cs b/WoWsShipBuilder.DataElements/DataElements/ValueDataElement.cs deleted file mode 100644 index 74d3332b0..000000000 --- a/WoWsShipBuilder.DataElements/DataElements/ValueDataElement.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace WoWsShipBuilder.DataElements.DataElements; - -/// -/// A record that represent a single value. -/// -/// The value of the element. -/// If the value is a localizer key. -/// If the value is an app localization key. -public readonly record struct ValueDataElement(string Value, bool IsValueKey, bool IsValueAppLocalization) : IDataElement; diff --git a/WoWsShipBuilder.DataElements/FormattedTextDataElement.cs b/WoWsShipBuilder.DataElements/FormattedTextDataElement.cs new file mode 100644 index 000000000..795f89db5 --- /dev/null +++ b/WoWsShipBuilder.DataElements/FormattedTextDataElement.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace WoWsShipBuilder.DataElements; + +/// +/// A record that represent a formatted text data element. +/// +/// The text to format. Need to respect specifications. +/// The enumerable that will be used by . +/// The of the text. +/// The of the arguments. +public sealed record FormattedTextDataElement(string Text, IEnumerable Arguments, DataElementTextKind ValueTextKind = DataElementTextKind.Plain, DataElementTextKind ArgumentsTextKind = DataElementTextKind.Plain) : IDataElement; diff --git a/WoWsShipBuilder.DataElements/DataElements/GroupedDataElement.cs b/WoWsShipBuilder.DataElements/GroupedDataElement.cs similarity index 88% rename from WoWsShipBuilder.DataElements/DataElements/GroupedDataElement.cs rename to WoWsShipBuilder.DataElements/GroupedDataElement.cs index c9bf6245b..3d4048a66 100644 --- a/WoWsShipBuilder.DataElements/DataElements/GroupedDataElement.cs +++ b/WoWsShipBuilder.DataElements/GroupedDataElement.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace WoWsShipBuilder.DataElements.DataElements; +namespace WoWsShipBuilder.DataElements; /// /// A record that represent a group of that share a common group. diff --git a/WoWsShipBuilder.DataElements/DataElements/IDataElement.cs b/WoWsShipBuilder.DataElements/IDataElement.cs similarity index 76% rename from WoWsShipBuilder.DataElements/DataElements/IDataElement.cs rename to WoWsShipBuilder.DataElements/IDataElement.cs index eb73de959..7ed750277 100644 --- a/WoWsShipBuilder.DataElements/DataElements/IDataElement.cs +++ b/WoWsShipBuilder.DataElements/IDataElement.cs @@ -1,4 +1,4 @@ -namespace WoWsShipBuilder.DataElements.DataElements; +namespace WoWsShipBuilder.DataElements; /// /// Base interface that marks a type as DataElement that can represent data that is supposed to be automatically rendered. diff --git a/WoWsShipBuilder.DataElements/KeyValueDataElement.cs b/WoWsShipBuilder.DataElements/KeyValueDataElement.cs new file mode 100644 index 000000000..e144512cb --- /dev/null +++ b/WoWsShipBuilder.DataElements/KeyValueDataElement.cs @@ -0,0 +1,9 @@ +namespace WoWsShipBuilder.DataElements; + +/// +/// Record that represent a key value pair. Localization is left to the UI. +/// +/// The key of the element. +/// The value of the element. +/// The of the . +public readonly record struct KeyValueDataElement(string Key, string Value, DataElementTextKind ValueTextKind) : IDataElement; diff --git a/WoWsShipBuilder.DataElements/DataElements/KeyValueUnitDataElement.cs b/WoWsShipBuilder.DataElements/KeyValueUnitDataElement.cs similarity index 87% rename from WoWsShipBuilder.DataElements/DataElements/KeyValueUnitDataElement.cs rename to WoWsShipBuilder.DataElements/KeyValueUnitDataElement.cs index fc58db8c3..f97fc79c3 100644 --- a/WoWsShipBuilder.DataElements/DataElements/KeyValueUnitDataElement.cs +++ b/WoWsShipBuilder.DataElements/KeyValueUnitDataElement.cs @@ -1,4 +1,4 @@ -namespace WoWsShipBuilder.DataElements.DataElements; +namespace WoWsShipBuilder.DataElements; /// /// Record that represent a key value pair, with a measurement unit to be applied to the value. diff --git a/WoWsShipBuilder.DataElements/DataElements/TooltipDataElement.cs b/WoWsShipBuilder.DataElements/TooltipDataElement.cs similarity index 89% rename from WoWsShipBuilder.DataElements/DataElements/TooltipDataElement.cs rename to WoWsShipBuilder.DataElements/TooltipDataElement.cs index 95ba692ce..120001fb7 100644 --- a/WoWsShipBuilder.DataElements/DataElements/TooltipDataElement.cs +++ b/WoWsShipBuilder.DataElements/TooltipDataElement.cs @@ -1,4 +1,4 @@ -namespace WoWsShipBuilder.DataElements.DataElements; +namespace WoWsShipBuilder.DataElements; /// /// A record that represent a key value pair with a tooltip text. diff --git a/WoWsShipBuilder.DataElements/ValueDataElement.cs b/WoWsShipBuilder.DataElements/ValueDataElement.cs new file mode 100644 index 000000000..d57e59978 --- /dev/null +++ b/WoWsShipBuilder.DataElements/ValueDataElement.cs @@ -0,0 +1,8 @@ +namespace WoWsShipBuilder.DataElements; + +/// +/// A record that represent a single value. +/// +/// The value of the element. +/// The of the value. +public readonly record struct ValueDataElement(string Value, DataElementTextKind ValueTextKind) : IDataElement; diff --git a/nuget.config b/nuget.config new file mode 100644 index 000000000..b52765b30 --- /dev/null +++ b/nuget.config @@ -0,0 +1,9 @@ + + + + + + + + + From 6b45dd3d8f2cf67ee43a01972d69a6d4b9621e2a Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 14 Oct 2023 22:18:28 +0200 Subject: [PATCH 04/26] remove ReleaseTest project for desktop --- .github/workflows/desktop-release-check.yml | 8 +-- .../Components/BuildConfigurationDialog.razor | 2 +- .../GithubApiResponse.cs | 21 -------- WoWsShipBuilder.ReleaseTest/ReleaseTest.cs | 52 ------------------- .../WoWsShipBuilder.ReleaseTest.csproj | 19 ------- WoWsShipBuilder.sln | 25 --------- dirs.proj | 5 +- 7 files changed, 6 insertions(+), 126 deletions(-) delete mode 100644 WoWsShipBuilder.ReleaseTest/GithubApiResponse.cs delete mode 100644 WoWsShipBuilder.ReleaseTest/ReleaseTest.cs delete mode 100644 WoWsShipBuilder.ReleaseTest/WoWsShipBuilder.ReleaseTest.csproj diff --git a/.github/workflows/desktop-release-check.yml b/.github/workflows/desktop-release-check.yml index 9d6a88761..085618ea6 100644 --- a/.github/workflows/desktop-release-check.yml +++ b/.github/workflows/desktop-release-check.yml @@ -6,9 +6,9 @@ on: - release/desktop jobs: - build-and-release: + build-and-test: runs-on: windows-latest - name: Release build and version check + name: Release build and test steps: - uses: actions/checkout@v3 @@ -19,9 +19,9 @@ jobs: with: global-json-file: global.json - name: Build application - run: dotnet build dirs.proj -c Release -p:ReleaseTest=true + run: dotnet build dirs.proj -c Release - name: Test application - run: dotnet test dirs.proj --no-build -c Release -p:ReleaseTest=true --verbosity normal + run: dotnet test dirs.proj --no-build -c Release --verbosity normal verify-squirrel-release: runs-on: windows-latest diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor b/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor index 7e4b68f9a..e0acdb716 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor @@ -401,4 +401,4 @@ } } } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.ReleaseTest/GithubApiResponse.cs b/WoWsShipBuilder.ReleaseTest/GithubApiResponse.cs deleted file mode 100644 index ce79d27e9..000000000 --- a/WoWsShipBuilder.ReleaseTest/GithubApiResponse.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace WoWsShipBuilder.ReleaseTest -{ - public class GithubApiResponse - { - public GithubApiResponse(long id, string name, bool prerelease, bool draft) - { - Id = id; - Name = name; - Prerelease = prerelease; - Draft = draft; - } - - public long Id { get; } - - public string Name { get; } - - public bool Prerelease { get; } - - public bool Draft { get; } - } -} diff --git a/WoWsShipBuilder.ReleaseTest/ReleaseTest.cs b/WoWsShipBuilder.ReleaseTest/ReleaseTest.cs deleted file mode 100644 index a907b0eed..000000000 --- a/WoWsShipBuilder.ReleaseTest/ReleaseTest.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Net.Http; -using System.Reflection; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using FluentAssertions; -using Newtonsoft.Json; -using NUnit.Framework; -using WoWsShipBuilder.Desktop.Features.BlazorWebView; - -namespace WoWsShipBuilder.ReleaseTest; - -public class Tests -{ - [Test] - public void EnsureReleaseVersion() - { - var assembly = Assembly.GetAssembly(typeof(BlazorWindow)); - string versionString = assembly!.GetCustomAttribute()!.InformationalVersion; - versionString = StripCommitFromVersion(versionString); - Version.TryParse(versionString, out _).Should().BeTrue(); - } - - [Test] - public async Task EnsureNewVersionIsIncrement() - { - var assembly = Assembly.GetAssembly(typeof(BlazorWindow)); - string versionString = assembly!.GetCustomAttribute()!.InformationalVersion; - versionString = StripCommitFromVersion(versionString); - var version = Version.Parse(versionString); - - const string uri = "https://api.github.com/repos/WoWs-Builder-Team/WoWs-ShipBuilder/releases/latest"; - var client = new HttpClient(); - client.DefaultRequestHeaders.Add("User-Agent", "C# test client"); - var response = await client.GetStringAsync(uri); - var apiResponse = JsonConvert.DeserializeObject(response); - var lastVersionString = Regex.Replace(apiResponse!.Name, "[^0-9.]", string.Empty); - var lastVersion = Version.Parse(lastVersionString); - (lastVersion < version).Should().BeTrue(); - } - - private static string StripCommitFromVersion(string rawVersion) - { - int commitStartIndex = rawVersion.IndexOf("+", StringComparison.Ordinal); - if (commitStartIndex > 0) - { - rawVersion = rawVersion[..commitStartIndex]; - } - - return rawVersion; - } -} diff --git a/WoWsShipBuilder.ReleaseTest/WoWsShipBuilder.ReleaseTest.csproj b/WoWsShipBuilder.ReleaseTest/WoWsShipBuilder.ReleaseTest.csproj deleted file mode 100644 index 4fd09794a..000000000 --- a/WoWsShipBuilder.ReleaseTest/WoWsShipBuilder.ReleaseTest.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net7.0-windows - false - - - - - - - - - - - - - - diff --git a/WoWsShipBuilder.sln b/WoWsShipBuilder.sln index b7a94b0fc..42aaafdc4 100644 --- a/WoWsShipBuilder.sln +++ b/WoWsShipBuilder.sln @@ -35,8 +35,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub Workflows", "GitHub .github\workflows\web-release-check.yaml = .github\workflows\web-release-check.yaml EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WoWsShipBuilder.ReleaseTest", "WoWsShipBuilder.ReleaseTest\WoWsShipBuilder.ReleaseTest.csproj", "{282ECA58-2A33-40FC-9CD8-773E093BF8FD}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WoWsShipBuilder.Web", "WoWsShipBuilder.Web\WoWsShipBuilder.Web.csproj", "{D0FAB2EE-BAD4-4A7A-B9AD-1FC1565E13CC}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WoWsShipBuilder.Web.Test", "WoWsShipBuilder.Web.Test\WoWsShipBuilder.Web.Test.csproj", "{EB9B20AB-09DC-447C-948F-ABEB0E240E7B}" @@ -57,66 +55,43 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU - ReleaseTest|Any CPU = ReleaseTest|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {EEF97171-B405-488E-A45D-DCDF8DCF0761}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EEF97171-B405-488E-A45D-DCDF8DCF0761}.Debug|Any CPU.Build.0 = Debug|Any CPU {EEF97171-B405-488E-A45D-DCDF8DCF0761}.Release|Any CPU.ActiveCfg = Release|Any CPU {EEF97171-B405-488E-A45D-DCDF8DCF0761}.Release|Any CPU.Build.0 = Release|Any CPU - {EEF97171-B405-488E-A45D-DCDF8DCF0761}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU - {EEF97171-B405-488E-A45D-DCDF8DCF0761}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU - {282ECA58-2A33-40FC-9CD8-773E093BF8FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {282ECA58-2A33-40FC-9CD8-773E093BF8FD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {282ECA58-2A33-40FC-9CD8-773E093BF8FD}.ReleaseTest|Any CPU.ActiveCfg = Release|Any CPU - {282ECA58-2A33-40FC-9CD8-773E093BF8FD}.ReleaseTest|Any CPU.Build.0 = Release|Any CPU {D0FAB2EE-BAD4-4A7A-B9AD-1FC1565E13CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D0FAB2EE-BAD4-4A7A-B9AD-1FC1565E13CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {D0FAB2EE-BAD4-4A7A-B9AD-1FC1565E13CC}.Release|Any CPU.ActiveCfg = Release|Any CPU {D0FAB2EE-BAD4-4A7A-B9AD-1FC1565E13CC}.Release|Any CPU.Build.0 = Release|Any CPU - {D0FAB2EE-BAD4-4A7A-B9AD-1FC1565E13CC}.ReleaseTest|Any CPU.ActiveCfg = Debug|Any CPU - {D0FAB2EE-BAD4-4A7A-B9AD-1FC1565E13CC}.ReleaseTest|Any CPU.Build.0 = Debug|Any CPU {EB9B20AB-09DC-447C-948F-ABEB0E240E7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EB9B20AB-09DC-447C-948F-ABEB0E240E7B}.Debug|Any CPU.Build.0 = Debug|Any CPU {EB9B20AB-09DC-447C-948F-ABEB0E240E7B}.Release|Any CPU.ActiveCfg = Release|Any CPU {EB9B20AB-09DC-447C-948F-ABEB0E240E7B}.Release|Any CPU.Build.0 = Release|Any CPU - {EB9B20AB-09DC-447C-948F-ABEB0E240E7B}.ReleaseTest|Any CPU.ActiveCfg = Debug|Any CPU - {EB9B20AB-09DC-447C-948F-ABEB0E240E7B}.ReleaseTest|Any CPU.Build.0 = Debug|Any CPU {20ECB4C1-F0B2-48D5-B3A5-0684C0F9705C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {20ECB4C1-F0B2-48D5-B3A5-0684C0F9705C}.Debug|Any CPU.Build.0 = Debug|Any CPU {20ECB4C1-F0B2-48D5-B3A5-0684C0F9705C}.Release|Any CPU.ActiveCfg = Release|Any CPU {20ECB4C1-F0B2-48D5-B3A5-0684C0F9705C}.Release|Any CPU.Build.0 = Release|Any CPU - {20ECB4C1-F0B2-48D5-B3A5-0684C0F9705C}.ReleaseTest|Any CPU.ActiveCfg = Debug|Any CPU - {20ECB4C1-F0B2-48D5-B3A5-0684C0F9705C}.ReleaseTest|Any CPU.Build.0 = Debug|Any CPU {0D42323B-A853-4968-94B2-4BD6C8CC3103}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0D42323B-A853-4968-94B2-4BD6C8CC3103}.Debug|Any CPU.Build.0 = Debug|Any CPU {0D42323B-A853-4968-94B2-4BD6C8CC3103}.Release|Any CPU.ActiveCfg = Release|Any CPU {0D42323B-A853-4968-94B2-4BD6C8CC3103}.Release|Any CPU.Build.0 = Release|Any CPU - {0D42323B-A853-4968-94B2-4BD6C8CC3103}.ReleaseTest|Any CPU.ActiveCfg = Debug|Any CPU - {0D42323B-A853-4968-94B2-4BD6C8CC3103}.ReleaseTest|Any CPU.Build.0 = Debug|Any CPU {FB141047-D909-4C88-85DF-8F14E6E2A23B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FB141047-D909-4C88-85DF-8F14E6E2A23B}.Debug|Any CPU.Build.0 = Debug|Any CPU {FB141047-D909-4C88-85DF-8F14E6E2A23B}.Release|Any CPU.ActiveCfg = Release|Any CPU {FB141047-D909-4C88-85DF-8F14E6E2A23B}.Release|Any CPU.Build.0 = Release|Any CPU - {FB141047-D909-4C88-85DF-8F14E6E2A23B}.ReleaseTest|Any CPU.ActiveCfg = Debug|Any CPU - {FB141047-D909-4C88-85DF-8F14E6E2A23B}.ReleaseTest|Any CPU.Build.0 = Debug|Any CPU {5236BCFD-053A-40AC-A919-11A0381FD7A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5236BCFD-053A-40AC-A919-11A0381FD7A9}.Debug|Any CPU.Build.0 = Debug|Any CPU {5236BCFD-053A-40AC-A919-11A0381FD7A9}.Release|Any CPU.ActiveCfg = Release|Any CPU {5236BCFD-053A-40AC-A919-11A0381FD7A9}.Release|Any CPU.Build.0 = Release|Any CPU - {5236BCFD-053A-40AC-A919-11A0381FD7A9}.ReleaseTest|Any CPU.ActiveCfg = Debug|Any CPU - {5236BCFD-053A-40AC-A919-11A0381FD7A9}.ReleaseTest|Any CPU.Build.0 = Debug|Any CPU {ADF8F4FA-286D-42FE-B5D2-E3FBEBE3732A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ADF8F4FA-286D-42FE-B5D2-E3FBEBE3732A}.Debug|Any CPU.Build.0 = Debug|Any CPU {ADF8F4FA-286D-42FE-B5D2-E3FBEBE3732A}.Release|Any CPU.ActiveCfg = Release|Any CPU {ADF8F4FA-286D-42FE-B5D2-E3FBEBE3732A}.Release|Any CPU.Build.0 = Release|Any CPU - {ADF8F4FA-286D-42FE-B5D2-E3FBEBE3732A}.ReleaseTest|Any CPU.ActiveCfg = Debug|Any CPU - {ADF8F4FA-286D-42FE-B5D2-E3FBEBE3732A}.ReleaseTest|Any CPU.Build.0 = Debug|Any CPU {344A6052-BB97-4E29-A61E-680DC42F644F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {344A6052-BB97-4E29-A61E-680DC42F644F}.Debug|Any CPU.Build.0 = Debug|Any CPU {344A6052-BB97-4E29-A61E-680DC42F644F}.Release|Any CPU.ActiveCfg = Release|Any CPU {344A6052-BB97-4E29-A61E-680DC42F644F}.Release|Any CPU.Build.0 = Release|Any CPU - {344A6052-BB97-4E29-A61E-680DC42F644F}.ReleaseTest|Any CPU.ActiveCfg = Debug|Any CPU - {344A6052-BB97-4E29-A61E-680DC42F644F}.ReleaseTest|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection EndGlobal diff --git a/dirs.proj b/dirs.proj index 043a3b07a..f46c38291 100644 --- a/dirs.proj +++ b/dirs.proj @@ -13,11 +13,8 @@ - - - - \ No newline at end of file + From dfbb170cf2d86932140a746301222778f152ff82 Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 14 Oct 2023 22:20:06 +0200 Subject: [PATCH 05/26] fix indentation error --- WoWsShipBuilder.Desktop/App.axaml.cs | 66 ++++++++++++++-------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/WoWsShipBuilder.Desktop/App.axaml.cs b/WoWsShipBuilder.Desktop/App.axaml.cs index d1bde2160..eab970845 100644 --- a/WoWsShipBuilder.Desktop/App.axaml.cs +++ b/WoWsShipBuilder.Desktop/App.axaml.cs @@ -41,11 +41,11 @@ public App() public IServiceProvider Services { - get => services; + get => this.services; init { - services = value; - logger = services.GetRequiredService>(); + this.services = value; + this.logger = this.services.GetRequiredService>(); } } @@ -66,17 +66,17 @@ public override void Initialize() public override void OnFrameworkInitializationCompleted() { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (this.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - Logging.Initialize(Services.GetRequiredService()); - InitializeSettings(); - var settings = Services.GetRequiredService(); + Logging.Initialize(this.Services.GetRequiredService()); + this.InitializeSettings(); + var settings = this.Services.GetRequiredService(); LogManager.ReconfigExistingLoggers(); - desktop.Exit += OnExit; - desktop.MainWindow = new SplashScreen(Services); - logger.LogInformation("AutoUpdate Enabled: {SettingsAutoUpdateEnabled}", settings.AutoUpdateEnabled); + desktop.Exit += this.OnExit; + desktop.MainWindow = new SplashScreen(this.Services); + this.logger.LogInformation("AutoUpdate Enabled: {SettingsAutoUpdateEnabled}", settings.AutoUpdateEnabled); if (settings.AutoUpdateEnabled) { @@ -84,12 +84,12 @@ public override void OnFrameworkInitializationCompleted() { if (OperatingSystem.IsWindows()) { - await UpdateCheck(Services.GetRequiredService()); - logger.LogInformation("Finished updatecheck"); + await this.UpdateCheck(this.Services.GetRequiredService()); + this.logger.LogInformation("Finished updatecheck"); } else { - logger.LogInformation("Skipped updatecheck"); + this.logger.LogInformation("Skipped updatecheck"); } }); } @@ -100,48 +100,48 @@ public override void OnFrameworkInitializationCompleted() private void InitializeSettings() { - var settingsAccessor = (DesktopSettingsAccessor)services.GetRequiredService(); + var settingsAccessor = (DesktopSettingsAccessor)this.services.GetRequiredService(); var settings = settingsAccessor.LoadSettingsSync(); settings ??= new(); - logger.LogDebug("Updating app settings with settings read from file..."); - var appSettings = services.GetRequiredService(); + this.logger.LogDebug("Updating app settings with settings read from file..."); + var appSettings = this.services.GetRequiredService(); appSettings.UpdateFromSettings(settings); AppData.IsInitialized = true; Thread.CurrentThread.CurrentCulture = appSettings.SelectedLanguage.CultureInfo; Thread.CurrentThread.CurrentUICulture = appSettings.SelectedLanguage.CultureInfo; - logger.LogDebug("Settings initialization complete"); + this.logger.LogDebug("Settings initialization complete"); } private void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs e) { - logger.LogInformation("Closing app, saving setting and builds"); - var settingsAccessor = (DesktopSettingsAccessor)Services.GetRequiredService(); - settingsAccessor.SaveSettingsSync(Services.GetRequiredService()); - logger.LogInformation("Exiting..."); - logger.LogInformation("------------------------------"); + this.logger.LogInformation("Closing app, saving setting and builds"); + var settingsAccessor = (DesktopSettingsAccessor)this.Services.GetRequiredService(); + settingsAccessor.SaveSettingsSync(this.Services.GetRequiredService()); + this.logger.LogInformation("Exiting..."); + this.logger.LogInformation("------------------------------"); } [SupportedOSPlatform("windows")] private async Task UpdateCheck(AppNotificationService notificationService) { - logger.LogInformation("Current version: {Version}", Assembly.GetExecutingAssembly().GetName().Version); + this.logger.LogInformation("Current version: {Version}", Assembly.GetExecutingAssembly().GetName().Version); using UpdateManager updateManager = new GithubUpdateManager("https://github.com/WoWs-Builder-Team/WoWs-ShipBuilder"); if (!updateManager.IsInstalledApp) { - logger.LogInformation("No update.exe found, aborting update check"); + this.logger.LogInformation("No update.exe found, aborting update check"); return; } - logger.LogInformation("Update manager initialized"); + this.logger.LogInformation("Update manager initialized"); try { // Can throw a null-reference-exception, no idea why. var updateInfo = await updateManager.CheckForUpdate(); if (!updateInfo.ReleasesToApply.Any()) { - logger.LogInformation("No app update found"); + this.logger.LogInformation("No app update found"); return; } @@ -149,16 +149,16 @@ private async Task UpdateCheck(AppNotificationService notificationService) var release = await updateManager.UpdateApp(); if (release == null) { - logger.LogInformation("No app update found"); + this.logger.LogInformation("No app update found"); return; } - logger.LogInformation("App updated to version {ReleaseVersion}", release.Version); + this.logger.LogInformation("App updated to version {ReleaseVersion}", release.Version); await notificationService.NotifyAppUpdateComplete(); - var result = await ShowUpdateRestartDialog((ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow, Services.GetRequiredService()); + var result = await ShowUpdateRestartDialog((this.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow, this.Services.GetRequiredService()); if (result.Equals(MessageBox.MessageBoxResult.Yes)) { - logger.LogInformation("User decided to restart after update"); + this.logger.LogInformation("User decided to restart after update"); if (OperatingSystem.IsWindows()) { UpdateManager.RestartApp(); @@ -167,14 +167,14 @@ private async Task UpdateCheck(AppNotificationService notificationService) } catch (NullReferenceException) { - logger.LogDebug("NullReferenceException during app update"); + this.logger.LogDebug("NullReferenceException during app update"); } catch (Exception e) { #if DEBUG - logger.LogWarning(e, "Exception during app update"); + this.logger.LogWarning(e, "Exception during app update"); #else - logger.LogError(e, "Exception during app update"); + this.logger.LogError(e, "Exception during app update"); #endif await notificationService.NotifyAppUpdateError(nameof(Translation.NotificationService_ErrorMessage)); } From 7d53feb9e8b78860dc0e21e696cd17978e53bc74 Mon Sep 17 00:00:00 2001 From: iTTo <13366390+iTTou@users.noreply.github.com> Date: Sat, 14 Oct 2023 22:22:32 +0200 Subject: [PATCH 06/26] Ship Comparison Revamp (#261) * Filters UI clean up * Initial work on ship comparison revamp * Implement #252 * revert ship stats panel chances * revert upgradedModulesUrlParameter * move loadSettings method code into vm constructor * change to use mudHidden instead of breakPointProvider to display filters * extract ship filter from ship comparison and fix wrapping #252 * fix nullability warning and improve margin for search box --- .../Components/BuildImageRenderDialog.razor | 2 +- .../Features/Settings/AppSettings.cs | 16 + .../ShipComparison/ComparisonShipFilter.razor | 279 +++++++++++++ .../ShipComparison/ShipComparison.razor | 379 +++++++++--------- .../ShipComparison/ShipComparisonViewModel.cs | 23 +- .../ShipStats/Components/ShipStatsPanel.razor | 2 +- .../Resources/Translation.Designer.cs | 18 + .../Localization/Resources/Translation.resx | 6 + WoWsShipBuilder.Common/wwwroot/css/app.css | 21 +- 9 files changed, 542 insertions(+), 204 deletions(-) create mode 100644 WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageRenderDialog.razor b/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageRenderDialog.razor index 6fb9bc9ce..819be4142 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageRenderDialog.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageRenderDialog.razor @@ -113,7 +113,7 @@ - + @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization diff --git a/WoWsShipBuilder.Common/Features/Settings/AppSettings.cs b/WoWsShipBuilder.Common/Features/Settings/AppSettings.cs index 9a887531d..1de6b8a3a 100644 --- a/WoWsShipBuilder.Common/Features/Settings/AppSettings.cs +++ b/WoWsShipBuilder.Common/Features/Settings/AppSettings.cs @@ -47,6 +47,14 @@ public AppSettings(CultureDetails? selectedLanguage = null) public bool[] BuildImageLayoutSettings { get; set; } = { true, false, true, true, true, true }; + public bool ShipComparisonUseUpgradedModules { get; set; } = true; + + public bool ShipComparisonHideShipsWithoutSection { get; set; } + + public double ShipComparisonFiringRange { get; set; } = 10; + + public string? ShipComparisonHiddenColumns { get; set; } + public void ClearSettings() { AutoUpdateEnabled = true; @@ -65,6 +73,10 @@ public void ClearSettings() OpenSecondariesAndAaExpandersByDefault = false; BetaAccessCodes = new(); BuildImageLayoutSettings = new[] { true, false, true, true, true, true }; + ShipComparisonFiringRange = 10; + ShipComparisonUseUpgradedModules = true; + ShipComparisonHideShipsWithoutSection = false; + ShipComparisonHiddenColumns = default; } public void UpdateFromSettings(AppSettings settings) @@ -85,5 +97,9 @@ public void UpdateFromSettings(AppSettings settings) OpenSecondariesAndAaExpandersByDefault = settings.OpenSecondariesAndAaExpandersByDefault; BetaAccessCodes = settings.BetaAccessCodes; BuildImageLayoutSettings = settings.BuildImageLayoutSettings; + ShipComparisonFiringRange = settings.ShipComparisonFiringRange; + ShipComparisonUseUpgradedModules = settings.ShipComparisonUseUpgradedModules; + ShipComparisonHideShipsWithoutSection = settings.ShipComparisonHideShipsWithoutSection; + ShipComparisonHiddenColumns = settings.ShipComparisonHiddenColumns; } } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor b/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor new file mode 100644 index 000000000..33f7a141a --- /dev/null +++ b/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor @@ -0,0 +1,279 @@ +@using WoWsShipBuilder.Infrastructure.Localization.Resources +@using WoWsShipBuilder.Infrastructure.GameData +@using WoWsShipBuilder.DataStructures + +@inherits ReactiveComponentBase + +@inject ILocalizer Localizer + + + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_TierFilter)) + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) + + + + + @for (int i = TiersRange.First(); i <= TiersRange.Last(); i++) + { + int tier = i; + bool isSelected = ViewModel!.SelectedTiers.Contains(tier); + + @tier.ToTierString() + + } + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_ClassFilter)) + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) + + + + + @foreach (var shipClass in ViewModel!.AvailableClasses) + { + bool isSelected = ViewModel.SelectedClasses.Contains(shipClass); + + @Localizer.GetAppLocalization(shipClass.ShipClassToString()).Localization + + } + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_NationFilter)) + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) + + + + + @foreach (var nation in ViewModel!.AvailableNations) + { + bool isSelected = ViewModel.SelectedNations.Contains(nation); + + @Localizer.GetAppLocalization(nation.ShipNationToString()).Localization + + } + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_TypeFilter)) + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) + + + + + @foreach (var category in ViewModel!.AvailableShipCategories) + { + bool isSelected = ViewModel.SelectedCategories.Contains(category); + + @Localizer.GetAppLocalization(category.ShipCategoryToString()).Localization + + } + + + + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_TierFilter)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_ClassFilter)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_NationFilter)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_TypeFilter)) + + + + + @for (int i = TiersRange.First(); i <= TiersRange.Last(); i++) + { + int tier = i; + bool isSelected = ViewModel!.SelectedTiers.Contains(tier); + + @tier.ToTierString() + + } + + + @foreach (var shipClass in ViewModel!.AvailableClasses) + { + bool isSelected = ViewModel.SelectedClasses.Contains(shipClass); + + @Localizer.GetAppLocalization(shipClass.ShipClassToString()).Localization + + } + + + @foreach (var nation in ViewModel!.AvailableNations) + { + bool isSelected = ViewModel.SelectedNations.Contains(nation); + + @Localizer.GetAppLocalization(nation.ShipNationToString()).Localization + + } + + + @foreach (var category in ViewModel!.AvailableShipCategories) + { + bool isSelected = ViewModel.SelectedCategories.Contains(category); + + @Localizer.GetAppLocalization(category.ShipCategoryToString()).Localization + + } + + + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) + + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) + + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) + + + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) + + + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) + + + + + + + + +@code { + private static readonly int[] TiersRange = { 1, 11 }; + + [Parameter, EditorRequired] + public Func SelectionChanged { get; set; } = default!; + + private static Variant GetVariantFromBool(bool active) + { + return active ? Variant.Filled : Variant.Outlined; + } + + private static Color GetColorFromBool(bool active) + { + return active ? Color.Primary : Color.Secondary; + } + + private async Task ToggleTierSelection(int tier, MouseEventArgs args) + { + if (args.Button == 2) + { + await ViewModel!.ToggleAllTiers(false, false); + } + + await ViewModel!.ToggleTierSelection(tier); + await SelectionChanged(); + } + + private async Task ToggleClassSelection(ShipClass shipClass, MouseEventArgs args) + { + if (args.Button == 2) + { + await ViewModel!.ToggleAllClasses(false, false); + } + + await ViewModel!.ToggleClassSelection(shipClass); + await SelectionChanged(); + } + + private async Task ToggleNationSelection(Nation nation, MouseEventArgs args) + { + if (args.Button == 2) + { + await ViewModel!.ToggleAllNations(false, false); + } + + await ViewModel!.ToggleNationSelection(nation); + await SelectionChanged(); + } + + private async Task ToggleCategorySelection(ShipCategory category, MouseEventArgs args) + { + if (args.Button == 2) + { + await ViewModel!.ToggleAllCategories(false, false); + } + + await ViewModel!.ToggleCategorySelection(category); + await SelectionChanged(); + } + + private async Task ToggleAllCategories(bool toggle) + { + await ViewModel!.ToggleAllCategories(toggle); + await SelectionChanged(); + } + + private async Task ToggleAllClasses(bool toggle) + { + await ViewModel!.ToggleAllClasses(toggle); + await SelectionChanged(); + } + + private async Task ToggleAllNations(bool toggle) + { + await ViewModel!.ToggleAllNations(toggle); + await SelectionChanged(); + } + + private async Task ToggleAllTiers(bool toggle) + { + await ViewModel!.ToggleAllTiers(toggle); + await SelectionChanged(); + } + +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparison.razor b/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparison.razor index 8d8fee8b8..928f30f8e 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparison.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparison.razor @@ -5,7 +5,6 @@ @using Microsoft.Extensions.Hosting @using Microsoft.Extensions.Options @using Prometheus -@using WoWsShipBuilder.DataStructures @using WoWsShipBuilder.Features.Builds @using WoWsShipBuilder.Features.Builds.Components @using WoWsShipBuilder.Features.Settings @@ -44,6 +43,7 @@ @inject ILocalizer Localizer @inject ISnackbar Snackbar @inject AppSettings AppSettings +@inject ISettingsAccessor SettingsAccessor @inject IOptions CdnOptions @inject NavigationManager NavManager @inject IJSRuntime JsRuntime @@ -55,7 +55,8 @@ @if (ViewModel is not null) { - +
+ if (!string.IsNullOrEmpty(ViewModel.ResearchedShip)) { @@ -65,7 +66,7 @@ - @(LocalizeShipName(ship.Index)) + @LocalizeShipName(ship.Index) @@ -73,121 +74,49 @@ } - - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_TierFilter)) - - - @for (int i = TiersRange.First(); i <= TiersRange.Last(); i++) - { - int tier = i; - bool isSelected = ViewModel.SelectedTiers.Contains(tier); - - @tier.ToTierString() - - } - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) - - - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_ClassFilter)) - - - @foreach (var shipClass in ViewModel!.AvailableClasses) - { - bool isSelected = ViewModel.SelectedClasses.Contains(shipClass); - - @Localizer.GetAppLocalization(shipClass.ShipClassToString()).Localization - - } - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) - - - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_NationFilter)) - - - @foreach (var nation in ViewModel!.AvailableNations) - { - bool isSelected = ViewModel.SelectedNations.Contains(nation); - - @Localizer.GetAppLocalization(nation.ShipNationToString()).Localization - - } - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) - - - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_TypeFilter)) - - - @foreach (var category in ViewModel!.AvailableShipCategories) - { - bool isSelected = ViewModel.SelectedCategories.Contains(category); - - @Localizer.GetAppLocalization(category.ShipCategoryToString()).Localization - - } - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) - - - + + + - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_DisplayOnlyPinnedShips)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_UseUpgradedModules)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_HideIfNoSection)) - + @(ViewModel.SelectAllShips ? Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_UnselectAll)) : Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_SelectAll))) - + @(ViewModel!.PinAllShips ? Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_UnpinAll)) : Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_PinAll))) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_ResetAll)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_Duplicate)) @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_EditBuilds)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_RemoveBuilds)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_ViewStats)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_ViewBallistic)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_ViewAcceleration)) @@ -206,33 +135,23 @@ - + - -
- -
- -
- -
- - @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_ActiveColumns)) + + + @($"{Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_HideColumns))} : {hiddenColumns.Count(x => x.Value)}") -
- -
- +
- + - + @@ -244,18 +163,39 @@ - - - @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_NoMatchingShipsFound)) @@ -314,10 +251,6 @@ private MudDataGrid dataGrid = default!; - private static readonly int[] GridPagination = { 25, 50, 75, 100, 150, 200 }; - - private static readonly int[] TiersRange = { 1, 11 }; - private const string StickyColumnsBackgroundColor = "background-color: #242424"; private const string TiersUrlParameter = "t"; @@ -334,8 +267,18 @@ private const string SectionUrlParameter = "s"; + private const string PinnedShipsUrlParameter = "p"; + + private const string PinnedShipsOnlyUrlParameter = "po"; + + private const string RangeUrlParameter = "r"; + + private const string HiddenColumnsUrlParameter = "hc"; + private Dictionary hiddenColumns = new(); + private string hiddeColumnsUrlString = default!; + private BuildConfigurationDialogHelper buildConfigurationHelper = default!; private bool isDialogOpen; @@ -353,6 +296,9 @@ NavManager.TryGetQueryString(UpgradedModulesUrlParameter, out string upgradedModules); NavManager.TryGetQueryString(HideUnfittingShipsUrlParameter, out string hideUnfittingShips); NavManager.TryGetQueryString(SectionUrlParameter, out string section); + NavManager.TryGetQueryString(RangeUrlParameter, out string range); + NavManager.TryGetQueryString(PinnedShipsUrlParameter, out string pinnedShips); + NavManager.TryGetQueryString(PinnedShipsOnlyUrlParameter, out string pinnedShipsOnly); var applyFilters = false; @@ -395,33 +341,63 @@ if (!string.IsNullOrEmpty(section)) { applyFilters = true; - ViewModel.SelectedDataSection = Enum.Parse(section); + ViewModel.SelectedDataSection = (ShipComparisonDataSections)int.Parse(section); } - if (applyFilters) + if (!string.IsNullOrEmpty(range)) { - await ViewModel.ApplyFilters(); + applyFilters = true; + ViewModel!.UpdateRange(double.Parse(range)); + } + + if (!string.IsNullOrEmpty(pinnedShipsOnly)) + { + applyFilters = true; + ViewModel.ShowPinnedShipsOnly = true; } - var buildContainers = SessionStateCache.GetAndResetBuildTransferContainers(); + if (!string.IsNullOrEmpty(pinnedShips)) + { + await AddShip(pinnedShips.Split(','), false); + } + + List? buildContainers = SessionStateCache.GetAndResetBuildTransferContainers(); if (buildContainers is not null) { - foreach (var container in buildContainers) - { - ViewModel!.AddShip(container); - } + await AddShip(buildContainers, false); + } + + if (applyFilters) + { + await ViewModel.ApplyFilters(); } } - protected override void OnAfterRender(bool firstRender) + protected override async Task OnAfterRenderAsync(bool firstRender) { - base.OnAfterRender(firstRender); + await base.OnAfterRenderAsync(firstRender); if (firstRender) { MetricsService.PageAccessCount.WithLabels("comparison").Inc(); - } - hiddenColumns = dataGrid.RenderedColumns.Where(x => x.Hideable is true).ToDictionary(x => x.FieldId, x => hiddenColumns.TryGetValue(x.FieldId, out bool hidden) && hidden); + hiddenColumns = dataGrid.RenderedColumns.Where(x => x.Hideable is true).ToDictionary(x => x.FieldId, x => hiddenColumns.TryGetValue(x.FieldId, out bool hidden) && hidden); + + NavManager.TryGetQueryString(HiddenColumnsUrlParameter, out hiddeColumnsUrlString); + if (string.IsNullOrEmpty(hiddeColumnsUrlString)) + { + hiddeColumnsUrlString = AppSettings.ShipComparisonHiddenColumns ?? default!; + } + + if (!string.IsNullOrEmpty(hiddeColumnsUrlString)) + { + foreach (var index in hiddeColumnsUrlString.Split(',')) + { + hiddenColumns[hiddenColumns.ElementAt(int.Parse(index)).Key] = true; + } + } + + await UpdateUrl(); + } } private static Variant GetVariantFromBool(bool active) @@ -494,7 +470,9 @@ MetricsService.ShipComparisonActions.WithLabels("hide-ships-without-section").Inc(); } + AppSettings.ShipComparisonHideShipsWithoutSection = ViewModel.HideShipsWithoutSelectedSection; await UpdateUrl(); + await SettingsAccessor.SaveSettings(AppSettings); await dataGrid.ReloadServerData(); } @@ -502,6 +480,7 @@ { MetricsService.ShipComparisonActions.WithLabels("toggle-pin").Inc(); await ViewModel!.AddPinnedShip(wrapper); + await UpdateUrl(); await dataGrid.ReloadServerData(); } @@ -538,90 +517,61 @@ MetricsService.ShipComparisonActions.WithLabels("use-upgraded-modules").Inc(); } + AppSettings.ShipComparisonUseUpgradedModules = ViewModel.UseUpgradedModules; await UpdateUrl(); + await SettingsAccessor.SaveSettings(AppSettings); await dataGrid.ReloadServerData(); } - private async Task AddSearchedShip(object? obj) + private async Task UpdateRange(double range) { - ViewModel!.AddShip(obj); - await dataGrid.ReloadServerData(); + ViewModel!.UpdateRange(range); + AppSettings.ShipComparisonFiringRange = ViewModel.Range; + await UpdateUrl(); + await SettingsAccessor.SaveSettings(AppSettings); } - private async Task ToggleTierSelection(int tier, MouseEventArgs args) + private async Task AddSearchedShip(object? obj) { - if (args.Button == 2) - { - await ViewModel!.ToggleAllTiers(false, false); - } - - await ViewModel!.ToggleTierSelection(tier); - await UpdateUrl(); + ViewModel!.AddShip(obj); await dataGrid.ReloadServerData(); } - private async Task ToggleClassSelection(ShipClass shipClass, MouseEventArgs args) + private async Task NotifySelectionChangedAsync() { - if (args.Button == 2) - { - await ViewModel!.ToggleAllClasses(false, false); - } - - await ViewModel!.ToggleClassSelection(shipClass); await UpdateUrl(); await dataGrid.ReloadServerData(); } - private async Task ToggleNationSelection(Nation nation, MouseEventArgs args) + private async Task AddShip(object obj, bool updateUrl = true) { - if (args.Button == 2) + switch (obj) { - await ViewModel!.ToggleAllNations(false, false); + case List shipBuildContainerList: + { + foreach (var container in shipBuildContainerList) + { + ViewModel!.AddShip(container); + } + break; + } + case string[] pinnedShips: + { + foreach (var pinnedShip in pinnedShips) + { + ViewModel!.AddShip(pinnedShip); + } + break; + } + default: + ViewModel!.AddShip(obj); + break; } - await ViewModel!.ToggleNationSelection(nation); - await UpdateUrl(); - await dataGrid.ReloadServerData(); - } - - private async Task ToggleCategorySelection(ShipCategory category, MouseEventArgs args) - { - if (args.Button == 2) + if (updateUrl) { - await ViewModel!.ToggleAllCategories(false, false); + await UpdateUrl(); } - - await ViewModel!.ToggleCategorySelection(category); - await UpdateUrl(); - await dataGrid.ReloadServerData(); - } - - private async Task ToggleAllCategories(bool toggle) - { - await ViewModel!.ToggleAllCategories(toggle); - await UpdateUrl(); - await dataGrid.ReloadServerData(); - } - - private async Task ToggleAllClasses(bool toggle) - { - await ViewModel!.ToggleAllClasses(toggle); - await UpdateUrl(); - await dataGrid.ReloadServerData(); - } - - private async Task ToggleAllNations(bool toggle) - { - await ViewModel!.ToggleAllNations(toggle); - await UpdateUrl(); - await dataGrid.ReloadServerData(); - } - - private async Task ToggleAllTiers(bool toggle) - { - await ViewModel!.ToggleAllTiers(toggle); - await UpdateUrl(); - await dataGrid.ReloadServerData(); } private async Task Search(string obj) @@ -685,8 +635,13 @@ { hiddenColumns[item.Key] = item.Value; } - StateHasChanged(); + + SetHiddenColumnsUrlString(); + AppSettings.ShipComparisonHiddenColumns = hiddeColumnsUrlString; + await UpdateUrl(); + await SettingsAccessor.SaveSettings(AppSettings); } + isDialogOpen = false; } @@ -728,7 +683,7 @@ } MetricsService.ComparisonShipCount.Observe(data.Count); - return Task.FromResult>(new() { TotalItems = data.Count, Items = data.Skip(state.Page * state.PageSize).Take(state.PageSize).ToList() }); + return Task.FromResult>(new() { TotalItems = data.Count, Items = data }); } } @@ -782,7 +737,23 @@ private bool IsColumnHidden(string section, string columnTitle) { - return !ViewModel!.SelectedDataSection.AsString().Equals(section) || hiddenColumns.TryGetValue($"{section}_{columnTitle}", out bool hidden) && hidden; + return !ViewModel!.SelectedDataSection.AsString().Equals(section) || (hiddenColumns.TryGetValue($"{section}_{columnTitle}", out bool hidden) && hidden); + } + + private void SetHiddenColumnsUrlString() + { + var list = new List(); + var count = 0; + foreach (var column in hiddenColumns) + { + if (column.Value) + { + list.Add(count); + } + count++; + } + + hiddeColumnsUrlString = string.Join(',', list); } private async Task UpdateUrl() @@ -820,7 +791,27 @@ if (ViewModel!.SelectedDataSection != ShipComparisonDataSections.General) { - url.Add(SectionUrlParameter, ViewModel!.SelectedDataSection.AsString()); + url.Add(SectionUrlParameter, $"{(int)ViewModel!.SelectedDataSection}"); + } + + if (ViewModel!.Range is > 10 or < 10) + { + url.Add(RangeUrlParameter, $"{ViewModel!.Range}"); + } + + if (!string.IsNullOrEmpty(hiddeColumnsUrlString)) + { + url.Add(HiddenColumnsUrlParameter, hiddeColumnsUrlString); + } + + if (ViewModel!.ShowPinnedShipsOnly) + { + url.Add(PinnedShipsOnlyUrlParameter, "1"); + } + + if (ViewModel!.PinnedShipList.Any()) + { + url.Add(PinnedShipsUrlParameter, string.Join(',', ViewModel!.PinnedShipList.Take(100).Select(x => x.Value.ShipIndex))); } // Required instead of NavManager.NavigateTo in order to keep scroll state of the current page diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs b/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs index 94cbee3ee..5bed49e30 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs @@ -54,6 +54,10 @@ public ShipComparisonViewModel(ILocalizer localizer, AppSettings appSettings) { this.localizer = localizer; this.appSettings = appSettings; + + useUpgradedModules = appSettings.ShipComparisonUseUpgradedModules; + hideShipsWithoutSelectedSection = appSettings.ShipComparisonHideShipsWithoutSection; + Range = appSettings.ShipComparisonFiringRange; } private Dictionary FilteredShipList @@ -88,7 +92,7 @@ private Dictionary FilteredShipList public Dictionary DispersionCache { get; } = new(); - public double Range { get; private set; } = 10; + public double Range { get; private set; } public string ResearchedShip { @@ -119,10 +123,10 @@ public Task ApplyFilters() dictionary.AddRange(filteredShips.Where(x => !dictionary.ContainsKey(x.Key))); - Dictionary cachedWrappers = wrappersCache.Where(data => SelectedTiers.Contains(data.Value.Ship.Tier) && - SelectedClasses.Contains(data.Value.Ship.ShipClass) && - SelectedNations.Contains(data.Value.Ship.ShipNation) && - SelectedCategories.Contains(data.Value.Ship.ShipCategory)).ToDictionary(x => x.Key, x => x.Value); + var cachedWrappers = wrappersCache.Where(data => SelectedTiers.Contains(data.Value.Ship.Tier) && + SelectedClasses.Contains(data.Value.Ship.ShipClass) && + SelectedNations.Contains(data.Value.Ship.ShipNation) && + SelectedCategories.Contains(data.Value.Ship.ShipCategory)).ToDictionary(x => x.Key, x => x.Value); dictionary.AddRange(cachedWrappers.Where(x => !dictionary.ContainsKey(x.Key))); @@ -291,7 +295,7 @@ public void EditBuilds(IEnumerable> newWrapp public Dictionary RemoveBuilds(IEnumerable> wrappers) { Dictionary warnings = new(); - Dictionary buildList = wrappers.ToDictionary(x => x.Key, x => x.Value); + var buildList = wrappers.ToDictionary(x => x.Key, x => x.Value); foreach (var wrapper in buildList) { if (FilteredShipList.Count(x => x.Value.Ship.Index.Equals(wrapper.Value.Ship.Index)) > 1) @@ -334,7 +338,7 @@ public void ResetAllBuilds() { RemoveBuilds(FilteredShipList); SelectedShipList.Clear(); - Dictionary list = FilteredShipList.Where(x => x.Value.Build is not null).ToDictionary(x => x.Key, x => ResetBuild(x.Value)); + var list = FilteredShipList.Where(x => x.Value.Build is not null).ToDictionary(x => x.Key, x => ResetBuild(x.Value)); EditBuilds(list, true); SetSelectAndPinAllButtonsStatus(); } @@ -463,6 +467,11 @@ public void AddShip(object? obj) { newWrapper = new(ShipBuildContainer.CreateNew(ship, null, null) with { ShipDataContainer = GetShipDataContainer(ship) }); } + else if (obj is string shipIndex) + { + var shipFromIndex = fullShipList.First(x => x.Index.Equals(shipIndex, StringComparison.Ordinal)); + newWrapper = new(ShipBuildContainer.CreateNew(shipFromIndex, null, null) with { ShipDataContainer = GetShipDataContainer(shipFromIndex) }); + } else { return; diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor index 9eea18651..5b446033b 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor @@ -587,4 +587,4 @@ return description; } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Infrastructure/Localization/Resources/Translation.Designer.cs b/WoWsShipBuilder.Common/Infrastructure/Localization/Resources/Translation.Designer.cs index 02856e6cb..0d13bcc29 100644 --- a/WoWsShipBuilder.Common/Infrastructure/Localization/Resources/Translation.Designer.cs +++ b/WoWsShipBuilder.Common/Infrastructure/Localization/Resources/Translation.Designer.cs @@ -2285,6 +2285,15 @@ public static string ShipComparison_General { } } + /// + /// Looks up a localized string similar to Hide Columns. + /// + public static string ShipComparison_HideColumns { + get { + return ResourceManager.GetString("ShipComparison_HideColumns", resourceCulture); + } + } + /// /// Looks up a localized string similar to Hide ships without selected section. /// @@ -2483,6 +2492,15 @@ public static string ShipComparison_SelectAll { } } + /// + /// Looks up a localized string similar to Ships per page:. + /// + public static string ShipComparison_ShipsPerPage { + get { + return ResourceManager.GetString("ShipComparison_ShipsPerPage", resourceCulture); + } + } + /// /// Looks up a localized string similar to Smoke Firing. /// diff --git a/WoWsShipBuilder.Common/Infrastructure/Localization/Resources/Translation.resx b/WoWsShipBuilder.Common/Infrastructure/Localization/Resources/Translation.resx index 94340a943..0790bbab6 100644 --- a/WoWsShipBuilder.Common/Infrastructure/Localization/Resources/Translation.resx +++ b/WoWsShipBuilder.Common/Infrastructure/Localization/Resources/Translation.resx @@ -2054,4 +2054,10 @@ You can use the Change builds button to manage the builds of single ships. You c The depth of submarines shown in game is expressed as "ship_meter". Subs can dive 60[ship_m] = 120[m]. + + Ships per page: + + + Hide Columns + \ No newline at end of file diff --git a/WoWsShipBuilder.Common/wwwroot/css/app.css b/WoWsShipBuilder.Common/wwwroot/css/app.css index 6424bc154..45b216b84 100644 --- a/WoWsShipBuilder.Common/wwwroot/css/app.css +++ b/WoWsShipBuilder.Common/wwwroot/css/app.css @@ -253,4 +253,23 @@ div.mud-expand-panel { padding: 4px 8px; min-height: 24px; background-color: rgba(80, 80, 80, 40%); -} \ No newline at end of file +} +.mud-data-grid button.drag-icon-options { + visibility: hidden; + width: 0; + padding: 0; +} + +.mud-data-grid .mud-table-cell { + padding: 1px 3px !important; + margin: 0; +} + +.mud-data-grid-range-selector div.mud-input-control-input-container { + margin: 0 10px 10px auto; + width: 100px +} + +.mud-data-grid-range-selector label.mud-input-label-text { + display: ruby !important; +} From 6ce71c6c2f64b06277031851b6f0e1b7be1f6c1a Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 14 Oct 2023 22:27:28 +0200 Subject: [PATCH 07/26] fix second sonar.login usage in sonar workflow --- .github/workflows/sonar-code-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonar-code-analysis.yml b/.github/workflows/sonar-code-analysis.yml index 1d798be35..a780d1db2 100644 --- a/.github/workflows/sonar-code-analysis.yml +++ b/.github/workflows/sonar-code-analysis.yml @@ -50,4 +50,4 @@ jobs: ./.sonar/scanner/dotnet-sonarscanner begin /k:"WoWs-Builder-Team_WoWs-ShipBuilder" /o:"wows-builder-team" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="TestResults/*/*.xml" dotnet build dirs.proj -c Release --no-restore dotnet test dirs.proj -c Release --no-build --collect:"XPlat Code Coverage;Format=opencover" --results-directory TestResults - ./.sonar/scanner/dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" + ./.sonar/scanner/dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" From 2939771704800a1da8326575ffb148b9a10577d8 Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 14 Oct 2023 23:05:51 +0200 Subject: [PATCH 08/26] reduce complexity of some large methods --- .../Components/CaptainSkillSelector.razor | 8 +- .../ShipStats/Components/ShipStatsTab.razor | 68 +++++---- .../Features/ShipStats/ShipStats.razor | 34 +++-- .../ViewModels/SkillItemViewModel.cs | 139 ++++++++---------- 4 files changed, 127 insertions(+), 122 deletions(-) diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor index 8265457f6..dab019667 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor @@ -44,7 +44,7 @@ @foreach ((string skillName, var skill) in ViewModel.SkillList!) { - + @@ -166,12 +166,12 @@ private string GetSubFix() { - return ShipClass != ShipClass.Submarine ? "" : "flex-basis: 20%; max-width: 20%;"; + return ShipClass != ShipClass.Submarine ? string.Empty : "flex-basis: 20%; max-width: 20%;"; } private string GetOrder(SkillPosition single) { - return $"order: {single.Tier * 10 + single.XPosition};"; + return $"order: {(single.Tier * 10) + single.XPosition};"; } private bool ShouldShowBadge(Skill skill) @@ -258,4 +258,4 @@ await dialog.Result; ViewModel!.SkillActivationPopupOpen = false; } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor index e4a4fafa8..3fcdd97b3 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor @@ -319,40 +319,52 @@ else if (ViewModel is not null) if (result is { Canceled: false, Data: BuildShareResult shareResult }) { - BuildName = shareResult.BuildName; - var build = ViewModel!.CreateBuild(shareResult.BuildName); - var buildString = build.CreateShortStringFromBuild(); - string urlBase; - if (NavManager.BaseUri.Contains("0.0.0.0")) + await ProcessBuildShareResult(shareResult); + } + + if (result is { Canceled: false, Data: string name }) + { + await ProcessBuildNameChanged(name); + } + } + + private async Task ProcessBuildShareResult(BuildShareResult shareResult) + { + BuildName = shareResult.BuildName; + var build = ViewModel!.CreateBuild(shareResult.BuildName); + var buildString = build.CreateShortStringFromBuild(); + string urlBase; + if (NavManager.BaseUri.Contains("0.0.0.0")) + { + urlBase = AppSettings.SelectedServerType switch { - urlBase = AppSettings.SelectedServerType switch - { - ServerType.Live => $"{ShipBuilderOptions.Value.LiveServerUrl}/", - ServerType.Pts => $"{ShipBuilderOptions.Value.PtsServerUrl}/", - _ => $"{ShipBuilderOptions.Value.LiveServerUrl}/", + ServerType.Live => $"{ShipBuilderOptions.Value.LiveServerUrl}/", + ServerType.Pts => $"{ShipBuilderOptions.Value.PtsServerUrl}/", + _ => $"{ShipBuilderOptions.Value.LiveServerUrl}/", }; - } - else - { - urlBase = NavManager.BaseUri; - } + } + else + { + urlBase = NavManager.BaseUri; + } - var buildUrl = $"{urlBase}ship?shipIndexes={build.ShipIndex}&build={WebUtility.UrlEncode(buildString)}"; - await ClipboardService.SetTextAsync(shareResult.CreateShortLink ? (await LinkShortener.CreateShortLink(buildUrl)).Link : buildUrl); - if (AppSettings.StoreBuildOnShare) - { - await UserDataService.SaveBuildAsync(build); - } + var buildUrl = $"{urlBase}ship?shipIndexes={build.ShipIndex}&build={WebUtility.UrlEncode(buildString)}"; + await ClipboardService.SetTextAsync(shareResult.CreateShortLink + ? (await LinkShortener.CreateShortLink(buildUrl)).Link + : buildUrl); + if (AppSettings.StoreBuildOnShare) + { + await UserDataService.SaveBuildAsync(build); } + } - if (result is { Canceled: false, Data: string name }) + private async Task ProcessBuildNameChanged(string name) + { + BuildName = name; + if (AppSettings.StoreBuildOnShare) { - BuildName = name; - if (AppSettings.StoreBuildOnShare) - { - var build = ViewModel!.CreateBuild(BuildName); - await UserDataService.SaveBuildAsync(build); - } + var build = ViewModel!.CreateBuild(BuildName); + await UserDataService.SaveBuildAsync(build); } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor b/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor index 4ec742f3f..e69da92ca 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor @@ -225,21 +225,7 @@ } else { - if (container.Build is not null) - { - var viewModel = await ShipStatsTab.CreateViewModel(container.Ship.Index, container.Build, Localizer); - - List<(string, float)> modifiers = viewModel.UpgradePanelViewModel.GetModifierList(); - modifiers.AddRange(viewModel.ConsumableViewModel.GetModifiersList()); - modifiers.AddRange(viewModel.CaptainSkillSelectorViewModel?.GetModifiersList() ?? new List<(string, float)>()); - modifiers.AddRange(viewModel.SignalSelectorViewModel?.GetModifierList() ?? new List<(string, float)>()); - - buildContainers.Add(container with { Modifiers = modifiers, ShipDataContainer = calculateShipDataContainer ? DataContainerUtility.GetShipDataContainerFromBuild(container.Ship, container.Build.Modules, container.Ship.ShipUpgradeInfo.ShipUpgrades, modifiers) : container.ShipDataContainer }); - } - else - { - buildContainers.Add(calculateShipDataContainer ? container with { ShipDataContainer = DataContainerUtility.GetStockShipDataContainer(container.Ship) } : container); - } + buildContainers.Add(await UpdateShipDataContainer(calculateShipDataContainer, container)); } shipIndexes.Add(container.Ship.Index); @@ -249,6 +235,24 @@ return shipIndexes; } + private async Task UpdateShipDataContainer(bool calculateShipDataContainer, ShipBuildContainer container) + { + if (container.Build is not null) + { + var viewModel = await ShipStatsTab.CreateViewModel(container.Ship.Index, container.Build, Localizer); + + List<(string, float)> modifiers = viewModel.UpgradePanelViewModel.GetModifierList(); + modifiers.AddRange(viewModel.ConsumableViewModel.GetModifiersList()); + modifiers.AddRange(viewModel.CaptainSkillSelectorViewModel?.GetModifiersList() ?? new List<(string, float)>()); + modifiers.AddRange(viewModel.SignalSelectorViewModel?.GetModifierList() ?? new List<(string, float)>()); + + var newDataContainer = calculateShipDataContainer ? DataContainerUtility.GetShipDataContainerFromBuild(container.Ship, container.Build.Modules, container.Ship.ShipUpgradeInfo.ShipUpgrades, modifiers) : container.ShipDataContainer; + return container with { Modifiers = modifiers, ShipDataContainer = newDataContainer }; + } + + return calculateShipDataContainer ? container with { ShipDataContainer = DataContainerUtility.GetStockShipDataContainer(container.Ship) } : container; + } + private async Task OpenBallisticCharts() { MetricsService.ShipStatsActions.WithLabels("open-ballistic").Inc(); diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SkillItemViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SkillItemViewModel.cs index c4b4aa1a6..b1cc4fdf9 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SkillItemViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SkillItemViewModel.cs @@ -16,111 +16,100 @@ public class SkillItemViewModel : ReactiveObject private bool canExecute; - // TODO: update to new nullability state public SkillItemViewModel(Skill skill, CaptainSkillSelectorViewModel parent, ShipClass shipClass, Dictionary canAddCache, Dictionary canRemoveCache) { - Skill = skill; - SkillTier = skill.Tiers.First(x => x.ShipClass == shipClass).Tier; - SkillXPosition = skill.Tiers.First(x => x.ShipClass == shipClass).XPosition; + this.Skill = skill; + this.SkillPosition = skill.Tiers.First(x => x.ShipClass == shipClass); + this.SkillTier = this.SkillPosition.Tier; this.canAddCache = canAddCache; this.canRemoveCache = canRemoveCache; - if (skill.Modifiers is not null) - { - Modifiers = skill.Modifiers.Where(x => !x.Key.Contains('_') || x.Key.Contains("_" + shipClass)).ToDictionary(x => x.Key, x => x.Value); - } - - if (skill.ConditionalModifiers is not null) - { - ConditionalModifiers = skill.ConditionalModifiers.Where(x => !x.Key.Contains('_') || x.Key.Contains("_" + shipClass)).ToDictionary(x => x.Key, x => x.Value); - } + this.Modifiers = skill.Modifiers.Where(x => !x.Key.Contains('_') || x.Key.Contains("_" + shipClass)).ToDictionary(x => x.Key, x => x.Value); + this.ConditionalModifiers = skill.ConditionalModifiers.Where(x => !x.Key.Contains('_') || x.Key.Contains("_" + shipClass)).ToDictionary(x => x.Key, x => x.Value); this.shipClass = shipClass; this.parent = parent; - CanExecuteChanged(); + this.CanExecuteChanged(); } public Skill Skill { get; } public int SkillTier { get; } - public int SkillXPosition { get; } + public SkillPosition SkillPosition { get; } - public Dictionary Modifiers { get; } = new(); + public Dictionary Modifiers { get; } - public Dictionary ConditionalModifiers { get; } = new(); + public Dictionary ConditionalModifiers { get; } public bool CanExecute { - get => canExecute; - set => this.RaiseAndSetIfChanged(ref canExecute, value); + get => this.canExecute; + set => this.RaiseAndSetIfChanged(ref this.canExecute, value); } public void CanExecuteChanged() + { + bool result = !this.parent.SkillOrderList.Contains(this.Skill) ? this.CanAddSkill() : this.CanRemoveSkill(); + this.CanExecute = result; + } + + private bool CanAddSkill() { bool result; + if (this.canAddCache.TryGetValue(this.SkillTier, out bool canAdd)) + { + return canAdd; + } - // Can add skill - if (!parent.SkillOrderList.Contains(Skill)) + // If the points would go over 21, can't add the skill + if (this.parent.AssignedPoints + this.SkillTier + 1 > 21) { - if (canAddCache.TryGetValue(SkillTier, out bool canAdd)) - { - CanExecute = canAdd; - return; - } - - // If the points would go over 21, can't add the skill - if (parent.AssignedPoints + SkillTier + 1 > 21) - { - result = false; - } - - // If it's a skill of the first tier, i can always add it - else if (SkillTier == 0) - { - result = true; - } - else - { - // If it's not, i search the skill of the previous tier. If at least one exist, i can add it - result = parent.SkillOrderList.Select(s => s.Tiers.First(x => x.ShipClass == shipClass).Tier).Any(cost => cost == SkillTier - 1); - } - - canAddCache[SkillTier] = result; + result = false; } - // Can remove skill + // If it's a skill of the first tier, i can always add it + else if (this.SkillTier == 0) + { + result = true; + } + else + { + // If it's not, i search the skill of the previous tier. If at least one exist, i can add it + result = this.parent.SkillOrderList.Select(s => s.Tiers.First(x => x.ShipClass == this.shipClass).Tier).Any(cost => cost == this.SkillTier - 1); + } + + this.canAddCache[this.SkillTier] = result; + return result; + } + + private bool CanRemoveSkill() + { + // If the skill tier is 4 (tier 3, since our index start from 0), can always remove + if (this.SkillTier == 3) + { + return true; + } + + if (this.canRemoveCache.TryGetValue(this.SkillTier, out bool canRemove)) + { + return canRemove; + } + + var skillTiers = this.parent.SkillOrderList.Select(iteratedSkill => iteratedSkill.Tiers.First(x => x.ShipClass == this.shipClass).Tier).ToList(); + int nextTierSkillCount = skillTiers.Count(skillCost => skillCost > this.SkillTier); + int sameTierSkillCount = skillTiers.Count(skillCost => skillCost == this.SkillTier); + + bool result; + if (nextTierSkillCount > 0) + { + result = sameTierSkillCount > 1; + } else { - // If the skill tier is 4 (tier 3, since our index start from 0), can always remove - if (SkillTier == 3) - { - result = true; - } - else - { - if (canRemoveCache.TryGetValue(SkillTier, out bool canRemove)) - { - CanExecute = canRemove; - return; - } - - List skillTiers = parent.SkillOrderList.Select(iteratedSkill => iteratedSkill.Tiers.First(x => x.ShipClass == shipClass).Tier).ToList(); - int nextTierSkillCount = skillTiers.Count(skillCost => skillCost > SkillTier); - int sameTierSkillCount = skillTiers.Count(skillCost => skillCost == SkillTier); - - if (nextTierSkillCount > 0) - { - result = sameTierSkillCount > 1; - } - else - { - result = true; - } - - canRemoveCache[SkillTier] = result; - } + result = true; } - CanExecute = result; + this.canRemoveCache[this.SkillTier] = result; + return result; } } From d25deab90d4d6dc810e5e64c27b77695a9923dc5 Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 28 Oct 2023 22:37:30 +0200 Subject: [PATCH 09/26] Theme Rework (#270) * start reworking theme for web app #256 * more color scheme improvements, especially for dialogs * update ship comparison UI * extract theme creation to common project, minor theme tweaks * improvements from review * change talent panel elements color from info to primary * fix style for the talents activation button when talents and conditional modifiers are activated * Change the talent activation button style to match the one in the ship comparison page * minor theme improvements * update release notes for theme rework --------- Co-authored-by: iTTou <13366390+iTTou@users.noreply.github.com> --- ReleaseNotes.md | 24 +--- .../AccelerationCharts.razor | 42 +++---- .../CustomAccelerationDataDialog.razor | 7 +- .../ShipBuildContainerSelectionDialog.razor | 8 +- .../Features/BallisticCharts/Charts.razor | 14 +-- .../ShipAndShellSelectionDialog.razor | 13 +-- .../Components/BuildConfigurationDialog.razor | 22 ++-- .../Components/BuildImageRenderDialog.razor | 4 +- .../Components/BuildImageSettingsDialog.razor | 18 +-- .../CaptainSkillSelectorImageRender.razor | 8 +- .../SignalSelectorImageRender.razor | 4 +- .../ShipComparison/ComparisonShipFilter.razor | 53 ++++----- .../GridSections/AaDefenseFragment.razor | 46 ++------ .../AerialTorpedoesFragment.razor | 54 +++------ .../GridSections/AirStrikeFragment.razor | 62 +++------- .../GridSections/ApShellFragment.razor | 50 +++------ .../GridSections/AswFragment.razor | 62 +++------- .../GridSections/BombersFragment.razor | 106 +++++------------- .../GridSections/BombsFragment.razor | 78 ++++--------- .../GridSections/ConcealmentFragment.razor | 26 ++--- .../GridSections/HeShellFragment.razor | 50 +++------ .../GridSections/MainBatteryFragment.razor | 70 +++--------- .../ManeuverabilityFragment.razor | 50 +++------ .../GridSections/RocketPlanesFragment.razor | 102 +++++------------ .../GridSections/RocketsFragment.razor | 78 ++++--------- .../GridSections/SapShellFragment.razor | 42 ++----- .../SecondaryBatteryFragment.razor | 34 ++---- .../SecondaryBatteryShellsFragment.razor | 58 +++------- .../GridSections/SonarFragment.razor | 34 ++---- .../GridSections/SurvivabilityFragment.razor | 26 ++--- .../GridSections/TorpedoBombersFragment.razor | 102 +++++------------ .../GridSections/TorpedoesFragment.razor | 86 ++++---------- .../GridSections/UtilityFragments.razor | 10 ++ .../HideComparisonColumnsDialog.razor | 8 +- .../ShipComparison/ShipComparison.razor | 26 +++-- .../Features/ShipSelection/ShipSelector.razor | 81 +++++-------- .../Components/CaptainSkillSelector.razor | 24 ++-- ...tainTalentsAndConditionalSkillDialog.razor | 8 +- .../ShipStats/Components/ShipStatsPanel.razor | 71 ++++++------ .../ShipStats/Components/ShipStatsTab.razor | 4 +- .../ShipStats/Components/SignalSelector.razor | 18 +-- .../Features/ShipStats/ShipStats.razor | 14 +-- .../Infrastructure/Utility/Helpers.cs | 43 +++++++ WoWsShipBuilder.Common/wwwroot/css/app.css | 37 +++++- .../BlazorWebView/DesktopLayout.razor | 48 +------- .../Features/Settings/SettingsComponent.razor | 22 ++-- WoWsShipBuilder.Desktop/version.json | 2 +- WoWsShipBuilder.Desktop/wwwroot/index.html | 2 +- WoWsShipBuilder.Web/Common/MainLayout.razor | 45 +------- WoWsShipBuilder.Web/Common/TopMenu.razor | 6 +- .../Features/Host/_Layout.cshtml | 2 +- .../Features/UserSettings/UserSettings.razor | 22 ++-- WoWsShipBuilder.Web/Program.cs | 1 - WoWsShipBuilder.Web/version.json | 2 +- 54 files changed, 641 insertions(+), 1288 deletions(-) create mode 100644 WoWsShipBuilder.Common/Features/ShipComparison/GridSections/UtilityFragments.razor diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 36d16c558..510a8bb05 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,4 +1,4 @@ -# Update 2.1 +# Update 2.3 ## Download and Install @@ -12,25 +12,13 @@ Download [**WoWsShipBuilderSetup.exe**](https://github.com/WoWs-Builder-Team/WoW Click to show release notes ### Additions -- Penetration values for AP bombs and rockets -- Display Krupp for AP projectiles -- Add checks to prevent corrupted builds to be loaded ### Changes -- Update penetration formula with the one reverse engineered by TTaro_ -- Remove measurements units from grid headers in the ship comparison and add them to the cells -- Stats expanders now do not take extra vertical space when expanded -- Various other minor improvements +- Theme Rework: A complete overhaul for the existing app theme with new accent colors and an improved color palette + - The new theme follows the [Material Design](https://material.io/design) guidelines + - Better contrast for text and icons + - New accent colors for the app, the app is no longer just grey ### Bugfixes -- Fix AA Defense and ASW Expert consumable bonus not applying correctly -- Fix app crashing after language selection -- Fix scrolling in desktop settings dialog -- Fix stats column space distribution for subs -- Fix special ability description of some ships -- Various other minor fixes -### Known Issues -- None - - \ No newline at end of file + diff --git a/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor b/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor index 7af324885..ce2d2d583 100644 --- a/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor +++ b/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor @@ -46,29 +46,29 @@ @Localizer.GetAppLocalization(nameof(Translation.AccelerationChart_CustomDataTitle)).Localization
- - -1 - 0 - 1/4 - 2/4 - 3/4 - 4/4 + + -1 + 0 + 1/4 + 2/4 + 3/4 + 4/4 - - -1 - 0 - 1/4 - 2/4 - 3/4 - 4/4 + + -1 + 0 + 1/4 + 2/4 + 3/4 + 4/4 - - -1 - 0 - 1/4 - 2/4 - 3/4 - 4/4 + + -1 + 0 + 1/4 + 2/4 + 3/4 + 4/4 diff --git a/WoWsShipBuilder.Common/Features/AccelerationCharts/CustomAccelerationDataDialog.razor b/WoWsShipBuilder.Common/Features/AccelerationCharts/CustomAccelerationDataDialog.razor index a4e1c40a9..55aff8fd9 100644 --- a/WoWsShipBuilder.Common/Features/AccelerationCharts/CustomAccelerationDataDialog.razor +++ b/WoWsShipBuilder.Common/Features/AccelerationCharts/CustomAccelerationDataDialog.razor @@ -7,7 +7,6 @@ - @Localizer.GetAppLocalization(nameof(Translation.AccelerationChart_CustomDataTitle)).Localization @@ -61,10 +60,10 @@ - + @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization - + @Localizer.GetAppLocalization(nameof(Translation.Ok)).Localization @@ -178,4 +177,4 @@ forwardEngineForsagMaxSpeed > 0 && backwardEngineForsagMaxSpeed > 0; } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/AccelerationCharts/ShipBuildContainerSelectionDialog.razor b/WoWsShipBuilder.Common/Features/AccelerationCharts/ShipBuildContainerSelectionDialog.razor index d03a4c246..1cc4ccba2 100644 --- a/WoWsShipBuilder.Common/Features/AccelerationCharts/ShipBuildContainerSelectionDialog.razor +++ b/WoWsShipBuilder.Common/Features/AccelerationCharts/ShipBuildContainerSelectionDialog.razor @@ -7,15 +7,15 @@ @implements IDisposable @inject ILocalizer Localizer - + - + @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization - + @if (processing) { @@ -100,4 +100,4 @@ selectedShips.CollectionChanged -= SelectedShipsOnCollectionChanged; } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor b/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor index cb4d35c3a..ad2eda058 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor @@ -22,7 +22,7 @@ @inject SessionStateCache SessionStateCache WoWs ShipBuilder: Charts - + @@ -67,7 +67,7 @@ - @Localizer.GetAppLocalization(Translation.ResourceManager.GetString(item.ToString())!).Localization + @Localizer.GetAppLocalization(Translation.ResourceManager.GetString(item.ToString())!).Localization } @@ -133,10 +133,10 @@ - @Localizer.GetAppLocalization(nameof(Translation.DispersionGraphWindow_Horizontal)).Localization + @Localizer.GetAppLocalization(nameof(Translation.DispersionGraphWindow_Horizontal)).Localization - @Localizer.GetAppLocalization(nameof(Translation.DispersionGraphWindow_Vertical)).Localization + @Localizer.GetAppLocalization(nameof(Translation.DispersionGraphWindow_Vertical)).Localization @@ -145,7 +145,7 @@ - @Localizer.GetAppLocalization(item.ToString()).Localization + @Localizer.GetAppLocalization(item.ToString()).Localization } @@ -154,7 +154,7 @@ @foreach (var item in fusoPositionsList) { - @Localizer.GetAppLocalization(item.ToString()).Localization + @Localizer.GetAppLocalization(item.ToString()).Localization } @@ -254,7 +254,7 @@ - + diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor b/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor index f6048ea1b..27754d30e 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor @@ -13,10 +13,9 @@ @implements IDisposable @inject ILocalizer Localizer - + - @Localizer.GetAppLocalization(nameof(Translation.ShipAndShellSelectionDialogWeb_SelectShipsAndShells)).Localization @@ -31,7 +30,7 @@ @if (dataWrappers.Count == 0) { - + @Localizer.GetAppLocalization(Translation.ShipAndShellsSelectionDialog_NoShipSelected).Localization } @@ -42,7 +41,7 @@ @Localizer.GetGameLocalization($"{dataWrapper.ShipBuildContainer.Ship.Index}_FULL").Localization - + @if (dataWrapper.ShipBuildContainer.Ship.MainBatteryModuleList.Any()) { @@ -57,7 +56,7 @@ } else { - + @Localizer.GetAppLocalization(nameof(Translation.MessageBox_ShipNoGun)).Localization } @@ -72,10 +71,10 @@ - + @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization - + @if (processing) { diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor b/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor index e0acdb716..5c6008435 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor @@ -23,7 +23,7 @@ @inject IOptions LinkShorteningOptions @inject IJSRuntime Runtime - + @@ -48,16 +48,16 @@ - + @for (var i = 0; i < Ships.Count; i++) { int index = i; var shipData = Ships[index]; - + @Localizer.GetGameLocalization(Ships[index].Ship.Index + "_FULL").Localization - + @(Localizer.GetAppLocalization(Translation.ChartsWeb_Build).Localization + ": " + (buildNameDictionary.TryGetValue(shipData.Id, out string? value) ? value : !string.IsNullOrEmpty(shipData.Build?.BuildName) ? shipData.Build.BuildName : Build.DefaultBuildName)) @@ -79,10 +79,10 @@ - + @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization - + @Localizer.GetAppLocalization(nameof(Translation.MainWindow_ResetBuild)).Localization @@ -183,7 +183,7 @@ } @if (!SpecialAbilityDisabled && (shipData.Ship.SpecialAbility is not null || shipData.Ship.MainBatteryModuleList.Any(x => x.Value.BurstModeAbility is not null))) { - + } @@ -195,19 +195,19 @@ - - + + @Localizer.GetAppLocalization(Translation.BuildConfigurationDialog_Load).Localization - Import + Import - + } else diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageRenderDialog.razor b/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageRenderDialog.razor index 819be4142..fb9be3006 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageRenderDialog.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageRenderDialog.razor @@ -113,10 +113,10 @@ - + @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization - + @Localizer.SimpleAppLocalization(nameof(Translation.SettingsWindow_Settings)) diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageSettingsDialog.razor b/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageSettingsDialog.razor index 4a45eafa3..098edf753 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageSettingsDialog.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/BuildImageSettingsDialog.razor @@ -5,19 +5,19 @@ @Localizer.SimpleAppLocalization(nameof(Translation.BuildImageSettingsDialog_Layout)) - + @Localizer.SimpleAppLocalization(nameof(Translation.BuildImageSettingsDialog_Elements)) - - - - - + + + + + - @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization - + @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization + @Localizer.GetAppLocalization(nameof(Translation.Dialog_Save)).Localization @@ -88,4 +88,4 @@ ShowSignals = true; } } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor b/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor index 4172bb1b2..bc2bfc0ba 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor @@ -16,7 +16,7 @@ @Localizer.GetAppLocalization(nameof(Translation.CaptainSkillSelector_Points)).Localization @ViewModel.AssignedPoints/21 - + @Localizer.GetAppLocalization(Translation.ScreenshotWindow_Captain).Localization @Localizer.GetGameLocalization(ViewModel.SelectedCaptain!.Name).Localization @@ -150,7 +150,7 @@ private string GetImageStyle(SkillItemViewModel skillItem) { - return ViewModel!.SkillOrderList.Any(x => x.SkillNumber.Equals(skillItem.Skill.SkillNumber)) ? string.Empty : @"opacity: 0.4"; + return ViewModel!.SkillOrderList.Any(x => x.SkillNumber.Equals(skillItem.Skill.SkillNumber)) ? string.Empty : "opacity: 0.4"; } private int GetImageSize() @@ -179,6 +179,6 @@ private string GetMudPaperBorderColor(SkillItemViewModel skillItem) { - return " border-color: " + (ViewModel!.SkillOrderList.Any(x => x.SkillNumber.Equals(skillItem.Skill.SkillNumber)) ? "#BC0606" : "#3C3C3C") + ";"; + return $" border-color: {(ViewModel!.SkillOrderList.Any(x => x.SkillNumber.Equals(skillItem.Skill.SkillNumber)) ? "#BC0606" : "var(--mud-palette-text-disabled)")};"; } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/SignalSelectorImageRender.razor b/WoWsShipBuilder.Common/Features/Builds/Components/SignalSelectorImageRender.razor index 535c7d983..89ecb0cce 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/SignalSelectorImageRender.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/SignalSelectorImageRender.razor @@ -85,6 +85,6 @@ private string GetMudPaperStyle(bool isSelected) { - return " border-color: " + (isSelected ? "#BC0606;" : "#3C3C3C; opacity: 0.4;"); + return $" border-color: {(isSelected ? "#BC0606" : "var(--mud-palette-text-disabled); opacity: 0.4;")};"; } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor b/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor index 33f7a141a..68c2855b3 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor @@ -13,10 +13,10 @@ @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_TierFilter)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) @@ -26,7 +26,7 @@ { int tier = i; bool isSelected = ViewModel!.SelectedTiers.Contains(tier); - + @tier.ToTierString() } @@ -36,10 +36,10 @@ @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_ClassFilter)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) @@ -48,7 +48,7 @@ @foreach (var shipClass in ViewModel!.AvailableClasses) { bool isSelected = ViewModel.SelectedClasses.Contains(shipClass); - + @Localizer.GetAppLocalization(shipClass.ShipClassToString()).Localization } @@ -58,10 +58,10 @@ @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_NationFilter)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) @@ -70,7 +70,7 @@ @foreach (var nation in ViewModel!.AvailableNations) { bool isSelected = ViewModel.SelectedNations.Contains(nation); - + @Localizer.GetAppLocalization(nation.ShipNationToString()).Localization } @@ -80,10 +80,10 @@ @Localizer.SimpleAppLocalization(nameof(Translation.ShipSelectionWindow_TypeFilter)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) @@ -92,7 +92,7 @@ @foreach (var category in ViewModel!.AvailableShipCategories) { bool isSelected = ViewModel.SelectedCategories.Contains(category); - + @Localizer.GetAppLocalization(category.ShipCategoryToString()).Localization } @@ -120,7 +120,7 @@ { int tier = i; bool isSelected = ViewModel!.SelectedTiers.Contains(tier); - + @tier.ToTierString() } @@ -129,7 +129,7 @@ @foreach (var shipClass in ViewModel!.AvailableClasses) { bool isSelected = ViewModel.SelectedClasses.Contains(shipClass); - + @Localizer.GetAppLocalization(shipClass.ShipClassToString()).Localization } @@ -138,7 +138,7 @@ @foreach (var nation in ViewModel!.AvailableNations) { bool isSelected = ViewModel.SelectedNations.Contains(nation); - + @Localizer.GetAppLocalization(nation.ShipNationToString()).Localization } @@ -147,7 +147,7 @@ @foreach (var category in ViewModel!.AvailableShipCategories) { bool isSelected = ViewModel.SelectedCategories.Contains(category); - + @Localizer.GetAppLocalization(category.ShipCategoryToString()).Localization } @@ -155,34 +155,34 @@ - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_All)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_None)) @@ -198,11 +198,6 @@ [Parameter, EditorRequired] public Func SelectionChanged { get; set; } = default!; - private static Variant GetVariantFromBool(bool active) - { - return active ? Variant.Filled : Variant.Outlined; - } - private static Color GetColorFromBool(bool active) { return active ? Color.Primary : Color.Secondary; diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AaDefenseFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AaDefenseFragment.razor index 5c0ac1bb7..98d4b2a3e 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AaDefenseFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AaDefenseFragment.razor @@ -33,9 +33,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -50,9 +48,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -67,9 +63,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -84,9 +78,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -101,9 +93,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -118,9 +108,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -135,9 +123,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -152,9 +138,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -169,9 +153,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -186,9 +168,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -203,11 +183,9 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } }; -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AerialTorpedoesFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AerialTorpedoesFragment.razor index 592d8b291..94612396f 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AerialTorpedoesFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AerialTorpedoesFragment.razor @@ -49,9 +49,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -75,9 +73,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -101,9 +97,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -127,9 +121,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -153,9 +145,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -179,9 +169,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -205,9 +193,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -231,9 +217,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -257,9 +241,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -283,9 +265,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -309,9 +289,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -335,9 +313,7 @@ } else if (classes is null && !context.Item.TorpedoBombers.WeaponDamage.Any()) { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } else if (classes is not null) { @@ -356,11 +332,9 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } }; -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AirStrikeFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AirStrikeFragment.razor index 852325492..dd1435063 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AirStrikeFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AirStrikeFragment.razor @@ -40,9 +40,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -57,9 +55,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -74,9 +70,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -91,9 +85,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -108,9 +100,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -125,9 +115,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -142,9 +130,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -159,9 +145,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -176,9 +160,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -193,9 +175,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -210,9 +190,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -227,9 +205,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -244,9 +220,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -261,9 +235,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -278,11 +250,9 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } }; -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ApShellFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ApShellFragment.razor index b537d56b2..b4e561fc2 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ApShellFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ApShellFragment.razor @@ -38,9 +38,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -55,9 +53,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -72,9 +68,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -89,9 +83,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -106,9 +98,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -123,9 +113,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -140,9 +128,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -157,9 +143,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -174,9 +158,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -191,9 +173,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -208,9 +188,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -225,11 +203,9 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } }; -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AswFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AswFragment.razor index 1af2df3ad..682b1e564 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AswFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AswFragment.razor @@ -40,9 +40,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -57,9 +55,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -74,9 +70,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -91,9 +85,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -108,9 +100,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -125,9 +115,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -142,9 +130,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -159,9 +145,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -176,9 +160,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -193,9 +175,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -210,9 +190,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -227,9 +205,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -244,9 +220,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -261,9 +235,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -278,11 +250,9 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } }; -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/BombersFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/BombersFragment.razor index be69b1602..51184d2fe 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/BombersFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/BombersFragment.razor @@ -59,9 +59,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -85,9 +83,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -111,9 +107,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -137,9 +131,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -163,9 +155,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -189,9 +179,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -215,9 +203,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -241,9 +227,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -267,9 +251,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -293,9 +275,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -319,9 +299,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -345,9 +323,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -371,9 +347,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -397,9 +371,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -423,9 +395,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -449,9 +419,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -475,9 +443,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -501,9 +467,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -527,9 +491,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -553,9 +515,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -579,9 +539,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -605,9 +563,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -631,9 +587,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -657,9 +611,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -683,9 +635,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -709,11 +659,9 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } }; -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/BombsFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/BombsFragment.razor index 307470738..1f29e0d23 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/BombsFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/BombsFragment.razor @@ -48,9 +48,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -75,9 +73,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -101,9 +97,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -127,9 +121,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -153,9 +145,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -176,9 +166,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } if (i < items.Count - 1) { @@ -188,9 +176,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -211,9 +197,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } if (i < items.Count - 1) { @@ -223,9 +207,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -246,9 +228,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } if (i < items.Count - 1) { @@ -258,9 +238,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -281,9 +259,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } if (i < items.Count - 1) { @@ -293,9 +269,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -316,9 +290,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } if (i < items.Count - 1) { @@ -328,9 +300,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -351,9 +321,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } if (i < items.Count - 1) { @@ -363,9 +331,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -386,9 +352,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } if (i < items.Count - 1) { @@ -398,11 +362,9 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } }; -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ConcealmentFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ConcealmentFragment.razor index 210725916..4e090efa8 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ConcealmentFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ConcealmentFragment.razor @@ -27,9 +27,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -44,9 +42,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -61,9 +57,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -78,9 +72,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -95,9 +87,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -112,11 +102,9 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } }; -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/HeShellFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/HeShellFragment.razor index 41f66ed10..588122e67 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/HeShellFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/HeShellFragment.razor @@ -37,9 +37,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -54,9 +52,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -71,9 +67,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -88,9 +82,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -105,9 +97,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -122,9 +112,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -139,9 +127,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -156,9 +142,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -173,9 +157,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -190,9 +172,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -207,9 +187,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -224,11 +202,9 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } }; -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/MainBatteryFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/MainBatteryFragment.razor index 2acfe6b2f..4934982a7 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/MainBatteryFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/MainBatteryFragment.razor @@ -49,9 +49,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -66,9 +64,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -83,9 +79,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -100,9 +94,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -117,9 +109,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -134,9 +124,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -151,9 +139,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -168,9 +154,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -185,9 +169,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -203,9 +185,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -220,9 +200,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -237,9 +215,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -254,9 +230,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -271,9 +245,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -288,9 +260,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -305,9 +275,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -322,11 +290,9 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } }; -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ManeuverabilityFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ManeuverabilityFragment.razor index 97028b45a..539da4726 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ManeuverabilityFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/ManeuverabilityFragment.razor @@ -38,9 +38,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -55,9 +53,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -72,9 +68,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -89,9 +83,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -106,9 +98,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -123,9 +113,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -140,9 +128,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -157,9 +143,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -174,9 +158,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -191,9 +173,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -208,9 +188,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -225,9 +203,7 @@ } else { - - @ShipComparisonViewModel.DataNotAvailable - + @UtilityFragments.DataNotAvailableFragment } @@ -236,4 +212,4 @@ @@ -24,8 +24,8 @@ - @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization - @Localizer.GetAppLocalization(nameof(Translation.Dialog_Save)).Localization + @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization + @Localizer.GetAppLocalization(nameof(Translation.Dialog_Save)).Localization @@ -76,4 +76,4 @@ MudDialog.Close(DialogResult.Ok(result)); } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparison.razor b/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparison.razor index 928f30f8e..0bbb24c81 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparison.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparison.razor @@ -56,7 +56,9 @@ @if (ViewModel is not null) {
- + + + if (!string.IsNullOrEmpty(ViewModel.ResearchedShip)) { @@ -81,13 +83,13 @@ - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_DisplayOnlyPinnedShips)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_UseUpgradedModules)) - + @Localizer.SimpleAppLocalization(nameof(Translation.ShipComparison_HideIfNoSection)) @@ -144,17 +146,17 @@ - + - + - + - + - + @LocalizeShipName(context.Item.ShipIndex) @@ -208,7 +210,7 @@ } else { - + @Build.DefaultBuildName } @@ -243,7 +245,7 @@ - + } @@ -251,7 +253,7 @@ private MudDataGrid dataGrid = default!; - private const string StickyColumnsBackgroundColor = "background-color: #242424"; + private const string StickyColumnsBackgroundColor = "background-color: #262626"; private const string TiersUrlParameter = "t"; diff --git a/WoWsShipBuilder.Common/Features/ShipSelection/ShipSelector.razor b/WoWsShipBuilder.Common/Features/ShipSelection/ShipSelector.razor index 5b05a4ed4..7e2a1df6a 100644 --- a/WoWsShipBuilder.Common/Features/ShipSelection/ShipSelector.razor +++ b/WoWsShipBuilder.Common/Features/ShipSelection/ShipSelector.razor @@ -34,8 +34,8 @@ { - - + + @Localizer.GetAppLocalization(nameof(Translation.WebApp_LoadBuild)).Localization @@ -52,57 +52,61 @@ } - + @foreach (var item in tierList) { - @item + @item } - + @foreach (ShipClass? item in classList) { - @Localizer.GetAppLocalization(item.ToString()!).Localization + @Localizer.GetAppLocalization(item.ToString()!).Localization } - + @foreach (Nation? item in nationList) { - @Localizer.GetAppLocalization(item.ToString()!).Localization + @Localizer.GetAppLocalization(item.ToString()!).Localization } - + @foreach (ShipCategory? item in typeList) { - @Localizer.GetAppLocalization(item.ToString()!).Localization + @Localizer.GetAppLocalization(item.ToString()!).Localization } + + @* ship search box *@ + + @* ship list *@ - - - - + + + + @pair.Key @@ -110,6 +114,8 @@ + + @* selected ship list *@ @if (!HideSelectedShipList) { @@ -155,11 +161,13 @@ } + + @* saved build list *@ @if (EnableSavedBuildList) { - + @if (!filteredBuildsList.Any()) { @@ -216,10 +224,6 @@ private ImmutableList> shipNameList = ImmutableList>.Empty; - private MudList mudList = default!; - - private MudList? buildList; - private List> filteredSummaryList = new(); private IEnumerable savedBuilds = new List(); @@ -393,18 +397,15 @@ private void RemoveShip(ShipBuildContainer container) { SelectedShips.Remove(container); -#pragma warning disable BL0005 - mudList.SelectedValue = null; - if (buildList != null) - { - buildList.SelectedValue = null; - } -#pragma warning restore BL0005 } - private void AddShip(object? obj) + private void AddShip(string shipIndex) { - if (obj is not string shipIndex || !AllowCopies && SelectedShips.Any(x => x.Ship.Index.Equals(shipIndex))) return; + if (!AllowCopies && SelectedShips.Any(x => x.Ship.Index.Equals(shipIndex))) + { + return; + } + if (MultiSelect) { var ship = AppData.ShipDictionary[shipIndex]; @@ -415,12 +416,6 @@ var ship = AppData.ShipDictionary[shipIndex]; SelectedShips.Add(ShipBuildContainer.CreateNew(ship, null, null)); } - if (AllowCopies) - { -#pragma warning disable BL0005 - mudList.SelectedValue = null; -#pragma warning restore BL0005 - } } private void AddSavedBuild(Build build) @@ -437,29 +432,11 @@ MetricsService.BuildImports.WithLabels("ship-selector", "saved-builds").Inc(); SelectedShips.Add(ShipBuildContainer.CreateNew(AppData.ShipDictionary[build.ShipIndex], build, null)); } - - if (AllowCopies) - { -#pragma warning disable BL0005 - mudList.SelectedValue = null; - if (buildList != null) - { - buildList.SelectedValue = null; - } -#pragma warning restore BL0005 - } } private void RemoveAllShips() { SelectedShips.Clear(); -#pragma warning disable BL0005 - mudList.SelectedValue = null; - if (buildList != null) - { - buildList.SelectedValue = null; - } -#pragma warning restore BL0005 } private async Task AddBuild(ShipBuildContainer ship) diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor index dab019667..17a0c9f78 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor @@ -24,11 +24,11 @@ - + @foreach (var captain in ViewModel.CaptainList!) { - + @Localizer.GetGameLocalization(captain.Name).Localization @@ -36,7 +36,7 @@ - + @Localizer.GetAppLocalization(nameof(Translation.CaptainSkillSelector_SkillTalent)).Localization @@ -181,17 +181,7 @@ private Color GetColorFromState(SkillItemViewModel skillItem) { - if (ViewModel!.SkillOrderList.Any(x => x.SkillNumber.Equals(skillItem.Skill.SkillNumber))) - { - return Color.Error; - } - - if (!skillItem.CanExecute) - { - return Color.Primary; - } - - return Color.Secondary; + return ViewModel!.SkillOrderList.Any(x => x.SkillNumber.Equals(skillItem.Skill.SkillNumber)) ? Color.Error : Color.Default; } private void OnSkillClick(SkillItemViewModel skillItem) @@ -205,9 +195,9 @@ return !skillItem.CanExecute && !ViewModel!.SkillOrderList.Any(x => x.SkillNumber.Equals(skillItem.Skill.SkillNumber)) ? @"opacity: 0.4" : string.Empty; } - private string GetSkillOrTalentsEnabledIndicator() + private Color GetSkillOrTalentsEnabledIndicator() { - return ViewModel!.ArHpPercentage < 100 || ViewModel.TalentOrConditionalSkillEnabled ? "border: #BF0000FF solid 1px" : string.Empty; + return ViewModel!.ArHpPercentage < 100 || ViewModel.TalentOrConditionalSkillEnabled ? Color.Primary : Color.Default; } private int GetImageSize() @@ -236,7 +226,7 @@ private string GetMudPaperBorderColor(SkillItemViewModel skillItem) { - return " border-color: " + (ViewModel!.SkillOrderList.Any(x => x.SkillNumber.Equals(skillItem.Skill.SkillNumber)) ? "#BC0606" : "#3C3C3C") + ";"; + return " border-color: " + (ViewModel!.SkillOrderList.Any(x => x.SkillNumber.Equals(skillItem.Skill.SkillNumber)) ? "#BC0606" : "var(--mud-palette-text-disabled)") + ";"; } private async Task OpenSkillDialog() diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainTalentsAndConditionalSkillDialog.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainTalentsAndConditionalSkillDialog.razor index d30d42387..868a735dc 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainTalentsAndConditionalSkillDialog.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainTalentsAndConditionalSkillDialog.razor @@ -25,7 +25,7 @@ @(Localizer.GetAppLocalization(nameof(Translation.CaptainSkillSelector_CurrentArBonus)).Localization + ViewModel.ArHpPercentage + " %") - + } @if (ViewModel.ConditionalModifiersList.Count > 0) @@ -43,7 +43,7 @@ { } - + } } @@ -74,7 +74,7 @@ { } - + } } @@ -118,4 +118,4 @@ return sb.ToString(); } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor index 5b446033b..0557422f2 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor @@ -23,7 +23,7 @@ @if (ViewModel?.CurrentShipStats is not null) { - + @@ -31,7 +31,7 @@ @if (ViewModel.CurrentShipStats?.MainBatteryDataContainer is not null) { - + @foreach (var data in ViewModel.CurrentShipStats.MainBatteryDataContainer.DataElements) { @@ -83,7 +83,7 @@ - + @Localizer.GetAppLocalization(nameof(Translation.ShipStats_TurretAngles)).Localization @@ -92,13 +92,13 @@ @foreach (var shell in ViewModel.CurrentShipStats.MainBatteryDataContainer.ShellData) { - + @foreach (var data in shell.DataElements) { @DataElementFragment((data, Localizer)) } - + @Localizer.GetAppLocalization(nameof(Translation.ChartsWeb_ShowCharts)).Localization @@ -112,7 +112,7 @@ @if (ViewModel.CurrentShipStats?.PingerGunDataContainer is not null) { - + @foreach (var data in ViewModel.CurrentShipStats.PingerGunDataContainer.DataElements) { @@ -125,13 +125,13 @@ @if (ViewModel.CurrentShipStats?.TorpedoArmamentDataContainer is not null) { - + @foreach (var data in ViewModel.CurrentShipStats.TorpedoArmamentDataContainer.DataElements) { @DataElementFragment((data,Localizer)) } - + @Localizer.GetAppLocalization(nameof(Translation.ShipStats_ShowLaunchersAngles)).Localization @@ -139,7 +139,7 @@ @foreach (var torpedo in ViewModel.CurrentShipStats.TorpedoArmamentDataContainer.Torpedoes) { - + @if (torpedo.TorpedoType.Equals($"ShipStats_Torpedo{TorpedoType.Magnetic.TorpedoTypeToString()}")) { @@ -172,7 +172,7 @@ @if (torpedo.TorpedoType.Equals($"ShipStats_Torpedo{TorpedoType.Magnetic.TorpedoTypeToString()}")) { - + @for (var i = torpedo.DataElements.Count - 11; i < torpedo.DataElements.Count - 5; i++) { @@ -180,7 +180,7 @@ } - + @for (var i = torpedo.DataElements.Count - 5; i < torpedo.DataElements.Count; i++) { @@ -201,11 +201,11 @@ @if (ViewModel.CurrentShipStats?.CvAircraftDataContainer is not null) { - + @foreach (var plane in ViewModel.CurrentShipStats.CvAircraftDataContainer) { - +
@@ -219,7 +219,7 @@ { @DataElementFragment((data,Localizer)) } - + @foreach (var weaponData in plane.Weapon?.DataElements ?? new()) { @@ -271,11 +271,11 @@ @if (ViewModel.CurrentShipStats?.SecondaryBatteryUiDataContainer.Secondaries is not null) { - + @foreach (var secondary in ViewModel.CurrentShipStats.SecondaryBatteryUiDataContainer.Secondaries) { - + @foreach (var secondaryData in secondary.DataElements) { @@ -283,7 +283,7 @@ } - + @foreach (var data in secondary.Shell?.DataElements ?? new()) { @@ -301,12 +301,12 @@ @if (ViewModel.CurrentShipStats?.AntiAirDataContainer is not null) { - + @if (ViewModel.CurrentShipStats.AntiAirDataContainer.LongRangeAura is not null) { - + @foreach (var longData in ViewModel.CurrentShipStats.AntiAirDataContainer.LongRangeAura.DataElements) { @@ -319,7 +319,7 @@ @if (ViewModel.CurrentShipStats.AntiAirDataContainer.MediumRangeAura is not null) { - + @foreach (var longData in ViewModel.CurrentShipStats.AntiAirDataContainer.MediumRangeAura.DataElements) { @@ -332,7 +332,7 @@ @if (ViewModel.CurrentShipStats.AntiAirDataContainer.ShortRangeAura is not null) { - + @foreach (var longData in ViewModel.CurrentShipStats.AntiAirDataContainer.ShortRangeAura.DataElements) { @@ -345,16 +345,16 @@ } - + @if (ViewModel.CurrentShipStats?.AirstrikeDataContainer is not null) { - + @foreach (var data in ViewModel.CurrentShipStats.AirstrikeDataContainer.DataElements) { @DataElementFragment((data, Localizer)) } - + @foreach (var weaponData in ViewModel.CurrentShipStats?.AirstrikeDataContainer?.Weapon?.DataElements ?? new()) { @@ -366,22 +366,23 @@ } + @if (ViewModel.CurrentShipStats?.AswAirstrikeDataContainer is not null) { var dcDataContext = ViewModel.CurrentShipStats.AswAirstrikeDataContainer.Weapon as DepthChargeDataContainer ?? throw new InvalidOperationException("Expected DepthChargeDataContainer but found another type."); - + @foreach (var data in ViewModel.CurrentShipStats.AswAirstrikeDataContainer.DataElements) { @DataElementFragment((data, Localizer)) } - + @foreach (var weaponData in ViewModel.CurrentShipStats?.AswAirstrikeDataContainer?.Weapon?.DataElements ?? new()) { @DataElementFragment((weaponData,Localizer)) } - + @(showDepthChargeDamageDistributionChart ? Localizer.GetAppLocalization(nameof(Translation.ShipStats_HideDcDamageDistribution)).Localization : Localizer.GetAppLocalization(nameof(Translation.ShipStats_ShowDcDamageDistribution)).Localization)
@@ -397,7 +398,7 @@ @if (ViewModel.CurrentShipStats?.DepthChargeLauncherDataContainer is not null) { var dcDataContext = ViewModel.CurrentShipStats.DepthChargeLauncherDataContainer.DepthCharge!; - + @foreach (var data in ViewModel.CurrentShipStats.DepthChargeLauncherDataContainer.DataElements) { @@ -407,7 +408,7 @@ { @DataElementFragment((data, Localizer)) } - + @(showDepthChargeDamageDistributionChart ? Localizer.GetAppLocalization(nameof(Translation.ShipStats_HideDcDamageDistribution)).Localization : Localizer.GetAppLocalization(nameof(Translation.ShipStats_ShowDcDamageDistribution)).Localization)
@@ -424,20 +425,20 @@ - + @foreach (var data in ViewModel.CurrentShipStats?.ManeuverabilityDataContainer?.DataElements ?? new()) { @DataElementFragment((data, Localizer)) } - + @Localizer.GetAppLocalization(nameof(Translation.ShipStats_ShowAccelerationCharts)).Localization - + @foreach (var data in ViewModel.CurrentShipStats?.ConcealmentDataContainer.DataElements ?? new()) { @@ -447,7 +448,7 @@ - + @DataElementFragment((ViewModel.CurrentShipStats?.SurvivabilityDataContainer.DataElements[0]!, Localizer)) @@ -458,7 +459,7 @@ @DataElementFragment((ViewModel.CurrentShipStats?.SurvivabilityDataContainer.DataElements[i]!, Localizer)) } } - + @for (var i = 1; i < ViewModel.CurrentShipStats?.SurvivabilityDataContainer.DataElements.Count - j; i++) { @@ -473,7 +474,7 @@ @if (ViewModel.CurrentShipStats?.SpecialAbilityDataContainer is not null) { - + @if (ViewModel.CurrentShipStats.SpecialAbilityDataContainer.IsBurstMode) { diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor index 3fcdd97b3..fbee02287 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor @@ -97,10 +97,10 @@ else if (ViewModel is not null) - + @Localizer.GetAppLocalization(nameof(Translation.MainWindow_ShareBuild)).Localization - + @Localizer.SimpleAppLocalization(nameof(Translation.Dialog_Save)) diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/SignalSelector.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/SignalSelector.razor index 89daba6cf..e2939ef90 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/SignalSelector.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/SignalSelector.razor @@ -18,7 +18,7 @@ - + @@ -58,17 +58,7 @@ private Color GetColorFromState(SignalItemViewModel signalItem) { - if (ViewModel!.SelectedSignals.Any(x => x.Name.Equals(signalItem.Signal.Name))) - { - return Color.Error; - } - - if (!signalItem.CanExecute) - { - return Color.Primary; - } - - return Color.Secondary; + return ViewModel!.SelectedSignals.Any(x => x.Name.Equals(signalItem.Signal.Name)) ? Color.Error : Color.Default; } private void OnSignalClick(SignalItemViewModel signal) @@ -117,11 +107,11 @@ private string GetMudPaperStyle(bool isSelected) { - return " border-color: " + (isSelected ? "#BC0606;" : "#3C3C3C; opacity: 0.4;"); + return " border-color: " + (isSelected ? "#BC0606;" : "var(--mud-palette-text-disabled); opacity: 0.4;"); } private string GetImageStyle(bool isSelected) { return isSelected ? string.Empty : "opacity: 0.4;"; } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor b/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor index e69da92ca..ee9ec45d8 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor @@ -21,11 +21,11 @@ @* HideSlider is set to true because of an issue in MudBlazor. see https://github.com/MudBlazor/MudBlazor/issues/4742*@ - + @foreach (var container in shipContainers) { - + } @@ -34,25 +34,25 @@ - + - + - + - + - + @code { diff --git a/WoWsShipBuilder.Common/Infrastructure/Utility/Helpers.cs b/WoWsShipBuilder.Common/Infrastructure/Utility/Helpers.cs index 2aaabc361..50908e732 100644 --- a/WoWsShipBuilder.Common/Infrastructure/Utility/Helpers.cs +++ b/WoWsShipBuilder.Common/Infrastructure/Utility/Helpers.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Hosting; +using MudBlazor; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.GameData; @@ -62,4 +63,46 @@ public static string GenerateRandomColor() { return $"#{Random.Shared.Next(0x1000000):X6}"; } + + public static MudTheme CreateDarkTheme(bool sharpCorners) + { + return new() + { + LayoutProperties = + { + DefaultBorderRadius = sharpCorners ? "0" : "4px", + }, + PaletteDark = + { + Black = "#121212FF", + White = "#FDFDFDFF", + Primary = "#6186FF", + PrimaryContrastText = "#242424", + Secondary = "#D4D4D4", + SecondaryContrastText = "#282828", + Tertiary = "#FFD700", + TertiaryContrastText = "#282828", + InfoContrastText = "#FDFDFDFF", + Success = "#00CD42", + SuccessContrastText = "#282828", + WarningContrastText = "#282828", + Error = "#BF0000FF", + ErrorContrastText = "#FDFDFDFF", + Dark = "#505050", + DarkContrastText = "#FDFDFDFF", + Surface = "#232323", + HoverOpacity = 0.165, + AppbarBackground = "#121212FF", + Background = "#282828", + BackgroundGrey = "#1E1E1E", + GrayDark = "#505050", + }, + ZIndex = + { + Dialog = 2000, + Popover = 3000, + Tooltip = 4000, + }, + }; + } } diff --git a/WoWsShipBuilder.Common/wwwroot/css/app.css b/WoWsShipBuilder.Common/wwwroot/css/app.css index 45b216b84..24d50f7ed 100644 --- a/WoWsShipBuilder.Common/wwwroot/css/app.css +++ b/WoWsShipBuilder.Common/wwwroot/css/app.css @@ -223,6 +223,7 @@ a.kofi-button:active { border-radius: 4px; } +/*noinspection CssUnresolvedCustomProperty*/ div.mud-expand-panel { border-radius: var(--mud-default-borderradius) !important; } @@ -243,17 +244,21 @@ div.mud-expand-panel { padding: 12px; } +/*noinspection CssUnresolvedCustomProperty*/ .custom-expansion-panel-header .mud-expand-panel-header { padding: 4px 8px; min-height: 24px; - background-color: rgb(80, 80, 80); + background-color: var(--mud-palette-grey-dark); + border-radius: var(--mud-default-borderradius); } +/*noinspection CssUnresolvedCustomProperty*/ .custom-child-expansion-panel-header .mud-expand-panel-header { padding: 4px 8px; min-height: 24px; - background-color: rgba(80, 80, 80, 40%); + background-color: color-mix(in srgb, var(--mud-palette-grey-dark), transparent 40%); } + .mud-data-grid button.drag-icon-options { visibility: hidden; width: 0; @@ -273,3 +278,31 @@ div.mud-expand-panel { .mud-data-grid-range-selector label.mud-input-label-text { display: ruby !important; } + +/*noinspection CssUnresolvedCustomProperty*/ +div.default-label-background label { + background-color: var(--mud-palette-background) !important; +} + +/*noinspection CssUnresolvedCustomProperty*/ +.link-text { + color: var(--mud-palette-primary-lighten) !important; + text-decoration: underline; + cursor: pointer; +} + +/*noinspection CssUnresolvedCustomProperty*/ +.ship-stats-tabs .mud-tabs-toolbar .mud-tab-active { + background-color: var(--mud-palette-primary); + color: var(--mud-palette-primary-text); + + /*noinspection CssUnresolvedCustomProperty*/ + & svg { + fill: var(--mud-palette-primary-text); + } +} + +/*noinspection CssUnresolvedCustomProperty*/ +.default-background { + background-color: var(--mud-palette-background); +} diff --git a/WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopLayout.razor b/WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopLayout.razor index d9aaae119..225321fcf 100644 --- a/WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopLayout.razor +++ b/WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopLayout.razor @@ -1,4 +1,5 @@ -@inherits LayoutComponentBase +@using WoWsShipBuilder.Infrastructure.Utility +@inherits LayoutComponentBase @@ -17,48 +18,5 @@ { private readonly bool settingsInitialized = true; - private readonly MudTheme theme = new() - { - LayoutProperties = - { - // DefaultBorderRadius = "0", - }, - PaletteDark = - { - Black = "#121212FF", - White = "#FDFDFDFF", - Primary = "#505050FF", - PrimaryContrastText = "#DEDEDEFF", - Secondary = "#DEDEDEFF", - Info = "#5C60DBFF", - InfoContrastText = "#FAF7F9FF", - Success = "#008C3AFF", - SuccessContrastText = "#FAF7F9FF", - Warning = "#BF7300FF", - WarningContrastText = "#FAF7F9FF", - Error = "#BF0000FF", - ErrorContrastText = "#FAF7F9FF", - Dark = "#282828FF", - DarkContrastText = "#DEDEDEFF", - TextPrimary = "#DEDEDEFF", - TextSecondary = "#FFFFFF89", - TextDisabled = "#FFFFFF60", - ActionDefault = "#FFFFFF89", - ActionDisabled = "#FFFFFF42", - ActionDisabledBackground = " #FFFFFF1E", - Surface = "#282828FF", - LinesDefault = "#FFFFFF4D", - LinesInputs = "#808080", - AppbarBackground = "#121212FF", - HoverOpacity = 0.2, - DrawerBackground = "#1F1F1F", - DividerLight = "#FFFFFFCC", - }, - ZIndex = - { - Dialog = 2000, - Popover = 3000, - Tooltip = 4000, - }, - }; + private readonly MudTheme theme = Helpers.CreateDarkTheme(false); } diff --git a/WoWsShipBuilder.Desktop/Features/Settings/SettingsComponent.razor b/WoWsShipBuilder.Desktop/Features/Settings/SettingsComponent.razor index d32cf0ca4..f5913f2b8 100644 --- a/WoWsShipBuilder.Desktop/Features/Settings/SettingsComponent.razor +++ b/WoWsShipBuilder.Desktop/Features/Settings/SettingsComponent.razor @@ -88,17 +88,17 @@ @($"Saved builds ({savedBuilds.Count})") - + @Localizer.SimpleAppLocalization(nameof(Translation.SettingsWindow_Export)) - + @Localizer.SimpleAppLocalization(nameof(Translation.BuildImport_Import)) - + @Localizer.SimpleAppLocalization(nameof(Translation.SettingsWindow_DeleteAll)) @@ -108,28 +108,28 @@ @Localizer.GetAppLocalization(nameof(Translation.WebApp_ExpanderSettingHeader)).Localization - - - + + + - + - + - + @@ -138,7 +138,7 @@ - + @Localizer.SimpleAppLocalization(currentDownloadInfo) @@ -335,7 +335,7 @@ customBuildImagePath = path; } } - + private async Task ExportSavedBuilds() { var mainWindow = (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow!; diff --git a/WoWsShipBuilder.Desktop/version.json b/WoWsShipBuilder.Desktop/version.json index 77c008877..b296c5fc4 100644 --- a/WoWsShipBuilder.Desktop/version.json +++ b/WoWsShipBuilder.Desktop/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.2", + "version": "2.3", "publicReleaseRefSpec": [ "^refs/heads/release/desktop$" ], diff --git a/WoWsShipBuilder.Desktop/wwwroot/index.html b/WoWsShipBuilder.Desktop/wwwroot/index.html index 36a00f18e..811a9ad75 100644 --- a/WoWsShipBuilder.Desktop/wwwroot/index.html +++ b/WoWsShipBuilder.Desktop/wwwroot/index.html @@ -10,7 +10,7 @@ - + diff --git a/WoWsShipBuilder.Web/Common/MainLayout.razor b/WoWsShipBuilder.Web/Common/MainLayout.razor index 142c03e7c..b6c86f33d 100644 --- a/WoWsShipBuilder.Web/Common/MainLayout.razor +++ b/WoWsShipBuilder.Web/Common/MainLayout.razor @@ -48,50 +48,7 @@ } } - private readonly MudTheme theme = new() - { - LayoutProperties = - { - DefaultBorderRadius = "0", - }, - PaletteDark = - { - Black = "#121212FF", - White = "#FDFDFDFF", - Primary = "#505050FF", - PrimaryContrastText = "#DEDEDEFF", - Secondary = "#DEDEDEFF", - Info = "#5C60DBFF", - InfoContrastText = "#FAF7F9FF", - Success = "#008C3AFF", - SuccessContrastText = "#FAF7F9FF", - Warning = "#BF7300FF", - WarningContrastText = "#FAF7F9FF", - Error = "#BF0000FF", - ErrorContrastText = "#FAF7F9FF", - Dark = "#282828FF", - DarkContrastText = "#DEDEDEFF", - TextPrimary = "#DEDEDEFF", - TextSecondary = "#FFFFFF89", - TextDisabled = "#FFFFFF60", - ActionDefault = "#FFFFFF89", - ActionDisabled = "#FFFFFF42", - ActionDisabledBackground = " #FFFFFF1E", - Surface = "#282828FF", - LinesDefault = "#FFFFFF4D", - LinesInputs = "#808080", - AppbarBackground = "#121212FF", - HoverOpacity = 0.2, - DrawerBackground = "#1F1F1F", - DividerLight = "#FFFFFFCC", - }, - ZIndex = - { - Dialog = 2000, - Popover = 3000, - Tooltip = 4000, - }, - }; + private readonly MudTheme theme = Helpers.CreateDarkTheme(true); private readonly MudTheme aprilFoolTheme = new() { diff --git a/WoWsShipBuilder.Web/Common/TopMenu.razor b/WoWsShipBuilder.Web/Common/TopMenu.razor index 8d0a1e725..31c17f8af 100644 --- a/WoWsShipBuilder.Web/Common/TopMenu.razor +++ b/WoWsShipBuilder.Web/Common/TopMenu.razor @@ -174,11 +174,11 @@ WoWs‑ShipBuilder - + @Localizer.SimpleAppLocalization(nameof(Translation.NavigationHome)) - @Localizer.SimpleAppLocalization(nameof(Translation.NavigationAccelerationCharts)) - @Localizer.SimpleAppLocalization(nameof(Translation.NavigationComparison)) @Localizer.SimpleAppLocalization(nameof(Translation.NavigationCharts)) + @Localizer.SimpleAppLocalization(nameof(Translation.NavigationAccelerationCharts)) + @Localizer.SimpleAppLocalization(nameof(Translation.NavigationComparison)) Donate @* Test page *@ diff --git a/WoWsShipBuilder.Web/Features/Host/_Layout.cshtml b/WoWsShipBuilder.Web/Features/Host/_Layout.cshtml index e5157865b..19039189b 100644 --- a/WoWsShipBuilder.Web/Features/Host/_Layout.cshtml +++ b/WoWsShipBuilder.Web/Features/Host/_Layout.cshtml @@ -27,7 +27,7 @@ Custom builds." property="og:description"> - + @RenderBody() diff --git a/WoWsShipBuilder.Web/Features/UserSettings/UserSettings.razor b/WoWsShipBuilder.Web/Features/UserSettings/UserSettings.razor index 4c342b679..81e4e21c5 100644 --- a/WoWsShipBuilder.Web/Features/UserSettings/UserSettings.razor +++ b/WoWsShipBuilder.Web/Features/UserSettings/UserSettings.razor @@ -53,9 +53,9 @@ @Localizer.GetAppLocalization(nameof(Translation.WebApp_ExpanderSettingHeader)).Localization - - - + + + @@ -64,17 +64,17 @@ @($"Saved builds ({savedBuilds.Count}/1000)") - + @Localizer.SimpleAppLocalization(nameof(Translation.SettingsWindow_Export)) - + @Localizer.SimpleAppLocalization(nameof(Translation.BuildImport_Import)) - + @Localizer.SimpleAppLocalization(nameof(Translation.SettingsWindow_DeleteAll)) @@ -84,14 +84,14 @@ - + @Localizer.SimpleAppLocalization(nameof(Translation.BetaAccess_Heading)) - + @Localizer.SimpleAppLocalization(nameof(Translation.BetaAccess_AddCode)) @@ -111,7 +111,7 @@ @(BetaAccessManager.FindBetaByCode(context)?.LocalizationKey ?? "N/A") - + @@ -119,10 +119,10 @@ - @Localizer.GetAppLocalization(nameof(Translation.SettingsWindow_Save)).Localization + @Localizer.GetAppLocalization(nameof(Translation.SettingsWindow_Save)).Localization - @Localizer.GetAppLocalization(nameof(Translation.SettingsWindow_Reset)).Localization + @Localizer.GetAppLocalization(nameof(Translation.SettingsWindow_Reset)).Localization diff --git a/WoWsShipBuilder.Web/Program.cs b/WoWsShipBuilder.Web/Program.cs index d1854ac2b..e804c584b 100644 --- a/WoWsShipBuilder.Web/Program.cs +++ b/WoWsShipBuilder.Web/Program.cs @@ -2,7 +2,6 @@ using NLog.Web; using Prometheus; using ReactiveUI; -using Splat; using WoWsShipBuilder.Infrastructure.ApplicationData; using WoWsShipBuilder.Infrastructure.Utility; using WoWsShipBuilder.Web.Features.Authentication; diff --git a/WoWsShipBuilder.Web/version.json b/WoWsShipBuilder.Web/version.json index 28a8d645d..65abfaabd 100644 --- a/WoWsShipBuilder.Web/version.json +++ b/WoWsShipBuilder.Web/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.2", + "version": "2.3", "publicReleaseRefSpec": [ "^refs/heads/release/web$" ], From c5c296cc4d3eca12b2ad0235746a294b716b638a Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 28 Oct 2023 22:42:33 +0200 Subject: [PATCH 10/26] remove unused leftovers from application template --- .../BlazorWebView/DesktopLayout.razor.css | 81 ------------------- .../Common/MainLayout.razor.css | 81 ------------------- WoWsShipBuilder.Web/Common/NavMenu.razor | 40 --------- WoWsShipBuilder.Web/Common/NavMenu.razor.css | 62 -------------- 4 files changed, 264 deletions(-) delete mode 100644 WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopLayout.razor.css delete mode 100644 WoWsShipBuilder.Web/Common/MainLayout.razor.css delete mode 100644 WoWsShipBuilder.Web/Common/NavMenu.razor delete mode 100644 WoWsShipBuilder.Web/Common/NavMenu.razor.css diff --git a/WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopLayout.razor.css b/WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopLayout.razor.css deleted file mode 100644 index bd3e067ec..000000000 --- a/WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopLayout.razor.css +++ /dev/null @@ -1,81 +0,0 @@ -.page { - position: relative; - display: flex; - flex-direction: column; -} - -main { - flex: 1; -} - -.sidebar { - background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); -} - -.top-row { - background-color: #f7f7f7; - border-bottom: 1px solid #d6d5d5; - justify-content: flex-end; - height: 3.5rem; - display: flex; - align-items: center; -} - - .top-row ::deep a, .top-row ::deep .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - text-decoration: none; - } - - .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { - text-decoration: underline; - } - - .top-row ::deep a:first-child { - overflow: hidden; - text-overflow: ellipsis; - } - -@media (max-width: 640.98px) { - .top-row:not(.auth) { - display: none; - } - - .top-row.auth { - justify-content: space-between; - } - - .top-row ::deep a, .top-row ::deep .btn-link { - margin-left: 0; - } -} - -@media (min-width: 641px) { - .page { - flex-direction: row; - } - - .sidebar { - width: 250px; - height: 100vh; - position: sticky; - top: 0; - } - - .top-row { - position: sticky; - top: 0; - z-index: 1; - } - - .top-row.auth ::deep a:first-child { - flex: 1; - text-align: right; - width: 0; - } - - .top-row, article { - padding-left: 2rem !important; - padding-right: 1.5rem !important; - } -} diff --git a/WoWsShipBuilder.Web/Common/MainLayout.razor.css b/WoWsShipBuilder.Web/Common/MainLayout.razor.css deleted file mode 100644 index c8654276b..000000000 --- a/WoWsShipBuilder.Web/Common/MainLayout.razor.css +++ /dev/null @@ -1,81 +0,0 @@ -.page { - position: relative; - display: flex; - flex-direction: column; -} - -main { - flex: 1; -} - -.sidebar { - background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); -} - -.top-row { - background-color: #f7f7f7; - border-bottom: 1px solid #d6d5d5; - justify-content: flex-end; - height: 3.5rem; - display: flex; - align-items: center; -} - - .top-row ::deep a, .top-row ::deep .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - text-decoration: none; - } - - .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { - text-decoration: underline; - } - - .top-row ::deep a:first-child { - overflow: hidden; - text-overflow: ellipsis; - } - -@media (max-width: 640.98px) { - .top-row:not(.auth) { - display: none; - } - - .top-row.auth { - justify-content: space-between; - } - - .top-row ::deep a, .top-row ::deep .btn-link { - margin-left: 0; - } -} - -@media (min-width: 641px) { - .page { - flex-direction: row; - } - - .sidebar { - width: 250px; - height: 100vh; - position: sticky; - top: 0; - } - - .top-row { - position: sticky; - top: 0; - z-index: 1; - } - - .top-row.auth ::deep a:first-child { - flex: 1; - text-align: right; - width: 0; - } - - .top-row, article { - padding-left: 2rem !important; - padding-right: 1.5rem !important; - } -} diff --git a/WoWsShipBuilder.Web/Common/NavMenu.razor b/WoWsShipBuilder.Web/Common/NavMenu.razor deleted file mode 100644 index 2fa194fb3..000000000 --- a/WoWsShipBuilder.Web/Common/NavMenu.razor +++ /dev/null @@ -1,40 +0,0 @@ - - -
- -
- -@code { - private bool collapseNavMenu = true; - - private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; - - private void ToggleNavMenu() - { - collapseNavMenu = !collapseNavMenu; - } - -} \ No newline at end of file diff --git a/WoWsShipBuilder.Web/Common/NavMenu.razor.css b/WoWsShipBuilder.Web/Common/NavMenu.razor.css deleted file mode 100644 index acc5f9f81..000000000 --- a/WoWsShipBuilder.Web/Common/NavMenu.razor.css +++ /dev/null @@ -1,62 +0,0 @@ -.navbar-toggler { - background-color: rgba(255, 255, 255, 0.1); -} - -.top-row { - height: 3.5rem; - background-color: rgba(0,0,0,0.4); -} - -.navbar-brand { - font-size: 1.1rem; -} - -.oi { - width: 2rem; - font-size: 1.1rem; - vertical-align: text-top; - top: -2px; -} - -.nav-item { - font-size: 0.9rem; - padding-bottom: 0.5rem; -} - - .nav-item:first-of-type { - padding-top: 1rem; - } - - .nav-item:last-of-type { - padding-bottom: 1rem; - } - - .nav-item ::deep a { - color: #d7d7d7; - border-radius: 4px; - height: 3rem; - display: flex; - align-items: center; - line-height: 3rem; - } - -.nav-item ::deep a.active { - background-color: rgba(255,255,255,0.25); - color: white; -} - -.nav-item ::deep a:hover { - background-color: rgba(255,255,255,0.1); - color: white; -} - -@media (min-width: 641px) { - .navbar-toggler { - display: none; - } - - .collapse { - /* Never collapse the sidebar for wide screens */ - display: block; - } -} From 8391e14d22da5e388af689123015a988c32920ee Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 28 Oct 2023 22:44:41 +0200 Subject: [PATCH 11/26] move BetaAccess feature in features folder --- WoWsShipBuilder.Web/Common/TopMenu.razor | 2 +- WoWsShipBuilder.Web/Features/AdminPage/AdminPage.razor | 2 +- .../BetaAccess/BetaAccessManager.cs | 6 +++--- .../BetaAccess/IBetaAccessManager.cs | 2 +- .../Features/UserSettings/UserSettings.razor | 7 ++++--- .../Infrastructure/ServiceCollectionExtensions.cs | 7 +++---- 6 files changed, 13 insertions(+), 13 deletions(-) rename WoWsShipBuilder.Web/{Infrastructure => Features}/BetaAccess/BetaAccessManager.cs (62%) rename WoWsShipBuilder.Web/{Infrastructure => Features}/BetaAccess/IBetaAccessManager.cs (76%) diff --git a/WoWsShipBuilder.Web/Common/TopMenu.razor b/WoWsShipBuilder.Web/Common/TopMenu.razor index 31c17f8af..3faa2b5b0 100644 --- a/WoWsShipBuilder.Web/Common/TopMenu.razor +++ b/WoWsShipBuilder.Web/Common/TopMenu.razor @@ -6,8 +6,8 @@ @using WoWsShipBuilder.Infrastructure.Localization @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Utility +@using WoWsShipBuilder.Web.Features.BetaAccess @using WoWsShipBuilder.Web.Infrastructure -@using WoWsShipBuilder.Web.Infrastructure.BetaAccess @implements IDisposable diff --git a/WoWsShipBuilder.Web/Features/AdminPage/AdminPage.razor b/WoWsShipBuilder.Web/Features/AdminPage/AdminPage.razor index 2930089cb..afd423f1e 100644 --- a/WoWsShipBuilder.Web/Features/AdminPage/AdminPage.razor +++ b/WoWsShipBuilder.Web/Features/AdminPage/AdminPage.razor @@ -5,8 +5,8 @@ @using WoWsShipBuilder.Infrastructure.DataTransfer @using WoWsShipBuilder.Infrastructure.Localization @using WoWsShipBuilder.Infrastructure.Localization.Resources -@using WoWsShipBuilder.Web.Infrastructure.BetaAccess @using System.Security.Claims +@using WoWsShipBuilder.Web.Features.BetaAccess @inject ILocalizer Localizer @inject IBetaAccessManager BetaAccessManager diff --git a/WoWsShipBuilder.Web/Infrastructure/BetaAccess/BetaAccessManager.cs b/WoWsShipBuilder.Web/Features/BetaAccess/BetaAccessManager.cs similarity index 62% rename from WoWsShipBuilder.Web/Infrastructure/BetaAccess/BetaAccessManager.cs rename to WoWsShipBuilder.Web/Features/BetaAccess/BetaAccessManager.cs index 5ef91f3e2..8c76ba752 100644 --- a/WoWsShipBuilder.Web/Infrastructure/BetaAccess/BetaAccessManager.cs +++ b/WoWsShipBuilder.Web/Features/BetaAccess/BetaAccessManager.cs @@ -1,6 +1,6 @@ using WoWsShipBuilder.Infrastructure.Localization.Resources; -namespace WoWsShipBuilder.Web.Infrastructure.BetaAccess; +namespace WoWsShipBuilder.Web.Features.BetaAccess; public class BetaAccessManager : IBetaAccessManager { @@ -11,9 +11,9 @@ public class BetaAccessManager : IBetaAccessManager UserAuth, }; - public BetaAccessEntry? FindBetaByCode(string code) => ActiveBetas.FirstOrDefault(b => b.Code == code); + public BetaAccessEntry? FindBetaByCode(string code) => this.ActiveBetas.FirstOrDefault(b => b.Code == code); - public bool IsBetaActive(BetaAccessEntry entry) => ActiveBetas.Contains(entry); + public bool IsBetaActive(BetaAccessEntry entry) => this.ActiveBetas.Contains(entry); } public sealed record BetaAccessEntry(string Code, string LocalizationKey); diff --git a/WoWsShipBuilder.Web/Infrastructure/BetaAccess/IBetaAccessManager.cs b/WoWsShipBuilder.Web/Features/BetaAccess/IBetaAccessManager.cs similarity index 76% rename from WoWsShipBuilder.Web/Infrastructure/BetaAccess/IBetaAccessManager.cs rename to WoWsShipBuilder.Web/Features/BetaAccess/IBetaAccessManager.cs index 883171724..d3cd42795 100644 --- a/WoWsShipBuilder.Web/Infrastructure/BetaAccess/IBetaAccessManager.cs +++ b/WoWsShipBuilder.Web/Features/BetaAccess/IBetaAccessManager.cs @@ -1,4 +1,4 @@ -namespace WoWsShipBuilder.Web.Infrastructure.BetaAccess; +namespace WoWsShipBuilder.Web.Features.BetaAccess; public interface IBetaAccessManager { diff --git a/WoWsShipBuilder.Web/Features/UserSettings/UserSettings.razor b/WoWsShipBuilder.Web/Features/UserSettings/UserSettings.razor index 81e4e21c5..71a845720 100644 --- a/WoWsShipBuilder.Web/Features/UserSettings/UserSettings.razor +++ b/WoWsShipBuilder.Web/Features/UserSettings/UserSettings.razor @@ -1,4 +1,6 @@ @page "/settings" +@using Newtonsoft.Json +@using WoWsShipBuilder.Features.Builds @using WoWsShipBuilder.Features.Settings @using WoWsShipBuilder.Infrastructure.ApplicationData @using WoWsShipBuilder.Infrastructure.DataTransfer @@ -6,12 +8,11 @@ @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Metrics @using WoWsShipBuilder.Infrastructure.Utility -@using WoWsShipBuilder.Web.Infrastructure.BetaAccess -@using WoWsShipBuilder.Features.Builds -@using Newtonsoft.Json +@using WoWsShipBuilder.Web.Features.BetaAccess @implements IDisposable @implements IAsyncDisposable + @inject ILocalizer Localizer @inject RefreshNotifierService RefreshNotifierService @inject AppSettings AppSettings diff --git a/WoWsShipBuilder.Web/Infrastructure/ServiceCollectionExtensions.cs b/WoWsShipBuilder.Web/Infrastructure/ServiceCollectionExtensions.cs index dcca7a7fa..8a6557c08 100644 --- a/WoWsShipBuilder.Web/Infrastructure/ServiceCollectionExtensions.cs +++ b/WoWsShipBuilder.Web/Infrastructure/ServiceCollectionExtensions.cs @@ -1,14 +1,13 @@ using WoWsShipBuilder.Infrastructure.ApplicationData; using WoWsShipBuilder.Infrastructure.DataTransfer; +using WoWsShipBuilder.Infrastructure.HttpClients; using WoWsShipBuilder.Infrastructure.Utility; using WoWsShipBuilder.Web.Features.Authentication; +using WoWsShipBuilder.Web.Features.BetaAccess; +using WoWsShipBuilder.Web.Infrastructure.Data; namespace WoWsShipBuilder.Web.Infrastructure; -using WoWsShipBuilder.Infrastructure.HttpClients; -using WoWsShipBuilder.Web.Infrastructure.BetaAccess; -using WoWsShipBuilder.Web.Infrastructure.Data; - public static class ServiceCollectionExtensions { public static IServiceCollection UseShipBuilderWeb(this IServiceCollection services) From 261f93ba37c4069d0084f147dff5bb107ba2d3dd Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 28 Oct 2023 22:51:03 +0200 Subject: [PATCH 12/26] rearrange root components --- .../Features/BlazorWebView/BlazorWindow.axaml.cs | 2 +- .../{AppRouter.razor => DesktopRootComponent.razor} | 2 +- WoWsShipBuilder.Web/Features/Host/_Host.cshtml | 4 ++-- .../{Common => Features/Layout}/MainLayout.razor | 0 .../{Common => Features/Layout}/ShipBuilderFooter.razor | 0 WoWsShipBuilder.Web/{Common => Features/Layout}/TopMenu.razor | 0 .../{Common => Features/Layout}/Unauthorized.razor | 0 .../App.razor => Features/Layout/WebRootComponent.razor} | 3 +-- 8 files changed, 5 insertions(+), 6 deletions(-) rename WoWsShipBuilder.Desktop/Features/BlazorWebView/{AppRouter.razor => DesktopRootComponent.razor} (85%) rename WoWsShipBuilder.Web/{Common => Features/Layout}/MainLayout.razor (100%) rename WoWsShipBuilder.Web/{Common => Features/Layout}/ShipBuilderFooter.razor (100%) rename WoWsShipBuilder.Web/{Common => Features/Layout}/TopMenu.razor (100%) rename WoWsShipBuilder.Web/{Common => Features/Layout}/Unauthorized.razor (100%) rename WoWsShipBuilder.Web/{Common/App.razor => Features/Layout/WebRootComponent.razor} (87%) diff --git a/WoWsShipBuilder.Desktop/Features/BlazorWebView/BlazorWindow.axaml.cs b/WoWsShipBuilder.Desktop/Features/BlazorWebView/BlazorWindow.axaml.cs index 265c8248e..edcb0e55d 100644 --- a/WoWsShipBuilder.Desktop/Features/BlazorWebView/BlazorWindow.axaml.cs +++ b/WoWsShipBuilder.Desktop/Features/BlazorWebView/BlazorWindow.axaml.cs @@ -18,7 +18,7 @@ public BlazorWindow() var services = (Application.Current as App)?.Services; var rootComponents = new RootComponentsCollection { - new("#app", typeof(AppRouter), null), + new("#app", typeof(DesktopRootComponent), null), }; Resources.Add("services", services); diff --git a/WoWsShipBuilder.Desktop/Features/BlazorWebView/AppRouter.razor b/WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopRootComponent.razor similarity index 85% rename from WoWsShipBuilder.Desktop/Features/BlazorWebView/AppRouter.razor rename to WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopRootComponent.razor index ca30c34cb..891a092a5 100644 --- a/WoWsShipBuilder.Desktop/Features/BlazorWebView/AppRouter.razor +++ b/WoWsShipBuilder.Desktop/Features/BlazorWebView/DesktopRootComponent.razor @@ -1,7 +1,7 @@ @using System.Reflection @using WoWsShipBuilder.Features.ShipStats - + diff --git a/WoWsShipBuilder.Web/Features/Host/_Host.cshtml b/WoWsShipBuilder.Web/Features/Host/_Host.cshtml index 66c4ed621..78f2f3747 100644 --- a/WoWsShipBuilder.Web/Features/Host/_Host.cshtml +++ b/WoWsShipBuilder.Web/Features/Host/_Host.cshtml @@ -1,9 +1,9 @@ @page "/" -@using WoWsShipBuilder.Web.Common +@using WoWsShipBuilder.Web.Features.Layout @namespace WoWsShipBuilder.Web.Features.Host @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ Layout = "_Layout.cshtml"; } - + diff --git a/WoWsShipBuilder.Web/Common/MainLayout.razor b/WoWsShipBuilder.Web/Features/Layout/MainLayout.razor similarity index 100% rename from WoWsShipBuilder.Web/Common/MainLayout.razor rename to WoWsShipBuilder.Web/Features/Layout/MainLayout.razor diff --git a/WoWsShipBuilder.Web/Common/ShipBuilderFooter.razor b/WoWsShipBuilder.Web/Features/Layout/ShipBuilderFooter.razor similarity index 100% rename from WoWsShipBuilder.Web/Common/ShipBuilderFooter.razor rename to WoWsShipBuilder.Web/Features/Layout/ShipBuilderFooter.razor diff --git a/WoWsShipBuilder.Web/Common/TopMenu.razor b/WoWsShipBuilder.Web/Features/Layout/TopMenu.razor similarity index 100% rename from WoWsShipBuilder.Web/Common/TopMenu.razor rename to WoWsShipBuilder.Web/Features/Layout/TopMenu.razor diff --git a/WoWsShipBuilder.Web/Common/Unauthorized.razor b/WoWsShipBuilder.Web/Features/Layout/Unauthorized.razor similarity index 100% rename from WoWsShipBuilder.Web/Common/Unauthorized.razor rename to WoWsShipBuilder.Web/Features/Layout/Unauthorized.razor diff --git a/WoWsShipBuilder.Web/Common/App.razor b/WoWsShipBuilder.Web/Features/Layout/WebRootComponent.razor similarity index 87% rename from WoWsShipBuilder.Web/Common/App.razor rename to WoWsShipBuilder.Web/Features/Layout/WebRootComponent.razor index 3a2bd1d53..08a3f7e83 100644 --- a/WoWsShipBuilder.Web/Common/App.razor +++ b/WoWsShipBuilder.Web/Features/Layout/WebRootComponent.razor @@ -1,9 +1,8 @@ @using System.Reflection @using WoWsShipBuilder.Features.ShipStats -@using WoWsShipBuilder.Web.Common - + From 7b740f2297e41432bff72a10fb7d5fc3e188dc72 Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 28 Oct 2023 22:59:52 +0200 Subject: [PATCH 13/26] move data containers into features directory --- .../AccelerationCharts/AccelerationCharts.razor | 2 +- .../Features/BallisticCharts/BallisticHelper.cs | 2 +- .../Features/BallisticCharts/Charts.razor | 2 +- .../Features/BallisticCharts/DispersionPlot.razor | 4 ++-- .../BallisticCharts/ShipAndShellSelectionDialog.razor | 2 +- .../Components/CaptainSkillSelectorImageRender.razor | 5 ++--- .../Components/ConsumableSelectorImageRender.razor | 6 +++--- .../Components/ShipUpgradeSelectorImageRender.razor | 5 +++-- .../Builds/Components/SignalSelectorImageRender.razor | 3 ++- .../Features/Builds/ShipBuildViewModel.cs | 2 +- .../DataContainers/AccelerationCalculator.cs | 2 +- .../DataContainers/Aircraft/AirstrikeDataContainer.cs | 2 +- .../DataContainers/Aircraft/CvAircraftDataContainer.cs | 2 +- .../Armament/DepthChargesLauncherDataContainer.cs | 2 +- .../Armament/MainBatteryDataContainer.cs | 8 ++++---- .../DataContainers/Armament/PingerGunDataContainer.cs | 2 +- .../Armament/SecondaryBatteryDataContainer.cs | 4 ++-- .../Armament/SecondaryBatteryUiDataContainer.cs | 2 +- .../Armament/TorpedoArmamentDataContainer.cs | 2 +- .../{ => Features}/DataContainers/Constants.cs | 2 +- .../DataContainers/DataContainerUtility.cs | 2 +- .../DataContainers/Projectiles/BombDataContainer.cs | 4 ++-- .../Projectiles/DepthChargeDataContainer.cs | 2 +- .../Projectiles/ProjectileDataContainer.cs | 2 +- .../DataContainers/Projectiles/RocketDataContainer.cs | 4 ++-- .../DataContainers/Projectiles/ShellDataContainer.cs | 4 ++-- .../DataContainers/Projectiles/TorpedoDataContainer.cs | 4 ++-- .../DataContainers/Ship/AntiAirDataContainer.cs | 2 +- .../DataContainers/Ship/AuraDataDataContainer.cs | 2 +- .../DataContainers/Ship/ConcealmentDataContainer.cs | 2 +- .../DataContainers/Ship/ConsumableDataContainer.cs | 2 +- .../Ship/ManeuverabilityDataContainer.cs | 2 +- .../DataContainers/Ship/ShipDataContainer.cs | 2 +- .../DataContainers/Ship/SpecialAbilityDataContainer.cs | 2 +- .../DataContainers/Ship/SurvivabilityDataContainer.cs | 2 +- .../ShipComparison/GridData/AswGridDataWrapper.cs | 2 +- .../ShipComparison/GridData/BomberGridDataWrapper.cs | 4 ++-- .../ShipComparison/GridData/GridDataWrapper.cs | 4 ++-- .../GridData/ManeuverabilityGridDataWrapper.cs | 2 +- .../GridData/RocketPlaneGridDataWrapper.cs | 4 ++-- .../GridData/SecondaryGridDataWrapper.cs | 3 +-- .../GridData/TorpedoBomberGridDataWrapper.cs | 4 ++-- .../ShipComparison/GridData/TorpedoGridDataWrapper.cs | 4 ++-- .../Features/ShipComparison/ShipComparisonViewModel.cs | 2 +- .../ShipStats/Components/CaptainSkillSelector.razor | 1 - .../ShipStats/Components/ConsumableSelector.razor | 6 +++--- .../DepthChargeDamageDistributionChart.razor | 5 +++-- .../Features/ShipStats/Components/ShipStatsPanel.razor | 4 ++-- .../Features/ShipStats/Components/ShipStatsTab.razor | 3 +-- .../ShipStats/Components/ShipUpgradeSelector.razor | 9 +++++---- .../Features/ShipStats/Components/SignalSelector.razor | 3 ++- .../Features/ShipStats/ShipStats.razor | 4 ++-- .../ShipStats/ViewModels/ConsumableSlotViewModel.cs | 2 +- .../ShipStats/ViewModels/ConsumableViewModel.cs | 3 +-- .../ShipStats/ViewModels/ShipStatsControlViewModel.cs | 2 +- .../Infrastructure/DataTransfer/ShipBuildContainer.cs | 4 ++-- .../WoWsShipBuilder.Common.csproj.DotSettings | 10 +++++----- WoWsShipBuilder.Web/Features/TestPage/TestPage.razor | 2 +- 58 files changed, 93 insertions(+), 93 deletions(-) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/AccelerationCalculator.cs (99%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Aircraft/AirstrikeDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Aircraft/CvAircraftDataContainer.cs (99%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Armament/DepthChargesLauncherDataContainer.cs (97%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Armament/MainBatteryDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Armament/PingerGunDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Armament/SecondaryBatteryDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Armament/SecondaryBatteryUiDataContainer.cs (88%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Armament/TorpedoArmamentDataContainer.cs (99%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Constants.cs (77%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/DataContainerUtility.cs (92%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Projectiles/BombDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Projectiles/DepthChargeDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Projectiles/ProjectileDataContainer.cs (67%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Projectiles/RocketDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Projectiles/ShellDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Projectiles/TorpedoDataContainer.cs (99%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Ship/AntiAirDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Ship/AuraDataDataContainer.cs (93%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Ship/ConcealmentDataContainer.cs (99%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Ship/ConsumableDataContainer.cs (99%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Ship/ManeuverabilityDataContainer.cs (99%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Ship/ShipDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Ship/SpecialAbilityDataContainer.cs (98%) rename WoWsShipBuilder.Common/{ => Features}/DataContainers/Ship/SurvivabilityDataContainer.cs (99%) diff --git a/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor b/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor index ce2d2d583..20f77bfc0 100644 --- a/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor +++ b/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor @@ -1,12 +1,12 @@ @page "/acceleration-charts" -@using WoWsShipBuilder.DataContainers @using WoWsShipBuilder.DataStructures @using WoWsShipBuilder.DataStructures.Ship @using WoWsShipBuilder.Features.BallisticCharts @using WoWsShipBuilder.Features.BallisticCharts.Data @using WoWsShipBuilder.Features.Builds @using WoWsShipBuilder.Features.Builds.Components +@using WoWsShipBuilder.Features.DataContainers @using WoWsShipBuilder.Infrastructure.ApplicationData @using WoWsShipBuilder.Infrastructure.DataTransfer @using WoWsShipBuilder.Infrastructure.GameData diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/BallisticHelper.cs b/WoWsShipBuilder.Common/Features/BallisticCharts/BallisticHelper.cs index 7d4bd860f..8e16885f7 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/BallisticHelper.cs +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/BallisticHelper.cs @@ -1,6 +1,6 @@ -using WoWsShipBuilder.DataContainers; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Projectile; +using WoWsShipBuilder.Features.DataContainers; namespace WoWsShipBuilder.Features.BallisticCharts; diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor b/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor index ad2eda058..a34137b1c 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor @@ -1,11 +1,11 @@ @page "/charts" -@using WoWsShipBuilder.DataContainers @using WoWsShipBuilder.DataStructures @using WoWsShipBuilder.DataStructures.Ship @using WoWsShipBuilder.DataStructures.Projectile @using WoWsShipBuilder.Features.BallisticCharts.Data @using WoWsShipBuilder.Features.Builds @using WoWsShipBuilder.Features.Builds.Components +@using WoWsShipBuilder.Features.DataContainers @using WoWsShipBuilder.Infrastructure.ApplicationData @using WoWsShipBuilder.Infrastructure.DataTransfer @using WoWsShipBuilder.Infrastructure.GameData diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/DispersionPlot.razor b/WoWsShipBuilder.Common/Features/BallisticCharts/DispersionPlot.razor index cc5833c92..cb03f252d 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/DispersionPlot.razor +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/DispersionPlot.razor @@ -1,7 +1,7 @@ -@using WoWsShipBuilder.DataContainers -@using WoWsShipBuilder.Features.BallisticCharts.Data +@using WoWsShipBuilder.Features.BallisticCharts.Data @using WoWsShipBuilder.Infrastructure.Localization @using WoWsShipBuilder.Infrastructure.Localization.Resources + @implements IAsyncDisposable @inject IJSRuntime Runtime @inject ILocalizer Localizer diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor b/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor index 27754d30e..1d9818af1 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor @@ -2,11 +2,11 @@ @using System.Collections.Specialized @using System.Linq @using DynamicData -@using WoWsShipBuilder.DataContainers @using WoWsShipBuilder.DataStructures @using WoWsShipBuilder.DataStructures.Ship @using WoWsShipBuilder.Features.BallisticCharts.Data @using WoWsShipBuilder.Features.Builds +@using WoWsShipBuilder.Features.DataContainers @using WoWsShipBuilder.Infrastructure.DataTransfer @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Utility diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor b/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor index bc2bfc0ba..2e7dbc37f 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor @@ -1,6 +1,5 @@ -@using WoWsShipBuilder.DataStructures -@using System.Text -@using WoWsShipBuilder.DataContainers +@using System.Text +@using WoWsShipBuilder.DataStructures @using WoWsShipBuilder.Features.ShipStats.ViewModels @using WoWsShipBuilder.DataStructures.Captain @using WoWsShipBuilder.Infrastructure.Localization.Resources diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/ConsumableSelectorImageRender.razor b/WoWsShipBuilder.Common/Features/Builds/Components/ConsumableSelectorImageRender.razor index 73fdf31d0..f10c62054 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/ConsumableSelectorImageRender.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/ConsumableSelectorImageRender.razor @@ -1,8 +1,8 @@ -@using WoWsShipBuilder.DataContainers +@using WoWsShipBuilder.Features.DataContainers @using WoWsShipBuilder.Features.ShipStats.Components @using WoWsShipBuilder.Infrastructure.Localization @using WoWsShipBuilder.Infrastructure.Utility -@using ConsumableDataContainer = WoWsShipBuilder.DataContainers.ConsumableDataContainer + @inherits ReactiveComponentBase @inject ILocalizer Localizer @@ -113,4 +113,4 @@ } } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/ShipUpgradeSelectorImageRender.razor b/WoWsShipBuilder.Common/Features/Builds/Components/ShipUpgradeSelectorImageRender.razor index 988fc12a6..0b5335395 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/ShipUpgradeSelectorImageRender.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/ShipUpgradeSelectorImageRender.razor @@ -1,8 +1,9 @@ @using WoWsShipBuilder.DataStructures.Upgrade -@using WoWsShipBuilder.DataContainers +@using WoWsShipBuilder.Features.DataContainers @using WoWsShipBuilder.Features.ShipStats.ViewModels @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Utility + @inherits ReactiveComponentBase @inject ILocalizer Localizer @@ -99,4 +100,4 @@ return "min-width: 60px; width: 60px; height: 60px; padding: 2px;"; } } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/SignalSelectorImageRender.razor b/WoWsShipBuilder.Common/Features/Builds/Components/SignalSelectorImageRender.razor index 89ecb0cce..ad43856ee 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/SignalSelectorImageRender.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/SignalSelectorImageRender.razor @@ -1,6 +1,7 @@ -@using WoWsShipBuilder.DataContainers +@using WoWsShipBuilder.Features.DataContainers @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Utility + @inherits ReactiveComponentBase @inject ILocalizer Localizer diff --git a/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs b/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs index bbb93fbab..3c0a6fe3e 100644 --- a/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs +++ b/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs @@ -1,6 +1,6 @@ using ReactiveUI; -using WoWsShipBuilder.DataContainers; using WoWsShipBuilder.DataStructures.Ship; +using WoWsShipBuilder.Features.DataContainers; using WoWsShipBuilder.Features.ShipStats.ViewModels; using WoWsShipBuilder.Infrastructure.ApplicationData; using WoWsShipBuilder.Infrastructure.DataTransfer; diff --git a/WoWsShipBuilder.Common/DataContainers/AccelerationCalculator.cs b/WoWsShipBuilder.Common/Features/DataContainers/AccelerationCalculator.cs similarity index 99% rename from WoWsShipBuilder.Common/DataContainers/AccelerationCalculator.cs rename to WoWsShipBuilder.Common/Features/DataContainers/AccelerationCalculator.cs index 88c936b98..a73297cc5 100644 --- a/WoWsShipBuilder.Common/DataContainers/AccelerationCalculator.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/AccelerationCalculator.cs @@ -2,7 +2,7 @@ using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.ApplicationData; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; public static class AccelerationCalculator { diff --git a/WoWsShipBuilder.Common/DataContainers/Aircraft/AirstrikeDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Aircraft/AirstrikeDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Aircraft/AirstrikeDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Aircraft/AirstrikeDataContainer.cs index 646c8bfd1..836badf37 100644 --- a/WoWsShipBuilder.Common/DataContainers/Aircraft/AirstrikeDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Aircraft/AirstrikeDataContainer.cs @@ -5,7 +5,7 @@ using WoWsShipBuilder.Infrastructure.ApplicationData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record AirstrikeDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/DataContainers/Aircraft/CvAircraftDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Aircraft/CvAircraftDataContainer.cs similarity index 99% rename from WoWsShipBuilder.Common/DataContainers/Aircraft/CvAircraftDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Aircraft/CvAircraftDataContainer.cs index 7dca33344..0e0feabc5 100644 --- a/WoWsShipBuilder.Common/DataContainers/Aircraft/CvAircraftDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Aircraft/CvAircraftDataContainer.cs @@ -8,7 +8,7 @@ using WoWsShipBuilder.Infrastructure.GameData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record CvAircraftDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/DepthChargesLauncherDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/DepthChargesLauncherDataContainer.cs similarity index 97% rename from WoWsShipBuilder.Common/DataContainers/Armament/DepthChargesLauncherDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Armament/DepthChargesLauncherDataContainer.cs index 17d36e9ef..5b751b0b2 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/DepthChargesLauncherDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/DepthChargesLauncherDataContainer.cs @@ -4,7 +4,7 @@ using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record DepthChargesLauncherDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/MainBatteryDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/MainBatteryDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Armament/MainBatteryDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Armament/MainBatteryDataContainer.cs index d5d3dbe3e..6f73b59e7 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/MainBatteryDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/MainBatteryDataContainer.cs @@ -8,7 +8,7 @@ using WoWsShipBuilder.Infrastructure.Utility; // ReSharper disable UnusedAutoPropertyAccessor.Global -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record MainBatteryDataContainer : DataContainerBase @@ -246,16 +246,16 @@ public partial record MainBatteryDataContainer : DataContainerBase private bool ShouldDisplayHeDpm(object obj) { - return DisplayHeDpm; + return this.DisplayHeDpm; } private bool ShouldDisplayApDpm(object obj) { - return DisplayApDpm; + return this.DisplayApDpm; } private bool ShouldDisplaySapDpm(object obj) { - return DisplaySapDpm; + return this.DisplaySapDpm; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/PingerGunDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/PingerGunDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Armament/PingerGunDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Armament/PingerGunDataContainer.cs index 540be959f..dc08fd044 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/PingerGunDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/PingerGunDataContainer.cs @@ -5,7 +5,7 @@ using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record PingerGunDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/SecondaryBatteryDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/SecondaryBatteryDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Armament/SecondaryBatteryDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Armament/SecondaryBatteryDataContainer.cs index 4939a0a93..9c623a48c 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/SecondaryBatteryDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/SecondaryBatteryDataContainer.cs @@ -7,7 +7,7 @@ using WoWsShipBuilder.Infrastructure.GameData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record SecondaryBatteryDataContainer : DataContainerBase @@ -142,6 +142,6 @@ public partial record SecondaryBatteryDataContainer : DataContainerBase private bool ShouldDisplayFpm(object obj) { - return DisplayFpm; + return this.DisplayFpm; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/SecondaryBatteryUiDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/SecondaryBatteryUiDataContainer.cs similarity index 88% rename from WoWsShipBuilder.Common/DataContainers/Armament/SecondaryBatteryUiDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Armament/SecondaryBatteryUiDataContainer.cs index 2825a302f..5775dd9e6 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/SecondaryBatteryUiDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/SecondaryBatteryUiDataContainer.cs @@ -1,6 +1,6 @@ using WoWsShipBuilder.DataStructures.Ship; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; public record SecondaryBatteryUiDataContainer(List? Secondaries) { diff --git a/WoWsShipBuilder.Common/DataContainers/Armament/TorpedoArmamentDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/TorpedoArmamentDataContainer.cs similarity index 99% rename from WoWsShipBuilder.Common/DataContainers/Armament/TorpedoArmamentDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Armament/TorpedoArmamentDataContainer.cs index bc9990430..d5d3ae641 100644 --- a/WoWsShipBuilder.Common/DataContainers/Armament/TorpedoArmamentDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/TorpedoArmamentDataContainer.cs @@ -6,7 +6,7 @@ using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record TorpedoArmamentDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/DataContainers/Constants.cs b/WoWsShipBuilder.Common/Features/DataContainers/Constants.cs similarity index 77% rename from WoWsShipBuilder.Common/DataContainers/Constants.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Constants.cs index 68394100a..f68a19375 100644 --- a/WoWsShipBuilder.Common/DataContainers/Constants.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Constants.cs @@ -1,4 +1,4 @@ -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; public static class Constants { diff --git a/WoWsShipBuilder.Common/DataContainers/DataContainerUtility.cs b/WoWsShipBuilder.Common/Features/DataContainers/DataContainerUtility.cs similarity index 92% rename from WoWsShipBuilder.Common/DataContainers/DataContainerUtility.cs rename to WoWsShipBuilder.Common/Features/DataContainers/DataContainerUtility.cs index 8fa3e98a5..c63f06915 100644 --- a/WoWsShipBuilder.Common/DataContainers/DataContainerUtility.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/DataContainerUtility.cs @@ -1,7 +1,7 @@ using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; public static class DataContainerUtility { diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/BombDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/BombDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Projectiles/BombDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Projectiles/BombDataContainer.cs index 5ff69265f..fa4b56486 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/BombDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/BombDataContainer.cs @@ -5,7 +5,7 @@ using WoWsShipBuilder.Infrastructure.GameData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record BombDataContainer : ProjectileDataContainer @@ -118,6 +118,6 @@ public static BombDataContainer FromBombName(string name, List<(string name, flo private bool ShouldDisplayBlastPenetration(object obj) { - return ShowBlastPenetration; + return this.ShowBlastPenetration; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/DepthChargeDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/DepthChargeDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Projectiles/DepthChargeDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Projectiles/DepthChargeDataContainer.cs index 027b37542..a6d915038 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/DepthChargeDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/DepthChargeDataContainer.cs @@ -3,7 +3,7 @@ using WoWsShipBuilder.Infrastructure.ApplicationData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record DepthChargeDataContainer : ProjectileDataContainer diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/ProjectileDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/ProjectileDataContainer.cs similarity index 67% rename from WoWsShipBuilder.Common/DataContainers/Projectiles/ProjectileDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Projectiles/ProjectileDataContainer.cs index fe19a2a02..b0e3d390e 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/ProjectileDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/ProjectileDataContainer.cs @@ -1,5 +1,5 @@ using WoWsShipBuilder.DataElements; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; public abstract record ProjectileDataContainer : DataContainerBase; diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/RocketDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/RocketDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Projectiles/RocketDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Projectiles/RocketDataContainer.cs index e432d1a77..f9e201194 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/RocketDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/RocketDataContainer.cs @@ -5,7 +5,7 @@ using WoWsShipBuilder.Infrastructure.GameData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record RocketDataContainer : ProjectileDataContainer @@ -112,6 +112,6 @@ public static RocketDataContainer FromRocketName(string name, List<(string name, private bool ShouldDisplayBlastPenetration(object obj) { - return ShowBlastPenetration; + return this.ShowBlastPenetration; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/ShellDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/ShellDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Projectiles/ShellDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Projectiles/ShellDataContainer.cs index 65d4b55f5..4adb7361f 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/ShellDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/ShellDataContainer.cs @@ -8,7 +8,7 @@ using WoWsShipBuilder.Infrastructure.GameData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record ShellDataContainer : DataContainerBase @@ -216,6 +216,6 @@ private static ShellDataContainer ProcessShell(List<(string Name, float Value)> private bool ShouldDisplayBlastPenetration(object obj) { - return ShowBlastPenetration; + return this.ShowBlastPenetration; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Projectiles/TorpedoDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/TorpedoDataContainer.cs similarity index 99% rename from WoWsShipBuilder.Common/DataContainers/Projectiles/TorpedoDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Projectiles/TorpedoDataContainer.cs index 1753f4ab1..3f034b366 100644 --- a/WoWsShipBuilder.Common/DataContainers/Projectiles/TorpedoDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/TorpedoDataContainer.cs @@ -5,7 +5,7 @@ using WoWsShipBuilder.Infrastructure.GameData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record TorpedoDataContainer : ProjectileDataContainer @@ -205,6 +205,6 @@ public static List FromTorpedoName(List torpedoNam private bool ShouldDisplayName(object obj) { - return IsFromPlane; + return this.IsFromPlane; } } diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/AntiAirDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/AntiAirDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Ship/AntiAirDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Ship/AntiAirDataContainer.cs index 20a364ee2..165e69f1e 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/AntiAirDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/AntiAirDataContainer.cs @@ -3,7 +3,7 @@ using WoWsShipBuilder.Infrastructure.Utility; // ReSharper disable InconsistentNaming -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; public record AntiAirDataContainer { diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/AuraDataDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/AuraDataDataContainer.cs similarity index 93% rename from WoWsShipBuilder.Common/DataContainers/Ship/AuraDataDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Ship/AuraDataDataContainer.cs index 5cc0e0d54..4284aa5fd 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/AuraDataDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/AuraDataDataContainer.cs @@ -1,7 +1,7 @@ using WoWsShipBuilder.DataElements; using WoWsShipBuilder.DataElements.DataElementAttributes; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record AuraDataDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/ConcealmentDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ConcealmentDataContainer.cs similarity index 99% rename from WoWsShipBuilder.Common/DataContainers/Ship/ConcealmentDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Ship/ConcealmentDataContainer.cs index 67f40078d..b3cf0f9e3 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/ConcealmentDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ConcealmentDataContainer.cs @@ -4,7 +4,7 @@ using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record ConcealmentDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/ConsumableDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ConsumableDataContainer.cs similarity index 99% rename from WoWsShipBuilder.Common/DataContainers/Ship/ConsumableDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Ship/ConsumableDataContainer.cs index 60f0a156b..be2c520b9 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/ConsumableDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ConsumableDataContainer.cs @@ -9,7 +9,7 @@ using WoWsShipBuilder.Infrastructure.GameData; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record ConsumableDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/ManeuverabilityDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ManeuverabilityDataContainer.cs similarity index 99% rename from WoWsShipBuilder.Common/DataContainers/Ship/ManeuverabilityDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Ship/ManeuverabilityDataContainer.cs index 42ce84f70..d590f0a58 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/ManeuverabilityDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ManeuverabilityDataContainer.cs @@ -4,7 +4,7 @@ using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record ManeuverabilityDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/ShipDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ShipDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Ship/ShipDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Ship/ShipDataContainer.cs index 1b0a9723b..cc12027ea 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/ShipDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ShipDataContainer.cs @@ -1,6 +1,6 @@ using WoWsShipBuilder.DataStructures.Ship; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; public record ShipDataContainer(string Index) { diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/SpecialAbilityDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/SpecialAbilityDataContainer.cs similarity index 98% rename from WoWsShipBuilder.Common/DataContainers/Ship/SpecialAbilityDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Ship/SpecialAbilityDataContainer.cs index 2ae848071..f245ab1bf 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/SpecialAbilityDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/SpecialAbilityDataContainer.cs @@ -5,7 +5,7 @@ using WoWsShipBuilder.DataStructures.Ship; // ReSharper disable InconsistentNaming -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record SpecialAbilityDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/DataContainers/Ship/SurvivabilityDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/SurvivabilityDataContainer.cs similarity index 99% rename from WoWsShipBuilder.Common/DataContainers/Ship/SurvivabilityDataContainer.cs rename to WoWsShipBuilder.Common/Features/DataContainers/Ship/SurvivabilityDataContainer.cs index 9127b08fc..6ac1fb9de 100644 --- a/WoWsShipBuilder.Common/DataContainers/Ship/SurvivabilityDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/SurvivabilityDataContainer.cs @@ -6,7 +6,7 @@ using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; -namespace WoWsShipBuilder.DataContainers; +namespace WoWsShipBuilder.Features.DataContainers; [DataContainer] public partial record SurvivabilityDataContainer : DataContainerBase diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/AswGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/AswGridDataWrapper.cs index 69a0815b7..ffdf97a8f 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/AswGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/AswGridDataWrapper.cs @@ -1,4 +1,4 @@ -using WoWsShipBuilder.DataContainers; +using WoWsShipBuilder.Features.DataContainers; using WoWsShipBuilder.Infrastructure.Localization.Resources; namespace WoWsShipBuilder.Features.ShipComparison.GridData; diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/BomberGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/BomberGridDataWrapper.cs index 81ddfcfca..3edef43b1 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/BomberGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/BomberGridDataWrapper.cs @@ -1,5 +1,5 @@ -using WoWsShipBuilder.DataContainers; -using WoWsShipBuilder.DataStructures; +using WoWsShipBuilder.DataStructures; +using WoWsShipBuilder.Features.DataContainers; namespace WoWsShipBuilder.Features.ShipComparison.GridData; diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs index 738d5aa39..373ae3ec8 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs @@ -1,7 +1,7 @@ -using WoWsShipBuilder.DataContainers; -using WoWsShipBuilder.DataStructures; +using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Features.Builds; +using WoWsShipBuilder.Features.DataContainers; using WoWsShipBuilder.Infrastructure.DataTransfer; using WoWsShipBuilder.Infrastructure.GameData; diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/ManeuverabilityGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/ManeuverabilityGridDataWrapper.cs index 316de20a1..b5c844db8 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/ManeuverabilityGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/ManeuverabilityGridDataWrapper.cs @@ -1,4 +1,4 @@ -using WoWsShipBuilder.DataContainers; +using WoWsShipBuilder.Features.DataContainers; namespace WoWsShipBuilder.Features.ShipComparison.GridData; diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/RocketPlaneGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/RocketPlaneGridDataWrapper.cs index cda2c009e..8a516851e 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/RocketPlaneGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/RocketPlaneGridDataWrapper.cs @@ -1,5 +1,5 @@ -using WoWsShipBuilder.DataContainers; -using WoWsShipBuilder.DataStructures; +using WoWsShipBuilder.DataStructures; +using WoWsShipBuilder.Features.DataContainers; namespace WoWsShipBuilder.Features.ShipComparison.GridData; diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/SecondaryGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/SecondaryGridDataWrapper.cs index 9d1f1dbf4..4d759cd5f 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/SecondaryGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/SecondaryGridDataWrapper.cs @@ -1,5 +1,4 @@ -using SecondaryBatteryDataContainer = WoWsShipBuilder.DataContainers.SecondaryBatteryDataContainer; -using ShellDataContainer = WoWsShipBuilder.DataContainers.ShellDataContainer; +using WoWsShipBuilder.Features.DataContainers; namespace WoWsShipBuilder.Features.ShipComparison.GridData; diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoBomberGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoBomberGridDataWrapper.cs index cabfa2a0c..36256f437 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoBomberGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoBomberGridDataWrapper.cs @@ -1,5 +1,5 @@ -using WoWsShipBuilder.DataContainers; -using WoWsShipBuilder.DataStructures; +using WoWsShipBuilder.DataStructures; +using WoWsShipBuilder.Features.DataContainers; namespace WoWsShipBuilder.Features.ShipComparison.GridData; diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoGridDataWrapper.cs index 2635b0554..f58d321a7 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoGridDataWrapper.cs @@ -1,5 +1,5 @@ -using WoWsShipBuilder.DataContainers; -using WoWsShipBuilder.DataStructures; +using WoWsShipBuilder.DataStructures; +using WoWsShipBuilder.Features.DataContainers; namespace WoWsShipBuilder.Features.ShipComparison.GridData; diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs b/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs index 5bed49e30..99c74bba4 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs @@ -3,9 +3,9 @@ using System.Globalization; using DynamicData; using ReactiveUI; -using WoWsShipBuilder.DataContainers; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; +using WoWsShipBuilder.Features.DataContainers; using WoWsShipBuilder.Features.Settings; using WoWsShipBuilder.Features.ShipComparison.GridData; using WoWsShipBuilder.Infrastructure.ApplicationData; diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor index 17a0c9f78..e37218322 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/CaptainSkillSelector.razor @@ -3,7 +3,6 @@ @using System.Collections.Specialized @using System.Reflection @using System.Reflection.Metadata.Ecma335 -@using WoWsShipBuilder.DataContainers @using WoWsShipBuilder.Features.ShipStats.ViewModels @using WoWsShipBuilder.DataStructures.Captain @using WoWsShipBuilder.Infrastructure.Localization.Resources diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/ConsumableSelector.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/ConsumableSelector.razor index fe33ce149..f147baa1f 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/ConsumableSelector.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/ConsumableSelector.razor @@ -1,11 +1,11 @@ @using WoWsShipBuilder.DataStructures -@using WoWsShipBuilder.DataContainers @using WoWsShipBuilder.DataElements @using WoWsShipBuilder.Features.ShipStats.ViewModels +@using WoWsShipBuilder.Features.DataContainers; @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Metrics @using WoWsShipBuilder.Infrastructure.Utility -@using ConsumableDataContainer = WoWsShipBuilder.DataContainers.ConsumableDataContainer + @inherits ReactiveComponentBase @inject ILocalizer Localizer @inject MetricsService MetricsService @@ -225,4 +225,4 @@ } } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/DepthChargeDamageDistributionChart.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/DepthChargeDamageDistributionChart.razor index 8e3dc7e34..4c028e652 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/DepthChargeDamageDistributionChart.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/DepthChargeDamageDistributionChart.razor @@ -1,5 +1,6 @@ @using WoWsShipBuilder.DataStructures -@using WoWsShipBuilder.DataContainers +@using WoWsShipBuilder.Features.DataContainers; + @implements IAsyncDisposable @inject IJSRuntime Runtime @@ -40,4 +41,4 @@ } } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor index 0557422f2..fa3d6cb15 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsPanel.razor @@ -4,7 +4,7 @@ @using System.Text @using WoWsShipBuilder.DataStructures.Ship.Components @using System.ComponentModel.DataAnnotations -@using WoWsShipBuilder.DataContainers +@using WoWsShipBuilder.Features.DataContainers @using WoWsShipBuilder.Features.FiringAngleDiagram @using WoWsShipBuilder.Features.Settings @using WoWsShipBuilder.Infrastructure @@ -13,7 +13,7 @@ @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Metrics @using WoWsShipBuilder.Infrastructure.Utility -@using DepthChargeDataContainer = WoWsShipBuilder.DataContainers.DepthChargeDataContainer + @inherits ReactiveComponentBase @inject ILocalizer Localizer @inject NavigationManager NavManager diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor index fbee02287..8a45d23b2 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipStatsTab.razor @@ -3,8 +3,8 @@ @using Microsoft.Extensions.Hosting @using Microsoft.Extensions.Options @using Prometheus -@using WoWsShipBuilder.DataContainers @using WoWsShipBuilder.Features.Builds.Components +@using WoWsShipBuilder.Features.DataContainers @using WoWsShipBuilder.Features.ShipStats.ViewModels @using WoWsShipBuilder.Features.Builds @using WoWsShipBuilder.Features.LinkShortening @@ -16,7 +16,6 @@ @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Metrics @using WoWsShipBuilder.Infrastructure.Utility -@using ShipViewModel = WoWsShipBuilder.Features.ShipStats.ViewModels.ShipViewModel @using System.Diagnostics @inject IHostEnvironment Environment diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipUpgradeSelector.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipUpgradeSelector.razor index 81a46e862..443e02655 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipUpgradeSelector.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/ShipUpgradeSelector.razor @@ -1,11 +1,12 @@ -@using WoWsShipBuilder.DataStructures -@using System.Collections.ObjectModel -@using WoWsShipBuilder.DataContainers +@using System.Collections.ObjectModel +@using WoWsShipBuilder.DataStructures +@using WoWsShipBuilder.Features.DataContainers @using WoWsShipBuilder.Features.ShipStats.ViewModels @using WoWsShipBuilder.DataStructures.Upgrade @using WoWsShipBuilder.Infrastructure.Localization @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Utility + @inherits ReactiveComponentBase @inject ILocalizer Localizer @@ -158,4 +159,4 @@ return "min-width: 60px; width: 60px; height: 60px; padding: 2px;"; } } -} \ No newline at end of file +} diff --git a/WoWsShipBuilder.Common/Features/ShipStats/Components/SignalSelector.razor b/WoWsShipBuilder.Common/Features/ShipStats/Components/SignalSelector.razor index e2939ef90..026f1a060 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/Components/SignalSelector.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/Components/SignalSelector.razor @@ -1,7 +1,8 @@ -@using WoWsShipBuilder.DataContainers +@using WoWsShipBuilder.Features.DataContainers @using WoWsShipBuilder.Features.ShipStats.ViewModels @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Utility + @inherits ReactiveComponentBase @inject ILocalizer Localizer diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor b/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor index ee9ec45d8..a8042b4e1 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor +++ b/WoWsShipBuilder.Common/Features/ShipStats/ShipStats.razor @@ -1,9 +1,9 @@ @page "/ship" @using DynamicData -@using WoWsShipBuilder.DataContainers -@using WoWsShipBuilder.Features.ShipStats.Components @using WoWsShipBuilder.Features.Builds +@using WoWsShipBuilder.Features.DataContainers +@using WoWsShipBuilder.Features.ShipStats.Components @using WoWsShipBuilder.Infrastructure.ApplicationData @using WoWsShipBuilder.Infrastructure.DataTransfer @using WoWsShipBuilder.Infrastructure.Localization.Resources diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableSlotViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableSlotViewModel.cs index 8b8cb2238..85570c0e6 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableSlotViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableSlotViewModel.cs @@ -3,7 +3,7 @@ using ReactiveUI; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; -using ConsumableDataContainer = WoWsShipBuilder.DataContainers.ConsumableDataContainer; +using WoWsShipBuilder.Features.DataContainers; namespace WoWsShipBuilder.Features.ShipStats.ViewModels; diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableViewModel.cs index 4a9ccd798..77f5c2b37 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableViewModel.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using ReactiveUI; -using WoWsShipBuilder.DataContainers; using WoWsShipBuilder.DataStructures; using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Infrastructure.Utility; @@ -75,7 +74,7 @@ public List SaveBuild() /// /// Updates the consumable data for each slot. - /// This method only replaces the ConsumableDataContainer objects in each slot viewmodel but not the viewmodels themselves. + /// This method only replaces the ConsumableDataContainer objects in each slot viewmodel but not the viewmodels themselves. /// /// The list of modifiers applied to the current ship. /// The HP of the ship after modifiers have been applied. diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipStatsControlViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipStatsControlViewModel.cs index 425acb98e..9d43db56c 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipStatsControlViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipStatsControlViewModel.cs @@ -1,6 +1,6 @@ using ReactiveUI; -using WoWsShipBuilder.DataContainers; using WoWsShipBuilder.DataStructures.Ship; +using WoWsShipBuilder.Features.DataContainers; namespace WoWsShipBuilder.Features.ShipStats.ViewModels; diff --git a/WoWsShipBuilder.Common/Infrastructure/DataTransfer/ShipBuildContainer.cs b/WoWsShipBuilder.Common/Infrastructure/DataTransfer/ShipBuildContainer.cs index 9493f7cfe..458c76ee0 100644 --- a/WoWsShipBuilder.Common/Infrastructure/DataTransfer/ShipBuildContainer.cs +++ b/WoWsShipBuilder.Common/Infrastructure/DataTransfer/ShipBuildContainer.cs @@ -1,6 +1,6 @@ -using WoWsShipBuilder.DataContainers; -using WoWsShipBuilder.DataStructures.Ship; +using WoWsShipBuilder.DataStructures.Ship; using WoWsShipBuilder.Features.Builds; +using WoWsShipBuilder.Features.DataContainers; namespace WoWsShipBuilder.Infrastructure.DataTransfer; diff --git a/WoWsShipBuilder.Common/WoWsShipBuilder.Common.csproj.DotSettings b/WoWsShipBuilder.Common/WoWsShipBuilder.Common.csproj.DotSettings index d017b1bcf..378573660 100644 --- a/WoWsShipBuilder.Common/WoWsShipBuilder.Common.csproj.DotSettings +++ b/WoWsShipBuilder.Common/WoWsShipBuilder.Common.csproj.DotSettings @@ -1,6 +1,6 @@  - True - True - True - True - \ No newline at end of file + True + True + True + True + diff --git a/WoWsShipBuilder.Web/Features/TestPage/TestPage.razor b/WoWsShipBuilder.Web/Features/TestPage/TestPage.razor index 6e527fb30..de3eadff1 100644 --- a/WoWsShipBuilder.Web/Features/TestPage/TestPage.razor +++ b/WoWsShipBuilder.Web/Features/TestPage/TestPage.razor @@ -10,7 +10,7 @@ @using WoWsShipBuilder.Infrastructure.Localization @using WoWsShipBuilder.Infrastructure.Localization.Resources @using WoWsShipBuilder.Infrastructure.Utility -@using MainBatteryDataContainer = WoWsShipBuilder.DataContainers.MainBatteryDataContainer +@using MainBatteryDataContainer = WoWsShipBuilder.Features.DataContainers.MainBatteryDataContainer @inject ISettingsAccessor SettingsAccessor @inject AppSettings AppSettings @inject ILocalizer Localizer From 0588c32b3624a758ca25ff6cde445c3b480da715 Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sat, 28 Oct 2023 23:08:55 +0200 Subject: [PATCH 14/26] apply "this" qualifier style to entire solution --- .editorconfig | 11 +- .../BuildTests/BuildStringCreation.cs | 4 +- .../ShipModuleTests/SortShipUpgrades.cs | 2 +- .../BallisticCharts/ChartJsInterop.cs | 42 +-- .../BallisticCharts/DispersionPlotHelper.cs | 24 +- .../Features/Builds/Build.cs | 30 +- .../Features/Builds/ShipBuildViewModel.cs | 28 +- .../LinkShortening/FirebaseLinkShortener.cs | 32 +- .../Features/Settings/AppSettings.cs | 82 ++--- .../GridData/AswGridDataWrapper.cs | 30 +- .../GridData/BomberGridDataWrapper.cs | 76 ++--- .../GridData/GridDataWrapper.cs | 64 ++-- .../ManeuverabilityGridDataWrapper.cs | 28 +- .../GridData/RocketPlaneGridDataWrapper.cs | 72 ++-- .../GridData/SecondaryGridDataWrapper.cs | 44 +-- .../GridData/TorpedoBomberGridDataWrapper.cs | 72 ++-- .../GridData/TorpedoGridDataWrapper.cs | 24 +- .../ShipComparison/ShipComparisonViewModel.cs | 312 +++++++++--------- .../Features/ShipStats/MouseEventInterop.cs | 14 +- .../CaptainSkillSelectorViewModel.cs | 202 ++++++------ .../ViewModels/ConsumableSlotViewModel.cs | 30 +- .../ViewModels/ConsumableViewModel.cs | 28 +- .../ViewModels/ShipModuleViewModel.cs | 28 +- .../ViewModels/ShipStatsControlViewModel.cs | 10 +- .../ShipStats/ViewModels/ShipViewModel.cs | 114 +++---- .../ViewModels/SignalSelectorViewModel.cs | 44 +-- .../SkillActivationItemViewModel.cs | 14 +- .../ViewModels/UpgradePanelViewModelBase.cs | 34 +- .../Features/ShipStats/VmCache.cs | 8 +- .../DataTransfer/SessionStateCache.cs | 8 +- .../DataTransfer/ShipBuildContainer.cs | 12 +- .../Localization/LocalizationProvider.cs | 6 +- .../Infrastructure/Localization/Localizer.cs | 8 +- .../Utility/CustomObservableCollection.cs | 16 +- .../Utility/RefreshNotifierService.cs | 2 +- .../DesktopDataServiceTest.cs | 22 +- .../CheckJsonFileVersions.cs | 36 +- .../LocalDataUpdaterTest.cs | 8 +- .../LocalDataUpdaterTests/ShouldUpdaterRun.cs | 10 +- .../LocalDataUpdaterTests/ValidateData.cs | 30 +- .../Common/AppHeader.axaml.cs | 44 +-- .../BlazorWebView/BlazorWindow.axaml.cs | 8 +- .../Features/MessageBox/MessageBox.axaml.cs | 2 +- .../SplashScreen/SplashScreen.axaml.cs | 8 +- .../SplashScreen/SplashScreenViewModel.cs | 18 +- .../Features/Updater/LocalDataUpdater.cs | 133 ++++---- .../Infrastructure/AppNotificationService.cs | 16 +- .../Infrastructure/AwsClient/AwsClient.cs | 20 +- .../Infrastructure/AwsClient/ClientBase.cs | 12 +- .../Data/DesktopAppDataService.cs | 36 +- .../Infrastructure/Data/DesktopDataService.cs | 32 +- .../Data/DesktopUserDataService.cs | 36 +- .../Infrastructure/DesktopSettingsAccessor.cs | 18 +- .../Infrastructure/LocalizeConverter.cs | 2 +- .../Infrastructure/WebView/BlazorWebView.cs | 96 +++--- .../WebView/CustomizedWebView.cs | 4 +- .../ServerAwsClientTest.cs | 12 +- .../Features/Authentication/AuthController.cs | 28 +- .../Authentication/AuthenticationService.cs | 14 +- .../Features/Host/Error.cshtml.cs | 4 +- .../Infrastructure/AppSettingsHelper.cs | 14 +- .../Infrastructure/Data/DataInitializer.cs | 8 +- .../Data/ServerAppDataService.cs | 28 +- .../Infrastructure/Data/WebUserDataService.cs | 54 +-- .../Metrics/ReferrerTrackingMiddleware.cs | 4 +- .../Infrastructure/ServerAwsClient.cs | 16 +- .../Infrastructure/WebClipboardService.cs | 4 +- 67 files changed, 1158 insertions(+), 1174 deletions(-) diff --git a/.editorconfig b/.editorconfig index c707c9c26..f0b3c4d69 100644 --- a/.editorconfig +++ b/.editorconfig @@ -51,10 +51,10 @@ dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggesti dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:suggestion dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion dotnet_style_predefined_type_for_member_access = true:suggestion -dotnet_style_qualification_for_event = true:suggestion -dotnet_style_qualification_for_field = true:suggestion -dotnet_style_qualification_for_method = true:suggestion -dotnet_style_qualification_for_property = true:suggestion +dotnet_style_qualification_for_event = true:warning +dotnet_style_qualification_for_field = true:warning +dotnet_style_qualification_for_method = true:warning +dotnet_style_qualification_for_property = true:warning dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion # ReSharper properties @@ -84,7 +84,6 @@ resharper_use_indent_from_vs = false # ReSharper inspection severities resharper_arrange_redundant_parentheses_highlighting = hint -resharper_arrange_this_qualifier_highlighting = hint resharper_arrange_type_member_modifiers_highlighting = hint resharper_arrange_type_modifiers_highlighting = hint resharper_async_void_lambda_highlighting = suggestion @@ -113,7 +112,7 @@ dotnet_diagnostic.sa0001.severity = none # Ignore disabled xml documentation dotnet_diagnostic.sa1000.severity = none # Ignore missing space after "new" dotnet_diagnostic.sa1009.severity = none # Ignore missing space after closing parenthesis dotnet_diagnostic.sa1100.severity = none # Ignore base. prefix if there is no local override -dotnet_diagnostic.sa1101.severity = suggestion # Ignore missing this prefix for local calls +dotnet_diagnostic.sa1101.severity = warning # Ignore missing this prefix for local calls dotnet_diagnostic.sa1122.severity = none # Don't force the use of string.Empty dotnet_diagnostic.sa1124.severity = none # Allow the use of regions dotnet_diagnostic.sa1127.severity = none # Generic constraints may share a line with other declarations diff --git a/WoWsShipBuilder.Common.Test/BuildTests/BuildStringCreation.cs b/WoWsShipBuilder.Common.Test/BuildTests/BuildStringCreation.cs index bee573c0d..36cde8cc1 100644 --- a/WoWsShipBuilder.Common.Test/BuildTests/BuildStringCreation.cs +++ b/WoWsShipBuilder.Common.Test/BuildTests/BuildStringCreation.cs @@ -31,7 +31,7 @@ public void EmptyBuild_CreateShortStringWithBuildName_MatchesRegex() var build = new Build(buildName, shipIndex, Nation.Usa, new(), new(), new(), "PCW001", new(), new()); string buildString = build.CreateShortStringFromBuild(); - var result = buildRegex.Match(buildString); + var result = this.buildRegex.Match(buildString); result.Success.Should().BeTrue(); result.Length.Should().Be(buildString.Length); @@ -48,7 +48,7 @@ public void EmptyBuild_CreateShortStringWithoutBuildName_MatchesRegex() var build = new Build(string.Empty, shipIndex, Nation.Usa, new(), new(), new(), "PCW001", new(), new()); string buildString = build.CreateShortStringFromBuild(); - var result = buildRegex.Match(buildString); + var result = this.buildRegex.Match(buildString); result.Success.Should().BeTrue(); result.Length.Should().Be(buildString.Length); diff --git a/WoWsShipBuilder.Common.Test/Infrastructure/GameData/ShipModuleTests/SortShipUpgrades.cs b/WoWsShipBuilder.Common.Test/Infrastructure/GameData/ShipModuleTests/SortShipUpgrades.cs index 9217961a6..add53e0d4 100644 --- a/WoWsShipBuilder.Common.Test/Infrastructure/GameData/ShipModuleTests/SortShipUpgrades.cs +++ b/WoWsShipBuilder.Common.Test/Infrastructure/GameData/ShipModuleTests/SortShipUpgrades.cs @@ -11,7 +11,7 @@ public class SortShipUpgrades [Test] public void SortShipUpgrades_SimpleUnsortedList() { - var data = CreateUpgradeList(); + var data = this.CreateUpgradeList(); var sortedData = ShipModuleHelper.GroupAndSortUpgrades(data); diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/ChartJsInterop.cs b/WoWsShipBuilder.Common/Features/BallisticCharts/ChartJsInterop.cs index 403fdd215..839998cbf 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/ChartJsInterop.cs +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/ChartJsInterop.cs @@ -17,20 +17,20 @@ public ChartJsInterop(IJSRuntime runtime) public async Task SetupGlobalChartConfigAsync(double aspectRatio) { - await InitializeModule(); - await module.InvokeVoidAsync("SetupGlobalChartConfig", aspectRatio); + await this.InitializeModule(); + await this.module.InvokeVoidAsync("SetupGlobalChartConfig", aspectRatio); } public async Task CreateChartAsync(string chartId, string title, string xLabel, string yLabel, string xUnit, string yUnit) { - await InitializeModule(); - await module.InvokeVoidAsync("CreateChart", chartId, title, xLabel, yLabel, xUnit, yUnit); + await this.InitializeModule(); + await this.module.InvokeVoidAsync("CreateChart", chartId, title, xLabel, yLabel, xUnit, yUnit); } public async Task ChangeSuggestedMaxAsync(string chartId, double newSuggestedMax) { - await InitializeModule(); - await module.InvokeVoidAsync("ChangeSuggestedMax", chartId, newSuggestedMax); + await this.InitializeModule(); + await this.module.InvokeVoidAsync("ChangeSuggestedMax", chartId, newSuggestedMax); } public async Task BatchAddDataAsync(List chartIds, List newChartData) @@ -40,26 +40,26 @@ public async Task BatchAddDataAsync(List chartIds, List chartId, List id) { - await InitializeModule(); - await module.InvokeVoidAsync("BatchRemoveData", chartId, id); + await this.InitializeModule(); + await this.module.InvokeVoidAsync("BatchRemoveData", chartId, id); } public async Task BatchUpdateDataAsync(string chartId, List updatedChartData) { - await InitializeModule(); - await module.InvokeVoidAsync("BatchUpdateData", chartId, updatedChartData); + await this.InitializeModule(); + await this.module.InvokeVoidAsync("BatchUpdateData", chartId, updatedChartData); } public async Task BatchUpdateDataNewLabelsAsync(string chartId, List updatedChartData) { - await InitializeModule(); - await module.InvokeVoidAsync("BatchUpdateDataNewLabels", chartId, updatedChartData); + await this.InitializeModule(); + await this.module.InvokeVoidAsync("BatchUpdateDataNewLabels", chartId, updatedChartData); } public async Task MultipleBatchUpdateDataNewLabels(List chartIds, List multipleUpdatedChartDataList) @@ -69,8 +69,8 @@ public async Task MultipleBatchUpdateDataNewLabels(List chartIds, List chartIds, List multipleUpdatedChartDataList) @@ -80,8 +80,8 @@ public async Task MultipleBatchAddOrUpdateDataNewLabels(List chartIds, L throw new InvalidOperationException("The number of chartId is not equal to the number of dataset of each MultipleUpdatedChartDataList"); } - await InitializeModule(); - await module.InvokeVoidAsync("MultipleBatchAddOrUpdateDataNewLabels", chartIds, multipleUpdatedChartDataList); + await this.InitializeModule(); + await this.module.InvokeVoidAsync("MultipleBatchAddOrUpdateDataNewLabels", chartIds, multipleUpdatedChartDataList); } [MemberNotNull(nameof(module))] @@ -89,17 +89,17 @@ private async Task InitializeModule() { // module is not null after this method but apparently, Roslyn does not want to recognize that. #pragma warning disable CS8774 - module ??= await runtime.InvokeAsync("import", "/_content/WoWsShipBuilder.Common/scripts/ChartsHelper.js"); + this.module ??= await this.runtime.InvokeAsync("import", "/_content/WoWsShipBuilder.Common/scripts/ChartsHelper.js"); #pragma warning restore CS8774 } async ValueTask IAsyncDisposable.DisposeAsync() { - if (module is not null) + if (this.module is not null) { try { - await module.DisposeAsync(); + await this.module.DisposeAsync(); } catch (JSDisconnectedException) { diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/DispersionPlotHelper.cs b/WoWsShipBuilder.Common/Features/BallisticCharts/DispersionPlotHelper.cs index 7cd24aa2f..a5314140b 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/DispersionPlotHelper.cs +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/DispersionPlotHelper.cs @@ -145,18 +145,18 @@ public DispersionEllipse(string name, Dispersion dispersionData, ArtilleryShell double projectedOnPerpendicularToWaterVerticalRadiusHalfHitPoints) : this(name, dispersionData, shell, sigma, maxRange, modifier) { - HorizontalRadius = horizontalRadius; - VerticalRadius = verticalRadius; - ProjectedOnWaterVerticalRadius = projectedOnWaterVerticalRadius; - ProjectedOnPerpendicularToWaterVerticalRadius = projectedOnPerpendicularToWaterVerticalRadius; - RealHitPoints = realHitPoints; - OnWaterHitPoints = onWaterHitPoints; - PerpendicularToWaterHitPoints = onPerpendicularToWaterHitPoints; - HorizontalRadiusHalfHitPoints = horizontalRadiusHalfHitPoints; - VerticalRadiusHalfHitPoints = verticalRadiusHalfHitPoints; - ProjectedOnWaterVerticalRadiusHalfHitPoints = projectedOnWaterVerticalRadiusHalfHitPoints; - ProjectedOnPerpendicularToWaterVerticalRadiusHalfHitPoints = projectedOnPerpendicularToWaterVerticalRadiusHalfHitPoints; - IsValid = true; + this.HorizontalRadius = horizontalRadius; + this.VerticalRadius = verticalRadius; + this.ProjectedOnWaterVerticalRadius = projectedOnWaterVerticalRadius; + this.ProjectedOnPerpendicularToWaterVerticalRadius = projectedOnPerpendicularToWaterVerticalRadius; + this.RealHitPoints = realHitPoints; + this.OnWaterHitPoints = onWaterHitPoints; + this.PerpendicularToWaterHitPoints = onPerpendicularToWaterHitPoints; + this.HorizontalRadiusHalfHitPoints = horizontalRadiusHalfHitPoints; + this.VerticalRadiusHalfHitPoints = verticalRadiusHalfHitPoints; + this.ProjectedOnWaterVerticalRadiusHalfHitPoints = projectedOnWaterVerticalRadiusHalfHitPoints; + this.ProjectedOnPerpendicularToWaterVerticalRadiusHalfHitPoints = projectedOnPerpendicularToWaterVerticalRadiusHalfHitPoints; + this.IsValid = true; } public bool IsValid { get; } diff --git a/WoWsShipBuilder.Common/Features/Builds/Build.cs b/WoWsShipBuilder.Common/Features/Builds/Build.cs index 1db936dae..8219f439a 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Build.cs +++ b/WoWsShipBuilder.Common/Features/Builds/Build.cs @@ -20,18 +20,18 @@ public class Build [JsonConstructor] private Build(string buildName, string shipIndex, Nation nation, List modules, List upgrades, List consumables, string captain, List skills, List signals, int buildVersion = CurrentBuildVersion) { - BuildName = buildName; - ShipIndex = shipIndex; - Nation = nation; - Modules = modules; - Upgrades = upgrades; - Captain = captain; - Skills = skills; - Signals = signals; - Consumables = consumables; - BuildVersion = buildVersion; - - Hash = CreateHash(this); + this.BuildName = buildName; + this.ShipIndex = shipIndex; + this.Nation = nation; + this.Modules = modules; + this.Upgrades = upgrades; + this.Captain = captain; + this.Skills = skills; + this.Signals = signals; + this.Consumables = consumables; + this.BuildVersion = buildVersion; + + this.Hash = CreateHash(this); } public Build(string buildName, string shipIndex, Nation nation, List modules, List upgrades, List consumables, string captain, List skills, List signals) @@ -176,7 +176,7 @@ private static string CreateHash(Build build) public override int GetHashCode() { var hashCode = default(HashCode); - hashCode.Add(Hash); + hashCode.Add(this.Hash); return hashCode.ToHashCode(); } @@ -184,7 +184,7 @@ public override bool Equals(object? obj) { if (obj is Build build) { - return Hash == build.Hash; + return this.Hash == build.Hash; } return false; @@ -209,7 +209,7 @@ public string CreateStringFromBuild() public string CreateShortStringFromBuild() { - string buildString = $"{ShipIndex};{string.Join(ListSeparator, ReduceToIndex(Modules))};{string.Join(ListSeparator, ReduceToIndex(Upgrades))};{Captain};{string.Join(ListSeparator, Skills)};{string.Join(ListSeparator, ReduceToIndex(Consumables))};{string.Join(ListSeparator, ReduceToIndex(Signals))};{BuildVersion};{BuildName}"; + string buildString = $"{this.ShipIndex};{string.Join(ListSeparator, ReduceToIndex(this.Modules))};{string.Join(ListSeparator, ReduceToIndex(this.Upgrades))};{this.Captain};{string.Join(ListSeparator, this.Skills)};{string.Join(ListSeparator, ReduceToIndex(this.Consumables))};{string.Join(ListSeparator, ReduceToIndex(this.Signals))};{this.BuildVersion};{this.BuildName}"; return buildString; } diff --git a/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs b/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs index 3c0a6fe3e..7e5abee9d 100644 --- a/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs +++ b/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs @@ -23,7 +23,7 @@ public partial class ShipBuildViewModel : ReactiveObject private ShipBuildViewModel(Ship ship) { - CurrentShip = ship; + this.CurrentShip = ship; } public ShipModuleViewModel ShipModuleViewModel { get; private init; } = default!; @@ -67,12 +67,10 @@ public static ShipBuildViewModel Create(ShipBuildContainer shipBuildContainer) private Build? DumpToBuild() { - bool isCustomBuild = !string.IsNullOrWhiteSpace(BuildName) || ShipModuleViewModel.SelectedModules.Any(m => !string.IsNullOrEmpty(m.Prev)) || - UpgradePanelViewModel.SelectedModernizationList.Any() || ConsumableViewModel.ActivatedSlots.Any() || - CaptainSkillSelectorViewModel.SkillOrderList.Any() || SignalSelectorViewModel.SelectedSignals.Any(); + bool isCustomBuild = !string.IsNullOrWhiteSpace(this.BuildName) || this.ShipModuleViewModel.SelectedModules.Any(m => !string.IsNullOrEmpty(m.Prev)) || this.UpgradePanelViewModel.SelectedModernizationList.Any() || this.ConsumableViewModel.ActivatedSlots.Any() || this.CaptainSkillSelectorViewModel.SkillOrderList.Any() || this.SignalSelectorViewModel.SelectedSignals.Any(); if (isCustomBuild) { - return new(BuildName.Trim(), CurrentShip.Index, CurrentShip.ShipNation, ShipModuleViewModel.SaveBuild(), UpgradePanelViewModel.SaveBuild(), ConsumableViewModel.SaveBuild(), CaptainSkillSelectorViewModel.GetCaptainIndex(), CaptainSkillSelectorViewModel.GetSkillNumberList(), SignalSelectorViewModel.GetFlagList()); + return new(this.BuildName.Trim(), this.CurrentShip.Index, this.CurrentShip.ShipNation, this.ShipModuleViewModel.SaveBuild(), this.UpgradePanelViewModel.SaveBuild(), this.ConsumableViewModel.SaveBuild(), this.CaptainSkillSelectorViewModel.GetCaptainIndex(), this.CaptainSkillSelectorViewModel.GetSkillNumberList(), this.SignalSelectorViewModel.GetFlagList()); } return null; @@ -80,32 +78,32 @@ public static ShipBuildViewModel Create(ShipBuildContainer shipBuildContainer) public ShipBuildContainer CreateShipBuildContainerAsync(ShipBuildContainer baseContainer) { - var build = DumpToBuild(); - List? activatedConsumables = ConsumableViewModel.ActivatedSlots.Any() ? ConsumableViewModel.ActivatedSlots.ToList() : null; - List<(string, float)> modifiers = GenerateModifierList(); + var build = this.DumpToBuild(); + List? activatedConsumables = this.ConsumableViewModel.ActivatedSlots.Any() ? this.ConsumableViewModel.ActivatedSlots.ToList() : null; + List<(string, float)> modifiers = this.GenerateModifierList(); return baseContainer with { Build = build, ActivatedConsumableSlots = activatedConsumables, - SpecialAbilityActive = SpecialAbilityActive, - ShipDataContainer = CreateDataContainerAsync(modifiers), + SpecialAbilityActive = this.SpecialAbilityActive, + ShipDataContainer = this.CreateDataContainerAsync(modifiers), Modifiers = modifiers, }; } private ShipDataContainer CreateDataContainerAsync(List<(string, float)> modifiers) { - return ShipDataContainer.CreateFromShip(CurrentShip, ShipModuleViewModel.SelectedModules.ToList(), modifiers); + return ShipDataContainer.CreateFromShip(this.CurrentShip, this.ShipModuleViewModel.SelectedModules.ToList(), modifiers); } private List<(string, float)> GenerateModifierList() { var modifiers = new List<(string, float)>(); - modifiers.AddRange(UpgradePanelViewModel.GetModifierList()); - modifiers.AddRange(SignalSelectorViewModel.GetModifierList()); - modifiers.AddRange(CaptainSkillSelectorViewModel.GetModifiersList()); - modifiers.AddRange(ConsumableViewModel.GetModifiersList()); + modifiers.AddRange(this.UpgradePanelViewModel.GetModifierList()); + modifiers.AddRange(this.SignalSelectorViewModel.GetModifierList()); + modifiers.AddRange(this.CaptainSkillSelectorViewModel.GetModifiersList()); + modifiers.AddRange(this.ConsumableViewModel.GetModifiersList()); return modifiers; } } diff --git a/WoWsShipBuilder.Common/Features/LinkShortening/FirebaseLinkShortener.cs b/WoWsShipBuilder.Common/Features/LinkShortening/FirebaseLinkShortener.cs index 8a2bffabe..d8ebdf278 100644 --- a/WoWsShipBuilder.Common/Features/LinkShortening/FirebaseLinkShortener.cs +++ b/WoWsShipBuilder.Common/Features/LinkShortening/FirebaseLinkShortener.cs @@ -29,47 +29,47 @@ public FirebaseLinkShortener(HttpClient httpClient, IOptions CreateLinkForBuild(Build build) { - logger.LogInformation("Creating short link for build {BuildHash}", build.Hash); + this.logger.LogInformation("Creating short link for build {BuildHash}", build.Hash); string buildString = build.CreateShortStringFromBuild(); string encodedBuild = WebUtility.UrlEncode(buildString); var path = $"/ship?shipIndexes={build.ShipIndex}&build={encodedBuild}"; - var request = new DynamicLinkRequest(new(options.UriPrefix, options.LinkBaseUrl + path), new(LinkSuffixType.SHORT)); - return await SendRequestAsync(request); + var request = new DynamicLinkRequest(new(this.options.UriPrefix, this.options.LinkBaseUrl + path), new(LinkSuffixType.SHORT)); + return await this.SendRequestAsync(request); } public async Task CreateShortLink(string link) { - logger.LogInformation("Creating short link for link {Link}", link); - var request = new DynamicLinkRequest(new(options.UriPrefix, link), new(LinkSuffixType.SHORT)); - return await SendRequestAsync(request); + this.logger.LogInformation("Creating short link for link {Link}", link); + var request = new DynamicLinkRequest(new(this.options.UriPrefix, link), new(LinkSuffixType.SHORT)); + return await this.SendRequestAsync(request); } private async Task SendRequestAsync(DynamicLinkRequest linkRequest) { - if (!await semaphore.WaitAsync(options.RequestTimeout)) + if (!await this.semaphore.WaitAsync(this.options.RequestTimeout)) { - logger.LogWarning("Timeout while waiting for dynamic link api access"); + this.logger.LogWarning("Timeout while waiting for dynamic link api access"); return new(false, linkRequest.DynamicLinkInfo.Link); } - var response = await httpClient.PostAsJsonAsync(options.ApiUrl + options.ApiKey, linkRequest, serializerOptions); + var response = await this.httpClient.PostAsJsonAsync(this.options.ApiUrl + this.options.ApiKey, linkRequest, this.serializerOptions); #pragma warning disable CS4014 - Task.Run(async () => await ResetLock()); + Task.Run(async () => await this.ResetLock()); #pragma warning restore CS4014 var result = await response.Content.ReadFromJsonAsync() ?? throw new InvalidOperationException(); return new(true, result.ShortLink); @@ -77,9 +77,9 @@ private async Task SendRequestAsync(DynamicLinkRequest linkReq private async Task ResetLock() { - logger.LogDebug("Scheduling reset for semaphore permit. Available permits: {PermitCount}", semaphore.CurrentCount); + this.logger.LogDebug("Scheduling reset for semaphore permit. Available permits: {PermitCount}", this.semaphore.CurrentCount); await Task.Delay(1000); - semaphore.Release(); - logger.LogDebug("Permit released. Available permits: {PermitCount}", semaphore.CurrentCount); + this.semaphore.Release(); + this.logger.LogDebug("Permit released. Available permits: {PermitCount}", this.semaphore.CurrentCount); } } diff --git a/WoWsShipBuilder.Common/Features/Settings/AppSettings.cs b/WoWsShipBuilder.Common/Features/Settings/AppSettings.cs index 1de6b8a3a..c7864b14e 100644 --- a/WoWsShipBuilder.Common/Features/Settings/AppSettings.cs +++ b/WoWsShipBuilder.Common/Features/Settings/AppSettings.cs @@ -10,7 +10,7 @@ public class AppSettings [JsonConstructor] public AppSettings(CultureDetails? selectedLanguage = null) { - SelectedLanguage = selectedLanguage ?? AppConstants.DefaultCultureDetails; + this.SelectedLanguage = selectedLanguage ?? AppConstants.DefaultCultureDetails; } public bool AutoUpdateEnabled { get; set; } = true; @@ -57,49 +57,49 @@ public AppSettings(CultureDetails? selectedLanguage = null) public void ClearSettings() { - AutoUpdateEnabled = true; - SelectedLanguage = AppConstants.DefaultCultureDetails; - SelectedServerType = ServerType.Live; - LastDataUpdateCheck = default; - CustomDataPath = default; - SendTelemetryData = default; - OpenExplorerAfterImageSave = default; - LastImageImportPath = default; - IncludeSignalsForImageExport = default; - CustomImagePath = default; - DispersionPlotSettings = new(); - OpenAllMainExpandersByDefault = true; - OpenAllAmmoExpandersByDefault = false; - OpenSecondariesAndAaExpandersByDefault = false; - BetaAccessCodes = new(); - BuildImageLayoutSettings = new[] { true, false, true, true, true, true }; - ShipComparisonFiringRange = 10; - ShipComparisonUseUpgradedModules = true; - ShipComparisonHideShipsWithoutSection = false; - ShipComparisonHiddenColumns = default; + this.AutoUpdateEnabled = true; + this.SelectedLanguage = AppConstants.DefaultCultureDetails; + this.SelectedServerType = ServerType.Live; + this.LastDataUpdateCheck = default; + this.CustomDataPath = default; + this.SendTelemetryData = default; + this.OpenExplorerAfterImageSave = default; + this.LastImageImportPath = default; + this.IncludeSignalsForImageExport = default; + this.CustomImagePath = default; + this.DispersionPlotSettings = new(); + this.OpenAllMainExpandersByDefault = true; + this.OpenAllAmmoExpandersByDefault = false; + this.OpenSecondariesAndAaExpandersByDefault = false; + this.BetaAccessCodes = new(); + this.BuildImageLayoutSettings = new[] { true, false, true, true, true, true }; + this.ShipComparisonFiringRange = 10; + this.ShipComparisonUseUpgradedModules = true; + this.ShipComparisonHideShipsWithoutSection = false; + this.ShipComparisonHiddenColumns = default; } public void UpdateFromSettings(AppSettings settings) { - AutoUpdateEnabled = settings.AutoUpdateEnabled; - SelectedLanguage = settings.SelectedLanguage; - SelectedServerType = settings.SelectedServerType; - LastDataUpdateCheck = settings.LastDataUpdateCheck; - CustomDataPath = settings.CustomDataPath; - SendTelemetryData = settings.SendTelemetryData; - OpenExplorerAfterImageSave = settings.OpenExplorerAfterImageSave; - LastImageImportPath = settings.LastImageImportPath; - IncludeSignalsForImageExport = settings.IncludeSignalsForImageExport; - CustomImagePath = settings.CustomImagePath; - DispersionPlotSettings = settings.DispersionPlotSettings; - OpenAllMainExpandersByDefault = settings.OpenAllMainExpandersByDefault; - OpenAllAmmoExpandersByDefault = settings.OpenAllAmmoExpandersByDefault; - OpenSecondariesAndAaExpandersByDefault = settings.OpenSecondariesAndAaExpandersByDefault; - BetaAccessCodes = settings.BetaAccessCodes; - BuildImageLayoutSettings = settings.BuildImageLayoutSettings; - ShipComparisonFiringRange = settings.ShipComparisonFiringRange; - ShipComparisonUseUpgradedModules = settings.ShipComparisonUseUpgradedModules; - ShipComparisonHideShipsWithoutSection = settings.ShipComparisonHideShipsWithoutSection; - ShipComparisonHiddenColumns = settings.ShipComparisonHiddenColumns; + this.AutoUpdateEnabled = settings.AutoUpdateEnabled; + this.SelectedLanguage = settings.SelectedLanguage; + this.SelectedServerType = settings.SelectedServerType; + this.LastDataUpdateCheck = settings.LastDataUpdateCheck; + this.CustomDataPath = settings.CustomDataPath; + this.SendTelemetryData = settings.SendTelemetryData; + this.OpenExplorerAfterImageSave = settings.OpenExplorerAfterImageSave; + this.LastImageImportPath = settings.LastImageImportPath; + this.IncludeSignalsForImageExport = settings.IncludeSignalsForImageExport; + this.CustomImagePath = settings.CustomImagePath; + this.DispersionPlotSettings = settings.DispersionPlotSettings; + this.OpenAllMainExpandersByDefault = settings.OpenAllMainExpandersByDefault; + this.OpenAllAmmoExpandersByDefault = settings.OpenAllAmmoExpandersByDefault; + this.OpenSecondariesAndAaExpandersByDefault = settings.OpenSecondariesAndAaExpandersByDefault; + this.BetaAccessCodes = settings.BetaAccessCodes; + this.BuildImageLayoutSettings = settings.BuildImageLayoutSettings; + this.ShipComparisonFiringRange = settings.ShipComparisonFiringRange; + this.ShipComparisonUseUpgradedModules = settings.ShipComparisonUseUpgradedModules; + this.ShipComparisonHideShipsWithoutSection = settings.ShipComparisonHideShipsWithoutSection; + this.ShipComparisonHiddenColumns = settings.ShipComparisonHiddenColumns; } } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/AswGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/AswGridDataWrapper.cs index ffdf97a8f..bfd379269 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/AswGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/AswGridDataWrapper.cs @@ -9,27 +9,27 @@ public AswGridDataWrapper(AirstrikeDataContainer? aswAirStrike, DepthChargesLaun { var depthCharge = depthChargeLauncher?.DepthCharge ?? aswAirStrike?.Weapon as DepthChargeDataContainer; - DcType = aswAirStrike switch + this.DcType = aswAirStrike switch { not null => nameof(Translation.ShipStats_AswAirstrike), null when depthChargeLauncher is not null => nameof(Translation.DepthCharge), _ => null, }; - Range = aswAirStrike?.MaximumDistance; - MaxDropLength = aswAirStrike?.MaximumFlightDistance; - DcReload = depthChargeLauncher?.Reload ?? aswAirStrike?.ReloadTime; - DcUses = depthChargeLauncher?.NumberOfUses ?? aswAirStrike?.NumberOfUses; - PlanesInSquadron = aswAirStrike?.NumberDuringAttack; - BombsPerPlane = aswAirStrike?.BombsPerPlane; - DcPerAttack = depthChargeLauncher?.BombsPerCharge; - DcDamage = depthCharge?.Damage; - DcFireChance = depthCharge?.FireChance; - DcFloodingChance = depthCharge?.FloodingChance; - DcSplashRadius = depthCharge?.DcSplashRadius; - DcSinkSpeed = depthCharge?.SinkSpeed; - DcDetonationTimer = depthCharge?.DetonationTimer; - DcDetonationDepth = depthCharge?.DetonationDepth; + this.Range = aswAirStrike?.MaximumDistance; + this.MaxDropLength = aswAirStrike?.MaximumFlightDistance; + this.DcReload = depthChargeLauncher?.Reload ?? aswAirStrike?.ReloadTime; + this.DcUses = depthChargeLauncher?.NumberOfUses ?? aswAirStrike?.NumberOfUses; + this.PlanesInSquadron = aswAirStrike?.NumberDuringAttack; + this.BombsPerPlane = aswAirStrike?.BombsPerPlane; + this.DcPerAttack = depthChargeLauncher?.BombsPerCharge; + this.DcDamage = depthCharge?.Damage; + this.DcFireChance = depthCharge?.FireChance; + this.DcFloodingChance = depthCharge?.FloodingChance; + this.DcSplashRadius = depthCharge?.DcSplashRadius; + this.DcSinkSpeed = depthCharge?.SinkSpeed; + this.DcDetonationTimer = depthCharge?.DetonationTimer; + this.DcDetonationDepth = depthCharge?.DetonationDepth; } public string? DcType { get; } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/BomberGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/BomberGridDataWrapper.cs index 3edef43b1..e7826eff0 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/BomberGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/BomberGridDataWrapper.cs @@ -7,47 +7,47 @@ public class BomberGridDataWrapper : PlaneGridDataWrapper { public BomberGridDataWrapper(IReadOnlyCollection? bombers) { - Type = bombers?.Select(x => x.PlaneVariant).ToList() ?? new(); - InSquadron = bombers?.Select(x => x.NumberInSquad).ToList() ?? new(); - PerAttack = bombers?.Select(x => x.NumberDuringAttack).ToList() ?? new(); - OnDeck = bombers?.Select(x => x.MaxNumberOnDeck).ToList() ?? new(); - RestorationTime = bombers?.Select(x => x.RestorationTime).ToList() ?? new(); - CruisingSpeed = bombers?.Select(x => x.CruisingSpeed).ToList() ?? new(); - MaxSpeed = bombers?.Select(x => x.MaxSpeed).ToList() ?? new(); - MinSpeed = bombers?.Select(x => x.MinSpeed).ToList() ?? new(); - EngineBoostDuration = bombers?.Select(x => x.MaxEngineBoostDuration).ToList() ?? new(); - InitialBoostDuration = bombers?.Select(x => x.JatoDuration).ToList() ?? new(); - InitialBoostValue = bombers?.Select(x => x.JatoSpeedMultiplier).ToList() ?? new(); - PlaneHp = bombers?.Select(x => x.PlaneHp).ToList() ?? new(); - SquadronHp = bombers?.Select(x => x.SquadronHp).ToList() ?? new(); - AttackGroupHp = bombers?.Select(x => x.AttackGroupHp).ToList() ?? new(); - DamageDuringAttack = bombers?.Select(x => x.DamageTakenDuringAttack).ToList() ?? new(); - WeaponsPerPlane = bombers?.Select(x => x.AmmoPerAttack).ToList() ?? new(); - PreparationTime = bombers?.Select(x => x.PreparationTime).ToList() ?? new(); - AimingTime = bombers?.Select(x => x.AimingTime).ToList() ?? new(); - TimeToFullyAimed = bombers?.Select(x => x.TimeToFullyAimed).ToList() ?? new(); - PostAttackInvulnerability = bombers?.Select(x => x.PostAttackInvulnerabilityDuration).ToList() ?? new(); - AttackCooldown = bombers?.Select(x => x.AttackCd).ToList() ?? new(); - Concealment = bombers?.Select(x => x.ConcealmentFromShips).ToList() ?? new(); - Spotting = bombers?.Select(x => x.MaxViewDistance).ToList() ?? new(); - AreaChangeAiming = bombers?.Select(x => x.AimingRateMoving).ToList() ?? new(); - AreaChangePreparation = bombers?.Select(x => x.AimingPreparationRateMoving).ToList() ?? new(); - InnerEllipse = bombers?.Select(x => x.InnerBombPercentage).ToList() ?? new(); + this.Type = bombers?.Select(x => x.PlaneVariant).ToList() ?? new(); + this.InSquadron = bombers?.Select(x => x.NumberInSquad).ToList() ?? new(); + this.PerAttack = bombers?.Select(x => x.NumberDuringAttack).ToList() ?? new(); + this.OnDeck = bombers?.Select(x => x.MaxNumberOnDeck).ToList() ?? new(); + this.RestorationTime = bombers?.Select(x => x.RestorationTime).ToList() ?? new(); + this.CruisingSpeed = bombers?.Select(x => x.CruisingSpeed).ToList() ?? new(); + this.MaxSpeed = bombers?.Select(x => x.MaxSpeed).ToList() ?? new(); + this.MinSpeed = bombers?.Select(x => x.MinSpeed).ToList() ?? new(); + this.EngineBoostDuration = bombers?.Select(x => x.MaxEngineBoostDuration).ToList() ?? new(); + this.InitialBoostDuration = bombers?.Select(x => x.JatoDuration).ToList() ?? new(); + this.InitialBoostValue = bombers?.Select(x => x.JatoSpeedMultiplier).ToList() ?? new(); + this.PlaneHp = bombers?.Select(x => x.PlaneHp).ToList() ?? new(); + this.SquadronHp = bombers?.Select(x => x.SquadronHp).ToList() ?? new(); + this.AttackGroupHp = bombers?.Select(x => x.AttackGroupHp).ToList() ?? new(); + this.DamageDuringAttack = bombers?.Select(x => x.DamageTakenDuringAttack).ToList() ?? new(); + this.WeaponsPerPlane = bombers?.Select(x => x.AmmoPerAttack).ToList() ?? new(); + this.PreparationTime = bombers?.Select(x => x.PreparationTime).ToList() ?? new(); + this.AimingTime = bombers?.Select(x => x.AimingTime).ToList() ?? new(); + this.TimeToFullyAimed = bombers?.Select(x => x.TimeToFullyAimed).ToList() ?? new(); + this.PostAttackInvulnerability = bombers?.Select(x => x.PostAttackInvulnerabilityDuration).ToList() ?? new(); + this.AttackCooldown = bombers?.Select(x => x.AttackCd).ToList() ?? new(); + this.Concealment = bombers?.Select(x => x.ConcealmentFromShips).ToList() ?? new(); + this.Spotting = bombers?.Select(x => x.MaxViewDistance).ToList() ?? new(); + this.AreaChangeAiming = bombers?.Select(x => x.AimingRateMoving).ToList() ?? new(); + this.AreaChangePreparation = bombers?.Select(x => x.AimingPreparationRateMoving).ToList() ?? new(); + this.InnerEllipse = bombers?.Select(x => x.InnerBombPercentage).ToList() ?? new(); List? bombs = bombers?.Select(x => x.Weapon as BombDataContainer).ToList(); - WeaponType = bombers?.Select(x => x.WeaponType).ToList() ?? new(); - WeaponBombType = bombs?.Select(x => x?.BombType ?? default!).ToList() ?? new(); - WeaponDamage = bombs?.Select(x => x?.Damage ?? 0).ToList() ?? new(); - WeaponSplashRadius = bombs?.Select(x => x?.SplashRadius ?? 0).ToList() ?? new(); - WeaponSplashDamage = bombs?.Select(x => x?.SplashDmg ?? 0).ToList() ?? new(); - WeaponPenetration = bombs?.Select(x => (x?.BombType == $"ArmamentType_{BombType.AP}" ? x.PenetrationAp : x?.Penetration) ?? 0).ToList() ?? new(); - WeaponFireChance = bombs?.Select(x => x?.FireChance ?? 0).ToList() ?? new(); - WeaponBlastRadius = bombs?.Select(x => x?.ExplosionRadius ?? 0).ToList() ?? new(); - WeaponBlastPenetration = bombs?.Select(x => x?.SplashCoeff ?? 0).ToList() ?? new(); - WeaponFuseTimer = bombs?.Select(x => x?.FuseTimer ?? 0).ToList() ?? new(); - WeaponArmingThreshold = bombs?.Select(x => x?.ArmingThreshold ?? 0).ToList() ?? new(); - WeaponRicochetAngles = bombs?.Select(x => x?.RicochetAngles ?? default!).ToList() ?? new(); + this.WeaponType = bombers?.Select(x => x.WeaponType).ToList() ?? new(); + this.WeaponBombType = bombs?.Select(x => x?.BombType ?? default!).ToList() ?? new(); + this.WeaponDamage = bombs?.Select(x => x?.Damage ?? 0).ToList() ?? new(); + this.WeaponSplashRadius = bombs?.Select(x => x?.SplashRadius ?? 0).ToList() ?? new(); + this.WeaponSplashDamage = bombs?.Select(x => x?.SplashDmg ?? 0).ToList() ?? new(); + this.WeaponPenetration = bombs?.Select(x => (x?.BombType == $"ArmamentType_{BombType.AP}" ? x.PenetrationAp : x?.Penetration) ?? 0).ToList() ?? new(); + this.WeaponFireChance = bombs?.Select(x => x?.FireChance ?? 0).ToList() ?? new(); + this.WeaponBlastRadius = bombs?.Select(x => x?.ExplosionRadius ?? 0).ToList() ?? new(); + this.WeaponBlastPenetration = bombs?.Select(x => x?.SplashCoeff ?? 0).ToList() ?? new(); + this.WeaponFuseTimer = bombs?.Select(x => x?.FuseTimer ?? 0).ToList() ?? new(); + this.WeaponArmingThreshold = bombs?.Select(x => x?.ArmingThreshold ?? 0).ToList() ?? new(); + this.WeaponRicochetAngles = bombs?.Select(x => x?.RicochetAngles ?? default!).ToList() ?? new(); } public List InnerEllipse { get; } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs index 373ae3ec8..89a0669d6 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs @@ -15,43 +15,43 @@ public sealed class GridDataWrapper { public GridDataWrapper(ShipBuildContainer shipBuildContainer) { - ShipBuildContainer = shipBuildContainer; + this.ShipBuildContainer = shipBuildContainer; - Ship = shipBuildContainer.Ship; - ShipDataContainer = shipBuildContainer.ShipDataContainer ?? throw new InvalidDataException("ShipDataContainer is null. ShipDataContainer must not be null."); - Build = shipBuildContainer.Build; - Id = shipBuildContainer.Id; + this.Ship = shipBuildContainer.Ship; + this.ShipDataContainer = shipBuildContainer.ShipDataContainer ?? throw new InvalidDataException("ShipDataContainer is null. ShipDataContainer must not be null."); + this.Build = shipBuildContainer.Build; + this.Id = shipBuildContainer.Id; - ShipIndex = shipBuildContainer.Ship.Index; - ShipNation = shipBuildContainer.Ship.ShipNation; - ShipClass = shipBuildContainer.Ship.ShipClass; - ShipCategory = shipBuildContainer.Ship.ShipCategory; - ShipTier = shipBuildContainer.Ship.Tier; - BuildName = shipBuildContainer.Build?.BuildName; + this.ShipIndex = shipBuildContainer.Ship.Index; + this.ShipNation = shipBuildContainer.Ship.ShipNation; + this.ShipClass = shipBuildContainer.Ship.ShipClass; + this.ShipCategory = shipBuildContainer.Ship.ShipCategory; + this.ShipTier = shipBuildContainer.Ship.Tier; + this.BuildName = shipBuildContainer.Build?.BuildName; - MainBattery = ShipBuildContainer.ShipDataContainer?.MainBatteryDataContainer; - HeShell = MainBattery?.ShellData.FirstOrDefault(x => x.Type.Equals($"ArmamentType_{ShellType.HE.ShellTypeToString()}")); - ApShell = MainBattery?.ShellData.FirstOrDefault(x => x.Type.Equals($"ArmamentType_{ShellType.AP.ShellTypeToString()}")); - SapShell = MainBattery?.ShellData.FirstOrDefault(x => x.Type.Equals($"ArmamentType_{ShellType.SAP.ShellTypeToString()}")); + this.MainBattery = this.ShipBuildContainer.ShipDataContainer?.MainBatteryDataContainer; + this.HeShell = this.MainBattery?.ShellData.FirstOrDefault(x => x.Type.Equals($"ArmamentType_{ShellType.HE.ShellTypeToString()}")); + this.ApShell = this.MainBattery?.ShellData.FirstOrDefault(x => x.Type.Equals($"ArmamentType_{ShellType.AP.ShellTypeToString()}")); + this.SapShell = this.MainBattery?.ShellData.FirstOrDefault(x => x.Type.Equals($"ArmamentType_{ShellType.SAP.ShellTypeToString()}")); var torpedoArmament = shipBuildContainer.ShipDataContainer.TorpedoArmamentDataContainer; - TorpedoLauncher = torpedoArmament; - Torpedo = new(torpedoArmament); - Secondary = new(shipBuildContainer.ShipDataContainer.SecondaryBatteryUiDataContainer.Secondaries); - AntiAirArmament = shipBuildContainer.ShipDataContainer.AntiAirDataContainer; - Asw = new(shipBuildContainer.ShipDataContainer.AswAirstrikeDataContainer, shipBuildContainer.ShipDataContainer.DepthChargeLauncherDataContainer); - - AirStrike = shipBuildContainer.ShipDataContainer.AirstrikeDataContainer; - AirStrikeWeapon = AirStrike?.Weapon as BombDataContainer; - - ManeuverabilityData = new(shipBuildContainer.ShipDataContainer.ManeuverabilityDataContainer); - Concealment = shipBuildContainer.ShipDataContainer.ConcealmentDataContainer; - Survivability = shipBuildContainer.ShipDataContainer.SurvivabilityDataContainer; - Sonar = shipBuildContainer.ShipDataContainer.PingerGunDataContainer; - - RocketPlanes = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Rocket.ProjectileTypeToString())).ToList()); - TorpedoBombers = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Torpedo.ProjectileTypeToString())).ToList()); - Bombers = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Bomb.ProjectileTypeToString()) || x.WeaponType.Equals(ProjectileType.SkipBomb.ProjectileTypeToString())).ToList()); + this.TorpedoLauncher = torpedoArmament; + this.Torpedo = new(torpedoArmament); + this.Secondary = new(shipBuildContainer.ShipDataContainer.SecondaryBatteryUiDataContainer.Secondaries); + this.AntiAirArmament = shipBuildContainer.ShipDataContainer.AntiAirDataContainer; + this.Asw = new(shipBuildContainer.ShipDataContainer.AswAirstrikeDataContainer, shipBuildContainer.ShipDataContainer.DepthChargeLauncherDataContainer); + + this.AirStrike = shipBuildContainer.ShipDataContainer.AirstrikeDataContainer; + this.AirStrikeWeapon = this.AirStrike?.Weapon as BombDataContainer; + + this.ManeuverabilityData = new(shipBuildContainer.ShipDataContainer.ManeuverabilityDataContainer); + this.Concealment = shipBuildContainer.ShipDataContainer.ConcealmentDataContainer; + this.Survivability = shipBuildContainer.ShipDataContainer.SurvivabilityDataContainer; + this.Sonar = shipBuildContainer.ShipDataContainer.PingerGunDataContainer; + + this.RocketPlanes = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Rocket.ProjectileTypeToString())).ToList()); + this.TorpedoBombers = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Torpedo.ProjectileTypeToString())).ToList()); + this.Bombers = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Bomb.ProjectileTypeToString()) || x.WeaponType.Equals(ProjectileType.SkipBomb.ProjectileTypeToString())).ToList()); } public ShipBuildContainer ShipBuildContainer { get; } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/ManeuverabilityGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/ManeuverabilityGridDataWrapper.cs index b5c844db8..8b49a0122 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/ManeuverabilityGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/ManeuverabilityGridDataWrapper.cs @@ -6,20 +6,20 @@ public class ManeuverabilityGridDataWrapper { public ManeuverabilityGridDataWrapper(ManeuverabilityDataContainer maneuverability) { - MaxSpeed = maneuverability.ManeuverabilityMaxSpeed != 0 ? maneuverability.ManeuverabilityMaxSpeed : maneuverability.ManeuverabilitySubsMaxSpeedOnSurface; - MaxSpeedAtPeriscopeDepth = maneuverability.ManeuverabilitySubsMaxSpeedAtPeriscope; - MaxSpeedAtMaxDepth = maneuverability.ManeuverabilitySubsMaxSpeedAtMaxDepth; - MaxReverseSpeed = maneuverability.ManeuverabilityMaxReverseSpeed != 0 ? maneuverability.ManeuverabilityMaxReverseSpeed : maneuverability.ManeuverabilitySubsMaxReverseSpeedOnSurface; - MaxReverseSpeedAtPeriscopeDepth = maneuverability.ManeuverabilitySubsMaxReverseSpeedAtPeriscope; - MaxReverseSpeedAtMaxDepth = maneuverability.ManeuverabilitySubsMaxReverseSpeedAtMaxDepth; - MaxDiveSpeed = maneuverability.ManeuverabilitySubsMaxDiveSpeed; - DivingPlaneShiftTime = maneuverability.ManeuverabilitySubsDivingPlaneShiftTime; - RudderShiftTime = maneuverability.ManeuverabilityRudderShiftTime; - TurningCircle = maneuverability.ManeuverabilityTurningCircle; - TimeToFullAhead = maneuverability.ForwardMaxSpeedTime; - TimeToFullReverse = maneuverability.ReverseMaxSpeedTime; - RudderProtection = maneuverability.RudderBlastProtection; - EngineProtection = maneuverability.EngineBlastProtection; + this.MaxSpeed = maneuverability.ManeuverabilityMaxSpeed != 0 ? maneuverability.ManeuverabilityMaxSpeed : maneuverability.ManeuverabilitySubsMaxSpeedOnSurface; + this.MaxSpeedAtPeriscopeDepth = maneuverability.ManeuverabilitySubsMaxSpeedAtPeriscope; + this.MaxSpeedAtMaxDepth = maneuverability.ManeuverabilitySubsMaxSpeedAtMaxDepth; + this.MaxReverseSpeed = maneuverability.ManeuverabilityMaxReverseSpeed != 0 ? maneuverability.ManeuverabilityMaxReverseSpeed : maneuverability.ManeuverabilitySubsMaxReverseSpeedOnSurface; + this.MaxReverseSpeedAtPeriscopeDepth = maneuverability.ManeuverabilitySubsMaxReverseSpeedAtPeriscope; + this.MaxReverseSpeedAtMaxDepth = maneuverability.ManeuverabilitySubsMaxReverseSpeedAtMaxDepth; + this.MaxDiveSpeed = maneuverability.ManeuverabilitySubsMaxDiveSpeed; + this.DivingPlaneShiftTime = maneuverability.ManeuverabilitySubsDivingPlaneShiftTime; + this.RudderShiftTime = maneuverability.ManeuverabilityRudderShiftTime; + this.TurningCircle = maneuverability.ManeuverabilityTurningCircle; + this.TimeToFullAhead = maneuverability.ForwardMaxSpeedTime; + this.TimeToFullReverse = maneuverability.ReverseMaxSpeedTime; + this.RudderProtection = maneuverability.RudderBlastProtection; + this.EngineProtection = maneuverability.EngineBlastProtection; } public decimal MaxSpeed { get; } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/RocketPlaneGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/RocketPlaneGridDataWrapper.cs index 8a516851e..1cee115b5 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/RocketPlaneGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/RocketPlaneGridDataWrapper.cs @@ -7,46 +7,46 @@ public class RocketPlaneGridDataWrapper : PlaneGridDataWrapper { public RocketPlaneGridDataWrapper(IReadOnlyCollection? rocketPlanes) { - Type = rocketPlanes?.Select(x => x.PlaneVariant).ToList() ?? new(); - InSquadron = rocketPlanes?.Select(x => x.NumberInSquad).ToList() ?? new(); - PerAttack = rocketPlanes?.Select(x => x.NumberDuringAttack).ToList() ?? new(); - OnDeck = rocketPlanes?.Select(x => x.MaxNumberOnDeck).ToList() ?? new(); - RestorationTime = rocketPlanes?.Select(x => x.RestorationTime).ToList() ?? new(); - CruisingSpeed = rocketPlanes?.Select(x => x.CruisingSpeed).ToList() ?? new(); - MaxSpeed = rocketPlanes?.Select(x => x.MaxSpeed).ToList() ?? new(); - MinSpeed = rocketPlanes?.Select(x => x.MinSpeed).ToList() ?? new(); - EngineBoostDuration = rocketPlanes?.Select(x => x.MaxEngineBoostDuration).ToList() ?? new(); - InitialBoostDuration = rocketPlanes?.Select(x => x.JatoDuration).ToList() ?? new(); - InitialBoostValue = rocketPlanes?.Select(x => x.JatoSpeedMultiplier).ToList() ?? new(); - PlaneHp = rocketPlanes?.Select(x => x.PlaneHp).ToList() ?? new(); - SquadronHp = rocketPlanes?.Select(x => x.SquadronHp).ToList() ?? new(); - AttackGroupHp = rocketPlanes?.Select(x => x.AttackGroupHp).ToList() ?? new(); - DamageDuringAttack = rocketPlanes?.Select(x => x.DamageTakenDuringAttack).ToList() ?? new(); - WeaponsPerPlane = rocketPlanes?.Select(x => x.AmmoPerAttack).ToList() ?? new(); - PreparationTime = rocketPlanes?.Select(x => x.PreparationTime).ToList() ?? new(); - AimingTime = rocketPlanes?.Select(x => x.AimingTime).ToList() ?? new(); - TimeToFullyAimed = rocketPlanes?.Select(x => x.TimeToFullyAimed).ToList() ?? new(); - PostAttackInvulnerability = rocketPlanes?.Select(x => x.PostAttackInvulnerabilityDuration).ToList() ?? new(); - AttackCooldown = rocketPlanes?.Select(x => x.AttackCd).ToList() ?? new(); - Concealment = rocketPlanes?.Select(x => x.ConcealmentFromShips).ToList() ?? new(); - Spotting = rocketPlanes?.Select(x => x.MaxViewDistance).ToList() ?? new(); - AreaChangeAiming = rocketPlanes?.Select(x => x.AimingRateMoving).ToList() ?? new(); - AreaChangePreparation = rocketPlanes?.Select(x => x.AimingPreparationRateMoving).ToList() ?? new(); + this.Type = rocketPlanes?.Select(x => x.PlaneVariant).ToList() ?? new(); + this.InSquadron = rocketPlanes?.Select(x => x.NumberInSquad).ToList() ?? new(); + this.PerAttack = rocketPlanes?.Select(x => x.NumberDuringAttack).ToList() ?? new(); + this.OnDeck = rocketPlanes?.Select(x => x.MaxNumberOnDeck).ToList() ?? new(); + this.RestorationTime = rocketPlanes?.Select(x => x.RestorationTime).ToList() ?? new(); + this.CruisingSpeed = rocketPlanes?.Select(x => x.CruisingSpeed).ToList() ?? new(); + this.MaxSpeed = rocketPlanes?.Select(x => x.MaxSpeed).ToList() ?? new(); + this.MinSpeed = rocketPlanes?.Select(x => x.MinSpeed).ToList() ?? new(); + this.EngineBoostDuration = rocketPlanes?.Select(x => x.MaxEngineBoostDuration).ToList() ?? new(); + this.InitialBoostDuration = rocketPlanes?.Select(x => x.JatoDuration).ToList() ?? new(); + this.InitialBoostValue = rocketPlanes?.Select(x => x.JatoSpeedMultiplier).ToList() ?? new(); + this.PlaneHp = rocketPlanes?.Select(x => x.PlaneHp).ToList() ?? new(); + this.SquadronHp = rocketPlanes?.Select(x => x.SquadronHp).ToList() ?? new(); + this.AttackGroupHp = rocketPlanes?.Select(x => x.AttackGroupHp).ToList() ?? new(); + this.DamageDuringAttack = rocketPlanes?.Select(x => x.DamageTakenDuringAttack).ToList() ?? new(); + this.WeaponsPerPlane = rocketPlanes?.Select(x => x.AmmoPerAttack).ToList() ?? new(); + this.PreparationTime = rocketPlanes?.Select(x => x.PreparationTime).ToList() ?? new(); + this.AimingTime = rocketPlanes?.Select(x => x.AimingTime).ToList() ?? new(); + this.TimeToFullyAimed = rocketPlanes?.Select(x => x.TimeToFullyAimed).ToList() ?? new(); + this.PostAttackInvulnerability = rocketPlanes?.Select(x => x.PostAttackInvulnerabilityDuration).ToList() ?? new(); + this.AttackCooldown = rocketPlanes?.Select(x => x.AttackCd).ToList() ?? new(); + this.Concealment = rocketPlanes?.Select(x => x.ConcealmentFromShips).ToList() ?? new(); + this.Spotting = rocketPlanes?.Select(x => x.MaxViewDistance).ToList() ?? new(); + this.AreaChangeAiming = rocketPlanes?.Select(x => x.AimingRateMoving).ToList() ?? new(); + this.AreaChangePreparation = rocketPlanes?.Select(x => x.AimingPreparationRateMoving).ToList() ?? new(); // Rockets List? rockets = rocketPlanes?.Select(x => x.Weapon as RocketDataContainer).ToList(); - WeaponType = rockets?.Select(x => x?.RocketType ?? default!).ToList() ?? new(); - WeaponDamage = rockets?.Select(x => x?.Damage ?? 0).ToList() ?? new(); - WeaponSplashRadius = rockets?.Select(x => x?.SplashRadius ?? 0).ToList() ?? new(); - WeaponSplashDamage = rockets?.Select(x => x?.SplashDmg ?? 0).ToList() ?? new(); - WeaponPenetration = rockets?.Select(x => (x?.RocketType == $"ArmamentType_{RocketType.AP}" ? x.PenetrationAp : x?.Penetration) ?? 0).ToList() ?? new(); - WeaponFireChance = rockets?.Select(x => x?.FireChance ?? 0).ToList() ?? new(); - WeaponFuseTimer = rockets?.Select(x => x?.FuseTimer ?? 0).ToList() ?? new(); - WeaponArmingThreshold = rockets?.Select(x => x?.ArmingThreshold ?? 0).ToList() ?? new(); - WeaponRicochetAngles = rockets?.Select(x => x?.RicochetAngles ?? default!).ToList() ?? new(); - WeaponBlastRadius = rockets?.Select(x => x?.ExplosionRadius ?? 0).ToList() ?? new(); - WeaponBlastPenetration = rockets?.Select(x => x?.SplashCoeff ?? 0).ToList() ?? new(); + this.WeaponType = rockets?.Select(x => x?.RocketType ?? default!).ToList() ?? new(); + this.WeaponDamage = rockets?.Select(x => x?.Damage ?? 0).ToList() ?? new(); + this.WeaponSplashRadius = rockets?.Select(x => x?.SplashRadius ?? 0).ToList() ?? new(); + this.WeaponSplashDamage = rockets?.Select(x => x?.SplashDmg ?? 0).ToList() ?? new(); + this.WeaponPenetration = rockets?.Select(x => (x?.RocketType == $"ArmamentType_{RocketType.AP}" ? x.PenetrationAp : x?.Penetration) ?? 0).ToList() ?? new(); + this.WeaponFireChance = rockets?.Select(x => x?.FireChance ?? 0).ToList() ?? new(); + this.WeaponFuseTimer = rockets?.Select(x => x?.FuseTimer ?? 0).ToList() ?? new(); + this.WeaponArmingThreshold = rockets?.Select(x => x?.ArmingThreshold ?? 0).ToList() ?? new(); + this.WeaponRicochetAngles = rockets?.Select(x => x?.RicochetAngles ?? default!).ToList() ?? new(); + this.WeaponBlastRadius = rockets?.Select(x => x?.ExplosionRadius ?? 0).ToList() ?? new(); + this.WeaponBlastPenetration = rockets?.Select(x => x?.SplashCoeff ?? 0).ToList() ?? new(); } public List WeaponType { get; } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/SecondaryGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/SecondaryGridDataWrapper.cs index 4d759cd5f..50e7065d6 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/SecondaryGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/SecondaryGridDataWrapper.cs @@ -7,32 +7,32 @@ public class SecondaryGridDataWrapper public SecondaryGridDataWrapper(IReadOnlyCollection? secondaryBattery) { // Secondaries - Caliber = secondaryBattery?.Select(x => x.GunCaliber).ToList() ?? new(); - BarrelCount = secondaryBattery?.Select(x => x.BarrelsCount).ToList() ?? new(); - BarrelsLayout = secondaryBattery?.Select(x => x.BarrelsLayout).ToList() ?? new(); - Range = secondaryBattery?.Select(x => x.Range).First(); - Reload = secondaryBattery?.Select(x => x.Reload).ToList() ?? new(); - RoF = secondaryBattery?.Select(x => x.RoF).ToList() ?? new(); - Dpm = secondaryBattery?.Select(x => x.TheoreticalDpm).ToList() ?? new(); - Fpm = secondaryBattery?.Select(x => x.PotentialFpm).ToList() ?? new(); - Sigma = secondaryBattery?.Select(x => x.Sigma).First(); + this.Caliber = secondaryBattery?.Select(x => x.GunCaliber).ToList() ?? new(); + this.BarrelCount = secondaryBattery?.Select(x => x.BarrelsCount).ToList() ?? new(); + this.BarrelsLayout = secondaryBattery?.Select(x => x.BarrelsLayout).ToList() ?? new(); + this.Range = secondaryBattery?.Select(x => x.Range).First(); + this.Reload = secondaryBattery?.Select(x => x.Reload).ToList() ?? new(); + this.RoF = secondaryBattery?.Select(x => x.RoF).ToList() ?? new(); + this.Dpm = secondaryBattery?.Select(x => x.TheoreticalDpm).ToList() ?? new(); + this.Fpm = secondaryBattery?.Select(x => x.PotentialFpm).ToList() ?? new(); + this.Sigma = secondaryBattery?.Select(x => x.Sigma).First(); // Secondary shells List? secondaryShellData = secondaryBattery?.Select(x => x.Shell).ToList(); - Type = secondaryShellData?.Select(x => x?.Type).First(); - Mass = secondaryShellData?.Select(x => x?.Mass ?? 0).ToList() ?? new(); - Damage = secondaryShellData?.Select(x => x?.Damage ?? 0).ToList() ?? new(); - SplashRadius = secondaryShellData?.Select(x => x?.SplashRadius ?? 0).ToList() ?? new(); - SplashDamage = secondaryShellData?.Select(x => x?.SplashDmg ?? 0).ToList() ?? new(); - Penetration = secondaryShellData?.Select(x => x?.Penetration ?? 0).ToList() ?? new(); - Speed = secondaryShellData?.Select(x => x?.ShellVelocity ?? 0).ToList() ?? new(); - AirDrag = secondaryShellData?.Select(x => x?.AirDrag ?? 0).ToList() ?? new(); - HeShellFireChance = secondaryShellData?.Select(x => x?.ShellFireChance ?? 0).ToList() ?? new(); - HeBlastRadius = secondaryShellData?.Select(x => x?.ExplosionRadius ?? 0).ToList() ?? new(); - HeBlastPenetration = secondaryShellData?.Select(x => x?.SplashCoeff ?? 0).ToList() ?? new(); - SapOvermatch = secondaryShellData?.Select(x => x?.Overmatch ?? 0).ToList() ?? new(); - SapRicochet = secondaryShellData?.Select(x => x?.RicochetAngles ?? default!).ToList() ?? new(); + this.Type = secondaryShellData?.Select(x => x?.Type).First(); + this.Mass = secondaryShellData?.Select(x => x?.Mass ?? 0).ToList() ?? new(); + this.Damage = secondaryShellData?.Select(x => x?.Damage ?? 0).ToList() ?? new(); + this.SplashRadius = secondaryShellData?.Select(x => x?.SplashRadius ?? 0).ToList() ?? new(); + this.SplashDamage = secondaryShellData?.Select(x => x?.SplashDmg ?? 0).ToList() ?? new(); + this.Penetration = secondaryShellData?.Select(x => x?.Penetration ?? 0).ToList() ?? new(); + this.Speed = secondaryShellData?.Select(x => x?.ShellVelocity ?? 0).ToList() ?? new(); + this.AirDrag = secondaryShellData?.Select(x => x?.AirDrag ?? 0).ToList() ?? new(); + this.HeShellFireChance = secondaryShellData?.Select(x => x?.ShellFireChance ?? 0).ToList() ?? new(); + this.HeBlastRadius = secondaryShellData?.Select(x => x?.ExplosionRadius ?? 0).ToList() ?? new(); + this.HeBlastPenetration = secondaryShellData?.Select(x => x?.SplashCoeff ?? 0).ToList() ?? new(); + this.SapOvermatch = secondaryShellData?.Select(x => x?.Overmatch ?? 0).ToList() ?? new(); + this.SapRicochet = secondaryShellData?.Select(x => x?.RicochetAngles ?? default!).ToList() ?? new(); } public List Caliber { get; } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoBomberGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoBomberGridDataWrapper.cs index 36256f437..bd7b15956 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoBomberGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoBomberGridDataWrapper.cs @@ -7,45 +7,45 @@ public class TorpedoBomberGridDataWrapper : PlaneGridDataWrapper { public TorpedoBomberGridDataWrapper(IReadOnlyCollection? torpedoBombers) { - Type = torpedoBombers?.Select(x => x.PlaneVariant).ToList() ?? new(); - InSquadron = torpedoBombers?.Select(x => x.NumberInSquad).ToList() ?? new(); - PerAttack = torpedoBombers?.Select(x => x.NumberDuringAttack).ToList() ?? new(); - OnDeck = torpedoBombers?.Select(x => x.MaxNumberOnDeck).ToList() ?? new(); - RestorationTime = torpedoBombers?.Select(x => x.RestorationTime).ToList() ?? new(); - CruisingSpeed = torpedoBombers?.Select(x => x.CruisingSpeed).ToList() ?? new(); - MaxSpeed = torpedoBombers?.Select(x => x.MaxSpeed).ToList() ?? new(); - MinSpeed = torpedoBombers?.Select(x => x.MinSpeed).ToList() ?? new(); - EngineBoostDuration = torpedoBombers?.Select(x => x.MaxEngineBoostDuration).ToList() ?? new(); - InitialBoostDuration = torpedoBombers?.Select(x => x.JatoDuration).ToList() ?? new(); - InitialBoostValue = torpedoBombers?.Select(x => x.JatoSpeedMultiplier).ToList() ?? new(); - PlaneHp = torpedoBombers?.Select(x => x.PlaneHp).ToList() ?? new(); - SquadronHp = torpedoBombers?.Select(x => x.SquadronHp).ToList() ?? new(); - AttackGroupHp = torpedoBombers?.Select(x => x.AttackGroupHp).ToList() ?? new(); - DamageDuringAttack = torpedoBombers?.Select(x => x.DamageTakenDuringAttack).ToList() ?? new(); - WeaponsPerPlane = torpedoBombers?.Select(x => x.AmmoPerAttack).ToList() ?? new(); - PreparationTime = torpedoBombers?.Select(x => x.PreparationTime).ToList() ?? new(); - AimingTime = torpedoBombers?.Select(x => x.AimingTime).ToList() ?? new(); - TimeToFullyAimed = torpedoBombers?.Select(x => x.TimeToFullyAimed).ToList() ?? new(); - PostAttackInvulnerability = torpedoBombers?.Select(x => x.PostAttackInvulnerabilityDuration).ToList() ?? new(); - AttackCooldown = torpedoBombers?.Select(x => x.AttackCd).ToList() ?? new(); - Concealment = torpedoBombers?.Select(x => x.ConcealmentFromShips).ToList() ?? new(); - Spotting = torpedoBombers?.Select(x => x.MaxViewDistance).ToList() ?? new(); - AreaChangeAiming = torpedoBombers?.Select(x => x.AimingRateMoving).ToList() ?? new(); - AreaChangePreparation = torpedoBombers?.Select(x => x.AimingPreparationRateMoving).ToList() ?? new(); + this.Type = torpedoBombers?.Select(x => x.PlaneVariant).ToList() ?? new(); + this.InSquadron = torpedoBombers?.Select(x => x.NumberInSquad).ToList() ?? new(); + this.PerAttack = torpedoBombers?.Select(x => x.NumberDuringAttack).ToList() ?? new(); + this.OnDeck = torpedoBombers?.Select(x => x.MaxNumberOnDeck).ToList() ?? new(); + this.RestorationTime = torpedoBombers?.Select(x => x.RestorationTime).ToList() ?? new(); + this.CruisingSpeed = torpedoBombers?.Select(x => x.CruisingSpeed).ToList() ?? new(); + this.MaxSpeed = torpedoBombers?.Select(x => x.MaxSpeed).ToList() ?? new(); + this.MinSpeed = torpedoBombers?.Select(x => x.MinSpeed).ToList() ?? new(); + this.EngineBoostDuration = torpedoBombers?.Select(x => x.MaxEngineBoostDuration).ToList() ?? new(); + this.InitialBoostDuration = torpedoBombers?.Select(x => x.JatoDuration).ToList() ?? new(); + this.InitialBoostValue = torpedoBombers?.Select(x => x.JatoSpeedMultiplier).ToList() ?? new(); + this.PlaneHp = torpedoBombers?.Select(x => x.PlaneHp).ToList() ?? new(); + this.SquadronHp = torpedoBombers?.Select(x => x.SquadronHp).ToList() ?? new(); + this.AttackGroupHp = torpedoBombers?.Select(x => x.AttackGroupHp).ToList() ?? new(); + this.DamageDuringAttack = torpedoBombers?.Select(x => x.DamageTakenDuringAttack).ToList() ?? new(); + this.WeaponsPerPlane = torpedoBombers?.Select(x => x.AmmoPerAttack).ToList() ?? new(); + this.PreparationTime = torpedoBombers?.Select(x => x.PreparationTime).ToList() ?? new(); + this.AimingTime = torpedoBombers?.Select(x => x.AimingTime).ToList() ?? new(); + this.TimeToFullyAimed = torpedoBombers?.Select(x => x.TimeToFullyAimed).ToList() ?? new(); + this.PostAttackInvulnerability = torpedoBombers?.Select(x => x.PostAttackInvulnerabilityDuration).ToList() ?? new(); + this.AttackCooldown = torpedoBombers?.Select(x => x.AttackCd).ToList() ?? new(); + this.Concealment = torpedoBombers?.Select(x => x.ConcealmentFromShips).ToList() ?? new(); + this.Spotting = torpedoBombers?.Select(x => x.MaxViewDistance).ToList() ?? new(); + this.AreaChangeAiming = torpedoBombers?.Select(x => x.AimingRateMoving).ToList() ?? new(); + this.AreaChangePreparation = torpedoBombers?.Select(x => x.AimingPreparationRateMoving).ToList() ?? new(); List? aerialTorpedoes = torpedoBombers?.Select(x => x.Weapon as TorpedoDataContainer).ToList(); - WeaponType = aerialTorpedoes?.Select(x => x?.TorpedoType ?? default!).ToList() ?? new(); - WeaponDamage = aerialTorpedoes?.Select(x => x?.Damage ?? 0).ToList() ?? new(); - WeaponRange = aerialTorpedoes?.Select(x => x?.Range ?? 0).ToList() ?? new(); - WeaponSpeed = aerialTorpedoes?.Select(x => x?.Speed ?? 0).ToList() ?? new(); - WeaponDetectabilityRange = aerialTorpedoes?.Select(x => x?.Detectability ?? 0).ToList() ?? new(); - WeaponArmingDistance = aerialTorpedoes?.Select(x => x?.ArmingDistance ?? 0).ToList() ?? new(); - WeaponReactionTime = aerialTorpedoes?.Select(x => x?.ReactionTime ?? 0).ToList() ?? new(); - WeaponFloodingChance = aerialTorpedoes?.Select(x => x?.FloodingChance ?? 0).ToList() ?? new(); - WeaponBlastRadius = aerialTorpedoes?.Select(x => x?.ExplosionRadius ?? 0).ToList() ?? new(); - WeaponBlastPenetration = aerialTorpedoes?.Select(x => x?.SplashCoeff ?? 0).ToList() ?? new(); - WeaponCanHit = aerialTorpedoes?.Select(x => x?.CanHitClasses).ToList() ?? new(); + this.WeaponType = aerialTorpedoes?.Select(x => x?.TorpedoType ?? default!).ToList() ?? new(); + this.WeaponDamage = aerialTorpedoes?.Select(x => x?.Damage ?? 0).ToList() ?? new(); + this.WeaponRange = aerialTorpedoes?.Select(x => x?.Range ?? 0).ToList() ?? new(); + this.WeaponSpeed = aerialTorpedoes?.Select(x => x?.Speed ?? 0).ToList() ?? new(); + this.WeaponDetectabilityRange = aerialTorpedoes?.Select(x => x?.Detectability ?? 0).ToList() ?? new(); + this.WeaponArmingDistance = aerialTorpedoes?.Select(x => x?.ArmingDistance ?? 0).ToList() ?? new(); + this.WeaponReactionTime = aerialTorpedoes?.Select(x => x?.ReactionTime ?? 0).ToList() ?? new(); + this.WeaponFloodingChance = aerialTorpedoes?.Select(x => x?.FloodingChance ?? 0).ToList() ?? new(); + this.WeaponBlastRadius = aerialTorpedoes?.Select(x => x?.ExplosionRadius ?? 0).ToList() ?? new(); + this.WeaponBlastPenetration = aerialTorpedoes?.Select(x => x?.SplashCoeff ?? 0).ToList() ?? new(); + this.WeaponCanHit = aerialTorpedoes?.Select(x => x?.CanHitClasses).ToList() ?? new(); } public List WeaponType { get; } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoGridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoGridDataWrapper.cs index f58d321a7..b31e9df08 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoGridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/TorpedoGridDataWrapper.cs @@ -9,18 +9,18 @@ public TorpedoGridDataWrapper(TorpedoArmamentDataContainer? torpedoArmament) { List? torpedoes = torpedoArmament?.Torpedoes; - FullSalvoDamage = new() { torpedoArmament?.FullSalvoDamage, torpedoArmament?.TorpFullSalvoDmg, torpedoArmament?.AltTorpFullSalvoDmg }; - Type = torpedoes?.Select(x => x.TorpedoType).ToList() ?? new(); - Damage = torpedoes?.Select(x => x.Damage).ToList() ?? new(); - Range = torpedoes?.Select(x => x.Range).ToList() ?? new(); - Speed = torpedoes?.Select(x => x.Speed).ToList() ?? new(); - DetectRange = torpedoes?.Select(x => x.Detectability).ToList() ?? new(); - ArmingDistance = torpedoes?.Select(x => x.ArmingDistance).ToList() ?? new(); - ReactionTime = torpedoes?.Select(x => x.ReactionTime).ToList() ?? new(); - FloodingChance = torpedoes?.Select(x => x.FloodingChance).ToList() ?? new(); - BlastRadius = torpedoes?.Select(x => x.ExplosionRadius).ToList() ?? new(); - BlastPenetration = torpedoes?.Select(x => x.SplashCoeff).ToList() ?? new(); - CanHit = torpedoes?.Select(x => x.CanHitClasses).ToList() ?? new(); + this.FullSalvoDamage = new() { torpedoArmament?.FullSalvoDamage, torpedoArmament?.TorpFullSalvoDmg, torpedoArmament?.AltTorpFullSalvoDmg }; + this.Type = torpedoes?.Select(x => x.TorpedoType).ToList() ?? new(); + this.Damage = torpedoes?.Select(x => x.Damage).ToList() ?? new(); + this.Range = torpedoes?.Select(x => x.Range).ToList() ?? new(); + this.Speed = torpedoes?.Select(x => x.Speed).ToList() ?? new(); + this.DetectRange = torpedoes?.Select(x => x.Detectability).ToList() ?? new(); + this.ArmingDistance = torpedoes?.Select(x => x.ArmingDistance).ToList() ?? new(); + this.ReactionTime = torpedoes?.Select(x => x.ReactionTime).ToList() ?? new(); + this.FloodingChance = torpedoes?.Select(x => x.FloodingChance).ToList() ?? new(); + this.BlastRadius = torpedoes?.Select(x => x.ExplosionRadius).ToList() ?? new(); + this.BlastPenetration = torpedoes?.Select(x => x.SplashCoeff).ToList() ?? new(); + this.CanHit = torpedoes?.Select(x => x.CanHitClasses).ToList() ?? new(); } public List FullSalvoDamage { get; } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs b/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs index 99c74bba4..48fecbdc4 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/ShipComparisonViewModel.cs @@ -55,15 +55,15 @@ public ShipComparisonViewModel(ILocalizer localizer, AppSettings appSettings) this.localizer = localizer; this.appSettings = appSettings; - useUpgradedModules = appSettings.ShipComparisonUseUpgradedModules; - hideShipsWithoutSelectedSection = appSettings.ShipComparisonHideShipsWithoutSection; - Range = appSettings.ShipComparisonFiringRange; + this.useUpgradedModules = appSettings.ShipComparisonUseUpgradedModules; + this.hideShipsWithoutSelectedSection = appSettings.ShipComparisonHideShipsWithoutSection; + this.Range = appSettings.ShipComparisonFiringRange; } private Dictionary FilteredShipList { - get => filteredShipList; - set => this.RaiseAndSetIfChanged(ref filteredShipList, value); + get => this.filteredShipList; + set => this.RaiseAndSetIfChanged(ref this.filteredShipList, value); } public Dictionary SelectedShipList { get; } = new(); @@ -96,12 +96,12 @@ private Dictionary FilteredShipList public string ResearchedShip { - get => researchedShip; + get => this.researchedShip; set { - researchedShip = value; - FindShips(); - this.RaiseAndSetIfChanged(ref researchedShip, value); + this.researchedShip = value; + this.FindShips(); + this.RaiseAndSetIfChanged(ref this.researchedShip, value); } } @@ -114,39 +114,29 @@ public Task ApplyFilters() { Dictionary dictionary = new(); - dictionary.AddRange(PinnedShipList); + dictionary.AddRange(this.PinnedShipList); - var filteredShips = FilteredShipList.Where(data => SelectedTiers.Contains(data.Value.Ship.Tier) && - SelectedClasses.Contains(data.Value.Ship.ShipClass) && - SelectedNations.Contains(data.Value.Ship.ShipNation) && - SelectedCategories.Contains(data.Value.Ship.ShipCategory)).ToDictionary(x => x.Key, x => x.Value); + var filteredShips = this.FilteredShipList.Where(data => this.SelectedTiers.Contains(data.Value.Ship.Tier) && this.SelectedClasses.Contains(data.Value.Ship.ShipClass) && this.SelectedNations.Contains(data.Value.Ship.ShipNation) && this.SelectedCategories.Contains(data.Value.Ship.ShipCategory)).ToDictionary(x => x.Key, x => x.Value); dictionary.AddRange(filteredShips.Where(x => !dictionary.ContainsKey(x.Key))); - var cachedWrappers = wrappersCache.Where(data => SelectedTiers.Contains(data.Value.Ship.Tier) && - SelectedClasses.Contains(data.Value.Ship.ShipClass) && - SelectedNations.Contains(data.Value.Ship.ShipNation) && - SelectedCategories.Contains(data.Value.Ship.ShipCategory)).ToDictionary(x => x.Key, x => x.Value); + var cachedWrappers = this.wrappersCache.Where(data => this.SelectedTiers.Contains(data.Value.Ship.Tier) && this.SelectedClasses.Contains(data.Value.Ship.ShipClass) && this.SelectedNations.Contains(data.Value.Ship.ShipNation) && this.SelectedCategories.Contains(data.Value.Ship.ShipCategory)).ToDictionary(x => x.Key, x => x.Value); dictionary.AddRange(cachedWrappers.Where(x => !dictionary.ContainsKey(x.Key))); - dictionary.AddRange(InitialiseShipBuildContainers(fullShipList.Where(data => !ContainsShipIndex(data.Index, filteredShips) && - !ContainsShipIndex(data.Index, cachedWrappers) && - SelectedTiers.Contains(data.Tier) && - SelectedClasses.Contains(data.ShipClass) && - SelectedNations.Contains(data.ShipNation) && - SelectedCategories.Contains(data.ShipCategory)))); + dictionary.AddRange(this.InitialiseShipBuildContainers(this.fullShipList.Where(data => !ContainsShipIndex(data.Index, filteredShips) && + !ContainsShipIndex(data.Index, cachedWrappers) && this.SelectedTiers.Contains(data.Tier) && this.SelectedClasses.Contains(data.ShipClass) && this.SelectedNations.Contains(data.ShipNation) && this.SelectedCategories.Contains(data.ShipCategory)))); - wrappersCache.RemoveMany(cachedWrappers); - FilteredShipList.RemoveMany(filteredShips); - SelectedShipList.RemoveMany(FilteredShipList.Where(x => SelectedShipList.ContainsKey(x.Key) && !PinnedShipList.ContainsKey(x.Key))); - wrappersCache.AddRange(FilteredShipList.Where(x => !wrappersCache.ContainsKey(x.Key))); + this.wrappersCache.RemoveMany(cachedWrappers); + this.FilteredShipList.RemoveMany(filteredShips); + this.SelectedShipList.RemoveMany(this.FilteredShipList.Where(x => this.SelectedShipList.ContainsKey(x.Key) && !this.PinnedShipList.ContainsKey(x.Key))); + this.wrappersCache.AddRange(this.FilteredShipList.Where(x => !this.wrappersCache.ContainsKey(x.Key))); - SetSelectAndPinAllButtonsStatus(dictionary); + this.SetSelectAndPinAllButtonsStatus(dictionary); - FilteredShipList = dictionary; + this.FilteredShipList = dictionary; - GetDataSectionsToDisplay(); + this.GetDataSectionsToDisplay(); // Keep the return type as task in order to allow making the method async in the future if there is heavy filtering logic that needs to run asynchronously. return Task.CompletedTask; @@ -154,142 +144,142 @@ public Task ApplyFilters() public void ToggleShowPinnedShipOnly() { - ShowPinnedShipsOnly = !ShowPinnedShipsOnly; - if (ShowPinnedShipsOnly) + this.ShowPinnedShipsOnly = !this.ShowPinnedShipsOnly; + if (this.ShowPinnedShipsOnly) { - PinAllShips = true; - SelectAllShips = FilteredShipList.Intersect(PinnedShipList).All(x => SelectedShipList.ContainsKey(x.Key)); + this.PinAllShips = true; + this.SelectAllShips = this.FilteredShipList.Intersect(this.PinnedShipList).All(x => this.SelectedShipList.ContainsKey(x.Key)); } else { - SetSelectAndPinAllButtonsStatus(); + this.SetSelectAndPinAllButtonsStatus(); } } public async Task ToggleTierSelection(int value) { - if (SelectedTiers.Contains(value)) + if (this.SelectedTiers.Contains(value)) { - SelectedTiers.Remove(value); + this.SelectedTiers.Remove(value); } else { - SelectedTiers.Add(value); + this.SelectedTiers.Add(value); } - await ApplyFilters(); + await this.ApplyFilters(); } public async Task ToggleClassSelection(ShipClass value) { - if (SelectedClasses.Contains(value)) + if (this.SelectedClasses.Contains(value)) { - SelectedClasses.Remove(value); + this.SelectedClasses.Remove(value); } else { - SelectedClasses.Add(value); + this.SelectedClasses.Add(value); } - await ApplyFilters(); + await this.ApplyFilters(); } public async Task ToggleNationSelection(Nation value) { - if (SelectedNations.Contains(value)) + if (this.SelectedNations.Contains(value)) { - SelectedNations.Remove(value); + this.SelectedNations.Remove(value); } else { - SelectedNations.Add(value); + this.SelectedNations.Add(value); } - await ApplyFilters(); + await this.ApplyFilters(); } public async Task ToggleCategorySelection(ShipCategory value) { - if (SelectedCategories.Contains(value)) + if (this.SelectedCategories.Contains(value)) { - SelectedCategories.Remove(value); + this.SelectedCategories.Remove(value); } else { - SelectedCategories.Add(value); + this.SelectedCategories.Add(value); } - await ApplyFilters(); + await this.ApplyFilters(); } public async Task ToggleAllTiers(bool activationState, bool applyFilters = true) { - SelectedTiers.Clear(); + this.SelectedTiers.Clear(); if (activationState) { - SelectedTiers.AddRange(Enumerable.Range(1, 11)); + this.SelectedTiers.AddRange(Enumerable.Range(1, 11)); } if (applyFilters) { - await ApplyFilters(); + await this.ApplyFilters(); } } public async Task ToggleAllClasses(bool activationState, bool applyFilters = true) { - SelectedClasses.Clear(); + this.SelectedClasses.Clear(); if (activationState) { - SelectedClasses.AddRange(Enum.GetValues().Except(new[] { ShipClass.Auxiliary })); + this.SelectedClasses.AddRange(Enum.GetValues().Except(new[] { ShipClass.Auxiliary })); } if (applyFilters) { - await ApplyFilters(); + await this.ApplyFilters(); } } public async Task ToggleAllNations(bool activationState, bool applyFilters = true) { - SelectedNations.Clear(); + this.SelectedNations.Clear(); if (activationState) { - SelectedNations.AddRange(Enum.GetValues().Except(new[] { Nation.Common })); + this.SelectedNations.AddRange(Enum.GetValues().Except(new[] { Nation.Common })); } if (applyFilters) { - await ApplyFilters(); + await this.ApplyFilters(); } } public async Task ToggleAllCategories(bool activationState, bool applyFilters = true) { - SelectedCategories.Clear(); + this.SelectedCategories.Clear(); if (activationState) { - SelectedCategories.AddRange(Enum.GetValues().Except(new[] { ShipCategory.Disabled, ShipCategory.Clan })); + this.SelectedCategories.AddRange(Enum.GetValues().Except(new[] { ShipCategory.Disabled, ShipCategory.Clan })); } if (applyFilters) { - await ApplyFilters(); + await this.ApplyFilters(); } } public Dictionary GetShipsToBeDisplayed() { - return GetShipsToBeDisplayed(false); + return this.GetShipsToBeDisplayed(false); } public void EditBuilds(IEnumerable> newWrappers) { - EditBuilds(newWrappers, false); + this.EditBuilds(newWrappers, false); } public Dictionary RemoveBuilds(IEnumerable> wrappers) @@ -298,25 +288,25 @@ public Dictionary RemoveBuilds(IEnumerable x.Key, x => x.Value); foreach (var wrapper in buildList) { - if (FilteredShipList.Count(x => x.Value.Ship.Index.Equals(wrapper.Value.Ship.Index)) > 1) + if (this.FilteredShipList.Count(x => x.Value.Ship.Index.Equals(wrapper.Value.Ship.Index)) > 1) { - FilteredShipList.Remove(wrapper.Key); + this.FilteredShipList.Remove(wrapper.Key); - PinnedShipList.Remove(wrapper.Key); + this.PinnedShipList.Remove(wrapper.Key); - if (wrappersCache.ContainsKey(wrapper.Key)) + if (this.wrappersCache.ContainsKey(wrapper.Key)) { - wrappersCache[wrapper.Key] = wrapper.Value; + this.wrappersCache[wrapper.Key] = wrapper.Value; } - DispersionCache.Remove(wrapper.Key); + this.DispersionCache.Remove(wrapper.Key); } else { if (wrapper.Value.Build is not null) { - var err = ResetBuild(wrapper.Value); - EditBuilds(new Dictionary { { err.Id, err } }); + var err = this.ResetBuild(wrapper.Value); + this.EditBuilds(new Dictionary { { err.Id, err } }); warnings.Add(err.Id, err); } else @@ -326,129 +316,129 @@ public Dictionary RemoveBuilds(IEnumerable x.Value.Build is not null).ToDictionary(x => x.Key, x => ResetBuild(x.Value)); - EditBuilds(list, true); - SetSelectAndPinAllButtonsStatus(); + this.RemoveBuilds(this.FilteredShipList); + this.SelectedShipList.Clear(); + var list = this.FilteredShipList.Where(x => x.Value.Build is not null).ToDictionary(x => x.Key, x => this.ResetBuild(x.Value)); + this.EditBuilds(list, true); + this.SetSelectAndPinAllButtonsStatus(); } public async Task AddPinnedShip(GridDataWrapper wrapper) { - if (!PinnedShipList.ContainsKey(wrapper.Id)) + if (!this.PinnedShipList.ContainsKey(wrapper.Id)) { - PinnedShipList.Add(wrapper.Id, wrapper); + this.PinnedShipList.Add(wrapper.Id, wrapper); } else { - await RemovePinnedShip(wrapper); + await this.RemovePinnedShip(wrapper); } - SetSelectAndPinAllButtonsStatus(); + this.SetSelectAndPinAllButtonsStatus(); } public void AddSelectedShip(GridDataWrapper wrapper) { - if (!SelectedShipList.ContainsKey(wrapper.Id)) + if (!this.SelectedShipList.ContainsKey(wrapper.Id)) { - SelectedShipList.Add(wrapper.Id, wrapper); + this.SelectedShipList.Add(wrapper.Id, wrapper); } else { - RemoveSelectedShip(wrapper); + this.RemoveSelectedShip(wrapper); } - SetSelectAndPinAllButtonsStatus(); + this.SetSelectAndPinAllButtonsStatus(); } public void ToggleUpgradedModules() { - UseUpgradedModules = !UseUpgradedModules; - ChangeModulesBatch(); + this.UseUpgradedModules = !this.UseUpgradedModules; + this.ChangeModulesBatch(); } public void ToggleHideShipsWithoutSelectedSection() { - HideShipsWithoutSelectedSection = !HideShipsWithoutSelectedSection; + this.HideShipsWithoutSelectedSection = !this.HideShipsWithoutSelectedSection; } public async Task SelectDataSection(ShipComparisonDataSections dataSection) { - SelectedDataSection = dataSection; - await ApplyFilters(); + this.SelectedDataSection = dataSection; + await this.ApplyFilters(); } public void SelectAllDisplayedShips() { - SelectAllShips = !SelectAllShips; + this.SelectAllShips = !this.SelectAllShips; - var list = GetShipsToBeDisplayed(); + var list = this.GetShipsToBeDisplayed(); - if (!string.IsNullOrEmpty(searchString)) + if (!string.IsNullOrEmpty(this.searchString)) { - list = list.Where(x => appSettings.SelectedLanguage.CultureInfo.CompareInfo.IndexOf(localizer.GetGameLocalization(x.Value.Ship.Index + "_FULL").Localization, searchString, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) != -1).ToDictionary(x => x.Key, x => x.Value); + list = list.Where(x => this.appSettings.SelectedLanguage.CultureInfo.CompareInfo.IndexOf(this.localizer.GetGameLocalization(x.Value.Ship.Index + "_FULL").Localization, this.searchString, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) != -1).ToDictionary(x => x.Key, x => x.Value); } - if (SelectAllShips) + if (this.SelectAllShips) { - SelectedShipList.AddRange(list.Where(x => !SelectedShipList.ContainsKey(x.Key))); + this.SelectedShipList.AddRange(list.Where(x => !this.SelectedShipList.ContainsKey(x.Key))); } else { - SelectedShipList.RemoveMany(list.Where(x => SelectedShipList.ContainsKey(x.Key))); + this.SelectedShipList.RemoveMany(list.Where(x => this.SelectedShipList.ContainsKey(x.Key))); } } public async Task PinAllDisplayedShips() { - PinAllShips = !PinAllShips; + this.PinAllShips = !this.PinAllShips; - var list = FilteredShipList; + var list = this.FilteredShipList; - if (!string.IsNullOrEmpty(searchString)) + if (!string.IsNullOrEmpty(this.searchString)) { - list = list.Where(x => appSettings.SelectedLanguage.CultureInfo.CompareInfo.IndexOf(localizer.GetGameLocalization(x.Value.Ship.Index + "_FULL").Localization, searchString, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) != -1).ToDictionary(x => x.Key, x => x.Value); + list = list.Where(x => this.appSettings.SelectedLanguage.CultureInfo.CompareInfo.IndexOf(this.localizer.GetGameLocalization(x.Value.Ship.Index + "_FULL").Localization, this.searchString, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) != -1).ToDictionary(x => x.Key, x => x.Value); } - if (PinAllShips) + if (this.PinAllShips) { - PinnedShipList.AddRange(list.Where(x => !PinnedShipList.ContainsKey(x.Key))); + this.PinnedShipList.AddRange(list.Where(x => !this.PinnedShipList.ContainsKey(x.Key))); } else { - PinnedShipList.RemoveMany(list.Where(x => PinnedShipList.ContainsKey(x.Key))); - await ApplyFilters(); + this.PinnedShipList.RemoveMany(list.Where(x => this.PinnedShipList.ContainsKey(x.Key))); + await this.ApplyFilters(); } } public void DuplicateSelectedShips() { - foreach (var selectedShip in SelectedShipList) + foreach (var selectedShip in this.SelectedShipList) { var newWrapper = new GridDataWrapper(selectedShip.Value.ShipBuildContainer with { Id = Guid.NewGuid() }); - FilteredShipList.Add(newWrapper.Id, newWrapper); - if (PinnedShipList.ContainsKey(selectedShip.Key)) + this.FilteredShipList.Add(newWrapper.Id, newWrapper); + if (this.PinnedShipList.ContainsKey(selectedShip.Key)) { - PinnedShipList.Add(newWrapper.Id, newWrapper); + this.PinnedShipList.Add(newWrapper.Id, newWrapper); } - if (DispersionCache.ContainsKey(selectedShip.Key)) + if (this.DispersionCache.ContainsKey(selectedShip.Key)) { - DispersionCache[newWrapper.Id] = DispersionCache[selectedShip.Key]; + this.DispersionCache[newWrapper.Id] = this.DispersionCache[selectedShip.Key]; } } - SetSelectAndPinAllButtonsStatus(); + this.SetSelectAndPinAllButtonsStatus(); } public void AddShip(object? obj) @@ -465,43 +455,43 @@ public void AddShip(object? obj) } else if (obj is Ship ship) { - newWrapper = new(ShipBuildContainer.CreateNew(ship, null, null) with { ShipDataContainer = GetShipDataContainer(ship) }); + newWrapper = new(ShipBuildContainer.CreateNew(ship, null, null) with { ShipDataContainer = this.GetShipDataContainer(ship) }); } else if (obj is string shipIndex) { - var shipFromIndex = fullShipList.First(x => x.Index.Equals(shipIndex, StringComparison.Ordinal)); - newWrapper = new(ShipBuildContainer.CreateNew(shipFromIndex, null, null) with { ShipDataContainer = GetShipDataContainer(shipFromIndex) }); + var shipFromIndex = this.fullShipList.First(x => x.Index.Equals(shipIndex, StringComparison.Ordinal)); + newWrapper = new(ShipBuildContainer.CreateNew(shipFromIndex, null, null) with { ShipDataContainer = this.GetShipDataContainer(shipFromIndex) }); } else { return; } - FilteredShipList.Add(newWrapper.Id, newWrapper); - PinnedShipList.Add(newWrapper.Id, newWrapper); + this.FilteredShipList.Add(newWrapper.Id, newWrapper); + this.PinnedShipList.Add(newWrapper.Id, newWrapper); - SetSelectAndPinAllButtonsStatus(); - GetDataSectionsToDisplay(); - SearchString = string.Empty; - ResearchedShip = string.Empty; - SearchedShips.Clear(); + this.SetSelectAndPinAllButtonsStatus(); + this.GetDataSectionsToDisplay(); + this.SearchString = string.Empty; + this.ResearchedShip = string.Empty; + this.SearchedShips.Clear(); } public void UpdateRange(double selectedValue) { - Range = selectedValue; + this.Range = selectedValue; } private Dictionary GetShipsToBeDisplayed(bool disableHideShipsIfNoSelectedSection) { - Dictionary list = ShowPinnedShipsOnly ? PinnedShipList : FilteredShipList; + Dictionary list = this.ShowPinnedShipsOnly ? this.PinnedShipList : this.FilteredShipList; if (!disableHideShipsIfNoSelectedSection) { - list = HideShipsIfNoSelectedSection(list); + list = this.HideShipsIfNoSelectedSection(list); } - CacheDispersion(list.Values); + this.CacheDispersion(list.Values); return list; } @@ -510,58 +500,58 @@ private void EditBuilds(IEnumerable> newWrap { foreach (var wrapper in newWrappers) { - FilteredShipList[wrapper.Key] = wrapper.Value; + this.FilteredShipList[wrapper.Key] = wrapper.Value; - if (PinnedShipList.ContainsKey(wrapper.Key)) + if (this.PinnedShipList.ContainsKey(wrapper.Key)) { - PinnedShipList[wrapper.Key] = wrapper.Value; + this.PinnedShipList[wrapper.Key] = wrapper.Value; } - else if (ContainsShipIndex(wrapper.Value.Ship.Index, PinnedShipList)) + else if (ContainsShipIndex(wrapper.Value.Ship.Index, this.PinnedShipList)) { - PinnedShipList.Add(wrapper.Key, wrapper.Value); + this.PinnedShipList.Add(wrapper.Key, wrapper.Value); } - if (!clearCache && wrappersCache.ContainsKey(wrapper.Key)) + if (!clearCache && this.wrappersCache.ContainsKey(wrapper.Key)) { - wrappersCache[wrapper.Key] = wrapper.Value; + this.wrappersCache[wrapper.Key] = wrapper.Value; } - if (SelectedShipList.ContainsKey(wrapper.Key)) + if (this.SelectedShipList.ContainsKey(wrapper.Key)) { - SelectedShipList[wrapper.Key] = wrapper.Value; + this.SelectedShipList[wrapper.Key] = wrapper.Value; } } if (clearCache) { - wrappersCache.Clear(); + this.wrappersCache.Clear(); } } private async Task RemovePinnedShip(GridDataWrapper wrapper) { - PinnedShipList.Remove(wrapper.Id); - await ApplyFilters(); + this.PinnedShipList.Remove(wrapper.Id); + await this.ApplyFilters(); } private void RemoveSelectedShip(GridDataWrapper wrapper) { - SelectedShipList.Remove(wrapper.Id); + this.SelectedShipList.Remove(wrapper.Id); } private Dictionary InitialiseShipBuildContainers(IEnumerable ships) { - return ships.Select(ship => new GridDataWrapper(ShipBuildContainer.CreateNew(ship, null, null) with { ShipDataContainer = GetShipDataContainer(ship) })).ToDictionary(x => x.Id, x => x); + return ships.Select(ship => new GridDataWrapper(ShipBuildContainer.CreateNew(ship, null, null) with { ShipDataContainer = this.GetShipDataContainer(ship) })).ToDictionary(x => x.Id, x => x); } private void ChangeModulesBatch() { - EditBuilds(FilteredShipList.Where(x => x.Value.Build is null).ToDictionary(x => x.Key, x => ResetBuild(x.Value))); + this.EditBuilds(this.FilteredShipList.Where(x => x.Value.Build is null).ToDictionary(x => x.Key, x => this.ResetBuild(x.Value))); } private List GetShipConfiguration(Ship ship) { - List shipConfiguration = UseUpgradedModules + List shipConfiguration = this.UseUpgradedModules ? ShipModuleHelper.GroupAndSortUpgrades(ship.ShipUpgradeInfo.ShipUpgrades) .OrderBy(entry => entry.Key) .Select(entry => entry.Value) @@ -577,17 +567,17 @@ private List GetShipConfiguration(Ship ship) private ShipDataContainer GetShipDataContainer(Ship ship) { - return ShipDataContainer.CreateFromShip(ship, GetShipConfiguration(ship), new()); + return ShipDataContainer.CreateFromShip(ship, this.GetShipConfiguration(ship), new()); } private Dictionary HideShipsIfNoSelectedSection(IEnumerable> list) { - if (!hideShipsWithoutSelectedSection) + if (!this.hideShipsWithoutSelectedSection) { return list.ToDictionary(x => x.Key, x => x.Value); } - Dictionary newList = SelectedDataSection switch + Dictionary newList = this.SelectedDataSection switch { ShipComparisonDataSections.MainBattery => list.Where(x => x.Value.ShipDataContainer.MainBatteryDataContainer is not null).ToDictionary(x => x.Key, x => x.Value), ShipComparisonDataSections.He => list.Where(x => x.Value.HeShell?.Damage is not null).ToDictionary(x => x.Key, x => x.Value), @@ -609,14 +599,14 @@ private Dictionary HideShipsIfNoSelectedSection(IEnumerab _ => list.ToDictionary(x => x.Key, x => x.Value), }; - newList.AddRange(PinnedShipList.Where(x => !newList.ContainsKey(x.Key))); + newList.AddRange(this.PinnedShipList.Where(x => !newList.ContainsKey(x.Key))); return newList; } private void GetDataSectionsToDisplay() { - var displayedShipList = GetShipsToBeDisplayed(true); - DataSections = !displayedShipList.Any() ? new() { ShipComparisonDataSections.General } : HideEmptyDataSections(displayedShipList); + var displayedShipList = this.GetShipsToBeDisplayed(true); + this.DataSections = !displayedShipList.Any() ? new() { ShipComparisonDataSections.General } : this.HideEmptyDataSections(displayedShipList); } [SuppressMessage("Performance", "CA1822", Justification = "not static to preserve file structure")] @@ -684,26 +674,26 @@ private List HideEmptyDataSections(Dictionary appSettings.SelectedLanguage.CultureInfo.CompareInfo.IndexOf(localizer.GetGameLocalization(ship.Index + "_FULL").Localization, researchedShip, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) != -1)); + this.SearchedShips.Clear(); + this.SearchedShips.AddRange(this.fullShipList.Where(ship => this.appSettings.SelectedLanguage.CultureInfo.CompareInfo.IndexOf(this.localizer.GetGameLocalization(ship.Index + "_FULL").Localization, this.researchedShip, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) != -1)); } - private void SetSelectAndPinAllButtonsStatus() => SetSelectAndPinAllButtonsStatus(GetShipsToBeDisplayed()); + private void SetSelectAndPinAllButtonsStatus() => this.SetSelectAndPinAllButtonsStatus(this.GetShipsToBeDisplayed()); private void SetSelectAndPinAllButtonsStatus(IReadOnlyDictionary list) { - SelectAllShips = list.All(wrapper => SelectedShipList.ContainsKey(wrapper.Key)); - PinAllShips = list.All(wrapper => PinnedShipList.ContainsKey(wrapper.Key)); + this.SelectAllShips = list.All(wrapper => this.SelectedShipList.ContainsKey(wrapper.Key)); + this.PinAllShips = list.All(wrapper => this.PinnedShipList.ContainsKey(wrapper.Key)); } private GridDataWrapper ResetBuild(GridDataWrapper wrapper) { - GridDataWrapper reset = new(wrapper.ShipBuildContainer with { Build = null, ActivatedConsumableSlots = null, SpecialAbilityActive = false, ShipDataContainer = GetShipDataContainer(wrapper.Ship), Modifiers = null }); + GridDataWrapper reset = new(wrapper.ShipBuildContainer with { Build = null, ActivatedConsumableSlots = null, SpecialAbilityActive = false, ShipDataContainer = this.GetShipDataContainer(wrapper.Ship), Modifiers = null }); return reset; } @@ -714,7 +704,7 @@ private void CacheDispersion(IEnumerable wrappers) { if (wrapper.MainBattery?.DispersionData is not null && wrapper.MainBattery?.DispersionModifier is not null && wrapper.MainBattery?.Range is not null) { - DispersionCache[wrapper.Id] = wrapper.MainBattery.DispersionData.CalculateDispersion(decimal.ToDouble(wrapper.MainBattery.Range * 1000), wrapper.MainBattery.DispersionModifier, Range * 1000); + this.DispersionCache[wrapper.Id] = wrapper.MainBattery.DispersionData.CalculateDispersion(decimal.ToDouble(wrapper.MainBattery.Range * 1000), wrapper.MainBattery.DispersionModifier, this.Range * 1000); } } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/MouseEventInterop.cs b/WoWsShipBuilder.Common/Features/ShipStats/MouseEventInterop.cs index 9bcce9fe0..0ff9ecde8 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/MouseEventInterop.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/MouseEventInterop.cs @@ -16,14 +16,14 @@ public MouseEventInterop(IJSRuntime runtime) public async Task PreventMiddleClickDefault(string id) { - await InitializeModule(); - await module.InvokeVoidAsync("PreventMiddleClickDefault", id); + await this.InitializeModule(); + await this.module.InvokeVoidAsync("PreventMiddleClickDefault", id); } public async Task PreventMiddleClickDefaultBatched(IEnumerable ids) { - await InitializeModule(); - await module.InvokeVoidAsync("PreventMiddleClickDefaultBatched", ids); + await this.InitializeModule(); + await this.module.InvokeVoidAsync("PreventMiddleClickDefaultBatched", ids); } [MemberNotNull(nameof(module))] @@ -31,17 +31,17 @@ private async Task InitializeModule() { // module is not null after this method but apparently, Roslyn does not want to recognize that. #pragma warning disable CS8774 - module ??= await runtime.InvokeAsync("import", "/_content/WoWsShipBuilder.Common/scripts/MouseEventHelper.js"); + this.module ??= await this.runtime.InvokeAsync("import", "/_content/WoWsShipBuilder.Common/scripts/MouseEventHelper.js"); #pragma warning restore CS8774 } async ValueTask IAsyncDisposable.DisposeAsync() { - if (module is not null) + if (this.module is not null) { try { - await module.DisposeAsync(); + await this.module.DisposeAsync(); } catch (JSDisconnectedException) { diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/CaptainSkillSelectorViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/CaptainSkillSelectorViewModel.cs index 5b5412c0d..c94f712dd 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/CaptainSkillSelectorViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/CaptainSkillSelectorViewModel.cs @@ -62,8 +62,8 @@ public CaptainSkillSelectorViewModel() public CaptainSkillSelectorViewModel(ShipClass shipClass, (Captain defaultCaptain, Dictionary? captainList) vmParams) { - logger = Logging.LoggerFactory.CreateLogger(); - currentClass = shipClass; + this.logger = Logging.LoggerFactory.CreateLogger(); + this.currentClass = shipClass; var defaultCaptain = vmParams.defaultCaptain; @@ -77,13 +77,13 @@ public CaptainSkillSelectorViewModel(ShipClass shipClass, (Captain defaultCaptai capList = capList.Union(nationCaptains).ToDictionary(x => x.Key, x => x.Value); } - CaptainList = capList.Select(x => x.Value).ToList(); - SelectedCaptain = CaptainList[0]; + this.CaptainList = capList.Select(x => x.Value).ToList(); + this.SelectedCaptain = this.CaptainList[0]; - this.WhenAnyValue(x => x.AssignedPoints).Do(_ => UpdateCanAddSkill()).Subscribe(); + this.WhenAnyValue(x => x.AssignedPoints).Do(_ => this.UpdateCanAddSkill()).Subscribe(); - CaptainTalentsList.CollectionChanged += CaptainTalentsListOnCollectionChanged; - ConditionalModifiersList.CollectionChanged += ConditionalModifiersListOnCollectionChanged; + this.CaptainTalentsList.CollectionChanged += this.CaptainTalentsListOnCollectionChanged; + this.ConditionalModifiersList.CollectionChanged += this.ConditionalModifiersListOnCollectionChanged; } /// @@ -91,17 +91,17 @@ public CaptainSkillSelectorViewModel(ShipClass shipClass, (Captain defaultCaptai /// public Captain? SelectedCaptain { - get => selectedCaptain; + get => this.selectedCaptain; set { - var newCaptain = value ?? selectedCaptain; - this.RaiseAndSetIfChanged(ref selectedCaptain, newCaptain); - SkillList = ConvertSkillToViewModel(currentClass, newCaptain); - CaptainTalentsList.Clear(); + var newCaptain = value ?? this.selectedCaptain; + this.RaiseAndSetIfChanged(ref this.selectedCaptain, newCaptain); + this.SkillList = this.ConvertSkillToViewModel(this.currentClass, newCaptain); + this.CaptainTalentsList.Clear(); if (newCaptain!.UniqueSkills.Any()) { - CaptainWithTalents = true; + this.CaptainWithTalents = true; foreach ((string _, UniqueSkill talent) in newCaptain.UniqueSkills) { SkillActivationItemViewModel talentModel; @@ -117,24 +117,24 @@ public Captain? SelectedCaptain talentModel = new(talent.TranslationId, -1, modifiers, false, talent.MaxTriggerNum, 1, talent.TranslationId + "_DESCRIPTION"); } - CaptainTalentsList.Add(talentModel); + this.CaptainTalentsList.Add(talentModel); } } else { - CaptainWithTalents = false; + this.CaptainWithTalents = false; } - var currentlySelectedNumbersList = SkillOrderList.Select(x => x.SkillNumber).ToList(); - SkillOrderList.Clear(); + var currentlySelectedNumbersList = this.SkillOrderList.Select(x => x.SkillNumber).ToList(); + this.SkillOrderList.Clear(); foreach (var skillNumber in currentlySelectedNumbersList) { - var skill = SkillList.Values.Single(x => x.Skill.SkillNumber.Equals(skillNumber)).Skill; - SkillOrderList.Add(skill); + var skill = this.SkillList.Values.Single(x => x.Skill.SkillNumber.Equals(skillNumber)).Skill; + this.SkillOrderList.Add(skill); } - UpdateCanAddSkill(); // Needs to be called to update the internal state of the skill viewmodels - SkillActivationButtonEnabled = CaptainTalentsList.Count > 0 || ConditionalModifiersList.Count > 0 || ShowArHpSelection; + this.UpdateCanAddSkill(); // Needs to be called to update the internal state of the skill viewmodels + this.SkillActivationButtonEnabled = this.CaptainTalentsList.Count > 0 || this.ConditionalModifiersList.Count > 0 || this.ShowArHpSelection; } } @@ -148,11 +148,11 @@ public Captain? SelectedCaptain ///
public bool ShowArHpSelection { - get => showArHpSelection; + get => this.showArHpSelection; set { - this.RaiseAndSetIfChanged(ref showArHpSelection, value); - TalentOrConditionalSkillEnabled = (showArHpSelection && ArHpPercentage < 100) || CaptainTalentsList.Any(talent => talent.Status) || ConditionalModifiersList.Any(skill => skill.Status); + this.RaiseAndSetIfChanged(ref this.showArHpSelection, value); + this.TalentOrConditionalSkillEnabled = (this.showArHpSelection && this.ArHpPercentage < 100) || this.CaptainTalentsList.Any(talent => talent.Status) || this.ConditionalModifiersList.Any(skill => skill.Status); } } @@ -171,11 +171,11 @@ public bool ShowArHpSelection ///
public bool SkillActivationPopupOpen { - get => skillActivationPopupOpen; + get => this.skillActivationPopupOpen; set { - this.RaiseAndSetIfChanged(ref skillActivationPopupOpen, value); - TalentOrConditionalSkillEnabled = (showArHpSelection && ArHpPercentage < 100) || CaptainTalentsList.Any(talent => talent.Status) || ConditionalModifiersList.Any(skill => skill.Status); + this.RaiseAndSetIfChanged(ref this.skillActivationPopupOpen, value); + this.TalentOrConditionalSkillEnabled = (this.showArHpSelection && this.ArHpPercentage < 100) || this.CaptainTalentsList.Any(talent => talent.Status) || this.ConditionalModifiersList.Any(skill => skill.Status); } } @@ -209,46 +209,46 @@ private static Captain ShallowCopyCaptain(Captain original) /// the to add. public void AddSkill(Skill skill) { - if (SkillOrderList.Contains(skill)) + if (this.SkillOrderList.Contains(skill)) { - logger.LogDebug("Adding skill {Skill} to skill order list", skill.SkillNumber); - SkillOrderList.Remove(skill); - ReorderSkillList(); - int pointCost = skill.Tiers.First(x => x.ShipClass == currentClass).Tier + 1; - AssignedPoints -= pointCost; + this.logger.LogDebug("Adding skill {Skill} to skill order list", skill.SkillNumber); + this.SkillOrderList.Remove(skill); + this.ReorderSkillList(); + int pointCost = skill.Tiers.First(x => x.ShipClass == this.currentClass).Tier + 1; + this.AssignedPoints -= pointCost; if (skill.SkillNumber == ArSkillNumber || skill.SkillNumber == ArSkillNumberSubs) { - ShowArHpSelection = false; + this.ShowArHpSelection = false; } if (skill.ConditionalModifiers is { Count: > 0 }) { - var skillName = SkillList!.Single(x => x.Value.Skill.Equals(skill)).Key; - ConditionalModifiersList.Remove(ConditionalModifiersList.Single(x => x.SkillName.Equals(skillName))); + var skillName = this.SkillList!.Single(x => x.Value.Skill.Equals(skill)).Key; + this.ConditionalModifiersList.Remove(this.ConditionalModifiersList.Single(x => x.SkillName.Equals(skillName))); } - this.RaisePropertyChanged(nameof(SkillOrderList)); + this.RaisePropertyChanged(nameof(this.SkillOrderList)); } else { - logger.LogDebug("Removing skill {Skill} from skill order list", skill.SkillNumber); - SkillOrderList.Add(skill); - var pointCost = skill.Tiers.First(x => x.ShipClass == currentClass).Tier + 1; - AssignedPoints += pointCost; + this.logger.LogDebug("Removing skill {Skill} from skill order list", skill.SkillNumber); + this.SkillOrderList.Add(skill); + var pointCost = skill.Tiers.First(x => x.ShipClass == this.currentClass).Tier + 1; + this.AssignedPoints += pointCost; if (skill.SkillNumber is ArSkillNumber or ArSkillNumberSubs) { - ShowArHpSelection = true; + this.ShowArHpSelection = true; } if (skill.ConditionalModifiers is { Count: > 0 }) { - ConditionalModifiersList.Add(CreateItemViewModelForSkill(skill)); + this.ConditionalModifiersList.Add(this.CreateItemViewModelForSkill(skill)); } - this.RaisePropertyChanged(nameof(SkillOrderList)); + this.RaisePropertyChanged(nameof(this.SkillOrderList)); } - SkillActivationButtonEnabled = CaptainTalentsList.Count > 0 || ConditionalModifiersList.Count > 0 || ShowArHpSelection; + this.SkillActivationButtonEnabled = this.CaptainTalentsList.Count > 0 || this.ConditionalModifiersList.Count > 0 || this.ShowArHpSelection; } /// @@ -257,41 +257,41 @@ public void AddSkill(Skill skill) /// The List of modifiers of the currently selected skill. public List<(string, float)> GetModifiersList() { - var modifiers = SkillOrderList.ToList() + var modifiers = this.SkillOrderList.ToList() .Where(skill => skill.Modifiers.Any() && skill.SkillNumber != ArSkillNumber && skill.SkillNumber != ArSkillNumberSubs && skill.SkillNumber != FuriousSkillNumber && skill.SkillNumber != ImprovedRepairPartyReadinessSkillNumber) .SelectMany(m => m.Modifiers) .Select(effect => (effect.Key, effect.Value)) .ToList(); // filter out modifiers that are class specific - modifiers = modifiers.Where(x => !x.Key.Contains('_') || x.Key.Contains("_" + currentClass)) + modifiers = modifiers.Where(x => !x.Key.Contains('_') || x.Key.Contains("_" + this.currentClass)) .Select(effect => (effect.Key, effect.Value)) .ToList(); - if (SkillOrderList.Any(skill => skill.SkillNumber == 14)) + if (this.SkillOrderList.Any(skill => skill.SkillNumber == 14)) { modifiers.Add(("fireResistanceEnabled", 1)); } - if (SkillOrderList.Any(skill => skill.SkillNumber == 22)) + if (this.SkillOrderList.Any(skill => skill.SkillNumber == 22)) { modifiers.Add(("interceptorSelected", 0)); } - if (ConditionalModifiersList.Count > 0) + if (this.ConditionalModifiersList.Count > 0) { - modifiers.AddRange(CollectConditionalModifiers()); + modifiers.AddRange(this.CollectConditionalModifiers()); } - var arSkill = SkillOrderList.SingleOrDefault(skill => skill.SkillNumber is ArSkillNumber or ArSkillNumberSubs); + var arSkill = this.SkillOrderList.SingleOrDefault(skill => skill.SkillNumber is ArSkillNumber or ArSkillNumberSubs); if (arSkill is not null) { - modifiers.Add(("lastChanceReloadCoefficient", arSkill.Modifiers["lastChanceReloadCoefficient"] * (100 - ArHpPercentage))); + modifiers.Add(("lastChanceReloadCoefficient", arSkill.Modifiers["lastChanceReloadCoefficient"] * (100 - this.ArHpPercentage))); } - if (CaptainTalentsList.Count > 0) + if (this.CaptainTalentsList.Count > 0) { - modifiers.AddRange(CollectTalentModifiers()); + modifiers.AddRange(this.CollectTalentModifiers()); } return modifiers; @@ -301,7 +301,7 @@ public void AddSkill(Skill skill) /// Create a list of skill numbers from the currently selected list. /// /// The list of currently selected skill numbers. - public List GetSkillNumberList() => SkillOrderList.Select(skill => skill.SkillNumber).ToList(); + public List GetSkillNumberList() => this.SkillOrderList.Select(skill => skill.SkillNumber).ToList(); /// /// Return the index of the selected captain. @@ -309,7 +309,7 @@ public void AddSkill(Skill skill) /// The index of the selected captain. public string GetCaptainIndex() { - return SelectedCaptain!.Index; + return this.SelectedCaptain!.Index; } public void LoadBuild(IEnumerable selectedSkills, string? captainIndex) @@ -317,42 +317,42 @@ public void LoadBuild(IEnumerable selectedSkills, string? captainIndex) // this check is purely for backward compatibility if (captainIndex != null) { - var captain = CaptainList!.Find(x => x.Index.Equals(captainIndex, StringComparison.Ordinal)); - SelectedCaptain = captain ?? CaptainList![0]; + var captain = this.CaptainList!.Find(x => x.Index.Equals(captainIndex, StringComparison.Ordinal)); + this.SelectedCaptain = captain ?? this.CaptainList![0]; } - var skills = selectedSkills.Select(skillId => SelectedCaptain!.Skills.First(captainSkill => captainSkill.Value.SkillNumber == skillId)).Select(pair => pair.Value); - SkillOrderList.AddRange(skills); - AssignedPoints = SkillOrderList.Sum(skill => skill.Tiers.First(t => t.ShipClass == currentClass).Tier + 1); - ReorderSkillList(); - foreach (var skill in SkillOrderList) + var skills = selectedSkills.Select(skillId => this.SelectedCaptain!.Skills.First(captainSkill => captainSkill.Value.SkillNumber == skillId)).Select(pair => pair.Value); + this.SkillOrderList.AddRange(skills); + this.AssignedPoints = this.SkillOrderList.Sum(skill => skill.Tiers.First(t => t.ShipClass == this.currentClass).Tier + 1); + this.ReorderSkillList(); + foreach (var skill in this.SkillOrderList) { if (skill.SkillNumber is ArSkillNumber or ArSkillNumberSubs) { - ShowArHpSelection = true; + this.ShowArHpSelection = true; } if (skill.ConditionalModifiers.Any()) { - ConditionalModifiersList.Add(CreateItemViewModelForSkill(skill)); + this.ConditionalModifiersList.Add(this.CreateItemViewModelForSkill(skill)); } } - SkillActivationButtonEnabled = CaptainTalentsList.Count > 0 || ConditionalModifiersList.Count > 0 || ShowArHpSelection; + this.SkillActivationButtonEnabled = this.CaptainTalentsList.Count > 0 || this.ConditionalModifiersList.Count > 0 || this.ShowArHpSelection; } private IEnumerable<(string, float)> CollectConditionalModifiers() { var modifiers = new List<(string, float)>(); - var conditionalModifiers = ConditionalModifiersList.Where(skill => skill.Status && skill.SkillId != FuriousSkillNumber) + var conditionalModifiers = this.ConditionalModifiersList.Where(skill => skill.Status && skill.SkillId != FuriousSkillNumber) .SelectMany(skill => skill.Modifiers) .Select(x => (x.Key, x.Value)); modifiers.AddRange(conditionalModifiers); // Custom handling for Furious skill. Needs to take into account the number of fires - var furiousSkill = SkillOrderList.SingleOrDefault(skill => skill.SkillNumber is FuriousSkillNumber); - var furiousSkillModifier = ConditionalModifiersList.SingleOrDefault(skill => skill.SkillId is FuriousSkillNumber); + var furiousSkill = this.SkillOrderList.SingleOrDefault(skill => skill.SkillNumber is FuriousSkillNumber); + var furiousSkillModifier = this.ConditionalModifiersList.SingleOrDefault(skill => skill.SkillId is FuriousSkillNumber); if (furiousSkill is not null && furiousSkillModifier is not null && furiousSkillModifier.Status) { var multiplier = (float)Math.Round(1 - (furiousSkillModifier.ActivationNumbers * (1 - furiousSkill.ConditionalModifiers["GMShotDelay"])), 2); @@ -360,8 +360,8 @@ public void LoadBuild(IEnumerable selectedSkills, string? captainIndex) } // Custom handling for Improved Repair Party Readiness Skill - var improvedRepairPartyReadinessSkill = SkillOrderList.SingleOrDefault(skill => skill.SkillNumber is ImprovedRepairPartyReadinessSkillNumber); - var improvedRepairPartyReadinessSkillModifier = ConditionalModifiersList.SingleOrDefault(skill => skill.SkillId is ImprovedRepairPartyReadinessSkillNumber); + var improvedRepairPartyReadinessSkill = this.SkillOrderList.SingleOrDefault(skill => skill.SkillNumber is ImprovedRepairPartyReadinessSkillNumber); + var improvedRepairPartyReadinessSkillModifier = this.ConditionalModifiersList.SingleOrDefault(skill => skill.SkillId is ImprovedRepairPartyReadinessSkillNumber); if (improvedRepairPartyReadinessSkill is not null && improvedRepairPartyReadinessSkillModifier is not null && improvedRepairPartyReadinessSkillModifier.Status) { float skillFactor = improvedRepairPartyReadinessSkill.ConditionalModifiers["regenCrewReloadCoeff"]; @@ -375,17 +375,17 @@ public void LoadBuild(IEnumerable selectedSkills, string? captainIndex) private IEnumerable<(string, float)> CollectTalentModifiers() { var modifiers = new List<(string, float)>(); - var talentModifiers = CaptainTalentsList.Where(talent => talent is { Status: true, MaximumActivations: <= 1 } && !talent.Modifiers.Any(modifier => modifier.Key.Equals("burnProbabilityBonus"))) + var talentModifiers = this.CaptainTalentsList.Where(talent => talent is { Status: true, MaximumActivations: <= 1 } && !talent.Modifiers.Any(modifier => modifier.Key.Equals("burnProbabilityBonus"))) .SelectMany(skill => skill.Modifiers) .Select(x => (x.Key, x.Value)); modifiers.AddRange(talentModifiers); - var talentMultipleActivationModifiers = CaptainTalentsList.Where(talent => talent is { Status: true, MaximumActivations: > 1 } && !talent.Modifiers.Any(modifier => modifier.Key.Equals("burnProbabilityBonus"))) + var talentMultipleActivationModifiers = this.CaptainTalentsList.Where(talent => talent is { Status: true, MaximumActivations: > 1 } && !talent.Modifiers.Any(modifier => modifier.Key.Equals("burnProbabilityBonus"))) .SelectMany(talent => talent.Modifiers.Select(modifier => (modifier.Key, Value: Math.Pow(modifier.Value, talent.ActivationNumbers)))) .Select(x => (x.Key, (float)x.Value)); modifiers.AddRange(talentMultipleActivationModifiers); - var talentFireChanceModifier = CaptainTalentsList.Where(talent => talent.Status && talent.Modifiers.Any(modifier => modifier.Key.Equals("burnProbabilityBonus"))) + var talentFireChanceModifier = this.CaptainTalentsList.Where(talent => talent.Status && talent.Modifiers.Any(modifier => modifier.Key.Equals("burnProbabilityBonus"))) .SelectMany(talent => talent.Modifiers.Select(modifier => (modifier.Key, Value: Math.Round(modifier.Value * talent.ActivationNumbers, 2)))) .Select(x => (x.Key, (float)x.Value)); modifiers.AddRange(talentFireChanceModifier); @@ -395,12 +395,12 @@ public void LoadBuild(IEnumerable selectedSkills, string? captainIndex) private void CaptainTalentsListOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { - TalentOrConditionalSkillEnabled = (showArHpSelection && ArHpPercentage < 100) || CaptainTalentsList.Any(talent => talent.Status); + this.TalentOrConditionalSkillEnabled = (this.showArHpSelection && this.ArHpPercentage < 100) || this.CaptainTalentsList.Any(talent => talent.Status); } private void ConditionalModifiersListOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { - TalentOrConditionalSkillEnabled = (showArHpSelection && ArHpPercentage < 100) || ConditionalModifiersList.Any(skill => skill.Status); + this.TalentOrConditionalSkillEnabled = (this.showArHpSelection && this.ArHpPercentage < 100) || this.ConditionalModifiersList.Any(skill => skill.Status); } /// @@ -411,13 +411,13 @@ private void ConditionalModifiersListOnCollectionChanged(object? sender, NotifyC /// A dictionary containing the skill for the class from the captain. private Dictionary ConvertSkillToViewModel(ShipClass shipClass, Captain? captain) { - logger.LogDebug("Getting skill for class {ShipClass} from captain {CaptainName}", shipClass.ToString(), captain!.Name); + this.logger.LogDebug("Getting skill for class {ShipClass} from captain {CaptainName}", shipClass.ToString(), captain!.Name); var skills = captain.Skills; var filteredSkills = skills.Where(x => x.Value.LearnableOn.Contains(shipClass)).ToList(); - var dictionary = filteredSkills.ToDictionary(x => x.Key, x => new SkillItemViewModel(x.Value, this, shipClass, canAddSkillCache, canRemoveSkillCache)); - logger.LogDebug("Found {SkillCount} skills", dictionary.Count); + var dictionary = filteredSkills.ToDictionary(x => x.Key, x => new SkillItemViewModel(x.Value, this, shipClass, this.canAddSkillCache, this.canRemoveSkillCache)); + this.logger.LogDebug("Found {SkillCount} skills", dictionary.Count); return dictionary; } @@ -427,14 +427,14 @@ private Dictionary ConvertSkillToViewModel(ShipClass /// private void UpdateCanAddSkill() { - if (SkillList == null) + if (this.SkillList == null) { return; } - canAddSkillCache.Clear(); - canRemoveSkillCache.Clear(); - foreach (KeyValuePair skill in SkillList) + this.canAddSkillCache.Clear(); + this.canRemoveSkillCache.Clear(); + foreach (KeyValuePair skill in this.SkillList) { skill.Value.CanExecuteChanged(); } @@ -442,7 +442,7 @@ private void UpdateCanAddSkill() private SkillActivationItemViewModel CreateItemViewModelForSkill(Skill skill) { - var skillName = SkillList!.Single(x => x.Value.Skill.Equals(skill)).Key; + var skillName = this.SkillList!.Single(x => x.Value.Skill.Equals(skill)).Key; SkillActivationItemViewModel result; if (skill.SkillNumber is FuriousSkillNumber) { @@ -466,35 +466,35 @@ private SkillActivationItemViewModel CreateItemViewModelForSkill(Skill skill) /// private void ReorderSkillList() { - if (SkillOrderList.Count == 0) + if (this.SkillOrderList.Count == 0) { return; } - logger.LogDebug("Reordering skills"); + this.logger.LogDebug("Reordering skills"); - var groups = SkillOrderList.GroupBy(skill => skill.Tiers.First(x => x.ShipClass == currentClass).Tier) + var groups = this.SkillOrderList.GroupBy(skill => skill.Tiers.First(x => x.ShipClass == this.currentClass).Tier) .Select(x => x.ToList()) .ToList() - .OrderBy(x => x[0].Tiers.First(skillPosition => skillPosition.ShipClass == currentClass).Tier) + .OrderBy(x => x[0].Tiers.First(skillPosition => skillPosition.ShipClass == this.currentClass).Tier) .ToList(); // Tier 0 skill reordering - ReorderTier0Skills(groups[0]); + this.ReorderTier0Skills(groups[0]); // Tier 1 skill reordering if (groups.Count > 2) { - ReorderTierSkills(groups[1], 1); + this.ReorderTierSkills(groups[1], 1); } // Tier 2 skill reordering if (groups.Count > 3) { - ReorderTierSkills(groups[2], 2); + this.ReorderTierSkills(groups[2], 2); } - logger.LogDebug("Finished reordering skills"); + this.logger.LogDebug("Finished reordering skills"); } private void ReorderTier0Skills(List tier0Skills) @@ -502,7 +502,7 @@ private void ReorderTier0Skills(List tier0Skills) var tier0SkillsFirst = false; foreach (var tier0Skill in tier0Skills) { - if (SkillOrderList.IndexOf(tier0Skill) == 0) + if (this.SkillOrderList.IndexOf(tier0Skill) == 0) { tier0SkillsFirst = true; } @@ -511,21 +511,21 @@ private void ReorderTier0Skills(List tier0Skills) if (!tier0SkillsFirst) { var firstTier0Skill = tier0Skills[0]; - SkillOrderList.Remove(firstTier0Skill); - SkillOrderList.Insert(0, firstTier0Skill); + this.SkillOrderList.Remove(firstTier0Skill); + this.SkillOrderList.Insert(0, firstTier0Skill); } } private void ReorderTierSkills(List tierSkills, int skillTier) { - var firstPrevTierSkillIndex = SkillOrderList.FindIndex(skill => skill.Tiers.First(x => x.ShipClass == currentClass).Tier == skillTier - 1); - var firstHigherTierSkillIndex = SkillOrderList.FindIndex(skill => skill.Tiers.First(x => x.ShipClass == currentClass).Tier > skillTier); + var firstPrevTierSkillIndex = this.SkillOrderList.FindIndex(skill => skill.Tiers.First(x => x.ShipClass == this.currentClass).Tier == skillTier - 1); + var firstHigherTierSkillIndex = this.SkillOrderList.FindIndex(skill => skill.Tiers.First(x => x.ShipClass == this.currentClass).Tier > skillTier); var currentTierSkillFirst = false; foreach (var skill in tierSkills) { - if (SkillOrderList.IndexOf(skill) > firstPrevTierSkillIndex && SkillOrderList.IndexOf(skill) < firstHigherTierSkillIndex) + if (this.SkillOrderList.IndexOf(skill) > firstPrevTierSkillIndex && this.SkillOrderList.IndexOf(skill) < firstHigherTierSkillIndex) { currentTierSkillFirst = true; } @@ -534,8 +534,8 @@ private void ReorderTierSkills(List tierSkills, int skillTier) if (!currentTierSkillFirst) { var skill = tierSkills[0]; - SkillOrderList.Remove(skill); - SkillOrderList.Insert(firstHigherTierSkillIndex, skill); + this.SkillOrderList.Remove(skill); + this.SkillOrderList.Insert(firstHigherTierSkillIndex, skill); } } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableSlotViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableSlotViewModel.cs index 85570c0e6..3077b7a27 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableSlotViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableSlotViewModel.cs @@ -29,44 +29,44 @@ private ConsumableSlotViewModel(IEnumerable shipConsumables, Act this.activationChangeHandler = activationChangeHandler; this.logger = logger; this.shipConsumables = new(shipConsumables); - Slot = this.shipConsumables[0].Slot; + this.Slot = this.shipConsumables[0].Slot; } public int Slot { get; } public List ConsumableData { - get => consumableData; + get => this.consumableData; set { - this.RaiseAndSetIfChanged(ref consumableData, value); - this.RaisePropertyChanged(nameof(SelectedIndex)); // Necessary to update index for selection popup + this.RaiseAndSetIfChanged(ref this.consumableData, value); + this.RaisePropertyChanged(nameof(this.SelectedIndex)); // Necessary to update index for selection popup } } public int SelectedIndex { - get => selectedIndex; + get => this.selectedIndex; set { - this.RaiseAndSetIfChanged(ref selectedIndex, value); - this.RaisePropertyChanged(nameof(SelectedConsumable)); - logger.LogDebug("Selected consumable changed to index {Index}", value); - ConsumableActivated = false; + this.RaiseAndSetIfChanged(ref this.selectedIndex, value); + this.RaisePropertyChanged(nameof(this.SelectedConsumable)); + this.logger.LogDebug("Selected consumable changed to index {Index}", value); + this.ConsumableActivated = false; } } public bool ConsumableActivated { - get => consumableActivated; + get => this.consumableActivated; set { - this.RaiseAndSetIfChanged(ref consumableActivated, value); - activationChangeHandler?.Invoke(Slot, value); + this.RaiseAndSetIfChanged(ref this.consumableActivated, value); + this.activationChangeHandler?.Invoke(this.Slot, value); } } - public ConsumableDataContainer SelectedConsumable => ConsumableData[SelectedIndex]; + public ConsumableDataContainer SelectedConsumable => this.ConsumableData[this.SelectedIndex]; public static ConsumableSlotViewModel Create(IEnumerable shipConsumables, ILoggerFactory loggerFactory, ShipClass shipClass, Action? activationChangeHandler = null) { @@ -77,7 +77,7 @@ public static ConsumableSlotViewModel Create(IEnumerable shipCon public void UpdateDataContainers(List<(string, float)> modifiers, int shipHp, ShipClass shipClass) { - var dataContainers = shipConsumables.Select(c => ConsumableDataContainer.FromTypeAndVariant(c, modifiers, false, shipHp, shipClass)); - ConsumableData = dataContainers.ToList(); + var dataContainers = this.shipConsumables.Select(c => ConsumableDataContainer.FromTypeAndVariant(c, modifiers, false, shipHp, shipClass)); + this.ConsumableData = dataContainers.ToList(); } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableViewModel.cs index 77f5c2b37..4ed76d9a2 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ConsumableViewModel.cs @@ -28,7 +28,7 @@ private ConsumableViewModel(Ship ship, ILogger logger) { this.ship = ship; this.logger = logger; - ConsumableSlots = new(); + this.ConsumableSlots = new(); } /// @@ -57,7 +57,7 @@ public static ConsumableViewModel Create(Ship ship, IEnumerable disabled public void LoadBuild(IEnumerable storedData) { - foreach (var slotViewModel in ConsumableSlots) + foreach (var slotViewModel in this.ConsumableSlots) { var index = slotViewModel.ConsumableData.FindIndex(consumable => storedData.Any(s => consumable.IconName.StartsWith(s, StringComparison.OrdinalIgnoreCase))); if (index > -1) @@ -69,7 +69,7 @@ public void LoadBuild(IEnumerable storedData) public List SaveBuild() { - return ConsumableSlots.Select(slot => slot.SelectedConsumable.IconName).ToList(); + return this.ConsumableSlots.Select(slot => slot.SelectedConsumable.IconName).ToList(); } /// @@ -81,15 +81,15 @@ public List SaveBuild() /// The class of the ship. public void UpdateConsumableData(List<(string, float)> modifiers, int shipHp, ShipClass shipClass) { - Parallel.ForEach(ConsumableSlots, consumableSlot => consumableSlot.UpdateDataContainers(modifiers, shipHp, shipClass)); + Parallel.ForEach(this.ConsumableSlots, consumableSlot => consumableSlot.UpdateDataContainers(modifiers, shipHp, shipClass)); } public IEnumerable<(string, float)> GetModifiersList() { var modifiers = new List<(string, float)>(); - foreach (int slot in ActivatedSlots) + foreach (int slot in this.ActivatedSlots) { - var consumable = ConsumableSlots[slot].SelectedConsumable; + var consumable = this.ConsumableSlots[slot].SelectedConsumable; if (consumable.Name.Contains("PCY015")) { modifiers.AddRange(consumable.Modifiers.Select(entry => ("speedBoost_" + entry.Key, entry.Value))); @@ -109,27 +109,27 @@ public void UpdateConsumableData(List<(string, float)> modifiers, int shipHp, Sh private void UpdateSlotViewModels(IEnumerable disabledConsumables) { - var rawSlots = ship.ShipConsumable.GroupBy(consumable => consumable.Slot) + var rawSlots = this.ship.ShipConsumable.GroupBy(consumable => consumable.Slot) .Select(group => group.Where(c => !disabledConsumables.Contains(c.ConsumableName))) .Where(consumables => consumables.Any()) - .Select(consumables => ConsumableSlotViewModel.Create(consumables, Logging.LoggerFactory, ship.ShipClass, ConsumableActivationChanged)) + .Select(consumables => ConsumableSlotViewModel.Create(consumables, Logging.LoggerFactory, this.ship.ShipClass, this.ConsumableActivationChanged)) .OrderBy(vm => vm.Slot); - ConsumableSlots.Clear(); - ConsumableSlots.AddRange(rawSlots); + this.ConsumableSlots.Clear(); + this.ConsumableSlots.AddRange(rawSlots); } private void ConsumableActivationChanged(int slot, bool activationState) { if (activationState) { - logger.LogDebug("Consumable slot {Slot} activated", slot); - ActivatedSlots.Add(slot); + this.logger.LogDebug("Consumable slot {Slot} activated", slot); + this.ActivatedSlots.Add(slot); } else { - logger.LogDebug("Consumable slot {Slot} deactivated", slot); - ActivatedSlots.Remove(slot); + this.logger.LogDebug("Consumable slot {Slot} deactivated", slot); + this.ActivatedSlots.Remove(slot); } } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipModuleViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipModuleViewModel.cs index 6beadf59c..63ec8d4cf 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipModuleViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipModuleViewModel.cs @@ -34,19 +34,19 @@ public ShipModuleViewModel() public ShipModuleViewModel(UpgradeInfo upgradeInfo) { - ShipUpgrades = ShipModuleHelper.GroupAndSortUpgrades(upgradeInfo.ShipUpgrades).OrderBy(entry => entry.Key).Select(entry => entry.Value).ToList(); - foreach (List upgrade in ShipUpgrades) + this.ShipUpgrades = ShipModuleHelper.GroupAndSortUpgrades(upgradeInfo.ShipUpgrades).OrderBy(entry => entry.Key).Select(entry => entry.Value).ToList(); + foreach (List upgrade in this.ShipUpgrades) { - SelectedModules.Add(upgrade[0]); + this.SelectedModules.Add(upgrade[0]); } } public List> ShipUpgrades { - get => shipUpgrades; + get => this.shipUpgrades; set { - shipUpgrades = value; + this.shipUpgrades = value; this.RaisePropertyChanged(); } } @@ -55,38 +55,38 @@ public List> ShipUpgrades public void SelectModuleExecute(ShipUpgrade parameter) { - if (SelectedModules.Contains(parameter)) + if (this.SelectedModules.Contains(parameter)) { return; } - ShipUpgrade? oldItem = SelectedModules.FirstOrDefault(module => module.UcType == parameter.UcType); + ShipUpgrade? oldItem = this.SelectedModules.FirstOrDefault(module => module.UcType == parameter.UcType); if (oldItem != null) { - SelectedModules.Replace(oldItem, parameter); + this.SelectedModules.Replace(oldItem, parameter); } else { - SelectedModules.Add(parameter); + this.SelectedModules.Add(parameter); } } public void LoadBuild(IEnumerable storedData) { var results = new List(); - foreach (List upgradeList in ShipUpgrades) + foreach (List upgradeList in this.ShipUpgrades) { results.AddRange(upgradeList.Where(upgrade => storedData.Contains(upgrade.Name.NameToIndex()))); } - var modulesToRemove = SelectedModules.Where(module => results.Exists(newSelection => newSelection.UcType == module.UcType)).ToList(); - SelectedModules.RemoveMany(modulesToRemove); - SelectedModules.AddRange(results); + var modulesToRemove = this.SelectedModules.Where(module => results.Exists(newSelection => newSelection.UcType == module.UcType)).ToList(); + this.SelectedModules.RemoveMany(modulesToRemove); + this.SelectedModules.AddRange(results); } public List SaveBuild() { - return SelectedModules.Select(upgrade => upgrade.Name.NameToIndex()).ToList(); + return this.SelectedModules.Select(upgrade => upgrade.Name.NameToIndex()).ToList(); } } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipStatsControlViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipStatsControlViewModel.cs index 9d43db56c..7fde30dd1 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipStatsControlViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipStatsControlViewModel.cs @@ -10,13 +10,13 @@ public class ShipStatsControlViewModel : ReactiveObject public ShipStatsControlViewModel(Ship ship) { - BaseShipStats = ship; + this.BaseShipStats = ship; } public ShipDataContainer? CurrentShipStats { - get => currentShipStats; - set => this.RaiseAndSetIfChanged(ref currentShipStats, value); + get => this.currentShipStats; + set => this.RaiseAndSetIfChanged(ref this.currentShipStats, value); } // this is the ship base stats. do not modify after creation @@ -24,7 +24,7 @@ public ShipDataContainer? CurrentShipStats public async Task UpdateShipStats(List selectedConfiguration, List<(string, float)> modifiers) { - ShipDataContainer shipStats = await Task.Run(() => ShipDataContainer.CreateFromShip(BaseShipStats, selectedConfiguration, modifiers)); - CurrentShipStats = shipStats; + ShipDataContainer shipStats = await Task.Run(() => ShipDataContainer.CreateFromShip(this.BaseShipStats, selectedConfiguration, modifiers)); + this.CurrentShipStats = shipStats; } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipViewModel.cs index 24f992c37..687b0b225 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/ShipViewModel.cs @@ -65,101 +65,101 @@ public sealed partial class ShipViewModel : ReactiveObject public ShipViewModel(ILogger logger, ShipViewModelParams viewModelParams) { - tokenSource = new(); + this.tokenSource = new(); this.logger = logger; - PreviousShip = viewModelParams.ShipSummary.PrevShipIndex is null ? null : AppData.ShipSummaryMapper[viewModelParams.ShipSummary.PrevShipIndex]; - CurrentShip = viewModelParams.ShipSummary; + this.PreviousShip = viewModelParams.ShipSummary.PrevShipIndex is null ? null : AppData.ShipSummaryMapper[viewModelParams.ShipSummary.PrevShipIndex]; + this.CurrentShip = viewModelParams.ShipSummary; } public void ResetBuild() { - logger.LogDebug("Resetting build"); - LoadNewShip(AppData.ShipSummaryMapper[CurrentShipIndex]); + this.logger.LogDebug("Resetting build"); + this.LoadNewShip(AppData.ShipSummaryMapper[this.CurrentShipIndex]); } public void InitializeData(ShipViewModelParams viewModelParams) { - InitializeData(viewModelParams.Ship, viewModelParams.ShipSummary.PrevShipIndex, viewModelParams.ShipSummary.NextShipsIndex, viewModelParams.Build); + this.InitializeData(viewModelParams.Ship, viewModelParams.ShipSummary.PrevShipIndex, viewModelParams.ShipSummary.NextShipsIndex, viewModelParams.Build); } public Build CreateBuild(string buildName) { - return new(buildName, CurrentShipIndex, RawShipData.ShipNation, ShipModuleViewModel.SaveBuild(), UpgradePanelViewModel.SaveBuild(), ConsumableViewModel.SaveBuild(), CaptainSkillSelectorViewModel!.GetCaptainIndex(), CaptainSkillSelectorViewModel!.GetSkillNumberList(), SignalSelectorViewModel!.GetFlagList()); + return new(buildName, this.CurrentShipIndex, this.RawShipData.ShipNation, this.ShipModuleViewModel.SaveBuild(), this.UpgradePanelViewModel.SaveBuild(), this.ConsumableViewModel.SaveBuild(), this.CaptainSkillSelectorViewModel!.GetCaptainIndex(), this.CaptainSkillSelectorViewModel!.GetSkillNumberList(), this.SignalSelectorViewModel!.GetFlagList()); } private void LoadNewShip(ShipSummary summary) { - disposables.Clear(); + this.disposables.Clear(); var ship = AppData.FindShipFromSummary(summary); - InitializeData(ship, summary.PrevShipIndex, summary.NextShipsIndex); + this.InitializeData(ship, summary.PrevShipIndex, summary.NextShipsIndex); } private void InitializeData(Ship ship, string? previousIndex, List? nextShipsIndexes, Build? build = null) { - logger.LogInformation("Loading data for ship {Index}", ship.Index); - logger.LogDebug("Build is null: {BuildIsNull}", build is null); + this.logger.LogInformation("Loading data for ship {Index}", ship.Index); + this.logger.LogDebug("Build is null: {BuildIsNull}", build is null); // Ship stats model - RawShipData = ship; - EffectiveShipData = RawShipData; + this.RawShipData = ship; + this.EffectiveShipData = this.RawShipData; - logger.LogDebug("Initializing view models"); + this.logger.LogDebug("Initializing view models"); // Viewmodel inits - SignalSelectorViewModel = new(); - CaptainSkillSelectorViewModel = new(RawShipData.ShipClass, CaptainSkillSelectorViewModel.LoadParams(ship.ShipNation)); - ShipModuleViewModel = new(RawShipData.ShipUpgradeInfo); - UpgradePanelViewModel = new(RawShipData, AppData.ModernizationCache); - ConsumableViewModel = ConsumableViewModel.Create(RawShipData, new List(), Logging.LoggerFactory); + this.SignalSelectorViewModel = new(); + this.CaptainSkillSelectorViewModel = new(this.RawShipData.ShipClass, CaptainSkillSelectorViewModel.LoadParams(ship.ShipNation)); + this.ShipModuleViewModel = new(this.RawShipData.ShipUpgradeInfo); + this.UpgradePanelViewModel = new(this.RawShipData, AppData.ModernizationCache); + this.ConsumableViewModel = ConsumableViewModel.Create(this.RawShipData, new List(), Logging.LoggerFactory); - ShipStatsControlViewModel = new(EffectiveShipData); + this.ShipStatsControlViewModel = new(this.EffectiveShipData); if (build != null) { - logger.LogDebug("Loading build"); - SignalSelectorViewModel.LoadBuild(build.Signals); - CaptainSkillSelectorViewModel.LoadBuild(build.Skills, build.Captain); - ShipModuleViewModel.LoadBuild(build.Modules); - UpgradePanelViewModel.LoadBuild(build.Upgrades); - ConsumableViewModel.LoadBuild(build.Consumables); + this.logger.LogDebug("Loading build"); + this.SignalSelectorViewModel.LoadBuild(build.Signals); + this.CaptainSkillSelectorViewModel.LoadBuild(build.Skills, build.Captain); + this.ShipModuleViewModel.LoadBuild(build.Modules); + this.UpgradePanelViewModel.LoadBuild(build.Upgrades); + this.ConsumableViewModel.LoadBuild(build.Consumables); } - CurrentShipIndex = ship.Index; - CurrentShipTier = ship.Tier; - CurrentShip = AppData.ShipSummaryMapper[ship.Index]; - PreviousShip = previousIndex is null ? null : AppData.ShipSummaryMapper[previousIndex]; - NextShips = nextShipsIndexes?.Select(index => AppData.ShipSummaryMapper[index]).ToList(); + this.CurrentShipIndex = ship.Index; + this.CurrentShipTier = ship.Tier; + this.CurrentShip = AppData.ShipSummaryMapper[ship.Index]; + this.PreviousShip = previousIndex is null ? null : AppData.ShipSummaryMapper[previousIndex]; + this.NextShips = nextShipsIndexes?.Select(index => AppData.ShipSummaryMapper[index]).ToList(); - AddChangeListeners(); - UpdateStatsViewModel(true); + this.AddChangeListeners(); + this.UpdateStatsViewModel(true); } private void AddChangeListeners() { - ShipModuleViewModel.SelectedModules.ToObservableChangeSet().Do(_ => UpdateStatsViewModel()).Subscribe().DisposeWith(disposables); - UpgradePanelViewModel.SelectedModernizationList.ToObservableChangeSet().Do(_ => UpdateStatsViewModel()).Subscribe().DisposeWith(disposables); - SignalSelectorViewModel?.SelectedSignals.ToObservableChangeSet().Do(_ => UpdateStatsViewModel()).Subscribe().DisposeWith(disposables); - CaptainSkillSelectorViewModel?.SkillOrderList.ToObservableChangeSet().Do(_ => UpdateStatsViewModel()).Subscribe().DisposeWith(disposables); - ConsumableViewModel.ActivatedSlots.ToObservableChangeSet().Do(_ => UpdateStatsViewModel()).Subscribe().DisposeWith(disposables); - - CaptainSkillSelectorViewModel.WhenAnyValue(x => x.SkillActivationPopupOpen).Subscribe(HandleCaptainParamsChange).DisposeWith(disposables); - CaptainSkillSelectorViewModel.WhenAnyValue(x => x.CaptainWithTalents).Subscribe(HandleCaptainParamsChange).DisposeWith(disposables); + this.ShipModuleViewModel.SelectedModules.ToObservableChangeSet().Do(_ => this.UpdateStatsViewModel()).Subscribe().DisposeWith(this.disposables); + this.UpgradePanelViewModel.SelectedModernizationList.ToObservableChangeSet().Do(_ => this.UpdateStatsViewModel()).Subscribe().DisposeWith(this.disposables); + this.SignalSelectorViewModel?.SelectedSignals.ToObservableChangeSet().Do(_ => this.UpdateStatsViewModel()).Subscribe().DisposeWith(this.disposables); + this.CaptainSkillSelectorViewModel?.SkillOrderList.ToObservableChangeSet().Do(_ => this.UpdateStatsViewModel()).Subscribe().DisposeWith(this.disposables); + this.ConsumableViewModel.ActivatedSlots.ToObservableChangeSet().Do(_ => this.UpdateStatsViewModel()).Subscribe().DisposeWith(this.disposables); + + this.CaptainSkillSelectorViewModel.WhenAnyValue(x => x.SkillActivationPopupOpen).Subscribe(this.HandleCaptainParamsChange).DisposeWith(this.disposables); + this.CaptainSkillSelectorViewModel.WhenAnyValue(x => x.CaptainWithTalents).Subscribe(this.HandleCaptainParamsChange).DisposeWith(this.disposables); } private void HandleCaptainParamsChange(bool newValue) { if (!newValue) { - UpdateStatsViewModel(); + this.UpdateStatsViewModel(); } } private void UpdateStatsViewModel(bool skipDelay = false) { - tokenSource.Cancel(); - tokenSource.Dispose(); - tokenSource = new(); - CancellationToken token = tokenSource.Token; + this.tokenSource.Cancel(); + this.tokenSource.Dispose(); + this.tokenSource = new(); + CancellationToken token = this.tokenSource.Token; Task.Run( async () => { @@ -172,16 +172,16 @@ private void UpdateStatsViewModel(bool skipDelay = false) if (!token.IsCancellationRequested) { - await semaphore.WaitAsync(token); - var modifiers = GenerateModifierList(); - if (ShipStatsControlViewModel != null) + await this.semaphore.WaitAsync(token); + var modifiers = this.GenerateModifierList(); + if (this.ShipStatsControlViewModel != null) { - logger.LogDebug("Updating ship stats"); - await ShipStatsControlViewModel.UpdateShipStats(ShipModuleViewModel.SelectedModules.ToList(), modifiers); + this.logger.LogDebug("Updating ship stats"); + await this.ShipStatsControlViewModel.UpdateShipStats(this.ShipModuleViewModel.SelectedModules.ToList(), modifiers); } - ConsumableViewModel.UpdateConsumableData(modifiers, ShipStatsControlViewModel!.CurrentShipStats!.SurvivabilityDataContainer.HitPoints, RawShipData.ShipClass); - semaphore.Release(); + this.ConsumableViewModel.UpdateConsumableData(modifiers, this.ShipStatsControlViewModel!.CurrentShipStats!.SurvivabilityDataContainer.HitPoints, this.RawShipData.ShipClass); + this.semaphore.Release(); } } catch (OperationCanceledException) @@ -196,10 +196,10 @@ private void UpdateStatsViewModel(bool skipDelay = false) { var modifiers = new List<(string, float)>(); - modifiers.AddRange(UpgradePanelViewModel.GetModifierList()); - modifiers.AddRange(SignalSelectorViewModel!.GetModifierList()); - modifiers.AddRange(CaptainSkillSelectorViewModel!.GetModifiersList()); - modifiers.AddRange(ConsumableViewModel.GetModifiersList()); + modifiers.AddRange(this.UpgradePanelViewModel.GetModifierList()); + modifiers.AddRange(this.SignalSelectorViewModel!.GetModifierList()); + modifiers.AddRange(this.CaptainSkillSelectorViewModel!.GetModifiersList()); + modifiers.AddRange(this.ConsumableViewModel.GetModifiersList()); return modifiers; } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SignalSelectorViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SignalSelectorViewModel.cs index 3a767c5a6..4f91be269 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SignalSelectorViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SignalSelectorViewModel.cs @@ -16,18 +16,18 @@ public class SignalSelectorViewModel : ReactiveObject public SignalSelectorViewModel() { - logger = Logging.LoggerFactory.CreateLogger(); - SignalList = LoadSignalList(); + this.logger = Logging.LoggerFactory.CreateLogger(); + this.SignalList = LoadSignalList(); - this.WhenAnyValue(x => x.SignalsNumber).Do(_ => UpdateCanToggleSkill()).Subscribe(); + this.WhenAnyValue(x => x.SignalsNumber).Do(_ => this.UpdateCanToggleSkill()).Subscribe(); } public List> SignalList { get; } public int SignalsNumber { - get => signalsNumber; - set => this.RaiseAndSetIfChanged(ref signalsNumber, value); + get => this.signalsNumber; + set => this.RaiseAndSetIfChanged(ref this.signalsNumber, value); } public CustomObservableCollection SelectedSignals { get; } = new(); @@ -48,41 +48,41 @@ private static List> LoadSignalList() public void SignalCommandExecute(Exterior flag) { - if (SelectedSignals.Contains(flag)) + if (this.SelectedSignals.Contains(flag)) { - SelectedSignals.Remove(flag); - SignalsNumber--; + this.SelectedSignals.Remove(flag); + this.SignalsNumber--; } else { - SelectedSignals.Add(flag); - SignalsNumber++; + this.SelectedSignals.Add(flag); + this.SignalsNumber++; } } public List<(string, float)> GetModifierList() { - return SelectedSignals.SelectMany(m => m.Modifiers.Select(effect => (effect.Key, (float)effect.Value))).ToList(); + return this.SelectedSignals.SelectMany(m => m.Modifiers.Select(effect => (effect.Key, (float)effect.Value))).ToList(); } public List GetFlagList() { - return SelectedSignals.Select(signal => signal.Index).ToList(); + return this.SelectedSignals.Select(signal => signal.Index).ToList(); } public void LoadBuild(IReadOnlyList initialSignalsNames) { - logger.LogInformation("Initial signal configuration found {SignalNames}", string.Join(", ", initialSignalsNames)); - var list = SignalList.Select(x => x.Value.Signal).Where(signal => initialSignalsNames.Contains(signal.Index)); - SelectedSignals.AddRange(list); - SignalsNumber = SelectedSignals.Count; + this.logger.LogInformation("Initial signal configuration found {SignalNames}", string.Join(", ", initialSignalsNames)); + var list = this.SignalList.Select(x => x.Value.Signal).Where(signal => initialSignalsNames.Contains(signal.Index)); + this.SelectedSignals.AddRange(list); + this.SignalsNumber = this.SelectedSignals.Count; } private void UpdateCanToggleSkill() { - foreach (var (_, value) in SignalList) + foreach (var (_, value) in this.SignalList) { - value.CanExecute = CheckSignalCommandExecute(value.Signal); + value.CanExecute = this.CheckSignalCommandExecute(value.Signal); } } @@ -93,7 +93,7 @@ private bool CheckSignalCommandExecute(object parameter) return false; } - return SelectedSignals.Contains(flag) || SignalsNumber < 8; + return this.SelectedSignals.Contains(flag) || this.SignalsNumber < 8; } } @@ -103,14 +103,14 @@ public class SignalItemViewModel : ReactiveObject public SignalItemViewModel(Exterior exterior) { - Signal = exterior; + this.Signal = exterior; } public Exterior Signal { get; } public bool CanExecute { - get => canExecute; - set => this.RaiseAndSetIfChanged(ref canExecute, value); + get => this.canExecute; + set => this.RaiseAndSetIfChanged(ref this.canExecute, value); } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SkillActivationItemViewModel.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SkillActivationItemViewModel.cs index c89f218cb..cc0d92bd5 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SkillActivationItemViewModel.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/SkillActivationItemViewModel.cs @@ -16,13 +16,13 @@ public partial class SkillActivationItemViewModel : ReactiveObject public SkillActivationItemViewModel(string name, int skillId, Dictionary modifiers, bool activationStatus, int maximumActivations = 0, int activationNumbers = 1, string description = "") { - SkillName = name; - Status = activationStatus; - SkillId = skillId; - MaximumActivations = maximumActivations; - ActivationNumbers = activationNumbers; - Modifiers = modifiers; - Description = description; + this.SkillName = name; + this.Status = activationStatus; + this.SkillId = skillId; + this.MaximumActivations = maximumActivations; + this.ActivationNumbers = activationNumbers; + this.Modifiers = modifiers; + this.Description = description; } public Dictionary Modifiers { get; } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/UpgradePanelViewModelBase.cs b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/UpgradePanelViewModelBase.cs index 31af8636e..5ca9dd932 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/UpgradePanelViewModelBase.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/ViewModels/UpgradePanelViewModelBase.cs @@ -34,25 +34,25 @@ public UpgradePanelViewModelBase(Ship ship, Dictionary up subList.Insert(0, PlaceholderModernization); } - AvailableModernizationList = groupedList; - SelectedModernizationList = new(AvailableModernizationList.Select(list => list[0]).Where(m => !string.IsNullOrEmpty(m.Index))); + this.AvailableModernizationList = groupedList; + this.SelectedModernizationList = new(this.AvailableModernizationList.Select(list => list[0]).Where(m => !string.IsNullOrEmpty(m.Index))); - OnModernizationSelected = (modernization, modernizationList) => + this.OnModernizationSelected = (modernization, modernizationList) => { - int listIndex = AvailableModernizationList.IndexOf(modernizationList); - var oldSelection = SelectedModernizationList.ToList().Find(m => AvailableModernizationList[listIndex].Contains(m)); + int listIndex = this.AvailableModernizationList.IndexOf(modernizationList); + var oldSelection = this.SelectedModernizationList.ToList().Find(m => this.AvailableModernizationList[listIndex].Contains(m)); if (oldSelection != null) { - SelectedModernizationList.Remove(oldSelection); + this.SelectedModernizationList.Remove(oldSelection); } if (modernization?.Index != null) { - SelectedModernizationList.Add(modernization); + this.SelectedModernizationList.Add(modernization); } - this.RaisePropertyChanged(nameof(SelectedModernizationList)); + this.RaisePropertyChanged(nameof(this.SelectedModernizationList)); }; } @@ -62,13 +62,13 @@ public UpgradePanelViewModelBase(Ship ship, Dictionary up public List> AvailableModernizationList { - get => availableModernizationList; - set => this.RaiseAndSetIfChanged(ref availableModernizationList, value); + get => this.availableModernizationList; + set => this.RaiseAndSetIfChanged(ref this.availableModernizationList, value); } public List<(string, float)> GetModifierList() { - var modifiers = SelectedModernizationList + var modifiers = this.SelectedModernizationList .Where(m => !string.IsNullOrEmpty(m.Index)) .SelectMany(m => m.Effect.Select(effect => (effect.Key, (float)effect.Value))) .ToList(); @@ -80,19 +80,19 @@ public List> AvailableModernizationList public void LoadBuild(IEnumerable storedData) { var selection = new List(); - foreach (List modernizations in AvailableModernizationList) + foreach (List modernizations in this.AvailableModernizationList) { selection.AddRange(modernizations.Where(modernization => storedData.Contains(modernization.Index))); } - var removeList = SelectedModernizationList.Where(selected => selection.Exists(newSelected => newSelected.Slot == selected.Slot)).ToList(); - SelectedModernizationList.RemoveMany(removeList); - SelectedModernizationList.AddRange(selection); - this.RaisePropertyChanged(nameof(SelectedModernizationList)); + var removeList = this.SelectedModernizationList.Where(selected => selection.Exists(newSelected => newSelected.Slot == selected.Slot)).ToList(); + this.SelectedModernizationList.RemoveMany(removeList); + this.SelectedModernizationList.AddRange(selection); + this.RaisePropertyChanged(nameof(this.SelectedModernizationList)); } public List SaveBuild() { - return SelectedModernizationList.Select(modernization => modernization.Index).ToList(); + return this.SelectedModernizationList.Select(modernization => modernization.Index).ToList(); } } diff --git a/WoWsShipBuilder.Common/Features/ShipStats/VmCache.cs b/WoWsShipBuilder.Common/Features/ShipStats/VmCache.cs index a0c97f301..8673240b3 100644 --- a/WoWsShipBuilder.Common/Features/ShipStats/VmCache.cs +++ b/WoWsShipBuilder.Common/Features/ShipStats/VmCache.cs @@ -8,13 +8,13 @@ public class VmCache public VmCacheEntry? this[Guid id] { - get => cacheEntries.GetValueOrDefault(id, default); - set => cacheEntries[id] = value; + get => this.cacheEntries.GetValueOrDefault(id, default); + set => this.cacheEntries[id] = value; } - public VmCacheEntry? GetOrDefault(Guid id) => cacheEntries.GetValueOrDefault(id, default); + public VmCacheEntry? GetOrDefault(Guid id) => this.cacheEntries.GetValueOrDefault(id, default); - public bool RemoveEntry(Guid id) => cacheEntries.Remove(id); + public bool RemoveEntry(Guid id) => this.cacheEntries.Remove(id); } public sealed record VmCacheEntry(ShipViewModel ViewModel, string BuildName = ""); diff --git a/WoWsShipBuilder.Common/Infrastructure/DataTransfer/SessionStateCache.cs b/WoWsShipBuilder.Common/Infrastructure/DataTransfer/SessionStateCache.cs index a9b359ce0..f7259317b 100644 --- a/WoWsShipBuilder.Common/Infrastructure/DataTransfer/SessionStateCache.cs +++ b/WoWsShipBuilder.Common/Infrastructure/DataTransfer/SessionStateCache.cs @@ -11,18 +11,18 @@ public class SessionStateCache public List? GetAndResetBuildTransferContainers() { - var result = buildTransferContainers; - buildTransferContainers = null; + var result = this.buildTransferContainers; + this.buildTransferContainers = null; return result; } public void SetBuildTransferContainers(List containers) { - buildTransferContainers = containers; + this.buildTransferContainers = containers; } public void SetBuildTransferContainers(ShipBuildContainer container) { - buildTransferContainers = new() { container }; + this.buildTransferContainers = new() { container }; } } diff --git a/WoWsShipBuilder.Common/Infrastructure/DataTransfer/ShipBuildContainer.cs b/WoWsShipBuilder.Common/Infrastructure/DataTransfer/ShipBuildContainer.cs index 458c76ee0..dd67025b6 100644 --- a/WoWsShipBuilder.Common/Infrastructure/DataTransfer/ShipBuildContainer.cs +++ b/WoWsShipBuilder.Common/Infrastructure/DataTransfer/ShipBuildContainer.cs @@ -24,32 +24,32 @@ public static ShipBuildContainer CreateNew(Ship ship, Build? build, IEnumerable< /// if all relevant properties have the same value, otherwise. public bool IsEquivalentTo(ShipBuildContainer newContainer) { - if (Ship.Index != newContainer.Ship.Index) + if (this.Ship.Index != newContainer.Ship.Index) { return false; } - if (Build is null && newContainer.Build is not null) + if (this.Build is null && newContainer.Build is not null) { return false; } - if (Build is not null && !Build.Equals(newContainer.Build)) + if (this.Build is not null && !this.Build.Equals(newContainer.Build)) { return false; } - if (SpecialAbilityActive != newContainer.SpecialAbilityActive) + if (this.SpecialAbilityActive != newContainer.SpecialAbilityActive) { return false; } - if ((ActivatedConsumableSlots is null && newContainer.ActivatedConsumableSlots is not null) || (ActivatedConsumableSlots is not null && newContainer.ActivatedConsumableSlots is null)) + if ((this.ActivatedConsumableSlots is null && newContainer.ActivatedConsumableSlots is not null) || (this.ActivatedConsumableSlots is not null && newContainer.ActivatedConsumableSlots is null)) { return false; } - IOrderedEnumerable oldConsumables = (ActivatedConsumableSlots ?? Enumerable.Empty()).OrderBy(i => i); + IOrderedEnumerable oldConsumables = (this.ActivatedConsumableSlots ?? Enumerable.Empty()).OrderBy(i => i); IOrderedEnumerable newConsumables = (newContainer.ActivatedConsumableSlots ?? Enumerable.Empty()).OrderBy(i => i); return oldConsumables.SequenceEqual(newConsumables); } diff --git a/WoWsShipBuilder.Common/Infrastructure/Localization/LocalizationProvider.cs b/WoWsShipBuilder.Common/Infrastructure/Localization/LocalizationProvider.cs index b4b42fd8c..2bba6e1ba 100644 --- a/WoWsShipBuilder.Common/Infrastructure/Localization/LocalizationProvider.cs +++ b/WoWsShipBuilder.Common/Infrastructure/Localization/LocalizationProvider.cs @@ -19,14 +19,14 @@ public async Task RefreshDataAsync(ServerType serverType, params CultureDetails[ { foreach (var culture in supportedCultures) { - var cultureLocalization = await appDataService.ReadLocalizationData(serverType, culture.LocalizationFileName) ?? throw new InvalidOperationException("Localization data not found"); - localizationData[culture] = cultureLocalization; + var cultureLocalization = await this.appDataService.ReadLocalizationData(serverType, culture.LocalizationFileName) ?? throw new InvalidOperationException("Localization data not found"); + this.localizationData[culture] = cultureLocalization; } } public string? GetString(string key, CultureDetails cultureDetails) { - if (!localizationData.TryGetValue(cultureDetails, out Dictionary? cultureLocalization)) + if (!this.localizationData.TryGetValue(cultureDetails, out Dictionary? cultureLocalization)) { return null; } diff --git a/WoWsShipBuilder.Common/Infrastructure/Localization/Localizer.cs b/WoWsShipBuilder.Common/Infrastructure/Localization/Localizer.cs index 0d8881c76..ee687603a 100644 --- a/WoWsShipBuilder.Common/Infrastructure/Localization/Localizer.cs +++ b/WoWsShipBuilder.Common/Infrastructure/Localization/Localizer.cs @@ -16,23 +16,23 @@ public Localizer(ILocalizationProvider gameLocalizationProvider, AppSettings app this.appSettings = appSettings; } - public LocalizationResult this[string key] => GetGameLocalization(key); + public LocalizationResult this[string key] => this.GetGameLocalization(key); public LocalizationResult GetGameLocalization(string key) { - string? result = gameLocalizationProvider.GetString(key, appSettings.SelectedLanguage); + string? result = this.gameLocalizationProvider.GetString(key, this.appSettings.SelectedLanguage); return new(result != null, result ?? key); } public LocalizationResult GetGameLocalization(string key, CultureDetails language) { - string? result = gameLocalizationProvider.GetString(key, language); + string? result = this.gameLocalizationProvider.GetString(key, language); return new(result != null, result ?? key); } public LocalizationResult GetAppLocalization(string key) { - string? result = Translation.ResourceManager.GetString(key, appSettings.SelectedLanguage.CultureInfo); + string? result = Translation.ResourceManager.GetString(key, this.appSettings.SelectedLanguage.CultureInfo); return new(result != null, result ?? key); } diff --git a/WoWsShipBuilder.Common/Infrastructure/Utility/CustomObservableCollection.cs b/WoWsShipBuilder.Common/Infrastructure/Utility/CustomObservableCollection.cs index 505559450..07ad7e87d 100644 --- a/WoWsShipBuilder.Common/Infrastructure/Utility/CustomObservableCollection.cs +++ b/WoWsShipBuilder.Common/Infrastructure/Utility/CustomObservableCollection.cs @@ -30,11 +30,11 @@ public void AddRange(IEnumerable items) { foreach (var item in itemList.SkipLast(1)) { - Items.Add(item); + this.Items.Add(item); } } - Add(itemList[^1]); + this.Add(itemList[^1]); } public void RemoveRange(IEnumerable items) @@ -49,16 +49,16 @@ public void RemoveRange(IEnumerable items) { foreach (var item in itemList.SkipLast(1)) { - Items.Remove(item); + this.Items.Remove(item); } } - Remove(itemList[^1]); + this.Remove(itemList[^1]); } public int FindIndex(Predicate match) { - int endIndex = Count; + int endIndex = this.Count; for (var i = 0; i < endIndex; i++) { if (match(this[i])) @@ -73,19 +73,19 @@ public int FindIndex(Predicate match) protected override void InsertItem(int index, T item) { base.InsertItem(index, item); - NotifyCountChanged(); + this.NotifyCountChanged(); } protected override void RemoveItem(int index) { base.RemoveItem(index); - NotifyCountChanged(); + this.NotifyCountChanged(); } protected override void ClearItems() { base.ClearItems(); - NotifyCountChanged(); + this.NotifyCountChanged(); } private void NotifyCountChanged() diff --git a/WoWsShipBuilder.Common/Infrastructure/Utility/RefreshNotifierService.cs b/WoWsShipBuilder.Common/Infrastructure/Utility/RefreshNotifierService.cs index 4719b0d05..a0249864e 100644 --- a/WoWsShipBuilder.Common/Infrastructure/Utility/RefreshNotifierService.cs +++ b/WoWsShipBuilder.Common/Infrastructure/Utility/RefreshNotifierService.cs @@ -4,5 +4,5 @@ public class RefreshNotifierService { public event Action? RefreshRequested; - public void NotifyRefreshRequested() => RefreshRequested?.Invoke(); + public void NotifyRefreshRequested() => this.RefreshRequested?.Invoke(); } diff --git a/WoWsShipBuilder.Desktop.Test/DesktopDataServiceTest.cs b/WoWsShipBuilder.Desktop.Test/DesktopDataServiceTest.cs index d4d620feb..7b923b3ab 100644 --- a/WoWsShipBuilder.Desktop.Test/DesktopDataServiceTest.cs +++ b/WoWsShipBuilder.Desktop.Test/DesktopDataServiceTest.cs @@ -16,8 +16,8 @@ public class DesktopDataServiceTest [SetUp] public void Setup() { - mockFileSystem = new(); - dataService = new DesktopDataService(mockFileSystem); + this.mockFileSystem = new(); + this.dataService = new DesktopDataService(this.mockFileSystem); } [Test] @@ -28,12 +28,12 @@ public void Store_DirectoryNotExisting_DirectoryCreated() const string customDataPath = "1234"; var testSettings = new AppSettings { AutoUpdateEnabled = false, CustomDataPath = customDataPath }; - dataService.Store(testSettings, settingsPath); + this.dataService.Store(testSettings, settingsPath); - mockFileSystem.FileExists(settingsPath).Should().BeTrue(); - mockFileSystem.Directory.Exists(settingsDirectory).Should().BeTrue(); + this.mockFileSystem.FileExists(settingsPath).Should().BeTrue(); + this.mockFileSystem.Directory.Exists(settingsDirectory).Should().BeTrue(); - var storedFile = mockFileSystem.File.ReadAllText(settingsPath); + var storedFile = this.mockFileSystem.File.ReadAllText(settingsPath); var storedSettings = JsonConvert.DeserializeObject(storedFile); storedSettings.Should().BeEquivalentTo(testSettings); } @@ -45,15 +45,15 @@ public async Task Store_FileAlreadyExists_FileReplaced() const string settingsPath = settingsDirectory + @"/settings.json"; const string customDataPath = "1234"; var testSettings = new AppSettings { AutoUpdateEnabled = false, CustomDataPath = customDataPath }; - mockFileSystem.AddFile(settingsPath, new(JsonConvert.SerializeObject(testSettings))); + this.mockFileSystem.AddFile(settingsPath, new(JsonConvert.SerializeObject(testSettings))); testSettings.AutoUpdateEnabled = true; - await dataService.StoreAsync(testSettings, settingsPath); + await this.dataService.StoreAsync(testSettings, settingsPath); - mockFileSystem.FileExists(settingsPath).Should().BeTrue(); - mockFileSystem.Directory.Exists(settingsDirectory).Should().BeTrue(); + this.mockFileSystem.FileExists(settingsPath).Should().BeTrue(); + this.mockFileSystem.Directory.Exists(settingsDirectory).Should().BeTrue(); - var storedFile = await mockFileSystem.File.ReadAllTextAsync(settingsPath); + var storedFile = await this.mockFileSystem.File.ReadAllTextAsync(settingsPath); var storedSettings = JsonConvert.DeserializeObject(storedFile); storedSettings.Should().BeEquivalentTo(testSettings); } diff --git a/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/CheckJsonFileVersions.cs b/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/CheckJsonFileVersions.cs index 354b496ec..f3160e92d 100644 --- a/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/CheckJsonFileVersions.cs +++ b/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/CheckJsonFileVersions.cs @@ -16,12 +16,12 @@ public partial class LocalDataUpdaterTest public async Task CheckJsonFileVersion_NoExistingData_AllFilesMarkedForDownload() { // Arrange - var testVersionInfo = CreateTestVersionInfo(1, new(Version.Parse("0.11.0"), GameVersionType.Live, 1)); - awsClientMock.Setup(x => x.DownloadVersionInfo(ServerType.Live)).ReturnsAsync(testVersionInfo); - mockFileSystem.AddDirectory(appDataHelper.Object.GetDataPath(ServerType.Live)); + var testVersionInfo = this.CreateTestVersionInfo(1, new(Version.Parse("0.11.0"), GameVersionType.Live, 1)); + this.awsClientMock.Setup(x => x.DownloadVersionInfo(ServerType.Live)).ReturnsAsync(testVersionInfo); + this.mockFileSystem.AddDirectory(this.appDataHelper.Object.GetDataPath(ServerType.Live)); // Act - var result = await new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, new(), NullLogger.Instance).CheckJsonFileVersions(ServerType.Live); + var result = await new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, new(), NullLogger.Instance).CheckJsonFileVersions(ServerType.Live); // Assert result.AvailableFileUpdates.Should() @@ -37,7 +37,7 @@ public async Task CheckJsonFileVersion_ExistingDataOneVersionDiff_IncrementalUpd // Arrange var currentVersion = new GameVersion(new(0, 10, 10), GameVersionType.Live, 1); var previousVersion = new GameVersion(new(0, 10, 9), GameVersionType.Live, 1); - var localVersionInfo = CreateTestVersionInfo(1, previousVersion); + var localVersionInfo = this.CreateTestVersionInfo(1, previousVersion); var testVersionInfo = new VersionInfo( new() { @@ -47,12 +47,12 @@ public async Task CheckJsonFileVersion_ExistingDataOneVersionDiff_IncrementalUpd 2, currentVersion, localVersionInfo.CurrentVersion); - awsClientMock.Setup(x => x.DownloadVersionInfo(ServerType.Live)).ReturnsAsync(testVersionInfo); - mockFileSystem.AddDirectory(appDataHelper.Object.GetDataPath(ServerType.Live)); - appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(localVersionInfo); + this.awsClientMock.Setup(x => x.DownloadVersionInfo(ServerType.Live)).ReturnsAsync(testVersionInfo); + this.mockFileSystem.AddDirectory(this.appDataHelper.Object.GetDataPath(ServerType.Live)); + this.appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(localVersionInfo); // Act - var result = await new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, new(), NullLogger.Instance).CheckJsonFileVersions(ServerType.Live); + var result = await new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, new(), NullLogger.Instance).CheckJsonFileVersions(ServerType.Live); // Assert result.AvailableFileUpdates.Should().HaveCount(2); @@ -65,13 +65,13 @@ public async Task CheckJsonFileVersion_ExistingDataOneVersionDiff_IncrementalUpd public async Task CheckJsonFileVersion_ExistingData_NoDownloads() { // Arrange - var testVersionInfo = CreateTestVersionInfo(1, new(Version.Parse("0.11.0"), GameVersionType.Live, 1)); - awsClientMock.Setup(x => x.DownloadVersionInfo(ServerType.Live)).ReturnsAsync(testVersionInfo); - mockFileSystem.AddDirectory(appDataHelper.Object.GetDataPath(ServerType.Live)); - appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(testVersionInfo); + var testVersionInfo = this.CreateTestVersionInfo(1, new(Version.Parse("0.11.0"), GameVersionType.Live, 1)); + this.awsClientMock.Setup(x => x.DownloadVersionInfo(ServerType.Live)).ReturnsAsync(testVersionInfo); + this.mockFileSystem.AddDirectory(this.appDataHelper.Object.GetDataPath(ServerType.Live)); + this.appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(testVersionInfo); // Act - var result = await new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, new(), NullLogger.Instance).CheckJsonFileVersions(ServerType.Live); + var result = await new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, new(), NullLogger.Instance).CheckJsonFileVersions(ServerType.Live); // Assert result.AvailableFileUpdates.Should().BeEmpty(); @@ -108,12 +108,12 @@ public async Task CheckJsonFileVersions_OneVersionDiffNewVersionNotSupported() { DataStructuresVersion = new(supportedDataVersion.Major, supportedDataVersion.Minor + 1, supportedDataVersion.Build), }; - awsClientMock.Setup(x => x.DownloadVersionInfo(ServerType.Live)).ReturnsAsync(testVersionInfo); - mockFileSystem.AddDirectory(appDataHelper.Object.GetDataPath(ServerType.Live)); - appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(localVersionInfo); + this.awsClientMock.Setup(x => x.DownloadVersionInfo(ServerType.Live)).ReturnsAsync(testVersionInfo); + this.mockFileSystem.AddDirectory(this.appDataHelper.Object.GetDataPath(ServerType.Live)); + this.appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(localVersionInfo); // Act - var result = await new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, new(), NullLogger.Instance).CheckJsonFileVersions(ServerType.Live); + var result = await new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, new(), NullLogger.Instance).CheckJsonFileVersions(ServerType.Live); // Assert result.AvailableFileUpdates.Should().BeEmpty(); diff --git a/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/LocalDataUpdaterTest.cs b/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/LocalDataUpdaterTest.cs index 7ddc2a50b..1d3fce396 100644 --- a/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/LocalDataUpdaterTest.cs +++ b/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/LocalDataUpdaterTest.cs @@ -21,10 +21,10 @@ public partial class LocalDataUpdaterTest [SetUp] public void Setup() { - mockFileSystem = new(); - awsClientMock = new(); - appDataHelper = new(); - appDataHelper.Setup(x => x.GetDataPath(ServerType.Live)).Returns(@"AppData/live"); + this.mockFileSystem = new(); + this.awsClientMock = new(); + this.appDataHelper = new(); + this.appDataHelper.Setup(x => x.GetDataPath(ServerType.Live)).Returns(@"AppData/live"); } private VersionInfo CreateTestVersionInfo(int versionCode, GameVersion gameVersion) diff --git a/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/ShouldUpdaterRun.cs b/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/ShouldUpdaterRun.cs index 337d53bc9..b1f3136b6 100644 --- a/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/ShouldUpdaterRun.cs +++ b/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/ShouldUpdaterRun.cs @@ -20,7 +20,7 @@ public async Task ShouldUpdaterRun_NoLastCheck_True() }; // Act - bool result = await new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, appSettings, NullLogger.Instance).ShouldUpdaterRun(ServerType.Live); + bool result = await new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, appSettings, NullLogger.Instance).ShouldUpdaterRun(ServerType.Live); // Assert result.Should().BeTrue(); @@ -34,10 +34,10 @@ public async Task ShouldUpdaterRun_LastCheckTwoHoursAgo_False() { LastDataUpdateCheck = DateTime.Now.Subtract(TimeSpan.FromHours(2)), }; - appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(CreateTestVersionInfo(1, GameVersion.Default)); + this.appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(this.CreateTestVersionInfo(1, GameVersion.Default)); // Act - bool result = await new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, appSettings, NullLogger.Instance).ShouldUpdaterRun(ServerType.Live); + bool result = await new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, appSettings, NullLogger.Instance).ShouldUpdaterRun(ServerType.Live); // Assert result.Should().BeFalse(); @@ -51,10 +51,10 @@ public async Task ShouldUpdaterRun_LocalVersionInfoNull_True() { LastDataUpdateCheck = DateTime.Now.Subtract(TimeSpan.FromHours(2)), }; - appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync((VersionInfo?)null); + this.appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync((VersionInfo?)null); // Act - bool result = await new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, appSettings, NullLogger.Instance).ShouldUpdaterRun(ServerType.Live); + bool result = await new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, appSettings, NullLogger.Instance).ShouldUpdaterRun(ServerType.Live); // Assert result.Should().BeTrue(); diff --git a/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/ValidateData.cs b/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/ValidateData.cs index 2fda762aa..d329090a9 100644 --- a/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/ValidateData.cs +++ b/WoWsShipBuilder.Desktop.Test/LocalDataUpdaterTests/ValidateData.cs @@ -14,7 +14,7 @@ public partial class LocalDataUpdaterTest public async Task ValidateData_NoLocalVersionInfo_False() { // Arrange - var updater = new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, new(), NullLogger.Instance); + var updater = new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, new(), NullLogger.Instance); // Act var result = await updater.ValidateData(ServerType.Live, @"json/live"); @@ -27,10 +27,10 @@ public async Task ValidateData_NoLocalVersionInfo_False() public async Task ValidateData_LocalVersionInfoNoFiles_False() { // Arrange - var versionInfo = CreateTestVersionInfo(1, GameVersion.Default); - appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(versionInfo); - mockFileSystem.AddDirectory(@"json/live/Ability"); - var updater = new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, new(), NullLogger.Instance); + var versionInfo = this.CreateTestVersionInfo(1, GameVersion.Default); + this.appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(versionInfo); + this.mockFileSystem.AddDirectory(@"json/live/Ability"); + var updater = new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, new(), NullLogger.Instance); // Act var result = await updater.ValidateData(ServerType.Live, @"json/live"); @@ -53,11 +53,11 @@ public async Task ValidateData_LocalVersionInfoAllFiles_True() }, versionCode, GameVersion.Default); - appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(versionInfo); - mockFileSystem.AddFile(@"json/live/Ability/Common.json", new("test")); - mockFileSystem.AddFile(@"json/live/Ship/Japan.json", new("test")); - mockFileSystem.AddFile(@"json/live/Ship/Germany.json", new("test")); - var updater = new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, new(), NullLogger.Instance); + this.appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(versionInfo); + this.mockFileSystem.AddFile(@"json/live/Ability/Common.json", new("test")); + this.mockFileSystem.AddFile(@"json/live/Ship/Japan.json", new("test")); + this.mockFileSystem.AddFile(@"json/live/Ship/Germany.json", new("test")); + var updater = new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, new(), NullLogger.Instance); // Act var result = await updater.ValidateData(ServerType.Live, @"json/live"); @@ -70,11 +70,11 @@ public async Task ValidateData_LocalVersionInfoAllFiles_True() public async Task ValidateData_LocalVersionInfoOneFileMissing_False() { // Arrange - var versionInfo = CreateTestVersionInfo(1, GameVersion.Default); - appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(versionInfo); - mockFileSystem.AddFile(@"json/live/Ability/Common.json", new MockFileData("test")); - mockFileSystem.AddFile(@"json/live/Ship/Japan.json", new MockFileData("test")); - var updater = new LocalDataUpdater(mockFileSystem, awsClientMock.Object, appDataHelper.Object, new(), NullLogger.Instance); + var versionInfo = this.CreateTestVersionInfo(1, GameVersion.Default); + this.appDataHelper.Setup(x => x.GetCurrentVersionInfo(ServerType.Live)).ReturnsAsync(versionInfo); + this.mockFileSystem.AddFile(@"json/live/Ability/Common.json", new MockFileData("test")); + this.mockFileSystem.AddFile(@"json/live/Ship/Japan.json", new MockFileData("test")); + var updater = new LocalDataUpdater(this.mockFileSystem, this.awsClientMock.Object, this.appDataHelper.Object, new(), NullLogger.Instance); // Act var result = await updater.ValidateData(ServerType.Live, @"json/live"); diff --git a/WoWsShipBuilder.Desktop/Common/AppHeader.axaml.cs b/WoWsShipBuilder.Desktop/Common/AppHeader.axaml.cs index 0b5d56ec6..18a04215d 100644 --- a/WoWsShipBuilder.Desktop/Common/AppHeader.axaml.cs +++ b/WoWsShipBuilder.Desktop/Common/AppHeader.axaml.cs @@ -25,47 +25,47 @@ public partial class AppHeader : UserControl public AppHeader() { - InitializeComponent(); + this.InitializeComponent(); } public bool ShowTitle { - get => GetValue(ShowTitleProperty); - set => SetValue(ShowTitleProperty, value); + get => this.GetValue(ShowTitleProperty); + set => this.SetValue(ShowTitleProperty, value); } public string Title { - get => GetValue(TitleProperty); - set => SetValue(TitleProperty, value); + get => this.GetValue(TitleProperty); + set => this.SetValue(TitleProperty, value); } public bool ShowMinimizeButton { - get => GetValue(ShowMinimizeButtonProperty); - set => SetValue(ShowMinimizeButtonProperty, value); + get => this.GetValue(ShowMinimizeButtonProperty); + set => this.SetValue(ShowMinimizeButtonProperty, value); } public bool ShowMaximizeButton { - get => GetValue(ShowMaximizeButtonProperty); - set => SetValue(ShowMaximizeButtonProperty, value); + get => this.GetValue(ShowMaximizeButtonProperty); + set => this.SetValue(ShowMaximizeButtonProperty, value); } public bool ShowCloseButton { - get => GetValue(ShowCloseButtonProperty); - set => SetValue(ShowCloseButtonProperty, value); + get => this.GetValue(ShowCloseButtonProperty); + set => this.SetValue(ShowCloseButtonProperty, value); } protected override void OnLoaded(RoutedEventArgs e) { base.OnLoaded(e); - MinimizeButton.Click += MinimizeWindow; - MaximizeButton.Click += MaximizeWindow; - CloseButton.Click += CloseWindow; + this.MinimizeButton.Click += this.MinimizeWindow; + this.MaximizeButton.Click += this.MaximizeWindow; + this.CloseButton.Click += this.CloseWindow; - SubscribeToWindowState(); + this.SubscribeToWindowState(); } private void CloseWindow(object? sender, RoutedEventArgs e) @@ -75,7 +75,7 @@ private void CloseWindow(object? sender, RoutedEventArgs e) return; } - Window hostWindow = (Window)VisualRoot!; + Window hostWindow = (Window)this.VisualRoot!; hostWindow.Close(); } @@ -86,7 +86,7 @@ private void MaximizeWindow(object? sender, RoutedEventArgs e) return; } - Window hostWindow = (Window)VisualRoot!; + Window hostWindow = (Window)this.VisualRoot!; if (hostWindow.WindowState == WindowState.Normal) { @@ -105,17 +105,17 @@ private void MinimizeWindow(object? sender, RoutedEventArgs e) return; } - Window hostWindow = (Window)VisualRoot!; + Window hostWindow = (Window)this.VisualRoot!; hostWindow.WindowState = WindowState.Minimized; } private async void SubscribeToWindowState() { - var hostWindow = (Window?)VisualRoot; + var hostWindow = (Window?)this.VisualRoot; while (hostWindow == null) { - hostWindow = (Window)VisualRoot!; + hostWindow = (Window)this.VisualRoot!; await Task.Delay(50); } @@ -123,13 +123,13 @@ private async void SubscribeToWindowState() { if (s != WindowState.Maximized) { - MaximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 2048v-2048h-2048v2048h2048zM1843 1843h-1638v-1638h1638v1638z"); + this.MaximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 2048v-2048h-2048v2048h2048zM1843 1843h-1638v-1638h1638v1638z"); hostWindow.Padding = new Thickness(0, 0, 0, 0); } if (s == WindowState.Maximized) { - MaximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 1638h-410v410h-1638v-1638h410v-410h1638v1638zm-614-1024h-1229v1229h1229v-1229zm409-409h-1229v205h1024v1024h205v-1229z"); + this.MaximizeIcon.Data = Avalonia.Media.Geometry.Parse("M2048 1638h-410v410h-1638v-1638h410v-410h1638v1638zm-614-1024h-1229v1229h1229v-1229zm409-409h-1229v205h1024v1024h205v-1229z"); // This should be a more universal approach in both cases, but I found it to be less reliable, when for example double-clicking the title bar. hostWindow.Padding = new Thickness( diff --git a/WoWsShipBuilder.Desktop/Features/BlazorWebView/BlazorWindow.axaml.cs b/WoWsShipBuilder.Desktop/Features/BlazorWebView/BlazorWindow.axaml.cs index edcb0e55d..27082b32e 100644 --- a/WoWsShipBuilder.Desktop/Features/BlazorWebView/BlazorWindow.axaml.cs +++ b/WoWsShipBuilder.Desktop/Features/BlazorWebView/BlazorWindow.axaml.cs @@ -21,12 +21,12 @@ public BlazorWindow() new("#app", typeof(DesktopRootComponent), null), }; - Resources.Add("services", services); - Resources.Add("rootComponents", rootComponents); + this.Resources.Add("services", services); + this.Resources.Add("rootComponents", rootComponents); var settings = services!.GetRequiredService(); var dataService = services!.GetRequiredService(); - Resources.Add("downloadPath", settings.CustomImagePath ?? dataService.CombinePaths(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), AppConstants.ShipBuilderName)); + this.Resources.Add("downloadPath", settings.CustomImagePath ?? dataService.CombinePaths(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), AppConstants.ShipBuilderName)); - InitializeComponent(); + this.InitializeComponent(); } } diff --git a/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml.cs b/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml.cs index 00a0a5e9d..567371e5f 100644 --- a/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml.cs +++ b/WoWsShipBuilder.Desktop/Features/MessageBox/MessageBox.axaml.cs @@ -11,7 +11,7 @@ public partial class MessageBox : Window { public MessageBox() { - InitializeComponent(); + this.InitializeComponent(); } public enum MessageBoxButtons diff --git a/WoWsShipBuilder.Desktop/Features/SplashScreen/SplashScreen.axaml.cs b/WoWsShipBuilder.Desktop/Features/SplashScreen/SplashScreen.axaml.cs index 29c8946e1..b9d27a78a 100644 --- a/WoWsShipBuilder.Desktop/Features/SplashScreen/SplashScreen.axaml.cs +++ b/WoWsShipBuilder.Desktop/Features/SplashScreen/SplashScreen.axaml.cs @@ -18,10 +18,10 @@ public partial class SplashScreen : ReactiveWindow { public SplashScreen(IServiceProvider services) { - InitializeComponent(services.GetRequiredService()); + this.InitializeComponent(services.GetRequiredService()); this.WhenActivated(_ => { - var vm = ViewModel ?? services.GetRequiredService(); + var vm = this.ViewModel ?? services.GetRequiredService(); Task.Run(async () => { @@ -63,7 +63,7 @@ await Dispatcher.UIThread.InvokeAsync(() => private void InitializeComponent(SplashScreenViewModel viewModel) { - InitializeComponent(); - ViewModel = viewModel; + this.InitializeComponent(); + this.ViewModel = viewModel; } } diff --git a/WoWsShipBuilder.Desktop/Features/SplashScreen/SplashScreenViewModel.cs b/WoWsShipBuilder.Desktop/Features/SplashScreen/SplashScreenViewModel.cs index a635a0225..4021c57d6 100644 --- a/WoWsShipBuilder.Desktop/Features/SplashScreen/SplashScreenViewModel.cs +++ b/WoWsShipBuilder.Desktop/Features/SplashScreen/SplashScreenViewModel.cs @@ -48,30 +48,30 @@ public SplashScreenViewModel(ILocalDataUpdater localDataUpdater, ILocalizationPr public async Task VersionCheck(bool forceVersionCheck = false, bool throwOnException = false) { - logger.LogDebug("Checking gamedata versions..."); + this.logger.LogDebug("Checking gamedata versions..."); IProgress<(int, string)> progressTracker = new Progress<(int state, string title)>(value => { // ReSharper disable once PossibleLossOfFraction - Progress = value.state * 100 / TaskNumber; - DownloadInfo = value.title; + this.Progress = value.state * 100 / TaskNumber; + this.DownloadInfo = value.title; }); try { - await localDataUpdater.RunDataUpdateCheck(appSettings.SelectedServerType, progressTracker, forceVersionCheck); - await localizationProvider.RefreshDataAsync(appSettings.SelectedServerType, appSettings.SelectedLanguage); - await appDataService.LoadLocalFilesAsync(appSettings.SelectedServerType); - logger.LogDebug("Version check and update tasks completed. Launching main window"); + await this.localDataUpdater.RunDataUpdateCheck(this.appSettings.SelectedServerType, progressTracker, forceVersionCheck); + await this.localizationProvider.RefreshDataAsync(this.appSettings.SelectedServerType, this.appSettings.SelectedLanguage); + await this.appDataService.LoadLocalFilesAsync(this.appSettings.SelectedServerType); + this.logger.LogDebug("Version check and update tasks completed. Launching main window"); } catch (Exception e) { if (throwOnException) { - logger.LogWarning(e, "Encountered unexpected exception during version check"); + this.logger.LogWarning(e, "Encountered unexpected exception during version check"); throw; } - logger.LogError(e, "Encountered unexpected exception during version check"); + this.logger.LogError(e, "Encountered unexpected exception during version check"); } progressTracker.Report((TaskNumber, nameof(Translation.SplashScreen_Done))); diff --git a/WoWsShipBuilder.Desktop/Features/Updater/LocalDataUpdater.cs b/WoWsShipBuilder.Desktop/Features/Updater/LocalDataUpdater.cs index cdb9d0699..a5620aa8f 100644 --- a/WoWsShipBuilder.Desktop/Features/Updater/LocalDataUpdater.cs +++ b/WoWsShipBuilder.Desktop/Features/Updater/LocalDataUpdater.cs @@ -55,54 +55,54 @@ public LocalDataUpdater(IFileSystem fileSystem, IDesktopAwsClient awsClient, IAp /// A representing the asynchronous operation. public async Task RunDataUpdateCheck(ServerType serverType, IProgress<(int, string)> progressTracker, bool overrideDateCheck = false) { - logger.LogInformation("UpdateCheck triggered. Checking whether update should execute..."); - if (!overrideDateCheck && !await ShouldUpdaterRun(serverType)) + this.logger.LogInformation("UpdateCheck triggered. Checking whether update should execute..."); + if (!overrideDateCheck && !await this.ShouldUpdaterRun(serverType)) { - logger.LogInformation("Skipping update check"); + this.logger.LogInformation("Skipping update check"); } else { - logger.LogInformation("Starting update check..."); - await CheckFilesAndDownloadUpdates(serverType, progressTracker); - logger.LogInformation("Completed update check"); + this.logger.LogInformation("Starting update check..."); + await this.CheckFilesAndDownloadUpdates(serverType, progressTracker); + this.logger.LogInformation("Completed update check"); } - logger.LogInformation("Checking installed localization files..."); - await CheckInstalledLocalizations(serverType); - logger.LogInformation("Starting data validation..."); - string dataBasePath = appDataService.GetDataPath(serverType); - var validation = await ValidateData(serverType, dataBasePath); + this.logger.LogInformation("Checking installed localization files..."); + await this.CheckInstalledLocalizations(serverType); + this.logger.LogInformation("Starting data validation..."); + string dataBasePath = this.appDataService.GetDataPath(serverType); + var validation = await this.ValidateData(serverType, dataBasePath); if (!validation.ValidationStatus) { - logger.LogInformation("Data validation failed. Selecting repair method..."); + this.logger.LogInformation("Data validation failed. Selecting repair method..."); if (validation.InvalidFiles != null) { - logger.LogInformation("List of corrupted files found. Attempting partial repair..."); - await awsClient.DownloadFiles(serverType, validation.InvalidFiles.ToList()); + this.logger.LogInformation("List of corrupted files found. Attempting partial repair..."); + await this.awsClient.DownloadFiles(serverType, validation.InvalidFiles.ToList()); } else { - logger.LogInformation("No list of corrupted files found. Attempting clean reload of gamedata..."); - fileSystem.Directory.Delete(dataBasePath, true); - await CheckFilesAndDownloadUpdates(serverType, progressTracker); + this.logger.LogInformation("No list of corrupted files found. Attempting clean reload of gamedata..."); + this.fileSystem.Directory.Delete(dataBasePath, true); + await this.CheckFilesAndDownloadUpdates(serverType, progressTracker); } - validation = await ValidateData(serverType, dataBasePath); + validation = await this.ValidateData(serverType, dataBasePath); if (!validation.ValidationStatus) { - logger.LogError("Invalid application data after data reload detected"); + this.logger.LogError("Invalid application data after data reload detected"); } else { - logger.LogInformation("Application data has been repaired and validated"); + this.logger.LogInformation("Application data has been repaired and validated"); } } else { - logger.LogInformation("Data validation successful"); + this.logger.LogInformation("Data validation successful"); } - logger.LogInformation("Completed update check run"); + this.logger.LogInformation("Completed update check run"); } /// @@ -113,15 +113,15 @@ public async Task RunDataUpdateCheck(ServerType serverType, IProgress<(int, stri /// A representing the asynchronous operation. public async Task UpdateLocalization(ServerType serverType) { - var installedLocales = await appDataService.GetInstalledLocales(serverType); + var installedLocales = await this.appDataService.GetInstalledLocales(serverType); - if (!installedLocales.Contains(appSettings.SelectedLanguage.LocalizationFileName + ".json")) + if (!installedLocales.Contains(this.appSettings.SelectedLanguage.LocalizationFileName + ".json")) { - installedLocales.Add(appSettings.SelectedLanguage.LocalizationFileName + ".json"); + installedLocales.Add(this.appSettings.SelectedLanguage.LocalizationFileName + ".json"); } var downloadList = installedLocales.Select(locale => ("Localization", locale)).ToList(); - await awsClient.DownloadFiles(serverType, downloadList); + await this.awsClient.DownloadFiles(serverType, downloadList); } /// @@ -132,9 +132,9 @@ public async Task UpdateLocalization(ServerType serverType) /// A containing the results of the version check. public async Task CheckJsonFileVersions(ServerType serverType) { - logger.LogInformation("Checking json file versions for server type {ServerType}", serverType.DisplayName()); - VersionInfo onlineVersionInfo = await awsClient.DownloadVersionInfo(serverType); - VersionInfo? localVersionInfo = await appDataService.GetCurrentVersionInfo(serverType); + this.logger.LogInformation("Checking json file versions for server type {ServerType}", serverType.DisplayName()); + VersionInfo onlineVersionInfo = await this.awsClient.DownloadVersionInfo(serverType); + VersionInfo? localVersionInfo = await this.appDataService.GetCurrentVersionInfo(serverType); List<(string, string)> filesToDownload; bool shouldImagesUpdate; @@ -144,7 +144,7 @@ public async Task CheckJsonFileVersions(ServerType serverType if (localVersionInfo == null) { // Local version info file being null means it does not exist or could not be found. Always requires a full data download. - logger.LogInformation("No local version info found. Downloading full data and flagging images for full update"); + this.logger.LogInformation("No local version info found. Downloading full data and flagging images for full update"); filesToDownload = onlineVersionInfo.Categories .SelectMany(category => category.Value.Select(file => (category.Key, file.FileName))) .ToList(); @@ -154,7 +154,7 @@ public async Task CheckJsonFileVersions(ServerType serverType } else if (localVersionInfo.CurrentVersionCode < onlineVersionInfo.CurrentVersionCode) { - logger.LogInformation( + this.logger.LogInformation( "Local data version ({CurrentVersionLocal}) is older than online data version ({CurrentVersionOnline}). Selecting files for update...", localVersionInfo.CurrentVersionCode, onlineVersionInfo.CurrentVersionCode); @@ -165,7 +165,7 @@ public async Task CheckJsonFileVersions(ServerType serverType localVersionInfo.Categories.TryGetValue(category, out var localCategoryFiles); if (localCategoryFiles == null) { - logger.LogInformation("Category {Category} not found in local version info file. Adding category to download list", category); + this.logger.LogInformation("Category {Category} not found in local version info file. Adding category to download list", category); filesToDownload.AddRange(fileVersions.Select(file => (category, file.FileName))); continue; } @@ -190,7 +190,7 @@ public async Task CheckJsonFileVersions(ServerType serverType } catch (Exception) { - logger.LogError( + this.logger.LogError( "Unable to strip suffix from a version name. Local version name: {LocalVersion}, Online version name: {OnlineVersion}", localVersionInfo.CurrentVersion, onlineVersionInfo.CurrentVersion); @@ -213,22 +213,19 @@ public async Task CheckJsonFileVersions(ServerType serverType var versionName = onlineVersionInfo.CurrentVersion.MainVersion.ToString(3); - if (SupportedDataStructureVersion.Major < onlineVersionInfo.DataStructuresVersion.Major || SupportedDataStructureVersion.Minor < onlineVersionInfo.DataStructuresVersion.Minor) + if (this.SupportedDataStructureVersion.Major < onlineVersionInfo.DataStructuresVersion.Major || this.SupportedDataStructureVersion.Minor < onlineVersionInfo.DataStructuresVersion.Minor) { - logger.LogWarning( - "Online data is incompatible with this application version. Online data version: {}, maximum supported version: {}", - SupportedDataStructureVersion, - onlineVersionInfo.DataStructuresVersion); + this.logger.LogWarning("Online data is incompatible with this application version. Online data version: {}, maximum supported version: {}", this.SupportedDataStructureVersion, onlineVersionInfo.DataStructuresVersion); return new(new(), false, false, false, versionName, serverType); } - if (SupportedDataStructureVersion.Build != onlineVersionInfo.DataStructuresVersion.Build) + if (this.SupportedDataStructureVersion.Build != onlineVersionInfo.DataStructuresVersion.Build) { - logger.LogWarning("The build version of the online data is different to the currently supported version. Some data may be unavailable"); + this.logger.LogWarning("The build version of the online data is different to the currently supported version. Some data may be unavailable"); } - else if (SupportedDataStructureVersion.Major > onlineVersionInfo.DataStructuresVersion.Major || SupportedDataStructureVersion.Minor > onlineVersionInfo.DataStructuresVersion.Minor) + else if (this.SupportedDataStructureVersion.Major > onlineVersionInfo.DataStructuresVersion.Major || this.SupportedDataStructureVersion.Minor > onlineVersionInfo.DataStructuresVersion.Minor) { - logger.LogWarning("Online data version is behind the currently supported data version. Loading data may crash the application"); + this.logger.LogWarning("Online data version is behind the currently supported data version. Loading data may crash the application"); } return new(filesToDownload, shouldImagesUpdate, canImagesDeltaUpdate, shouldLocalizationUpdate, versionName, serverType); @@ -244,10 +241,10 @@ public async Task CheckJsonFileVersions(ServerType serverType /// if the local data matches the structure of the version info file, otherwise. public async Task ValidateData(ServerType serverType, string dataBasePath) { - var versionInfo = await appDataService.GetCurrentVersionInfo(serverType); + var versionInfo = await this.appDataService.GetCurrentVersionInfo(serverType); if (versionInfo == null) { - logger.LogError("VersionInfo does not exist. AppData validation failed"); + this.logger.LogError("VersionInfo does not exist. AppData validation failed"); return new(false); } @@ -255,14 +252,14 @@ public async Task ValidateData(ServerType serverType, string d var categoryFiles = versionInfo.Categories.SelectMany(category => category.Value.Select(file => (category.Key, file))); foreach ((string category, var file) in categoryFiles) { - string path = fileSystem.Path.Combine(dataBasePath, category, file.FileName); - if (!fileSystem.File.Exists(path)) + string path = this.fileSystem.Path.Combine(dataBasePath, category, file.FileName); + if (!this.fileSystem.File.Exists(path)) { missingFiles.Add((category, file.FileName)); continue; } - await using var fs = fileSystem.File.OpenRead(path); + await using var fs = this.fileSystem.File.OpenRead(path); string hash = FileVersion.ComputeChecksum(fs); if (!hash.Equals(file.Checksum)) { @@ -275,7 +272,7 @@ public async Task ValidateData(ServerType serverType, string d return new(true); } - logger.LogWarning("Missing files during data validation. These files were missing: {MissingFiles}", string.Join(", ", missingFiles)); + this.logger.LogWarning("Missing files during data validation. These files were missing: {MissingFiles}", string.Join(", ", missingFiles)); return new(false) { InvalidFiles = missingFiles }; } @@ -287,23 +284,23 @@ public async Task ValidateData(ServerType serverType, string d public async Task ShouldUpdaterRun(ServerType serverType) { var today = DateTime.Today; - return appSettings.LastDataUpdateCheck == null || (today - appSettings.LastDataUpdateCheck).Value.TotalDays > 1 || - await appDataService.GetCurrentVersionInfo(serverType) == null; + return this.appSettings.LastDataUpdateCheck == null || (today - this.appSettings.LastDataUpdateCheck).Value.TotalDays > 1 || + await this.appDataService.GetCurrentVersionInfo(serverType) == null; } public async Task CheckInstalledLocalizations(ServerType serverType) { - List installedLocales = await appDataService.GetInstalledLocales(serverType, false); - if (!installedLocales.Contains(appSettings.SelectedLanguage.LocalizationFileName)) + List installedLocales = await this.appDataService.GetInstalledLocales(serverType, false); + if (!installedLocales.Contains(this.appSettings.SelectedLanguage.LocalizationFileName)) { - logger.LogInformation("Selected localization is not installed. Downloading file..."); - string localizationFile = appSettings.SelectedLanguage.LocalizationFileName + ".json"; - await awsClient.DownloadFiles(serverType, new() { ("Localization", localizationFile) }); - logger.LogInformation("Downloaded localization file for selected localization. Updating localizer data..."); + this.logger.LogInformation("Selected localization is not installed. Downloading file..."); + string localizationFile = this.appSettings.SelectedLanguage.LocalizationFileName + ".json"; + await this.awsClient.DownloadFiles(serverType, new() { ("Localization", localizationFile) }); + this.logger.LogInformation("Downloaded localization file for selected localization. Updating localizer data..."); } else { - logger.LogInformation("Selected localization is installed"); + this.logger.LogInformation("Selected localization is installed"); } } @@ -314,24 +311,24 @@ public async Task CheckInstalledLocalizations(ServerType serverType) /// An used to monitor the progress of the update. private async Task CheckFilesAndDownloadUpdates(ServerType serverType, IProgress<(int, string)> progressTracker) { - UpdateCheckResult checkResult = await CheckJsonFileVersions(serverType); + UpdateCheckResult checkResult = await this.CheckJsonFileVersions(serverType); if (checkResult.AvailableFileUpdates.Any()) { - logger.LogInformation("Updating {AvailableUpdateCount} files...", checkResult.AvailableFileUpdates.Count); + this.logger.LogInformation("Updating {AvailableUpdateCount} files...", checkResult.AvailableFileUpdates.Count); progressTracker.Report((1, nameof(Translation.SplashScreen_Json))); - await awsClient.DownloadFiles(serverType, checkResult.AvailableFileUpdates); + await this.awsClient.DownloadFiles(serverType, checkResult.AvailableFileUpdates); } if (checkResult.ShouldLocalizationUpdate) { - logger.LogInformation("Updating installed localizations..."); - await UpdateLocalization(serverType); + this.logger.LogInformation("Updating installed localizations..."); + await this.UpdateLocalization(serverType); } if (checkResult.ShouldImagesUpdate) { - logger.LogInformation("Updating images. Can delta update: {CanImagesDeltaUpdate}", checkResult.CanImagesDeltaUpdate); - await ImageUpdate(progressTracker, checkResult.CanImagesDeltaUpdate, checkResult.DataVersionName); + this.logger.LogInformation("Updating images. Can delta update: {CanImagesDeltaUpdate}", checkResult.CanImagesDeltaUpdate); + await this.ImageUpdate(progressTracker, checkResult.CanImagesDeltaUpdate, checkResult.DataVersionName); } } @@ -343,17 +340,17 @@ private async Task CheckFilesAndDownloadUpdates(ServerType serverType, IProgress /// The version name of the new image data, needs to be identical to the WG version name. private async Task ImageUpdate(IProgress<(int, string)> progressTracker, bool canDeltaUpdate, string? versionName) { - string imageBasePath = appDataService.AppDataImageDirectory; - var shipImageDirectory = fileSystem.DirectoryInfo.New(fileSystem.Path.Combine(imageBasePath, "Ships")); + string imageBasePath = this.appDataService.AppDataImageDirectory; + var shipImageDirectory = this.fileSystem.DirectoryInfo.New(this.fileSystem.Path.Combine(imageBasePath, "Ships")); if (!shipImageDirectory.Exists || !shipImageDirectory.GetFiles().Any() || !canDeltaUpdate) { progressTracker.Report((2, nameof(Translation.SplashScreen_ShipImages))); - await awsClient.DownloadImages(fileSystem); + await this.awsClient.DownloadImages(this.fileSystem); } else { progressTracker.Report((2, nameof(Translation.SplashScreen_ShipImages))); - await awsClient.DownloadImages(fileSystem, versionName); + await this.awsClient.DownloadImages(this.fileSystem, versionName); } } } diff --git a/WoWsShipBuilder.Desktop/Infrastructure/AppNotificationService.cs b/WoWsShipBuilder.Desktop/Infrastructure/AppNotificationService.cs index 02bdd367a..73105ba73 100644 --- a/WoWsShipBuilder.Desktop/Infrastructure/AppNotificationService.cs +++ b/WoWsShipBuilder.Desktop/Infrastructure/AppNotificationService.cs @@ -21,8 +21,8 @@ public class AppNotificationService : ReactiveObject /// public UpdateStatus AppUpdateStatus { - get => appUpdateStatus; - set => this.RaiseAndSetIfChanged(ref appUpdateStatus, value); + get => this.appUpdateStatus; + set => this.RaiseAndSetIfChanged(ref this.appUpdateStatus, value); } /// @@ -32,8 +32,8 @@ public UpdateStatus AppUpdateStatus /// public string AppUpdateMessage { - get => appUpdateMessage; - set => this.RaiseAndSetIfChanged(ref appUpdateMessage, value); + get => this.appUpdateMessage; + set => this.RaiseAndSetIfChanged(ref this.appUpdateMessage, value); } /// @@ -41,7 +41,7 @@ public string AppUpdateMessage /// public async Task NotifyAppUpdateStart() { - await Dispatcher.UIThread.InvokeAsync(() => AppUpdateStatus = UpdateStatus.Active); + await Dispatcher.UIThread.InvokeAsync(() => this.AppUpdateStatus = UpdateStatus.Active); } /// @@ -49,7 +49,7 @@ public async Task NotifyAppUpdateStart() /// public async Task NotifyAppUpdateComplete() { - await Dispatcher.UIThread.InvokeAsync(() => AppUpdateStatus = UpdateStatus.Completed); + await Dispatcher.UIThread.InvokeAsync(() => this.AppUpdateStatus = UpdateStatus.Completed); } /// @@ -61,10 +61,10 @@ public async Task NotifyAppUpdateError(string? message = null) { await Dispatcher.UIThread.InvokeAsync(() => { - AppUpdateStatus = UpdateStatus.Error; + this.AppUpdateStatus = UpdateStatus.Error; if (!string.IsNullOrWhiteSpace(message)) { - AppUpdateMessage = message; + this.AppUpdateMessage = message; } }); } diff --git a/WoWsShipBuilder.Desktop/Infrastructure/AwsClient/AwsClient.cs b/WoWsShipBuilder.Desktop/Infrastructure/AwsClient/AwsClient.cs index 75778efa0..4f96454aa 100644 --- a/WoWsShipBuilder.Desktop/Infrastructure/AwsClient/AwsClient.cs +++ b/WoWsShipBuilder.Desktop/Infrastructure/AwsClient/AwsClient.cs @@ -23,7 +23,7 @@ public class AwsClient : ClientBase, IDesktopAwsClient public AwsClient(IDataService dataService, IAppDataService appDataService, ILogger logger, HttpMessageHandler? handler = null) : base(dataService, appDataService) { - Client = new(new RetryHttpHandler(handler ?? new HttpClientHandler())); + this.Client = new(new RetryHttpHandler(handler ?? new HttpClientHandler())); this.logger = logger; } @@ -40,13 +40,13 @@ public AwsClient(IDataService dataService, IAppDataService appDataService, ILogg [UnsupportedOSPlatform("browser")] public async Task DownloadImages(IFileSystem fileSystem, string? fileName = null) { - logger.LogDebug("Downloading ship images"); + this.logger.LogDebug("Downloading ship images"); string zipName = fileName ?? "ship"; var zipUrl = @$"{Host}/images/ship/{zipName}.zip"; var localFolder = "Ships"; - string directoryPath = fileSystem.Path.Combine(AppDataService.AppDataImageDirectory, localFolder); + string directoryPath = fileSystem.Path.Combine(this.AppDataService.AppDataImageDirectory, localFolder); if (!fileSystem.Directory.Exists(directoryPath)) { @@ -56,25 +56,25 @@ public async Task DownloadImages(IFileSystem fileSystem, string? fileName = null string zipPath = fileSystem.Path.Combine(directoryPath, $"{zipName}.zip"); try { - await DownloadFileAsync(new(zipUrl), zipPath); + await this.DownloadFileAsync(new(zipUrl), zipPath); ZipFile.ExtractToDirectory(zipPath, directoryPath, true); fileSystem.File.Delete(zipPath); } catch (HttpRequestException e) { - logger.LogWarning(e, "Failed to download images from uri {}", zipUrl); + this.logger.LogWarning(e, "Failed to download images from uri {}", zipUrl); } } public async Task DownloadVersionInfo(ServerType serverType) { string url = @$"{Host}/api/{serverType.StringName()}/VersionInfo.json"; - return await GetJsonAsync(url) ?? throw new HttpRequestException("Unable to process VersionInfo response from AWS server."); + return await this.GetJsonAsync(url) ?? throw new HttpRequestException("Unable to process VersionInfo response from AWS server."); } public async Task DownloadFiles(ServerType serverType, List<(string, string)> relativeFilePaths, IProgress? downloadProgress = null) { - logger.LogWarning("Downloading files for server type {ServerType}", serverType); + this.logger.LogWarning("Downloading files for server type {ServerType}", serverType); string baseUrl = @$"{Host}/api/{serverType.StringName()}/"; var taskList = new List(); int totalFiles = relativeFilePaths.Count; @@ -86,17 +86,17 @@ public async Task DownloadFiles(ServerType serverType, List<(string, string)> re }); foreach ((string category, string fileName) in relativeFilePaths) { - string localFileName = DataService.CombinePaths(AppDataService.GetDataPath(serverType), category, fileName); + string localFileName = this.DataService.CombinePaths(this.AppDataService.GetDataPath(serverType), category, fileName); Uri uri = string.IsNullOrWhiteSpace(category) ? new(baseUrl + fileName) : new(baseUrl + $"{category}/{fileName}"); var task = Task.Run(async () => { try { - await DownloadFileAsync(uri, localFileName); + await this.DownloadFileAsync(uri, localFileName); } catch (HttpRequestException e) { - logger.LogWarning(e, "Encountered an exception while downloading a file with uri {} and filename {}", uri, localFileName); + this.logger.LogWarning(e, "Encountered an exception while downloading a file with uri {} and filename {}", uri, localFileName); } progress.Report(1); diff --git a/WoWsShipBuilder.Desktop/Infrastructure/AwsClient/ClientBase.cs b/WoWsShipBuilder.Desktop/Infrastructure/AwsClient/ClientBase.cs index 3356f3372..656542b11 100644 --- a/WoWsShipBuilder.Desktop/Infrastructure/AwsClient/ClientBase.cs +++ b/WoWsShipBuilder.Desktop/Infrastructure/AwsClient/ClientBase.cs @@ -13,8 +13,8 @@ public abstract class ClientBase { protected ClientBase(IDataService dataService, IAppDataService appDataService) { - DataService = dataService; - AppDataService = appDataService; + this.DataService = dataService; + this.AppDataService = appDataService; } protected IAppDataService AppDataService { get; } @@ -25,14 +25,14 @@ protected ClientBase(IDataService dataService, IAppDataService appDataService) protected virtual async Task DownloadFileAsync(Uri uri, string fileName) { - await using Stream stream = await Client.GetStreamAsync(uri); - await DataService.StoreAsync(stream, fileName); + await using Stream stream = await this.Client.GetStreamAsync(uri); + await this.DataService.StoreAsync(stream, fileName); } protected virtual async Task GetJsonAsync(string url, JsonSerializer? customSerializer = null) { - await using Stream stream = await Client.GetStreamAsync(url); - return GetJson(stream, customSerializer); + await using Stream stream = await this.Client.GetStreamAsync(url); + return this.GetJson(stream, customSerializer); } internal T? GetJson(Stream stream, JsonSerializer? customSerializer = null) diff --git a/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopAppDataService.cs b/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopAppDataService.cs index 13345b6fc..9210dea71 100644 --- a/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopAppDataService.cs +++ b/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopAppDataService.cs @@ -26,7 +26,7 @@ public DesktopAppDataService(IFileSystem fileSystem, IDataService dataService, A this.fileSystem = fileSystem; this.dataService = dataService; this.appSettings = appSettings; - DefaultAppDataDirectory = dataService.CombinePaths(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), AppConstants.ShipBuilderName); + this.DefaultAppDataDirectory = dataService.CombinePaths(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), AppConstants.ShipBuilderName); } public string DefaultAppDataDirectory { get; } @@ -37,19 +37,19 @@ public string AppDataDirectory { if (AppData.IsInitialized) { - return appSettings.CustomDataPath ?? DefaultAppDataDirectory; + return this.appSettings.CustomDataPath ?? this.DefaultAppDataDirectory; } - return DefaultAppDataDirectory; + return this.DefaultAppDataDirectory; } } - public string AppDataImageDirectory => dataService.CombinePaths(AppDataDirectory, "Images"); + public string AppDataImageDirectory => this.dataService.CombinePaths(this.AppDataDirectory, "Images"); public string GetDataPath(ServerType serverType) { string serverName = serverType.StringName(); - return dataService.CombinePaths(AppDataDirectory, "json", serverName); + return this.dataService.CombinePaths(this.AppDataDirectory, "json", serverName); } /// @@ -57,7 +57,7 @@ public string GetDataPath(ServerType serverType) /// /// The selected server type. /// The directory path of the current localization directory. - public string GetLocalizationPath(ServerType serverType) => dataService.CombinePaths(GetDataPath(serverType), "Localization"); + public string GetLocalizationPath(ServerType serverType) => this.dataService.CombinePaths(this.GetDataPath(serverType), "Localization"); /// /// Find the list of currently installed localizations. @@ -69,9 +69,9 @@ public async Task> GetInstalledLocales(ServerType serverType, bool { // TODO: return Task.FromResult await Task.CompletedTask; - fileSystem.Directory.CreateDirectory(GetLocalizationPath(serverType)); - var files = fileSystem.Directory.GetFiles(GetLocalizationPath(serverType)).Select(file => fileSystem.FileInfo.New(file)); - return includeFileType ? files.Select(file => file.Name).ToList() : files.Select(file => fileSystem.Path.GetFileNameWithoutExtension(file.Name)).ToList(); + this.fileSystem.Directory.CreateDirectory(this.GetLocalizationPath(serverType)); + var files = this.fileSystem.Directory.GetFiles(this.GetLocalizationPath(serverType)).Select(file => this.fileSystem.FileInfo.New(file)); + return includeFileType ? files.Select(file => file.Name).ToList() : files.Select(file => this.fileSystem.Path.GetFileNameWithoutExtension(file.Name)).ToList(); } /// @@ -81,14 +81,14 @@ public async Task> GetInstalledLocales(ServerType serverType, bool /// The local VersionInfo or null if none was found. public async Task GetCurrentVersionInfo(ServerType serverType) { - string filePath = dataService.CombinePaths(GetDataPath(serverType), "VersionInfo.json"); - return await DeserializeFile(filePath); + string filePath = this.dataService.CombinePaths(this.GetDataPath(serverType), "VersionInfo.json"); + return await this.DeserializeFile(filePath); } public async Task?> ReadLocalizationData(ServerType serverType, string language) { - string fileName = dataService.CombinePaths(GetDataPath(serverType), "Localization", $"{language}.json"); - return fileSystem.File.Exists(fileName) ? await DeserializeFile>(fileName) : null; + string fileName = this.dataService.CombinePaths(this.GetDataPath(serverType), "Localization", $"{language}.json"); + return this.fileSystem.File.Exists(fileName) ? await this.DeserializeFile>(fileName) : null; } public async Task LoadLocalFilesAsync(ServerType serverType) @@ -96,10 +96,10 @@ public async Task LoadLocalFilesAsync(ServerType serverType) var sw = Stopwatch.StartNew(); Logging.Logger.LogDebug("Loading local files from disk"); AppData.ResetCaches(); - var localVersionInfo = await GetCurrentVersionInfo(serverType) ?? throw new InvalidOperationException("No local data found"); + var localVersionInfo = await this.GetCurrentVersionInfo(serverType) ?? throw new InvalidOperationException("No local data found"); AppData.DataVersion = localVersionInfo.CurrentVersion.MainVersion.ToString(3) + "#" + localVersionInfo.CurrentVersion.DataIteration; - var dataRootInfo = fileSystem.DirectoryInfo.New(GetDataPath(serverType)); + var dataRootInfo = this.fileSystem.DirectoryInfo.New(this.GetDataPath(serverType)); IDirectoryInfo[] categories = dataRootInfo.GetDirectories(); // Multiple categories can be loaded simultaneously without concurrency issues because every cache is only used by one category. @@ -112,7 +112,7 @@ await Parallel.ForEachAsync(categories, async (category, ct) => foreach (var file in category.GetFiles()) { - string content = await fileSystem.File.ReadAllTextAsync(file.FullName, ct); + string content = await this.fileSystem.File.ReadAllTextAsync(file.FullName, ct); await DataCacheHelper.AddToCache(file.Name, category.Name, content); } }); @@ -128,12 +128,12 @@ await Parallel.ForEachAsync(categories, async (category, ct) => throw new ArgumentException("The provided file path must not be empty."); } - if (!fileSystem.File.Exists(filePath)) + if (!this.fileSystem.File.Exists(filePath)) { Logging.Logger.LogWarning("Tried to load file {FilePath}, but it was not found", filePath); return default; } - return await dataService.LoadAsync(filePath); + return await this.dataService.LoadAsync(filePath); } } diff --git a/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopDataService.cs b/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopDataService.cs index 17b0b13c9..a9dd52348 100644 --- a/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopDataService.cs +++ b/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopDataService.cs @@ -19,63 +19,63 @@ public DesktopDataService(IFileSystem fileSystem) public async Task StoreStringAsync(string content, string path) { - CreateDirectory(path); - await fileSystem.File.WriteAllTextAsync(path, content, Encoding.UTF8); + this.CreateDirectory(path); + await this.fileSystem.File.WriteAllTextAsync(path, content, Encoding.UTF8); } public async Task StoreAsync(object content, string path) { - CreateDirectory(path); + this.CreateDirectory(path); string fileContents = JsonConvert.SerializeObject(content); - await fileSystem.File.WriteAllTextAsync(path, fileContents, Encoding.UTF8); + await this.fileSystem.File.WriteAllTextAsync(path, fileContents, Encoding.UTF8); } public async Task StoreAsync(Stream stream, string path) { - CreateDirectory(path); - await using var fileStream = fileSystem.File.Open(path, FileMode.Create); + this.CreateDirectory(path); + await using var fileStream = this.fileSystem.File.Open(path, FileMode.Create); await stream.CopyToAsync(fileStream); } public void Store(object content, string path) { - CreateDirectory(path); + this.CreateDirectory(path); string fileContents = JsonConvert.SerializeObject(content); - fileSystem.File.WriteAllText(path, fileContents, Encoding.UTF8); + this.fileSystem.File.WriteAllText(path, fileContents, Encoding.UTF8); } public void Store(Stream stream, string path) { - CreateDirectory(path); - using var fileStream = fileSystem.File.OpenWrite(path); + this.CreateDirectory(path); + using var fileStream = this.fileSystem.File.OpenWrite(path); stream.CopyTo(fileStream); } public async Task LoadStringAsync(string path) { - return await fileSystem.File.ReadAllTextAsync(path, Encoding.UTF8); + return await this.fileSystem.File.ReadAllTextAsync(path, Encoding.UTF8); } public async Task LoadAsync(string path) { - string contents = await fileSystem.File.ReadAllTextAsync(path, Encoding.UTF8); + string contents = await this.fileSystem.File.ReadAllTextAsync(path, Encoding.UTF8); return JsonConvert.DeserializeObject(contents); } public T? Load(string path) { - string contents = fileSystem.File.ReadAllText(path, Encoding.UTF8); + string contents = this.fileSystem.File.ReadAllText(path, Encoding.UTF8); return JsonConvert.DeserializeObject(contents); } public string CombinePaths(params string[] paths) { - return fileSystem.Path.Combine(paths); + return this.fileSystem.Path.Combine(paths); } private void CreateDirectory(string path) { - string directoryName = fileSystem.Path.GetDirectoryName(path)!; - fileSystem.Directory.CreateDirectory(directoryName); + string directoryName = this.fileSystem.Path.GetDirectoryName(path)!; + this.fileSystem.Directory.CreateDirectory(directoryName); } } diff --git a/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopUserDataService.cs b/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopUserDataService.cs index 7a5b12854..ee4b77dea 100644 --- a/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopUserDataService.cs +++ b/WoWsShipBuilder.Desktop/Infrastructure/Data/DesktopUserDataService.cs @@ -29,25 +29,25 @@ public DesktopUserDataService(IDataService dataService, IAppDataService appDataS public async Task SaveBuildsAsync(IEnumerable builds) { - var path = dataService.CombinePaths(appDataService.DefaultAppDataDirectory, "builds.json"); + var path = this.dataService.CombinePaths(this.appDataService.DefaultAppDataDirectory, "builds.json"); var buildStrings = builds.Select(build => build.CreateShortStringFromBuild()).ToList(); - await dataService.StoreAsync(buildStrings, path); + await this.dataService.StoreAsync(buildStrings, path); } public async Task> LoadBuildsAsync() { - if (savedBuilds is not null) + if (this.savedBuilds is not null) { - return savedBuilds; + return this.savedBuilds; } - string path = dataService.CombinePaths(appDataService.DefaultAppDataDirectory, "builds.json"); - if (fileSystem.File.Exists(path)) + string path = this.dataService.CombinePaths(this.appDataService.DefaultAppDataDirectory, "builds.json"); + if (this.fileSystem.File.Exists(path)) { List? buildList = null; try { - buildList = await dataService.LoadAsync>(path); + buildList = await this.dataService.LoadAsync>(path); } catch (JsonReaderException) { @@ -73,10 +73,10 @@ public async Task> LoadBuildsAsync() } } - savedBuilds = builds.DistinctBy(x => x.Hash).ToList(); + this.savedBuilds = builds.DistinctBy(x => x.Hash).ToList(); } - return savedBuilds ?? Enumerable.Empty(); + return this.savedBuilds ?? Enumerable.Empty(); } return Enumerable.Empty(); @@ -84,26 +84,26 @@ public async Task> LoadBuildsAsync() public async Task ImportBuildsAsync(IEnumerable builds) { - savedBuilds ??= (await LoadBuildsAsync()).ToList(); + this.savedBuilds ??= (await this.LoadBuildsAsync()).ToList(); foreach (var build in builds.Where(x => AppData.ShipDictionary.ContainsKey(x.ShipIndex))) { - savedBuilds.RemoveAll(x => x.Equals(build)); - savedBuilds.Insert(0, build); + this.savedBuilds.RemoveAll(x => x.Equals(build)); + this.savedBuilds.Insert(0, build); } - await SaveBuildsAsync(savedBuilds); + await this.SaveBuildsAsync(this.savedBuilds); } - public async Task SaveBuildAsync(Build build) => await ImportBuildsAsync(new List { build }); + public async Task SaveBuildAsync(Build build) => await this.ImportBuildsAsync(new List { build }); - public async Task RemoveSavedBuildAsync(Build build) => await RemoveSavedBuildsAsync(new List { build }); + public async Task RemoveSavedBuildAsync(Build build) => await this.RemoveSavedBuildsAsync(new List { build }); public async Task RemoveSavedBuildsAsync(IEnumerable builds) { - savedBuilds ??= (await LoadBuildsAsync()).ToList(); - savedBuilds.RemoveMany(builds); + this.savedBuilds ??= (await this.LoadBuildsAsync()).ToList(); + this.savedBuilds.RemoveMany(builds); - await SaveBuildsAsync(savedBuilds); + await this.SaveBuildsAsync(this.savedBuilds); } } diff --git a/WoWsShipBuilder.Desktop/Infrastructure/DesktopSettingsAccessor.cs b/WoWsShipBuilder.Desktop/Infrastructure/DesktopSettingsAccessor.cs index 193cc62cc..709951187 100644 --- a/WoWsShipBuilder.Desktop/Infrastructure/DesktopSettingsAccessor.cs +++ b/WoWsShipBuilder.Desktop/Infrastructure/DesktopSettingsAccessor.cs @@ -25,15 +25,15 @@ public DesktopSettingsAccessor(IAppDataService appDataService, IDataService data this.dataService = dataService; this.fileSystem = fileSystem; this.logger = logger; - settingsFile = dataService.CombinePaths(appDataService.DefaultAppDataDirectory, "settings.json"); + this.settingsFile = dataService.CombinePaths(appDataService.DefaultAppDataDirectory, "settings.json"); } public async Task LoadSettings() { - if (fileSystem.File.Exists(settingsFile)) + if (this.fileSystem.File.Exists(this.settingsFile)) { - logger.LogInformation("Trying to load settings from settings file..."); - return await dataService.LoadAsync(settingsFile); + this.logger.LogInformation("Trying to load settings from settings file..."); + return await this.dataService.LoadAsync(this.settingsFile); } return null; @@ -41,10 +41,10 @@ public DesktopSettingsAccessor(IAppDataService appDataService, IDataService data public AppSettings? LoadSettingsSync() { - if (fileSystem.File.Exists(settingsFile)) + if (this.fileSystem.File.Exists(this.settingsFile)) { - logger.LogInformation("Trying to load settings from settings file..."); - return dataService.Load(settingsFile); + this.logger.LogInformation("Trying to load settings from settings file..."); + return this.dataService.Load(this.settingsFile); } return null; @@ -52,13 +52,13 @@ public DesktopSettingsAccessor(IAppDataService appDataService, IDataService data public async Task SaveSettings(AppSettings appSettings) { - await dataService.StoreAsync(appSettings, settingsFile); + await this.dataService.StoreAsync(appSettings, this.settingsFile); await UpdateUiThreadCultureAsync(appSettings.SelectedLanguage.CultureInfo); } public void SaveSettingsSync(AppSettings appSettings) { - dataService.Store(appSettings, settingsFile); + this.dataService.Store(appSettings, this.settingsFile); } private static async Task UpdateUiThreadCultureAsync(CultureInfo cultureInfo) diff --git a/WoWsShipBuilder.Desktop/Infrastructure/LocalizeConverter.cs b/WoWsShipBuilder.Desktop/Infrastructure/LocalizeConverter.cs index 365f5810f..9430f7ab6 100644 --- a/WoWsShipBuilder.Desktop/Infrastructure/LocalizeConverter.cs +++ b/WoWsShipBuilder.Desktop/Infrastructure/LocalizeConverter.cs @@ -135,7 +135,7 @@ public static void InitializeLocalizer(ILocalizer localizer) private sealed class DemoLocalizerImpl : ILocalizer { - public LocalizationResult this[string key] => GetGameLocalization(key); + public LocalizationResult this[string key] => this.GetGameLocalization(key); public LocalizationResult GetGameLocalization(string key) => new(true, key); diff --git a/WoWsShipBuilder.Desktop/Infrastructure/WebView/BlazorWebView.cs b/WoWsShipBuilder.Desktop/Infrastructure/WebView/BlazorWebView.cs index 27930a26c..856af3be5 100644 --- a/WoWsShipBuilder.Desktop/Infrastructure/WebView/BlazorWebView.cs +++ b/WoWsShipBuilder.Desktop/Infrastructure/WebView/BlazorWebView.cs @@ -52,22 +52,22 @@ public string? HostPage { get { - if (blazorWebView != null) + if (this.blazorWebView != null) { - hostPage = blazorWebView.HostPage; + this.hostPage = this.blazorWebView.HostPage; } - return hostPage; + return this.hostPage; } set { - if (hostPage != value) + if (this.hostPage != value) { - hostPage = value; - if (blazorWebView != null) + this.hostPage = value; + if (this.blazorWebView != null) { - blazorWebView.HostPage = value; + this.blazorWebView.HostPage = value; } } } @@ -77,22 +77,22 @@ public Uri? Source { get { - if (blazorWebView != null) + if (this.blazorWebView != null) { - source = blazorWebView.WebView.Source; + this.source = this.blazorWebView.WebView.Source; } - return source; + return this.source; } set { - if (source != value) + if (this.source != value) { - source = value; - if (blazorWebView != null) + this.source = value; + if (this.blazorWebView != null) { - blazorWebView.WebView.Source = value; + this.blazorWebView.WebView.Source = value; } } } @@ -102,22 +102,22 @@ public double ZoomFactor { get { - if (blazorWebView != null) + if (this.blazorWebView != null) { - zoomFactor = blazorWebView.WebView.ZoomFactor; + this.zoomFactor = this.blazorWebView.WebView.ZoomFactor; } - return zoomFactor; + return this.zoomFactor; } set { - if (zoomFactor != value) + if (this.zoomFactor != value) { - zoomFactor = value; - if (blazorWebView != null) + this.zoomFactor = value; + if (this.blazorWebView != null) { - blazorWebView.WebView.ZoomFactor = value; + this.blazorWebView.WebView.ZoomFactor = value; } } } @@ -125,41 +125,41 @@ public double ZoomFactor public IServiceProvider Services { - get => serviceProvider; + get => this.serviceProvider; set { - serviceProvider = value; - if (blazorWebView != null) + this.serviceProvider = value; + if (this.blazorWebView != null) { - blazorWebView.Services = serviceProvider; + this.blazorWebView.Services = this.serviceProvider; } } } public RootComponentsCollection RootComponents { - get => rootComponents; - set => rootComponents = value; + get => this.rootComponents; + set => this.rootComponents = value; } public string DefaultDownloadFolderPath { get { - if (blazorWebView is not null) + if (this.blazorWebView is not null) { - blazorWebView.WebView.CoreWebView2.Profile.DefaultDownloadFolderPath = defaultDownloadPath; + this.blazorWebView.WebView.CoreWebView2.Profile.DefaultDownloadFolderPath = this.defaultDownloadPath; } - return defaultDownloadPath; + return this.defaultDownloadPath; } set { - defaultDownloadPath = value; - if (blazorWebView is not null) + this.defaultDownloadPath = value; + if (this.blazorWebView is not null) { - blazorWebView.WebView.CoreWebView2.Profile.DefaultDownloadFolderPath = value; + this.blazorWebView.WebView.CoreWebView2.Profile.DefaultDownloadFolderPath = value; } } } @@ -168,17 +168,17 @@ protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle paren { if (OperatingSystem.IsWindows()) { - blazorWebView = new CustomizedWebView + this.blazorWebView = new CustomizedWebView { - HostPage = hostPage, - Services = serviceProvider, + HostPage = this.hostPage, + Services = this.serviceProvider, BackColor = Color.FromArgb(255, 40, 40, 40), }; - blazorWebView.WebView.CoreWebView2InitializationCompleted += WebViewOnCoreWebView2InitializationCompleted; - blazorWebView.WebView.DefaultBackgroundColor = Color.FromArgb(255, 40, 40, 40); - blazorWebView.WebView.ZoomFactor = Math.Clamp(zoomFactor, 0.1, 4.0); - blazorWebView.RootComponents.AddRange(rootComponents); - return new PlatformHandle(blazorWebView.Handle, "HWND"); + this.blazorWebView.WebView.CoreWebView2InitializationCompleted += this.WebViewOnCoreWebView2InitializationCompleted; + this.blazorWebView.WebView.DefaultBackgroundColor = Color.FromArgb(255, 40, 40, 40); + this.blazorWebView.WebView.ZoomFactor = Math.Clamp(this.zoomFactor, 0.1, 4.0); + this.blazorWebView.RootComponents.AddRange(this.rootComponents); + return new PlatformHandle(this.blazorWebView.Handle, "HWND"); } return base.CreateNativeControlCore(parent); @@ -186,17 +186,17 @@ protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle paren private void CoreWebView2OnIsDefaultDownloadDialogOpenChanged(object? sender, object e) { - if (blazorWebView?.WebView.CoreWebView2.IsDefaultDownloadDialogOpen == true) + if (this.blazorWebView?.WebView.CoreWebView2.IsDefaultDownloadDialogOpen == true) { - blazorWebView.WebView.CoreWebView2.CloseDefaultDownloadDialog(); + this.blazorWebView.WebView.CoreWebView2.CloseDefaultDownloadDialog(); } } private void WebViewOnCoreWebView2InitializationCompleted(object? sender, CoreWebView2InitializationCompletedEventArgs e) { // blazorWebView!.WebView.CoreWebView2.IsDefaultDownloadDialogOpenChanged += CoreWebView2OnIsDefaultDownloadDialogOpenChanged; - DefaultDownloadFolderPath = defaultDownloadPath; - blazorWebView!.WebView.CoreWebView2InitializationCompleted -= WebViewOnCoreWebView2InitializationCompleted; + this.DefaultDownloadFolderPath = this.defaultDownloadPath; + this.blazorWebView!.WebView.CoreWebView2InitializationCompleted -= this.WebViewOnCoreWebView2InitializationCompleted; } protected override void DestroyNativeControlCore(IPlatformHandle control) @@ -204,8 +204,8 @@ protected override void DestroyNativeControlCore(IPlatformHandle control) if (OperatingSystem.IsWindows()) { // blazorWebView!.WebView.CoreWebView2.IsDefaultDownloadDialogOpenChanged -= CoreWebView2OnIsDefaultDownloadDialogOpenChanged; - blazorWebView?.Dispose(); - blazorWebView = null; + this.blazorWebView?.Dispose(); + this.blazorWebView = null; } else { @@ -220,7 +220,7 @@ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e { // Do not use until dotnet 8 because disposing the webview will deadlock. see https://github.com/dotnet/maui/issues/7997#issuecomment-1258681003 // blazorWebView?.Dispose(); - blazorWebView = null; + this.blazorWebView = null; } } } diff --git a/WoWsShipBuilder.Desktop/Infrastructure/WebView/CustomizedWebView.cs b/WoWsShipBuilder.Desktop/Infrastructure/WebView/CustomizedWebView.cs index 91c5a5600..7dd040186 100644 --- a/WoWsShipBuilder.Desktop/Infrastructure/WebView/CustomizedWebView.cs +++ b/WoWsShipBuilder.Desktop/Infrastructure/WebView/CustomizedWebView.cs @@ -9,8 +9,8 @@ public class CustomizedWebView : Microsoft.AspNetCore.Components.WebView.Windows { public override IFileProvider CreateFileProvider(string contentRootDir) { - var appDataService = Services.GetRequiredService(); - var dataService = Services.GetRequiredService(); + var appDataService = this.Services.GetRequiredService(); + var dataService = this.Services.GetRequiredService(); return new CompositeFileProvider(new PhysicalFileProvider(dataService.CombinePaths(appDataService.AppDataImageDirectory, "Ships")), base.CreateFileProvider(contentRootDir)); } } diff --git a/WoWsShipBuilder.Web.Test/ServerAwsClientTest.cs b/WoWsShipBuilder.Web.Test/ServerAwsClientTest.cs index 3561c3128..52885e997 100644 --- a/WoWsShipBuilder.Web.Test/ServerAwsClientTest.cs +++ b/WoWsShipBuilder.Web.Test/ServerAwsClientTest.cs @@ -28,7 +28,7 @@ public class ServerAwsClientTest [SetUp] public void Setup() { - messageHandlerMock = new(); + this.messageHandlerMock = new(); AppData.ShipDictionary.Clear(); } @@ -39,14 +39,14 @@ public async Task DownloadFiles() const string testShipKey = "PGSA001"; var shipDictionary = new Dictionary { { testShipKey, new Ship { Index = testShipKey, Id = 1234 } } }; - messageHandlerMock.Protected().Setup>( + this.messageHandlerMock.Protected().Setup>( "SendAsync", ItExpr.Is(message => message.RequestUri!.AbsoluteUri.EndsWith("VersionInfo.json")), ItExpr.IsAny()) .ReturnsAsync(new HttpResponseMessage { Content = new StringContent(JsonConvert.SerializeObject(testVersionInfo)) }); var shipRequestExpression = ItExpr.Is(message => message.RequestUri!.AbsolutePath.Equals("/api/live/Ship/Germany.json")); - messageHandlerMock.Protected().Setup>( + this.messageHandlerMock.Protected().Setup>( "SendAsync", shipRequestExpression, ItExpr.IsAny()) @@ -54,7 +54,7 @@ public async Task DownloadFiles() var cdnOptions = new CdnOptions { Host = "https://example.com"}; IOptions? options = Options.Create(cdnOptions); - var client = new ServerAwsClient(new(messageHandlerMock.Object), options, NullLogger.Instance); + var client = new ServerAwsClient(new(this.messageHandlerMock.Object), options, NullLogger.Instance); var versionInfo = await client.DownloadVersionInfo(ServerType.Live); var files = versionInfo.Categories.SelectMany(category => category.Value.Select(file => (category.Key, file.FileName))).ToList(); @@ -62,7 +62,7 @@ public async Task DownloadFiles() AppData.ShipDictionary.Should().HaveCount(1); AppData.ShipDictionary.Should().ContainKey(testShipKey); - messageHandlerMock.Protected().Verify("SendAsync", Times.Exactly(1), shipRequestExpression, ItExpr.IsAny()); - messageHandlerMock.Protected().Verify("SendAsync", Times.Exactly(2), ItExpr.IsAny(), ItExpr.IsAny()); + this.messageHandlerMock.Protected().Verify("SendAsync", Times.Exactly(1), shipRequestExpression, ItExpr.IsAny()); + this.messageHandlerMock.Protected().Verify("SendAsync", Times.Exactly(2), ItExpr.IsAny(), ItExpr.IsAny()); } } diff --git a/WoWsShipBuilder.Web/Features/Authentication/AuthController.cs b/WoWsShipBuilder.Web/Features/Authentication/AuthController.cs index 4e03c7364..7abc3d57c 100644 --- a/WoWsShipBuilder.Web/Features/Authentication/AuthController.cs +++ b/WoWsShipBuilder.Web/Features/Authentication/AuthController.cs @@ -29,44 +29,44 @@ public async Task Authenticate([FromQuery(Name = "status")] string { if (status == "ok") { - return await AuthenticationConfirmed(HttpContext.Request.Query["access_token"]!, HttpContext.Request.Query["account_id"]!, HttpContext.Request.Query["nickname"]!); + return await this.AuthenticationConfirmed(this.HttpContext.Request.Query["access_token"]!, this.HttpContext.Request.Query["account_id"]!, this.HttpContext.Request.Query["nickname"]!); } - return await AuthenticationCanceled(status, HttpContext.Request.Query["message"]!, int.Parse(HttpContext.Request.Query["code"]!, CultureInfo.InvariantCulture)); + return await this.AuthenticationCanceled(status, this.HttpContext.Request.Query["message"]!, int.Parse(this.HttpContext.Request.Query["code"]!, CultureInfo.InvariantCulture)); } public async Task AuthenticationConfirmed(string accessToken, string accountId, string nickname) { - var authValid = await authenticationService.VerifyToken(accountId, accessToken); + var authValid = await this.authenticationService.VerifyToken(accountId, accessToken); if (!authValid) { - return Redirect("/auth-failed"); + return this.Redirect("/auth-failed"); } - var principal = authenticationService.CreatePrincipalForUser(accessToken, accountId, nickname); - await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new() { IsPersistent = true }); - return Redirect("/"); + var principal = this.authenticationService.CreatePrincipalForUser(accessToken, accountId, nickname); + await this.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new() { IsPersistent = true }); + return this.Redirect("/"); } public Task AuthenticationCanceled(string status, string message, int code) { - logger.LogDebug("Authentication canceled. Status: {Status}, Message: {Message}, Code: {Code}", status, message, code); - return Task.FromResult(Redirect("/")); + this.logger.LogDebug("Authentication canceled. Status: {Status}, Message: {Message}, Code: {Code}", status, message, code); + return Task.FromResult(this.Redirect("/")); } [HttpGet("login/{server:regex(^eu|asia|com$):required}")] public Task Login(string server) { - string baseUrl = $"{Request.Scheme}://{Request.Host}{Request.PathBase}"; + string baseUrl = $"{this.Request.Scheme}://{this.Request.Host}{this.Request.PathBase}"; var pageUrl = $"{baseUrl}/api/auth"; - string url = @$"https://api.worldoftanks.{server}/wot/auth/login/?application_id={options.WgApiKey}&redirect_uri={pageUrl}"; - return Task.FromResult(Redirect(url)); + string url = @$"https://api.worldoftanks.{server}/wot/auth/login/?application_id={this.options.WgApiKey}&redirect_uri={pageUrl}"; + return Task.FromResult(this.Redirect(url)); } [HttpGet("logout")] public async Task Logout() { - await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - return Redirect("/"); + await this.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + return this.Redirect("/"); } } diff --git a/WoWsShipBuilder.Web/Features/Authentication/AuthenticationService.cs b/WoWsShipBuilder.Web/Features/Authentication/AuthenticationService.cs index a6a83e395..93bcc7221 100644 --- a/WoWsShipBuilder.Web/Features/Authentication/AuthenticationService.cs +++ b/WoWsShipBuilder.Web/Features/Authentication/AuthenticationService.cs @@ -31,10 +31,10 @@ public async Task VerifyToken(string accountId, string accessToken) _ => throw new InvalidOperationException("unsupported account id range"), }; - logger.LogInformation("Verifying access token for account {}", accountId); - var checkUrl = @$"https://api.worldofwarships.{server}/wows/account/info/?application_id={options.WgApiKey}&account_id={accountId}&access_token={accessToken}&fields=private"; + this.logger.LogInformation("Verifying access token for account {}", accountId); + var checkUrl = @$"https://api.worldofwarships.{server}/wows/account/info/?application_id={this.options.WgApiKey}&account_id={accountId}&access_token={accessToken}&fields=private"; var request = new HttpRequestMessage(HttpMethod.Get, checkUrl); - var response = await client.SendAsync(request); + var response = await this.client.SendAsync(request); if (response.IsSuccessStatusCode) { @@ -42,12 +42,12 @@ public async Task VerifyToken(string accountId, string accessToken) if (responseData is not null && responseData.Status.Equals("ok")) { Dictionary? privateData = responseData.Data.FirstOrDefault().Value?.Private; - logger.LogInformation("Token-verification for account {} successful", accountId); + this.logger.LogInformation("Token-verification for account {} successful", accountId); return privateData is not null && privateData.Any(); } } - logger.LogInformation("Token-verification for account {} failed", accountId); + this.logger.LogInformation("Token-verification for account {} failed", accountId); return false; } @@ -60,12 +60,12 @@ public ClaimsPrincipal CreatePrincipalForUser(string accessToken, string account new(ClaimTypes.UserData, accessToken), }; - if (options.AdminUsers.Contains(accountId)) + if (this.options.AdminUsers.Contains(accountId)) { claims.Add(new(ClaimTypes.Role, AppConstants.AdminRoleName)); } - if (options.BuildCurators.Contains(accountId)) + if (this.options.BuildCurators.Contains(accountId)) { claims.Add(new(ClaimTypes.Role, AppConstants.BuildCuratorRoleName)); } diff --git a/WoWsShipBuilder.Web/Features/Host/Error.cshtml.cs b/WoWsShipBuilder.Web/Features/Host/Error.cshtml.cs index ed60b77a4..8473b9083 100644 --- a/WoWsShipBuilder.Web/Features/Host/Error.cshtml.cs +++ b/WoWsShipBuilder.Web/Features/Host/Error.cshtml.cs @@ -10,10 +10,10 @@ public class ErrorModel : PageModel { public string? RequestId { get; set; } - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + public bool ShowRequestId => !string.IsNullOrEmpty(this.RequestId); public void OnGet() { - RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + this.RequestId = Activity.Current?.Id ?? this.HttpContext.TraceIdentifier; } } diff --git a/WoWsShipBuilder.Web/Infrastructure/AppSettingsHelper.cs b/WoWsShipBuilder.Web/Infrastructure/AppSettingsHelper.cs index a50a7cc18..a6ccfb8e6 100644 --- a/WoWsShipBuilder.Web/Infrastructure/AppSettingsHelper.cs +++ b/WoWsShipBuilder.Web/Infrastructure/AppSettingsHelper.cs @@ -19,8 +19,8 @@ public WebSettingsAccessor(IJSRuntime runtime) public async Task LoadSettings() { - await InitializeModule(); - var settingsString = await module.InvokeAsync("getAppSettings"); + await this.InitializeModule(); + var settingsString = await this.module.InvokeAsync("getAppSettings"); var result = settingsString == null ? null : JsonConvert.DeserializeObject(settingsString); if (result is not null) { @@ -32,8 +32,8 @@ public WebSettingsAccessor(IJSRuntime runtime) public async Task SaveSettings(AppSettings appSettings) { - await InitializeModule(); - await module.InvokeVoidAsync("setAppSettings", JsonConvert.SerializeObject(appSettings)); + await this.InitializeModule(); + await this.module.InvokeVoidAsync("setAppSettings", JsonConvert.SerializeObject(appSettings)); } [MemberNotNull(nameof(module))] @@ -41,17 +41,17 @@ private async Task InitializeModule() { // module is not null after this method but apparently, Roslyn does not want to recognize that. #pragma warning disable CS8774 - module ??= await runtime.InvokeAsync("import", "/_content/WoWsShipBuilder.Common/scripts/settingsHelper.js"); + this.module ??= await this.runtime.InvokeAsync("import", "/_content/WoWsShipBuilder.Common/scripts/settingsHelper.js"); #pragma warning restore CS8774 } public async ValueTask DisposeAsync() { - if (module is not null) + if (this.module is not null) { try { - await module.DisposeAsync(); + await this.module.DisposeAsync(); } catch (JSDisconnectedException) { diff --git a/WoWsShipBuilder.Web/Infrastructure/Data/DataInitializer.cs b/WoWsShipBuilder.Web/Infrastructure/Data/DataInitializer.cs index c3f467333..48282df55 100644 --- a/WoWsShipBuilder.Web/Infrastructure/Data/DataInitializer.cs +++ b/WoWsShipBuilder.Web/Infrastructure/Data/DataInitializer.cs @@ -23,12 +23,12 @@ public DataInitializer(IOptions cdnOptions, ILocalizationProvider lo public async Task InitializeData() { - await localizationProvider.RefreshDataAsync(cdnOptions.Server, AppConstants.SupportedLanguages.ToArray()); - if (appDataService is ServerAppDataService serverAppDataService) + await this.localizationProvider.RefreshDataAsync(this.cdnOptions.Server, AppConstants.SupportedLanguages.ToArray()); + if (this.appDataService is ServerAppDataService serverAppDataService) { - if (cdnOptions.UseLocalFiles) + if (this.cdnOptions.UseLocalFiles) { - await serverAppDataService.LoadLocalFilesAsync(cdnOptions.Server); + await serverAppDataService.LoadLocalFilesAsync(this.cdnOptions.Server); } else { diff --git a/WoWsShipBuilder.Web/Infrastructure/Data/ServerAppDataService.cs b/WoWsShipBuilder.Web/Infrastructure/Data/ServerAppDataService.cs index d7c5e5867..1dd6a953e 100644 --- a/WoWsShipBuilder.Web/Infrastructure/Data/ServerAppDataService.cs +++ b/WoWsShipBuilder.Web/Infrastructure/Data/ServerAppDataService.cs @@ -32,27 +32,27 @@ public ServerAppDataService(IAwsClient awsClient, IOptions options, this.awsClient = awsClient; this.options = options.Value; this.logger = logger; - DefaultAppDataDirectory = string.Empty; - AppDataDirectory = string.Empty; - AppDataImageDirectory = string.Empty; + this.DefaultAppDataDirectory = string.Empty; + this.AppDataDirectory = string.Empty; + this.AppDataImageDirectory = string.Empty; } public async Task FetchData() { - logger.LogInformation("Starting to fetch data with server type {Server}...", options.Server); + this.logger.LogInformation("Starting to fetch data with server type {Server}...", this.options.Server); const string undefinedMarker = "undefined"; AppData.ResetCaches(); - var onlineVersionInfo = await awsClient.DownloadVersionInfo(options.Server); + var onlineVersionInfo = await this.awsClient.DownloadVersionInfo(this.options.Server); if (onlineVersionInfo.CurrentVersion is not null) { AppData.DataVersion = onlineVersionInfo.CurrentVersion.MainVersion.ToString(3) + "#" + onlineVersionInfo.CurrentVersion.DataIteration; - logger.LogInformation("Found online version info with version {Version}", AppData.DataVersion); + this.logger.LogInformation("Found online version info with version {Version}", AppData.DataVersion); } else { AppData.DataVersion = undefinedMarker; - logger.LogWarning("Online version info not available"); + this.logger.LogWarning("Online version info not available"); } SentrySdk.ConfigureScope(scope => @@ -62,8 +62,8 @@ public async Task FetchData() scope.SetTag("data.server", onlineVersionInfo.CurrentVersion?.VersionType.ToString() ?? undefinedMarker); }); var files = onlineVersionInfo.Categories.SelectMany(category => category.Value.Select(file => (category.Key, file.FileName))).ToList(); - await awsClient.DownloadFiles(options.Server, files); - logger.LogInformation("Finished fetching data"); + await this.awsClient.DownloadFiles(this.options.Server, files); + this.logger.LogInformation("Finished fetching data"); } public async Task LoadLocalFilesAsync(ServerType serverType) @@ -94,16 +94,16 @@ public async Task LoadLocalFilesAsync(ServerType serverType) public async Task GetCurrentVersionInfo(ServerType serverType) { - versionInfo ??= await awsClient.DownloadVersionInfo(serverType); - return versionInfo; + this.versionInfo ??= await this.awsClient.DownloadVersionInfo(serverType); + return this.versionInfo; } public async Task?> ReadLocalizationData(ServerType serverType, string language) { - if (options.UseLocalFiles) + if (this.options.UseLocalFiles) { const string shipBuilderDirectory = "WoWsShipBuilderDev"; - string localizationRoot = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), shipBuilderDirectory, "json", options.Server.StringName(), "Localization"); + string localizationRoot = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), shipBuilderDirectory, "json", this.options.Server.StringName(), "Localization"); string file = Path.Join(localizationRoot, $"{language}.json"); if (!File.Exists(file)) { @@ -114,7 +114,7 @@ public async Task LoadLocalFilesAsync(ServerType serverType) return JsonConvert.DeserializeObject>(fileContent); } - if (awsClient is ServerAwsClient serverAwsClient) + if (this.awsClient is ServerAwsClient serverAwsClient) { return await serverAwsClient.DownloadLocalization(language, serverType); } diff --git a/WoWsShipBuilder.Web/Infrastructure/Data/WebUserDataService.cs b/WoWsShipBuilder.Web/Infrastructure/Data/WebUserDataService.cs index 460ae686e..259049474 100644 --- a/WoWsShipBuilder.Web/Infrastructure/Data/WebUserDataService.cs +++ b/WoWsShipBuilder.Web/Infrastructure/Data/WebUserDataService.cs @@ -31,20 +31,20 @@ public WebUserDataService(IJSRuntime runtime, ISnackbar snackbar) public async Task SaveBuildsAsync(IEnumerable builds) { - await InitializeModule(); + await this.InitializeModule(); var buildStrings = builds.Select(x => x.CreateShortStringFromBuild()); - await module.InvokeVoidAsync("saveData", BuildFileName, JsonSerializer.Serialize(buildStrings)); + await this.module.InvokeVoidAsync("saveData", BuildFileName, JsonSerializer.Serialize(buildStrings)); } public async Task> LoadBuildsAsync() { - if (savedBuilds is not null) + if (this.savedBuilds is not null) { - return savedBuilds; + return this.savedBuilds; } - await InitializeModule(); - var buildStrings = await module.InvokeAsync("loadData", BuildFileName); + await this.InitializeModule(); + var buildStrings = await this.module.InvokeAsync("loadData", BuildFileName); if (buildStrings is not null) { IEnumerable? buildList = null; @@ -82,71 +82,71 @@ public async Task> LoadBuildsAsync() } if (counter > 0) { - snackbar.Add($"{counter} builds could not be loaded.", Severity.Warning); + this.snackbar.Add($"{counter} builds could not be loaded.", Severity.Warning); } - savedBuilds = builds.DistinctBy(x => x.Hash).ToList(); + this.savedBuilds = builds.DistinctBy(x => x.Hash).ToList(); } } - return savedBuilds ?? new List(); + return this.savedBuilds ?? new List(); } public async Task ImportBuildsAsync(IEnumerable builds) { - savedBuilds ??= (await LoadBuildsAsync()).ToList(); + this.savedBuilds ??= (await this.LoadBuildsAsync()).ToList(); foreach (var build in builds) { - savedBuilds.RemoveAll(x => x.Equals(build)); - savedBuilds.Insert(0, build); + this.savedBuilds.RemoveAll(x => x.Equals(build)); + this.savedBuilds.Insert(0, build); } - snackbar.Configuration.PositionClass = Defaults.Classes.Position.BottomEnd; + this.snackbar.Configuration.PositionClass = Defaults.Classes.Position.BottomEnd; // actual local storage limit is around 3700 builds but we limit it to 1000 for performance reasons - switch (savedBuilds.Count) + switch (this.savedBuilds.Count) { case < 1000: { - snackbar.Add("Builds have been saved.", Severity.Success); + this.snackbar.Add("Builds have been saved.", Severity.Success); break; } case 1000: { - snackbar.Add("Builds storage limit reached. Next addition will replace the oldest saved build.", Severity.Warning); + this.snackbar.Add("Builds storage limit reached. Next addition will replace the oldest saved build.", Severity.Warning); break; } case > 1000: { - snackbar.Add("Builds storage is full. The oldest saved build has been replaced.", Severity.Error); - savedBuilds = savedBuilds.Take(1000).ToList(); + this.snackbar.Add("Builds storage is full. The oldest saved build has been replaced.", Severity.Error); + this.savedBuilds = this.savedBuilds.Take(1000).ToList(); break; } } - await SaveBuildsAsync(savedBuilds); + await this.SaveBuildsAsync(this.savedBuilds); } - public async Task SaveBuildAsync(Build build) => await ImportBuildsAsync(new List { build }); + public async Task SaveBuildAsync(Build build) => await this.ImportBuildsAsync(new List { build }); - public async Task RemoveSavedBuildAsync(Build build) => await RemoveSavedBuildsAsync(new List { build }); + public async Task RemoveSavedBuildAsync(Build build) => await this.RemoveSavedBuildsAsync(new List { build }); public async Task RemoveSavedBuildsAsync(IEnumerable builds) { - savedBuilds ??= (await LoadBuildsAsync()).ToList(); - savedBuilds.RemoveMany(builds); + this.savedBuilds ??= (await this.LoadBuildsAsync()).ToList(); + this.savedBuilds.RemoveMany(builds); - await SaveBuildsAsync(savedBuilds); + await this.SaveBuildsAsync(this.savedBuilds); } public async ValueTask DisposeAsync() { - if (module is not null) + if (this.module is not null) { try { - await module.DisposeAsync(); + await this.module.DisposeAsync(); } catch (JSDisconnectedException) { @@ -160,7 +160,7 @@ private async Task InitializeModule() { // module is not null after this method but apparently, Roslyn does not want to recognize that. #pragma warning disable CS8774 - module ??= await runtime.InvokeAsync("import", JsFileName); + this.module ??= await this.runtime.InvokeAsync("import", JsFileName); #pragma warning restore CS8774 } } diff --git a/WoWsShipBuilder.Web/Infrastructure/Metrics/ReferrerTrackingMiddleware.cs b/WoWsShipBuilder.Web/Infrastructure/Metrics/ReferrerTrackingMiddleware.cs index cf587469e..7f10774d7 100644 --- a/WoWsShipBuilder.Web/Infrastructure/Metrics/ReferrerTrackingMiddleware.cs +++ b/WoWsShipBuilder.Web/Infrastructure/Metrics/ReferrerTrackingMiddleware.cs @@ -20,10 +20,10 @@ public async Task InvokeAsync(HttpContext context) { if (context.Request.Query.TryGetValue(ReferrerQueryParamName, out var refValue) && !string.IsNullOrWhiteSpace(refValue)) { - metricsService.RefCount.WithLabels(refValue!, context.Request.Path).Inc(); + this.metricsService.RefCount.WithLabels(refValue!, context.Request.Path).Inc(); } - await next(context); + await this.next(context); } } diff --git a/WoWsShipBuilder.Web/Infrastructure/ServerAwsClient.cs b/WoWsShipBuilder.Web/Infrastructure/ServerAwsClient.cs index ac8b247bf..1f963e14e 100644 --- a/WoWsShipBuilder.Web/Infrastructure/ServerAwsClient.cs +++ b/WoWsShipBuilder.Web/Infrastructure/ServerAwsClient.cs @@ -26,14 +26,14 @@ public ServerAwsClient(HttpClient httpClient, IOptions options, ILog public async Task DownloadVersionInfo(ServerType serverType) { - var url = @$"{options.Host}/api/{serverType.StringName()}/VersionInfo.json"; - string stringContent = await httpClient.GetStringAsync(url); + var url = @$"{this.options.Host}/api/{serverType.StringName()}/VersionInfo.json"; + string stringContent = await this.httpClient.GetStringAsync(url); return JsonConvert.DeserializeObject(stringContent) ?? throw new HttpRequestException("Unable to process VersionInfo response from AWS server."); } public async Task DownloadFiles(ServerType serverType, List<(string, string)> relativeFilePaths, IProgress? downloadProgress = null) { - string baseUrl = @$"{options.Host}/api/{serverType.StringName()}/"; + string baseUrl = @$"{this.options.Host}/api/{serverType.StringName()}/"; var taskList = new List(); int totalFiles = relativeFilePaths.Count; var finished = 0; @@ -50,11 +50,11 @@ public async Task DownloadFiles(ServerType serverType, List<(string, string)> re { try { - await DownloadFileAsync(uri, category, fileName); + await this.DownloadFileAsync(uri, category, fileName); } catch (HttpRequestException e) { - logger.LogWarning(e, "Encountered an exception while downloading a file with uri {Uri}", uri); + this.logger.LogWarning(e, "Encountered an exception while downloading a file with uri {Uri}", uri); } progress.Report(1); @@ -68,13 +68,13 @@ public async Task DownloadFiles(ServerType serverType, List<(string, string)> re public async Task> DownloadLocalization(string language, ServerType serverType) { - string baseUrl = @$"{options.Host}/api/{serverType.StringName()}/"; - return await httpClient.GetFromJsonAsync>($"{baseUrl}Localization/{language}.json") ?? throw new InvalidOperationException(); + string baseUrl = @$"{this.options.Host}/api/{serverType.StringName()}/"; + return await this.httpClient.GetFromJsonAsync>($"{baseUrl}Localization/{language}.json") ?? throw new InvalidOperationException(); } private async Task DownloadFileAsync(Uri uri, string category, string fileName) { - var str = await httpClient.GetStringAsync(uri); + var str = await this.httpClient.GetStringAsync(uri); await DataCacheHelper.AddToCache(fileName, category, str); } } diff --git a/WoWsShipBuilder.Web/Infrastructure/WebClipboardService.cs b/WoWsShipBuilder.Web/Infrastructure/WebClipboardService.cs index 0a0c93085..efe484b83 100644 --- a/WoWsShipBuilder.Web/Infrastructure/WebClipboardService.cs +++ b/WoWsShipBuilder.Web/Infrastructure/WebClipboardService.cs @@ -19,12 +19,12 @@ public WebClipboardService(IJSRuntime jsRuntime) public async Task GetTextAsync() { - return await jsRuntime.InvokeAsync("navigator.clipboard.readText"); + return await this.jsRuntime.InvokeAsync("navigator.clipboard.readText"); } public async Task SetTextAsync(string text) { - await jsRuntime.InvokeVoidAsync("navigator.clipboard.writeText", text); + await this.jsRuntime.InvokeVoidAsync("navigator.clipboard.writeText", text); } public Task ClearAsync() From 7627e6430b0b0e6455bc03ba50abcacb273c6f46 Mon Sep 17 00:00:00 2001 From: floribe2000 Date: Sun, 29 Oct 2023 02:00:49 +0200 Subject: [PATCH 15/26] resolve sonarlint warnings --- .../BuildTests/BuildStringCreation.cs | 15 ++++--- .../AccelerationCharts.razor | 8 ++-- .../BallisticCharts/BallisticHelper.cs | 14 ------ .../Features/BallisticCharts/Charts.razor | 6 +-- .../ShipAndShellSelectionDialog.razor | 7 ++- .../Features/Builds/Build.cs | 2 +- .../Features/Builds/BuildValidation.cs | 2 +- .../Components/BuildConfigurationDialog.razor | 22 ++++------ .../CaptainSkillSelectorImageRender.razor | 6 +-- .../Features/Builds/ShipBuildViewModel.cs | 6 +-- .../DataContainers/AccelerationCalculator.cs | 2 +- .../Aircraft/CvAircraftDataContainer.cs | 21 ++++----- .../DepthChargesLauncherDataContainer.cs | 4 +- .../Armament/MainBatteryDataContainer.cs | 16 +++---- .../Armament/PingerGunDataContainer.cs | 6 +-- .../Armament/SecondaryBatteryDataContainer.cs | 10 ++--- .../Armament/TorpedoArmamentDataContainer.cs | 12 ++--- .../Projectiles/TorpedoDataContainer.cs | 44 +++++++++---------- .../Ship/AntiAirDataContainer.cs | 13 ++---- .../Ship/ConcealmentDataContainer.cs | 12 ++--- .../Ship/ManeuverabilityDataContainer.cs | 4 +- .../ShipComparison/ComparisonShipFilter.razor | 4 +- .../GridData/GridDataWrapper.cs | 12 ++--- .../GridSections/AaDefenseFragment.razor | 2 +- .../CaptainSkillSelectorViewModel.cs | 10 ++--- WoWsShipBuilder.Common/wwwroot/css/app.css | 2 +- 26 files changed, 117 insertions(+), 145 deletions(-) diff --git a/WoWsShipBuilder.Common.Test/BuildTests/BuildStringCreation.cs b/WoWsShipBuilder.Common.Test/BuildTests/BuildStringCreation.cs index 36cde8cc1..4061386d0 100644 --- a/WoWsShipBuilder.Common.Test/BuildTests/BuildStringCreation.cs +++ b/WoWsShipBuilder.Common.Test/BuildTests/BuildStringCreation.cs @@ -6,19 +6,19 @@ namespace WoWsShipBuilder.Test.BuildTests; [TestFixture] -public class BuildStringCreation +public partial class BuildStringCreation { - private readonly Regex buildRegex = new(@"^(?[^;]*);(?[A-Z0-9,]*);(?[A-Z0-9,]*);(?[A-Z0-9]+);(?[0-9,]*);(?[A-Z0-9,]*);(?[A-Z0-9,]*);(?\d+)(;(?[^;]*))?$"); + private readonly Regex buildRegex = BuildRegex(); [Test] public void EmptyBuild_CreateShortString_ExpectedResult() { const string buildName = "test-build"; const string shipIndex = "PASC020"; - string expectedString = $"{shipIndex};;;PCW001;;;;{Build.CurrentBuildVersion};{buildName}"; + var expectedString = $"{shipIndex};;;PCW001;;;;{Build.CurrentBuildVersion};{buildName}"; var build = new Build(buildName, shipIndex, Nation.Usa, new(), new(), new(), "PCW001", new(), new()); - string result = build.CreateShortStringFromBuild(); + var result = build.CreateShortStringFromBuild(); result.Should().Be(expectedString); } @@ -29,7 +29,7 @@ public void EmptyBuild_CreateShortStringWithBuildName_MatchesRegex() const string buildName = "test-build"; const string shipIndex = "PASC020"; var build = new Build(buildName, shipIndex, Nation.Usa, new(), new(), new(), "PCW001", new(), new()); - string buildString = build.CreateShortStringFromBuild(); + var buildString = build.CreateShortStringFromBuild(); var result = this.buildRegex.Match(buildString); @@ -46,7 +46,7 @@ public void EmptyBuild_CreateShortStringWithoutBuildName_MatchesRegex() { const string shipIndex = "PASC020"; var build = new Build(string.Empty, shipIndex, Nation.Usa, new(), new(), new(), "PCW001", new(), new()); - string buildString = build.CreateShortStringFromBuild(); + var buildString = build.CreateShortStringFromBuild(); var result = this.buildRegex.Match(buildString); @@ -57,4 +57,7 @@ public void EmptyBuild_CreateShortStringWithoutBuildName_MatchesRegex() result.Groups["buildName"].Success.Should().BeTrue(); result.Groups["buildName"].Value.Should().BeEmpty(); } + + [GeneratedRegex("^(?[^;]*);(?[A-Z0-9,]*);(?[A-Z0-9,]*);(?[A-Z0-9]+);(?[0-9,]*);(?[A-Z0-9,]*);(?[A-Z0-9,]*);(?\\d+)(;(?[^;]*))?$")] + private static partial Regex BuildRegex(); } diff --git a/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor b/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor index 20f77bfc0..cc513d658 100644 --- a/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor +++ b/WoWsShipBuilder.Common/Features/AccelerationCharts/AccelerationCharts.razor @@ -148,8 +148,8 @@ modules.AddRange(upgradeList.Where(upgrade => shipWrapper.Build.Modules.Contains(upgrade.Name.NameToIndex()))); } - hull = shipWrapper.Ship.Hulls[modules.First(x => x.UcType == ComponentType.Hull).Components.First(x => x.Key == ComponentType.Hull).Value.First()]; - engine = shipWrapper.Ship.Engines[modules.First(x => x.UcType == ComponentType.Engine).Components.First(x => x.Key == ComponentType.Engine).Value.First()]; + hull = shipWrapper.Ship.Hulls[modules.First(x => x.UcType == ComponentType.Hull).Components.First(x => x.Key == ComponentType.Hull).Value[0]]; + engine = shipWrapper.Ship.Engines[modules.First(x => x.UcType == ComponentType.Engine).Components.First(x => x.Key == ComponentType.Engine).Value[0]]; } else { @@ -186,8 +186,8 @@ modules.AddRange(upgradeList.Where(upgrade => shipWrapper.Build.Modules.Contains(upgrade.Name.NameToIndex()))); } - hull = shipWrapper.Ship.Hulls[modules.First(x => x.UcType == ComponentType.Hull).Components.First(x => x.Key == ComponentType.Hull).Value.First()]; - engine = shipWrapper.Ship.Engines[modules.First(x => x.UcType == ComponentType.Engine).Components.First(x => x.Key == ComponentType.Engine).Value.First()]; + hull = shipWrapper.Ship.Hulls[modules.First(x => x.UcType == ComponentType.Hull).Components.First(x => x.Key == ComponentType.Hull).Value[0]]; + engine = shipWrapper.Ship.Engines[modules.First(x => x.UcType == ComponentType.Engine).Components.First(x => x.Key == ComponentType.Engine).Value[0]]; } else { diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/BallisticHelper.cs b/WoWsShipBuilder.Common/Features/BallisticCharts/BallisticHelper.cs index 8e16885f7..16f038cec 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/BallisticHelper.cs +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/BallisticHelper.cs @@ -51,20 +51,6 @@ private static List CreateCalculationAngles() return list; } - private static double GetNormalization(double caliber) - { - double norm = caliber switch - { - <= 0.139 => 10 * Math.PI / 180, - <= 0.152 => 8.5 * Math.PI / 180, - <= 0.24 => 7 * Math.PI / 180, - < 0.51 => 6 * Math.PI / 180, - _ => 15 * Math.PI / 180, - }; - - return norm; - } - /// /// Calculate all values for a shell. /// diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor b/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor index a34137b1c..c3cb2c630 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/Charts.razor @@ -704,13 +704,13 @@ private void UpdateDispersionPlotParameters() { - foreach (var wrapper in displayedShips.Values) + foreach (var selectedShells in displayedShips.Values.Select(wrapper => wrapper.SelectedShells)) { - foreach (var (shellIndex, shellData) in wrapper.SelectedShells.ToDictionary(x => x.Key, x => x.Value)) + foreach (var (shellIndex, shellData) in selectedShells.ToDictionary(x => x.Key, x => x.Value)) { var dispPlotShipsCache = shellData.DispPlotShipsCache; var dispersionPlotParameter = DispersionPlotHelper.CalculateDispersionPlotParameters(dispPlotShipsCache!.Label, dispPlotShipsCache.DispersionData, dispPlotShipsCache.Shell, dispPlotShipsCache.MaxRange, aimingRange * 1000, dispPlotShipsCache.Sigma, shotsNumber, dispPlotShipsCache.Modifier); - wrapper.SelectedShells[shellIndex] = shellData with { DispPlotShipsCache = dispersionPlotParameter }; + selectedShells[shellIndex] = shellData with { DispPlotShipsCache = dispersionPlotParameter }; } } } diff --git a/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor b/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor index 1d9818af1..5ab5cff5a 100644 --- a/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor +++ b/WoWsShipBuilder.Common/Features/BallisticCharts/ShipAndShellSelectionDialog.razor @@ -74,7 +74,7 @@ @Localizer.GetAppLocalization(nameof(Translation.Cancel)).Localization - + @if (processing) { @@ -220,7 +220,7 @@ else { commonHullName = wrapper.ShipBuildContainer.Ship.ShellCompatibilities[selectedShells.Single()].CompatibleHullArtilleryModulesCombo.Keys.First(); - commonArtilleryName = wrapper.ShipBuildContainer.Ship.ShellCompatibilities[selectedShells.Single()].CompatibleHullArtilleryModulesCombo[commonHullName].First(); + commonArtilleryName = wrapper.ShipBuildContainer.Ship.ShellCompatibilities[selectedShells.Single()].CompatibleHullArtilleryModulesCombo[commonHullName][0]; } var ship = wrapper.ShipBuildContainer.Ship; @@ -324,10 +324,9 @@ private static void UpgradeModuleInShipConfiguration(List shipUpgrades, ShipUpgrade shipUpgrade) { - ShipUpgrade? oldItem = shipUpgrades.FirstOrDefault(module => module.UcType == shipUpgrade.UcType); + var oldItem = shipUpgrades.Find(module => module.UcType == shipUpgrade.UcType); if (oldItem != null) { - // SelectedModules.Remove(oldItem); shipUpgrades.Replace(oldItem, shipUpgrade); } else diff --git a/WoWsShipBuilder.Common/Features/Builds/Build.cs b/WoWsShipBuilder.Common/Features/Builds/Build.cs index 8219f439a..56f49652b 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Build.cs +++ b/WoWsShipBuilder.Common/Features/Builds/Build.cs @@ -215,6 +215,6 @@ public string CreateShortStringFromBuild() private static IEnumerable ReduceToIndex(IEnumerable names) { - return names.Select(x => x.Split("_").First()); + return names.Select(x => x.Split("_")[0]); } } diff --git a/WoWsShipBuilder.Common/Features/Builds/BuildValidation.cs b/WoWsShipBuilder.Common/Features/Builds/BuildValidation.cs index 77d8d3c2a..4fb9f166c 100644 --- a/WoWsShipBuilder.Common/Features/Builds/BuildValidation.cs +++ b/WoWsShipBuilder.Common/Features/Builds/BuildValidation.cs @@ -40,7 +40,7 @@ public static async Task ValidateBuildString(string try { var build = Build.CreateBuildFromString(buildStr); - if (selectedShipIndex.Equals(build.ShipIndex)) + if (selectedShipIndex.Equals(build.ShipIndex, StringComparison.Ordinal)) { validatedBuildString = buildStr; return new(null, validatedBuildString); diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor b/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor index 5c6008435..fde1265fb 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/BuildConfigurationDialog.razor @@ -127,7 +127,7 @@ private string inputBuildString = string.Empty; - private readonly Dictionary buildNameDictionary = new(); + private readonly ConcurrentDictionary buildNameDictionary = new(); private readonly RenderFragment tabContent; @@ -228,19 +228,7 @@ protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); - UpdateViewModel(); - - // TODO Check why this Task.Run is even used and if it can be removed - await Task.Run(() => - { - foreach (var container in Ships.Skip(1)) - { - var vm = LoadShipViewModel(container); - vmCache.TryAdd(container.Id, vm); - buildNameDictionary[container.Id] = !string.IsNullOrEmpty(container.Build?.BuildName) ? container.Build.BuildName : Build.DefaultBuildName; - } - }); StateHasChanged(); } @@ -249,6 +237,12 @@ if (firstRender) { module ??= await Runtime.InvokeAsync("import", "/_content/WoWsShipBuilder.Common/scripts/buildImageDecoder.js"); + foreach (var container in Ships.Skip(1)) + { + var vm = LoadShipViewModel(container); + vmCache.TryAdd(container.Id, vm); + buildNameDictionary[container.Id] = !string.IsNullOrEmpty(container.Build?.BuildName) ? container.Build.BuildName : Build.DefaultBuildName; + } } await base.OnAfterRenderAsync(firstRender); } @@ -293,7 +287,7 @@ var result = new List(); foreach (var container in Ships) { - result.Add(vmCache.TryGetValue(container.Id, out var vm) ? vm.CreateShipBuildContainerAsync(container) : container); + result.Add(vmCache.TryGetValue(container.Id, out var vm) ? vm.CreateShipBuildContainer(container) : container); } MudDialog.Close(DialogResult.Ok(result)); diff --git a/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor b/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor index 2e7dbc37f..95963c867 100644 --- a/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor +++ b/WoWsShipBuilder.Common/Features/Builds/Components/CaptainSkillSelectorImageRender.razor @@ -24,7 +24,7 @@ - + @@ -93,14 +93,14 @@ @code { + private static readonly string SpecialIconPath = """"""; + [Parameter] public ShipClass ShipClass { get; set; } [CascadingParameter] private Breakpoint Breakpoint { get; set; } - private string specialIconPath = @""; - private static string ToSnakeCase(string camelCaseString) { if (camelCaseString == null) diff --git a/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs b/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs index 7e5abee9d..c7427a3b1 100644 --- a/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs +++ b/WoWsShipBuilder.Common/Features/Builds/ShipBuildViewModel.cs @@ -76,7 +76,7 @@ public static ShipBuildViewModel Create(ShipBuildContainer shipBuildContainer) return null; } - public ShipBuildContainer CreateShipBuildContainerAsync(ShipBuildContainer baseContainer) + public ShipBuildContainer CreateShipBuildContainer(ShipBuildContainer baseContainer) { var build = this.DumpToBuild(); List? activatedConsumables = this.ConsumableViewModel.ActivatedSlots.Any() ? this.ConsumableViewModel.ActivatedSlots.ToList() : null; @@ -86,12 +86,12 @@ public ShipBuildContainer CreateShipBuildContainerAsync(ShipBuildContainer baseC Build = build, ActivatedConsumableSlots = activatedConsumables, SpecialAbilityActive = this.SpecialAbilityActive, - ShipDataContainer = this.CreateDataContainerAsync(modifiers), + ShipDataContainer = this.CreateDataContainer(modifiers), Modifiers = modifiers, }; } - private ShipDataContainer CreateDataContainerAsync(List<(string, float)> modifiers) + private ShipDataContainer CreateDataContainer(List<(string, float)> modifiers) { return ShipDataContainer.CreateFromShip(this.CurrentShip, this.ShipModuleViewModel.SelectedModules.ToList(), modifiers); } diff --git a/WoWsShipBuilder.Common/Features/DataContainers/AccelerationCalculator.cs b/WoWsShipBuilder.Common/Features/DataContainers/AccelerationCalculator.cs index a73297cc5..8153d8ce6 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/AccelerationCalculator.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/AccelerationCalculator.cs @@ -166,7 +166,7 @@ public static AccelerationData CalculateAcceleration( /// The value of the ratio. private static int GetPfToPbRatio(ShipClass shipClass, string shipIndex) { - if (shipIndex.Equals(CaraccioloId)) + if (shipIndex.Equals(CaraccioloId, StringComparison.Ordinal)) { return 3; } diff --git a/WoWsShipBuilder.Common/Features/DataContainers/Aircraft/CvAircraftDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Aircraft/CvAircraftDataContainer.cs index 0e0feabc5..3741570c0 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/Aircraft/CvAircraftDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Aircraft/CvAircraftDataContainer.cs @@ -97,8 +97,6 @@ public partial record CvAircraftDataContainer : DataContainerBase public string WeaponType { get; set; } = default!; - public bool IsLast { get; set; } - public ProjectileDataContainer? Weapon { get; set; } public List PlaneConsumables { get; set; } = default!; @@ -120,31 +118,31 @@ public partial record CvAircraftDataContainer : DataContainerBase var list = new List(); var planes = new List(); - var rocketConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Fighter); + var rocketConfiguration = shipConfiguration.Find(c => c.UcType == ComponentType.Fighter); if (rocketConfiguration != null) { - List skipModule = ship.CvPlanes[rocketConfiguration.Components[ComponentType.Fighter].First()]; + List skipModule = ship.CvPlanes[rocketConfiguration.Components[ComponentType.Fighter][0]]; planes.AddRange(skipModule); } - var torpConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.TorpedoBomber); + var torpConfiguration = shipConfiguration.Find(c => c.UcType == ComponentType.TorpedoBomber); if (torpConfiguration != null) { - List skipModule = ship.CvPlanes[torpConfiguration.Components[ComponentType.TorpedoBomber].First()]; + List skipModule = ship.CvPlanes[torpConfiguration.Components[ComponentType.TorpedoBomber][0]]; planes.AddRange(skipModule); } - var diveConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.DiveBomber); + var diveConfiguration = shipConfiguration.Find(c => c.UcType == ComponentType.DiveBomber); if (diveConfiguration != null) { - List diveModule = ship.CvPlanes[diveConfiguration.Components[ComponentType.DiveBomber].First()]; + List diveModule = ship.CvPlanes[diveConfiguration.Components[ComponentType.DiveBomber][0]]; planes.AddRange(diveModule); } - var skipConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.SkipBomber); + var skipConfiguration = shipConfiguration.Find(c => c.UcType == ComponentType.SkipBomber); if (skipConfiguration != null) { - List skipModule = ship.CvPlanes[skipConfiguration.Components[ComponentType.SkipBomber].First()]; + List skipModule = ship.CvPlanes[skipConfiguration.Components[ComponentType.SkipBomber][0]]; planes.AddRange(skipModule); } @@ -157,7 +155,6 @@ public partial record CvAircraftDataContainer : DataContainerBase list.Add(planeDataContainer); } - list.Last().IsLast = true; return list; } @@ -291,7 +288,7 @@ private static CvAircraftDataContainer ProcessCvPlane(Aircraft plane, int shipTi { plane.BombName, }; - weapon = TorpedoDataContainer.FromTorpedoName(torpList, modifiers, true).First(); + weapon = TorpedoDataContainer.FromTorpedoName(torpList, modifiers, true)[0]; break; case ProjectileType.Rocket: weapon = RocketDataContainer.FromRocketName(plane.BombName, modifiers); diff --git a/WoWsShipBuilder.Common/Features/DataContainers/Armament/DepthChargesLauncherDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/DepthChargesLauncherDataContainer.cs index 5b751b0b2..9783bdc92 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/Armament/DepthChargesLauncherDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/DepthChargesLauncherDataContainer.cs @@ -22,7 +22,7 @@ public partial record DepthChargesLauncherDataContainer : DataContainerBase public static DepthChargesLauncherDataContainer? FromShip(Ship ship, List shipConfiguration, List<(string Key, float Value)> modifiers) { - var shipHull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull].First()]; + var shipHull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull][0]]; var depthChargesArray = shipHull.DepthChargeArray; @@ -32,7 +32,7 @@ public partial record DepthChargesLauncherDataContainer : DataContainerBase } int ammoPerAttack = depthChargesArray.DepthCharges.Sum(charge => charge.DepthChargesNumber) * depthChargesArray.NumShots; - string ammoName = depthChargesArray.DepthCharges.First(charge => charge.DepthChargesNumber > 0).AmmoList.First(); + string ammoName = depthChargesArray.DepthCharges.First(charge => charge.DepthChargesNumber > 0).AmmoList[0]; int numberOfUses = modifiers.FindModifiers("dcNumPacksBonus").Aggregate(depthChargesArray.MaxPacks, (current, modifier) => current + (int)modifier); diff --git a/WoWsShipBuilder.Common/Features/DataContainers/Armament/MainBatteryDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/MainBatteryDataContainer.cs index 6f73b59e7..357a07895 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/Armament/MainBatteryDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/MainBatteryDataContainer.cs @@ -102,7 +102,7 @@ public partial record MainBatteryDataContainer : DataContainerBase public static MainBatteryDataContainer? FromShip(Ship ship, List shipConfiguration, List<(string name, float value)> modifiers) { - var artilleryConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Artillery); + var artilleryConfiguration = shipConfiguration.Find(c => c.UcType == ComponentType.Artillery); if (artilleryConfiguration == null) { return null; @@ -114,7 +114,7 @@ public partial record MainBatteryDataContainer : DataContainerBase TurretModule? mainBattery; if (artilleryOptions.Length == 1) { - mainBattery = ship.MainBatteryModuleList[supportedModules.First()]; + mainBattery = ship.MainBatteryModuleList[supportedModules[0]]; } else { @@ -122,7 +122,7 @@ public partial record MainBatteryDataContainer : DataContainerBase mainBattery = ship.MainBatteryModuleList[hullArtilleryName]; } - var suoName = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Suo)?.Components[ComponentType.Suo].First(); + var suoName = shipConfiguration.Find(c => c.UcType == ComponentType.Suo)?.Components[ComponentType.Suo][0]; var suoConfiguration = suoName is not null ? ship.FireControlList[suoName] : null; List<(int BarrelCount, int TurretCount, string GunName)> arrangementList = mainBattery.Guns @@ -145,7 +145,7 @@ public partial record MainBatteryDataContainer : DataContainerBase barrelCount += current.TurretCount * current.BarrelCount; } - var gun = mainBattery.Guns.First(); + var gun = mainBattery.Guns[0]; // Calculate main battery reload var reloadModifiers = modifiers.FindModifiers("GMShotDelay"); @@ -183,7 +183,7 @@ public partial record MainBatteryDataContainer : DataContainerBase var nfi = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone(); nfi.NumberGroupSeparator = "'"; - var shellData = ShellDataContainer.FromShellName(mainBattery.Guns.First().AmmoList, modifiers, barrelCount, true); + var shellData = ShellDataContainer.FromShellName(mainBattery.Guns[0].AmmoList, modifiers, barrelCount, true); var (horizontalDispersion, verticalDispersion) = dispersion.CalculateDispersion((double)range * 1000, dispersionModifier); @@ -220,7 +220,7 @@ public partial record MainBatteryDataContainer : DataContainerBase if (mainBatteryDataContainer.DisplayHeDpm) { - var heShell = shellData.First(x => x.Type.Equals($"ArmamentType_{ShellType.HE.ShellTypeToString()}")); + var heShell = shellData.First(x => x.Type.Equals($"ArmamentType_{ShellType.HE.ShellTypeToString()}", StringComparison.Ordinal)); mainBatteryDataContainer.TheoreticalHeDpm = Math.Round(heShell.Damage * barrelCount * rateOfFire).ToString("n0", nfi); mainBatteryDataContainer.HeSalvo = Math.Round(heShell.Damage * barrelCount).ToString("n0", nfi); mainBatteryDataContainer.PotentialFpm = Math.Round(heShell.ShellFireChance / 100 * barrelCount * rateOfFire, 2); @@ -228,14 +228,14 @@ public partial record MainBatteryDataContainer : DataContainerBase if (mainBatteryDataContainer.DisplayApDpm) { - decimal shellDamage = shellData.First(x => x.Type.Equals($"ArmamentType_{ShellType.AP.ShellTypeToString()}")).Damage; + decimal shellDamage = shellData.First(x => x.Type.Equals($"ArmamentType_{ShellType.AP.ShellTypeToString()}", StringComparison.Ordinal)).Damage; mainBatteryDataContainer.TheoreticalApDpm = Math.Round(shellDamage * barrelCount * rateOfFire).ToString("n0", nfi); mainBatteryDataContainer.ApSalvo = Math.Round(shellDamage * barrelCount).ToString("n0", nfi); } if (mainBatteryDataContainer.DisplaySapDpm) { - decimal shellDamage = shellData.First(x => x.Type.Equals($"ArmamentType_{ShellType.SAP.ShellTypeToString()}")).Damage; + decimal shellDamage = shellData.First(x => x.Type.Equals($"ArmamentType_{ShellType.SAP.ShellTypeToString()}", StringComparison.Ordinal)).Damage; mainBatteryDataContainer.TheoreticalSapDpm = Math.Round(shellDamage * barrelCount * rateOfFire).ToString("n0", nfi); mainBatteryDataContainer.SapSalvo = Math.Round(shellDamage * barrelCount).ToString("n0", nfi); } diff --git a/WoWsShipBuilder.Common/Features/DataContainers/Armament/PingerGunDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/PingerGunDataContainer.cs index dc08fd044..750b44a70 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/Armament/PingerGunDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/PingerGunDataContainer.cs @@ -57,7 +57,7 @@ public partial record PingerGunDataContainer : DataContainerBase // Safe approach is necessary because data up until 0.11.9#1 does not include this data due to an issue in the data converter if (pingerUpgrade.Components.TryGetValue(ComponentType.Sonar, out string[]? pingerGunInfo)) { - pingerGun = ship.PingerGunList[pingerGunInfo.First()]; + pingerGun = ship.PingerGunList[pingerGunInfo[0]]; } else { @@ -65,7 +65,7 @@ public partial record PingerGunDataContainer : DataContainerBase pingerGun = ship.PingerGunList.First().Value; } - var pingSpeed = pingerGun.WaveParams.First().WaveSpeed.First(); + var pingSpeed = pingerGun.WaveParams[0].WaveSpeed[0]; var pingSpeedModifiers = modifiers.FindModifiers("pingerWaveSpeedCoeff"); pingSpeed = pingSpeedModifiers.Aggregate(pingSpeed, (current, pingSpeedModifier) => current * (decimal)pingSpeedModifier); @@ -92,7 +92,7 @@ public partial record PingerGunDataContainer : DataContainerBase Range = pingerGun.WaveDistance / 1000, FirstPingDuration = Math.Round(firstPingDuration, 1), SecondPingDuration = Math.Round(secondPingDuration, 1), - PingWidth = pingerGun.WaveParams.First().StartWaveWidth, + PingWidth = pingerGun.WaveParams[0].StartWaveWidth, PingSpeed = Math.Round(pingSpeed, 0), }; diff --git a/WoWsShipBuilder.Common/Features/DataContainers/Armament/SecondaryBatteryDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/SecondaryBatteryDataContainer.cs index 9c623a48c..b423f9552 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/Armament/SecondaryBatteryDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/SecondaryBatteryDataContainer.cs @@ -51,7 +51,7 @@ public partial record SecondaryBatteryDataContainer : DataContainerBase public static List? FromShip(Ship ship, IEnumerable shipConfiguration, List<(string, float)> modifiers) { - var secondary = ship.Hulls[shipConfiguration.First(c => c.UcType == ComponentType.Hull).Components[ComponentType.Hull].First()].SecondaryModule; + var secondary = ship.Hulls[shipConfiguration.First(c => c.UcType == ComponentType.Hull).Components[ComponentType.Hull][0]].SecondaryModule; if (secondary == null) { return null; @@ -66,7 +66,7 @@ public partial record SecondaryBatteryDataContainer : DataContainerBase foreach (List secondaryGroup in groupedSecondaries) { - var secondaryGun = secondaryGroup.First(); + var secondaryGun = secondaryGroup[0]; string arrangementString = $"{secondaryGroup.Count} x {secondaryGun.NumBarrels} {{0}}"; List turretName = new() { secondaryGun.Name }; @@ -106,7 +106,7 @@ public partial record SecondaryBatteryDataContainer : DataContainerBase ShellDataContainer? shellData; try { - shellData = ShellDataContainer.FromShellName(secondaryGun.AmmoList, modifiers, barrelCount, false).First(); + shellData = ShellDataContainer.FromShellName(secondaryGun.AmmoList, modifiers, barrelCount, false)[0]; } catch (KeyNotFoundException e) { @@ -122,7 +122,7 @@ public partial record SecondaryBatteryDataContainer : DataContainerBase } secondaryBatteryDataContainer.Shell = shellData; - secondaryBatteryDataContainer.DisplayFpm = shellData.Type.Equals($"ArmamentType_{ShellType.HE.ShellTypeToString()}"); + secondaryBatteryDataContainer.DisplayFpm = shellData.Type.Equals($"ArmamentType_{ShellType.HE.ShellTypeToString()}", StringComparison.Ordinal); secondaryBatteryDataContainer.TheoreticalDpm = Math.Round(shellData.Damage * barrelCount * rof).ToString("n0", nfi); if (secondaryBatteryDataContainer.DisplayFpm) @@ -135,7 +135,7 @@ public partial record SecondaryBatteryDataContainer : DataContainerBase result.Add(secondaryBatteryDataContainer); } - result.Last().IsLast = true; + result[^1].IsLast = true; return result; } diff --git a/WoWsShipBuilder.Common/Features/DataContainers/Armament/TorpedoArmamentDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Armament/TorpedoArmamentDataContainer.cs index d5d3ae641..0875ea87c 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/Armament/TorpedoArmamentDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Armament/TorpedoArmamentDataContainer.cs @@ -58,7 +58,7 @@ public partial record TorpedoArmamentDataContainer : DataContainerBase public static TorpedoArmamentDataContainer? FromShip(Ship ship, List shipConfiguration, List<(string name, float value)> modifiers) { - var torpConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Torpedoes); + var torpConfiguration = shipConfiguration.Find(c => c.UcType == ComponentType.Torpedoes); if (torpConfiguration == null) { return null; @@ -70,7 +70,7 @@ public partial record TorpedoArmamentDataContainer : DataContainerBase TorpedoModule? torpedoModule; if (torpedoOptions.Length == 1) { - torpedoModule = ship.TorpedoModules[supportedModules.First()]; + torpedoModule = ship.TorpedoModules[supportedModules[0]]; } else { @@ -78,7 +78,7 @@ public partial record TorpedoArmamentDataContainer : DataContainerBase torpedoModule = ship.TorpedoModules[hullTorpedoName]; } - var launcher = torpedoModule.TorpedoLaunchers.First(); + var launcher = torpedoModule.TorpedoLaunchers[0]; List<(int BarrelCount, int LauncherCount, string LauncherName)> arrangementList = torpedoModule.TorpedoLaunchers .GroupBy(torpModule => torpModule.NumBarrels) @@ -119,13 +119,13 @@ public partial record TorpedoArmamentDataContainer : DataContainerBase var nfi = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone(); nfi.NumberGroupSeparator = "'"; - var fullSalvoDamage = (torpCount * torpedoes.First().Damage).ToString("n0", nfi); + var fullSalvoDamage = (torpCount * torpedoes[0].Damage).ToString("n0", nfi); string torpFullSalvoDmg = default!; string altTorpFullSalvoDmg = default!; if (torpedoes.Count > 1) { torpFullSalvoDmg = fullSalvoDamage; - altTorpFullSalvoDmg = (torpCount * torpedoes.Last().Damage).ToString("n0", nfi); + altTorpFullSalvoDmg = (torpCount * torpedoes[^1].Damage).ToString("n0", nfi); fullSalvoDamage = default!; } @@ -165,7 +165,7 @@ public partial record TorpedoArmamentDataContainer : DataContainerBase torpedoArmamentDataContainer.LoadersCount = loadersSum; - torpedoArmamentDataContainer.Torpedoes.Last().IsLast = true; + torpedoArmamentDataContainer.Torpedoes[^1].IsLast = true; torpedoArmamentDataContainer.UpdateDataElements(); return torpedoArmamentDataContainer; diff --git a/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/TorpedoDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/TorpedoDataContainer.cs index 3f034b366..d7f50c8a1 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/TorpedoDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Projectiles/TorpedoDataContainer.cs @@ -160,18 +160,18 @@ public static List FromTorpedoName(List torpedoNam if (torp.TorpedoType == DataStructures.TorpedoType.Magnetic) { - torpedoDataContainer.MaxTurningSpeedFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.MaxTurningSpeed.First(), 1); - torpedoDataContainer.MaxTurningSpeedSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.MaxTurningSpeed.Last(), 1); - torpedoDataContainer.TurningAccelerationFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.TurningAcceleration.First(), 1); - torpedoDataContainer.TurningAccelerationSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.TurningAcceleration.Last(), 1); - torpedoDataContainer.MaxVerticalSpeedFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.MaxVerticalSpeed.First(), 1); - torpedoDataContainer.MaxVerticalSpeedSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.MaxVerticalSpeed.Last(), 1); - torpedoDataContainer.VerticalAccelerationFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.VerticalAcceleration.First(), 1); - torpedoDataContainer.VerticalAccelerationSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.VerticalAcceleration.Last(), 1); - torpedoDataContainer.SearchRadiusFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.SearchRadius.First(), 1); - torpedoDataContainer.SearchRadiusSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.SearchRadius.Last(), 1); - torpedoDataContainer.SearchAngleFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.SearchAngle.First(), 1); - torpedoDataContainer.SearchAngleSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.SearchAngle.Last(), 1); + torpedoDataContainer.MaxTurningSpeedFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.MaxTurningSpeed[0], 1); + torpedoDataContainer.MaxTurningSpeedSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.MaxTurningSpeed[^1], 1); + torpedoDataContainer.TurningAccelerationFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.TurningAcceleration[0], 1); + torpedoDataContainer.TurningAccelerationSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.TurningAcceleration[^1], 1); + torpedoDataContainer.MaxVerticalSpeedFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.MaxVerticalSpeed[0], 1); + torpedoDataContainer.MaxVerticalSpeedSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.MaxVerticalSpeed[^1], 1); + torpedoDataContainer.VerticalAccelerationFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.VerticalAcceleration[0], 1); + torpedoDataContainer.VerticalAccelerationSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.VerticalAcceleration[^1], 1); + torpedoDataContainer.SearchRadiusFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.SearchRadius[0], 1); + torpedoDataContainer.SearchRadiusSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.SearchRadius[^1], 1); + torpedoDataContainer.SearchAngleFirstPing = Math.Round((decimal)torp.MagneticTorpedoParams.SearchAngle[0], 1); + torpedoDataContainer.SearchAngleSecondPing = Math.Round((decimal)torp.MagneticTorpedoParams.SearchAngle[^1], 1); var ddCutOff = torp.MagneticTorpedoParams.DropTargetAtDistance.First(x => x.Key == ShipClass.Destroyer).Value; var bbCutOff = torp.MagneticTorpedoParams.DropTargetAtDistance.First(x => x.Key == ShipClass.Battleship).Value; @@ -179,16 +179,16 @@ public static List FromTorpedoName(List torpedoNam var subCutOff = torp.MagneticTorpedoParams.DropTargetAtDistance.First(x => x.Key == ShipClass.Submarine).Value; var cvCutOff = torp.MagneticTorpedoParams.DropTargetAtDistance.First(x => x.Key == ShipClass.AirCarrier).Value; - torpedoDataContainer.DestroyerCutOffFirstPing = Math.Round((decimal)ddCutOff.First(), 1); - torpedoDataContainer.DestroyerCutOffSecondPing = Math.Round((decimal)ddCutOff.Last(), 1); - torpedoDataContainer.BattleshipCutOffFirstPing = Math.Round((decimal)bbCutOff.First(), 1); - torpedoDataContainer.BattleshipCutOffSecondPing = Math.Round((decimal)bbCutOff.Last(), 1); - torpedoDataContainer.CruiserCutOffFirstPing = Math.Round((decimal)caCutOff.First(), 1); - torpedoDataContainer.CruiserCutOffSecondPing = Math.Round((decimal)caCutOff.Last(), 1); - torpedoDataContainer.SubCutOffFirstPing = Math.Round((decimal)subCutOff.First(), 1); - torpedoDataContainer.SubCutOffSecondPing = Math.Round((decimal)subCutOff.Last(), 1); - torpedoDataContainer.CvCutOffFirstPing = Math.Round((decimal)cvCutOff.First(), 1); - torpedoDataContainer.CvCutOffSecondPing = Math.Round((decimal)cvCutOff.Last(), 1); + torpedoDataContainer.DestroyerCutOffFirstPing = Math.Round((decimal)ddCutOff[0], 1); + torpedoDataContainer.DestroyerCutOffSecondPing = Math.Round((decimal)ddCutOff[^1], 1); + torpedoDataContainer.BattleshipCutOffFirstPing = Math.Round((decimal)bbCutOff[0], 1); + torpedoDataContainer.BattleshipCutOffSecondPing = Math.Round((decimal)bbCutOff[^1], 1); + torpedoDataContainer.CruiserCutOffFirstPing = Math.Round((decimal)caCutOff[0], 1); + torpedoDataContainer.CruiserCutOffSecondPing = Math.Round((decimal)caCutOff[^1], 1); + torpedoDataContainer.SubCutOffFirstPing = Math.Round((decimal)subCutOff[0], 1); + torpedoDataContainer.SubCutOffSecondPing = Math.Round((decimal)subCutOff[^1], 1); + torpedoDataContainer.CvCutOffFirstPing = Math.Round((decimal)cvCutOff[0], 1); + torpedoDataContainer.CvCutOffSecondPing = Math.Round((decimal)cvCutOff[^1], 1); } if (torp.IgnoreClasses != null && torp.IgnoreClasses.Any()) diff --git a/WoWsShipBuilder.Common/Features/DataContainers/Ship/AntiAirDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/AntiAirDataContainer.cs index 165e69f1e..5706014c5 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/Ship/AntiAirDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/AntiAirDataContainer.cs @@ -25,11 +25,11 @@ public record AntiAirDataContainer return null; } - var hull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull].First()]; + var hull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull][0]]; TurretModule? guns = null; if (ship.MainBatteryModuleList is { Count: > 0 }) { - guns = ship.MainBatteryModuleList[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Artillery).Components[ComponentType.Artillery].First()]; + guns = ship.MainBatteryModuleList[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Artillery).Components[ComponentType.Artillery][0]]; } decimal flakDamageBonus = modifiers.FindModifiers("AABubbleDamage").Aggregate(1M, (current, value) => current * (decimal)value); @@ -52,14 +52,7 @@ public record AntiAirDataContainer if (guns?.AntiAir != null) { - if (longRange is null) - { - longRange = guns.AntiAir; - } - else - { - longRange = longRange.AddAura(guns.AntiAir); - } + longRange = longRange is null ? guns.AntiAir : longRange.AddAura(guns.AntiAir); } var flakAmount = 0; diff --git a/WoWsShipBuilder.Common/Features/DataContainers/Ship/ConcealmentDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ConcealmentDataContainer.cs index b3cf0f9e3..5c6fda55b 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/Ship/ConcealmentDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ConcealmentDataContainer.cs @@ -33,7 +33,7 @@ public partial record ConcealmentDataContainer : DataContainerBase public static ConcealmentDataContainer FromShip(Ship ship, List shipConfiguration, List<(string Key, float Value)> modifiers) { - var hull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull].First()]; + var hull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull][0]]; // Sea Detection decimal concealmentBySea = hull.SurfaceDetection; @@ -66,22 +66,22 @@ public static ConcealmentDataContainer FromShip(Ship ship, List shi } // Checks for Heavy He - var artilleryConfiguration = shipConfiguration.FirstOrDefault(c => c.UcType == ComponentType.Artillery); + var artilleryConfiguration = shipConfiguration.Find(c => c.UcType == ComponentType.Artillery); if (artilleryConfiguration != null) { - string[]? artilleryOptions = artilleryConfiguration.Components[ComponentType.Artillery]; + string[] artilleryOptions = artilleryConfiguration.Components[ComponentType.Artillery]; TurretModule? mainBattery; if (artilleryOptions.Length == 1) { - mainBattery = ship.MainBatteryModuleList[artilleryConfiguration.Components[ComponentType.Artillery].First()]; + mainBattery = ship.MainBatteryModuleList[artilleryConfiguration.Components[ComponentType.Artillery][0]]; } else { - string? hullArtilleryName = shipConfiguration.First(c => c.UcType == ComponentType.Hull).Components[ComponentType.Artillery].First(); + string hullArtilleryName = shipConfiguration.First(c => c.UcType == ComponentType.Hull).Components[ComponentType.Artillery][0]; mainBattery = ship.MainBatteryModuleList[hullArtilleryName]; } - var gun = mainBattery.Guns.First(); + var gun = mainBattery.Guns[0]; // GMBigGunVisibilityCoeff if (gun.BarrelDiameter >= 0.149M) diff --git a/WoWsShipBuilder.Common/Features/DataContainers/Ship/ManeuverabilityDataContainer.cs b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ManeuverabilityDataContainer.cs index d590f0a58..081127571 100644 --- a/WoWsShipBuilder.Common/Features/DataContainers/Ship/ManeuverabilityDataContainer.cs +++ b/WoWsShipBuilder.Common/Features/DataContainers/Ship/ManeuverabilityDataContainer.cs @@ -61,9 +61,9 @@ public partial record ManeuverabilityDataContainer : DataContainerBase public static ManeuverabilityDataContainer FromShip(Ship ship, List shipConfiguration, List<(string Key, float Value)> modifiers) { - var hull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull].First()]; + var hull = ship.Hulls[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Hull).Components[ComponentType.Hull][0]]; - var engine = ship.Engines[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Engine).Components[ComponentType.Engine].First()]; + var engine = ship.Engines[shipConfiguration.First(upgrade => upgrade.UcType == ComponentType.Engine).Components[ComponentType.Engine][0]]; decimal maxSpeedModifier = modifiers.FindModifiers("speedCoef", true).Aggregate(1m, (current, modifier) => current * (decimal)modifier); maxSpeedModifier = modifiers.FindModifiers("shipSpeedCoeff", true).Aggregate(maxSpeedModifier, (current, modifier) => current * (decimal)modifier); diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor b/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor index 68c2855b3..9d3bb8e5e 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/ComparisonShipFilter.razor @@ -22,7 +22,7 @@ - @for (int i = TiersRange.First(); i <= TiersRange.Last(); i++) + @for (int i = TiersRange[0]; i <= TiersRange[^1]; i++) { int tier = i; bool isSelected = ViewModel!.SelectedTiers.Contains(tier); @@ -116,7 +116,7 @@ - @for (int i = TiersRange.First(); i <= TiersRange.Last(); i++) + @for (int i = TiersRange[0]; i <= TiersRange[^1]; i++) { int tier = i; bool isSelected = ViewModel!.SelectedTiers.Contains(tier); diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs index 89a0669d6..0c1854e3f 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridData/GridDataWrapper.cs @@ -30,9 +30,9 @@ public GridDataWrapper(ShipBuildContainer shipBuildContainer) this.BuildName = shipBuildContainer.Build?.BuildName; this.MainBattery = this.ShipBuildContainer.ShipDataContainer?.MainBatteryDataContainer; - this.HeShell = this.MainBattery?.ShellData.FirstOrDefault(x => x.Type.Equals($"ArmamentType_{ShellType.HE.ShellTypeToString()}")); - this.ApShell = this.MainBattery?.ShellData.FirstOrDefault(x => x.Type.Equals($"ArmamentType_{ShellType.AP.ShellTypeToString()}")); - this.SapShell = this.MainBattery?.ShellData.FirstOrDefault(x => x.Type.Equals($"ArmamentType_{ShellType.SAP.ShellTypeToString()}")); + this.HeShell = this.MainBattery?.ShellData.Find(x => x.Type.Equals($"ArmamentType_{ShellType.HE.ShellTypeToString()}", StringComparison.Ordinal)); + this.ApShell = this.MainBattery?.ShellData.Find(x => x.Type.Equals($"ArmamentType_{ShellType.AP.ShellTypeToString()}", StringComparison.Ordinal)); + this.SapShell = this.MainBattery?.ShellData.Find(x => x.Type.Equals($"ArmamentType_{ShellType.SAP.ShellTypeToString()}", StringComparison.Ordinal)); var torpedoArmament = shipBuildContainer.ShipDataContainer.TorpedoArmamentDataContainer; this.TorpedoLauncher = torpedoArmament; @@ -49,9 +49,9 @@ public GridDataWrapper(ShipBuildContainer shipBuildContainer) this.Survivability = shipBuildContainer.ShipDataContainer.SurvivabilityDataContainer; this.Sonar = shipBuildContainer.ShipDataContainer.PingerGunDataContainer; - this.RocketPlanes = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Rocket.ProjectileTypeToString())).ToList()); - this.TorpedoBombers = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Torpedo.ProjectileTypeToString())).ToList()); - this.Bombers = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Bomb.ProjectileTypeToString()) || x.WeaponType.Equals(ProjectileType.SkipBomb.ProjectileTypeToString())).ToList()); + this.RocketPlanes = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Rocket.ProjectileTypeToString(), StringComparison.Ordinal)).ToList()); + this.TorpedoBombers = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Torpedo.ProjectileTypeToString(), StringComparison.Ordinal)).ToList()); + this.Bombers = new(shipBuildContainer.ShipDataContainer.CvAircraftDataContainer?.Where(x => x.WeaponType.Equals(ProjectileType.Bomb.ProjectileTypeToString(), StringComparison.Ordinal) || x.WeaponType.Equals(ProjectileType.SkipBomb.ProjectileTypeToString(), StringComparison.Ordinal)).ToList()); } public ShipBuildContainer ShipBuildContainer { get; } diff --git a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AaDefenseFragment.razor b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AaDefenseFragment.razor index 98d4b2a3e..67a459bd8 100644 --- a/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AaDefenseFragment.razor +++ b/WoWsShipBuilder.Common/Features/ShipComparison/GridSections/AaDefenseFragment.razor @@ -68,7 +68,7 @@ -