From 523d5d281e6919d57f3b1d6efa90a9dabea6a28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannik=20H=C3=B6flich?= Date: Fri, 1 Sep 2023 17:34:20 +0200 Subject: [PATCH] Refactoring --- .../ColorHelperTests.cs | 38 +++--- .../ImageHelperTests.cs | 10 +- .../Data/Converter/ColorHelper.cs | 16 ++- .../DisplayApplication.Checks.cs | 59 +--------- .../DependencyInjection/DisplayApplication.cs | 62 ++++------ .../Helper/ServiceInitializer.cs | 111 ++++++++++++++++++ .../DependencyInjection/ServiceInizializer.cs | 54 --------- .../ScreenGenerators/ErrorScreen.cs | 2 +- .../ScreenGenerators/TemperatureScreen.cs | 2 +- .../ScreenGenerators/TimeScreen.cs | 4 +- .../Services/DeviceService.cs | 8 +- .../Services/InternetService.cs | 10 +- .../Services/SpotifyService.cs | 2 +- .../Services/CachedWeatherClient.cs | 14 +-- .../Services/WeatherService.cs | 6 +- .../Data/Config/ConfigLayout.cs | 6 +- .../MatrixWeb.Extensions/Data/RawConfig.cs | 14 ++- .../MatrixWeb.Extensions/Logging/Logger.cs | 3 - .../MatrixWeb.Extensions/Logging/Provider.cs | 10 +- .../Services/ConfigService.cs | 10 +- .../Services/Loader/SymbolLoader.cs | 4 +- .../Services/Translation/Text.cs | 2 +- src/MatrixWeb/Pages/Settings.razor | 12 +- src/MatrixWeb/Pages/SpotifyCallback.razor | 2 +- src/MatrixWeb/Program.cs | 2 +- src/MatrixWeb/Shared/ConfigInput.razor | 34 ++++-- .../Shared/Inputs/ExtendedInput.razor | 4 +- src/MatrixWeb/Shared/Inputs/HourInput.cs | 8 +- src/MatrixWeb/Shared/Inputs/PercentInput.cs | 8 +- src/MatrixWeb/Shared/Inputs/SecondInput.cs | 6 +- src/MatrixWeb/Shared/OverlayWindow.razor | 2 +- 31 files changed, 263 insertions(+), 262 deletions(-) create mode 100644 src/MatrixWeatherDisplay/DependencyInjection/Helper/ServiceInitializer.cs delete mode 100644 src/MatrixWeatherDisplay/DependencyInjection/ServiceInizializer.cs diff --git a/Tests/MatrixWeatherDisplay.UnitTests/ColorHelperTests.cs b/Tests/MatrixWeatherDisplay.UnitTests/ColorHelperTests.cs index 7d15266..e3a9a66 100644 --- a/Tests/MatrixWeatherDisplay.UnitTests/ColorHelperTests.cs +++ b/Tests/MatrixWeatherDisplay.UnitTests/ColorHelperTests.cs @@ -10,69 +10,69 @@ namespace MatrixWeatherDisplay.UnitTests; public class ColorHelperTests { - private ColorHelper _colorHelper = new(new ConfigService()); + private readonly ColorHelper _colorHelper = new(new ConfigService()); private Color _color; [Fact] public void Temperature() { - _color = _colorHelper.MapTemperature(-20); + _color = ColorHelper.MapTemperature(-20); Assert.Equal(Color.FromRgb(0, 0, 255), _color); - _color = _colorHelper.MapTemperature(-10); + _color = ColorHelper.MapTemperature(-10); Assert.Equal(Color.FromRgb(0, 0, 255), _color); - _color = _colorHelper.MapTemperature(45); + _color = ColorHelper.MapTemperature(45); Assert.Equal(Color.FromRgb(255, 0, 0), _color); - _color = _colorHelper.MapTemperature(55); + _color = ColorHelper.MapTemperature(55); Assert.Equal(Color.FromRgb(255, 0, 0), _color); } [Fact] public void Hour() { - _color = _colorHelper.MapHour(0); + _color = ColorHelper.MapHour(0); Assert.Equal(Color.FromRgb(0, 0, 255), _color); - _color = _colorHelper.MapHour(4); + _color = ColorHelper.MapHour(4); Assert.Equal(Color.FromRgb(255, 0, 255), _color); - _color = _colorHelper.MapHour(8); + _color = ColorHelper.MapHour(8); Assert.Equal(Color.FromRgb(255, 0, 0), _color); - _color = _colorHelper.MapHour(12); + _color = ColorHelper.MapHour(12); Assert.Equal(Color.FromRgb(255, 255, 0), _color); - _color = _colorHelper.MapHour(16); + _color = ColorHelper.MapHour(16); Assert.Equal(Color.FromRgb(0, 255, 0), _color); - _color = _colorHelper.MapHour(20); + _color = ColorHelper.MapHour(20); Assert.Equal(Color.FromRgb(0, 255, 255), _color); - _color = _colorHelper.MapHour(24); + _color = ColorHelper.MapHour(24); Assert.Equal(Color.FromRgb(0, 0, 255), _color); } [Fact] public void Minute() { - _color = _colorHelper.MapMinute(0); + _color = ColorHelper.MapMinute(0); Assert.Equal(Color.FromRgb(255, 0, 0), _color); - _color = _colorHelper.MapMinute(10); + _color = ColorHelper.MapMinute(10); Assert.Equal(Color.FromRgb(255, 255, 0), _color); - _color = _colorHelper.MapMinute(20); + _color = ColorHelper.MapMinute(20); Assert.Equal(Color.FromRgb(0, 255, 0), _color); - _color = _colorHelper.MapMinute(30); + _color = ColorHelper.MapMinute(30); Assert.Equal(Color.FromRgb(0, 255, 255), _color); - _color = _colorHelper.MapMinute(40); + _color = ColorHelper.MapMinute(40); Assert.Equal(Color.FromRgb(0, 0, 255), _color); - _color = _colorHelper.MapMinute(50); + _color = ColorHelper.MapMinute(50); Assert.Equal(Color.FromRgb(255, 0, 255), _color); - _color = _colorHelper.MapMinute(60); + _color = ColorHelper.MapMinute(60); Assert.Equal(Color.FromRgb(255, 0, 0), _color); } } \ No newline at end of file diff --git a/Tests/MatrixWeatherDisplay.UnitTests/ImageHelperTests.cs b/Tests/MatrixWeatherDisplay.UnitTests/ImageHelperTests.cs index a06d0c7..9b34cea 100644 --- a/Tests/MatrixWeatherDisplay.UnitTests/ImageHelperTests.cs +++ b/Tests/MatrixWeatherDisplay.UnitTests/ImageHelperTests.cs @@ -11,8 +11,8 @@ namespace MatrixWeatherDisplay.UnitTests; public class ImageHelperTests { - Image _image; - Random _random = new Random(420); + readonly Image _image; + readonly Random _random = new(420); public ImageHelperTests() { _image = new Image(16, 16); @@ -29,13 +29,13 @@ public ImageHelperTests() { [Fact] public void SetColor() { var color = Color.FromRgb(255, 0, 0); - var testPixelColor = color.ToPixel(); - var testPixelBlack = Color.Black.ToPixel(); + Rgb24 testPixelColor = color.ToPixel(); + Rgb24 testPixelBlack = Color.Black.ToPixel(); ImageHelper.SetColor(_image, color); for (int y = 0; y < _image.Height; y++) { for (int x = 0; x < _image.Width; x++) { - var pixel = _image[x, y]; + Rgb24 pixel = _image[x, y]; if(pixel != testPixelColor && pixel != testPixelBlack) { Assert.Fail($"Each pixel must be either {color} or black"); } diff --git a/src/MatrixWeatherDisplay/Data/Converter/ColorHelper.cs b/src/MatrixWeatherDisplay/Data/Converter/ColorHelper.cs index 05cc2a4..e9e032c 100644 --- a/src/MatrixWeatherDisplay/Data/Converter/ColorHelper.cs +++ b/src/MatrixWeatherDisplay/Data/Converter/ColorHelper.cs @@ -14,7 +14,7 @@ public class ColorHelper: IInitializable { public ConfigLayout ConfigLayout { get; } = new() { ConfigName = s_configName, - Keys = new ConfigKey[] { } + Keys = Array.Empty() }; public ColorHelper(ConfigService configService) { _configService = configService; @@ -22,22 +22,20 @@ public ColorHelper(ConfigService configService) { public InitResult Init() { RawConfig? config = _configService.GetConfig(s_configName); - if(config is null) { - return InitResult.NoConfig(); - } - - return InitResult.Success; + return config is not null + ? InitResult.Success + : InitResult.NoConfig(); } - public Color MapTemperature(int temperature) + public static Color MapTemperature(int temperature) => MapColor(temperature, -10, 45, 240, 0); - public Color MapHour(double hours) + public static Color MapHour(double hours) => MapColor(hours, 0, 24, 240, 240 + 360); - public Color MapMinute(double minutes) + public static Color MapMinute(double minutes) => MapColor(minutes, 0, 60, 0, 360); diff --git a/src/MatrixWeatherDisplay/DependencyInjection/DisplayApplication.Checks.cs b/src/MatrixWeatherDisplay/DependencyInjection/DisplayApplication.Checks.cs index 68a2334..d757da3 100644 --- a/src/MatrixWeatherDisplay/DependencyInjection/DisplayApplication.Checks.cs +++ b/src/MatrixWeatherDisplay/DependencyInjection/DisplayApplication.Checks.cs @@ -13,7 +13,7 @@ namespace MatrixWeatherDisplay.DependencyInjection; public partial class DisplayApplication { - private static async Task ShouldScreenGeneratorSkipAsync(InternetService? internetService, IScreenGenerator? screenGenerator) + private static async Task ShouldScreenGeneratorSkipAsync(InternetService? internetService, [NotNullWhen(false)] IScreenGenerator? screenGenerator) => screenGenerator is null || screenGenerator.ScreenTime <= TimeSpan.Zero || !screenGenerator.IsEnabled || @@ -22,71 +22,20 @@ private static async Task ShouldScreenGeneratorSkipAsync(InternetService? private static async Task HasInternetErrorAsync(IScreenGenerator screenGenerator, InternetService? internetService) { return internetService is not null && screenGenerator.RequiresInternet && - !await internetService.HasInternetConnection(); + !await internetService.HasInternetConnectionAsync(); } private async Task LogIfSkippedLastAsync(int skips, IScreenGenerator? screenGenerator) { if (skips > 0) { - _logger.LogDebug("Skipping screen '{screenName}'", screenGenerator?.GetType().Name); + _logger?.LogDebug("Skipping screen '{screenName}'", screenGenerator?.GetType().Name); } if (skips > ScreenGenerators.ScreenGeneratorCount) { - _logger.LogInformation("Skipped all screen generators, waiting 30 Seconds to retry"); + _logger?.LogInformation("Skipped all screen generators, waiting 30 Seconds to retry"); await Extensions.SleepAsync(TimeSpan.FromSeconds(30), () => !_shouldRun); return true; } return false; } - - - private bool HandleInitResult(IInitializable service, InitResult result) => HandleInitResult(GetName(service), result); - private bool HandleInitResult(IAsyncInitializable service, InitResult result) => HandleInitResult(GetName(service), result); - - private bool HandleInitResult(string name, InitResult result) { - if (result == InitResult.Success) { - return false; - } - - if (result.ResultType == InitResultType.Warning) { - _logger.LogInformation("Warning initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN)); - return false; - } - if (result.ResultType == InitResultType.Error) { - _logger.LogWarning("Error initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN)); - return false; - } - - if (result.ResultType == InitResultType.Critical) { - _logger.LogCritical("Critical error initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN)); - _logger.LogCritical("Stopping!"); - _ = StopAsync(); - return true; - } - - _logger.LogInformation("Unknown result from initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN)); - return false; - } - - private string GetName(IAsyncInitializable service) { - return TryGetNameFromConfig(service.ConfigLayout, out string? name) - ? name - : service.GetType().Name; - } - - private string GetName(IInitializable service) { - return TryGetNameFromConfig(service.ConfigLayout, out string? name) - ? name - : service.GetType().Name; - } - - private bool TryGetNameFromConfig(ConfigLayout configLayout, [NotNullWhen(true)] out string? name) { - if(configLayout is not null && !string.IsNullOrWhiteSpace(configLayout.ConfigName)) { - name = configLayout.ConfigName; - return true; - } - - name = null; - return false; - } } diff --git a/src/MatrixWeatherDisplay/DependencyInjection/DisplayApplication.cs b/src/MatrixWeatherDisplay/DependencyInjection/DisplayApplication.cs index 1a67f71..0b1509f 100644 --- a/src/MatrixWeatherDisplay/DependencyInjection/DisplayApplication.cs +++ b/src/MatrixWeatherDisplay/DependencyInjection/DisplayApplication.cs @@ -1,6 +1,8 @@ -using System.Xml.Serialization; +using System.Data.SqlTypes; +using System.Xml.Serialization; using MatrixWeatherDisplay.Data; +using MatrixWeatherDisplay.DependencyInjection.Helper; using MatrixWeatherDisplay.DependencyInjection.ScreenGeneratorCollections; using MatrixWeatherDisplay.Screens; using MatrixWeatherDisplay.Services; @@ -23,7 +25,7 @@ public partial class DisplayApplication { internal ServiceDescriptor[]? Initializables { get; init; } internal ServiceDescriptor[]? AsyncInitializables { get; init; } - private ILogger _logger; + private ILogger? _logger; private bool _running = false; private bool _shouldRun = false; @@ -42,56 +44,40 @@ internal DisplayApplication(IServiceProvider services, IScreenGeneratorProvider /// true if the code flow should be continued, false if a critical error accured and the program should not be started. /// public async Task InitDefaultServicesAsync() { - ConfigService configService = Services.GetService() ?? throw new InvalidOperationException("The service 'ConfigService' has to be registered"); + if (Initializables is null || AsyncInitializables is null) { + _logger?.LogCritical("The display application didn't get information about services to initialize."); + return false; + } - IEnumerable initializables = Initializables.Select(x => x.GetService(Services)).OfType().ToArray(); - IEnumerable asyncInitializables = AsyncInitializables.Select(x => x.GetService(Services)).OfType().ToArray(); + var serviceInitializer = new ServiceInitializer(Services, Initializables, AsyncInitializables); - var configLayouts = initializables.Select(x => x.ConfigLayout).Concat( - asyncInitializables.Select(x => x.ConfigLayout)) - .Where(x => x != ConfigLayout.Empty && x.Keys.Length > 0) - .DistinctBy(x => x.Keys) - .ToList(); + IReadOnlyCollection configLayouts = serviceInitializer.GetConfigLayouts(); + ConfigService configService = Services.GetService() ?? throw new InvalidOperationException("The service 'ConfigService' has to be registered"); await configService.InitAsync(configLayouts); ILogger? newLogger = Services.GetService>(); if (newLogger is not null) { _logger = newLogger; + serviceInitializer.Logger = _logger; } BrightnessService autoBrightnessService = Services.GetService() ?? throw new InvalidOperationException("The Service of type 'AutoBrightnessService' must be registered"); RedManager = new RedSettings(autoBrightnessService); - if (Initializables is not null) { - foreach (IInitializable service in initializables) { - InitResult result = service.Init(); - if(HandleInitResult(service, result)) { - return false; - } - } - } - - if (AsyncInitializables is not null) { - foreach (IAsyncInitializable service in asyncInitializables) { - InitResult result = await service.InitAsync(); - if (HandleInitResult(service, result)) { - return false; - } - } - } + bool result = await serviceInitializer.InitAllAsync(); await configService.SaveAsync(); - return true; + return result; } public async Task RunAsync() { if (_running) { - _logger.LogInformation("Already running"); + _logger?.LogInformation("Already running"); return; } - _logger.LogInformation("Starting up"); + _logger?.LogInformation("Starting up"); _running = true; _shouldRun = true; @@ -122,9 +108,9 @@ private async Task ShowNextScreenAndWaitAsync(DeviceService deviceService, Inter } private async Task SendScreenAsync(DeviceService deviceService, ByteScreen screen) { - _logger.LogTrace("sending gif"); + _logger?.LogTrace("sending gif"); await deviceService.SendGifAsync(screen.Image); - _logger.LogTrace("waiting {screen time}ms", screen.ScreenTime.TotalMilliseconds); + _logger?.LogTrace("waiting {screen time}ms", screen.ScreenTime.TotalMilliseconds); SetWaitUntil(screen.ScreenTime); } @@ -137,7 +123,7 @@ private async Task SendScreenAsync(DeviceService deviceService, ByteScreen scree } screenGenerator = ScreenGenerators.GetNextScreenGenerator(); - _logger.LogTrace("Trying to show '{screen}'", screenGenerator?.Name); + _logger?.LogTrace("Trying to show '{screen}'", screenGenerator?.Name); if (await ShouldScreenGeneratorSkipAsync(internetService, screenGenerator)) { skips++; @@ -151,7 +137,7 @@ private async Task SendScreenAsync(DeviceService deviceService, ByteScreen scree Screen rawScreen = await screenGenerator.GenerateImageAsync(); screen = await ByteScreen.FromScreenAsync(rawScreen, turnRed); } catch (Exception ex) { - _logger.LogError("Error creating next screen {ex}", ex); + _logger?.LogError("Error creating next screen {ex}", ex); screen = null; } @@ -167,15 +153,15 @@ private async Task SendScreenAsync(DeviceService deviceService, ByteScreen scree } public async Task StopAsync() { - _logger.LogInformation($"Stopping"); + _logger?.LogInformation($"Stopping"); _shouldRun = false; await Extensions.SleepAsync(TimeSpan.FromSeconds(1), () => !_running); if (_running) { - _logger.LogError($"Didn't stop after 1 Seconds."); - _logger.LogError($"Probably stuck in a task or already stopped because of an error!"); - _logger.LogError($"Pretending to be stopped!"); + _logger?.LogError($"Didn't stop after 1 Seconds."); + _logger?.LogError($"Probably stuck in a task or already stopped because of an error!"); + _logger?.LogError($"Pretending to be stopped!"); _running = false; } } diff --git a/src/MatrixWeatherDisplay/DependencyInjection/Helper/ServiceInitializer.cs b/src/MatrixWeatherDisplay/DependencyInjection/Helper/ServiceInitializer.cs new file mode 100644 index 0000000..7a81516 --- /dev/null +++ b/src/MatrixWeatherDisplay/DependencyInjection/Helper/ServiceInitializer.cs @@ -0,0 +1,111 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection.Metadata.Ecma335; +using System.Text; +using System.Threading.Tasks; + +using MatrixWeatherDisplay.Data; +using MatrixWeatherDisplay.Services; +using MatrixWeb.Extensions; +using MatrixWeb.Extensions.Data.Config; +using MatrixWeb.Extensions.Services; +using MatrixWeb.Extensions.Services.Translation; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using System; + +namespace MatrixWeatherDisplay.DependencyInjection.Helper; +internal record struct ServiceInitializer(IServiceProvider Services, ImmutableArray Initializables, ImmutableArray AsyncInitializables) { + public ILogger? Logger { private get; set; } + + public ServiceInitializer(IServiceProvider Services, IEnumerable Initializables, IEnumerable AsyncInitializables) + : this(Services, + Initializables.Select(x => x.GetService(Services)).OfType().ToImmutableArray(), + AsyncInitializables.Select(x => x.GetService(Services)).OfType().ToImmutableArray() + ) { } + + public async Task InitAllAsync() { + ILogger? newLogger = Services.GetService>(); + if (newLogger is not null) { + Logger = newLogger; + } + + foreach (IInitializable service in Initializables) { + InitResult result = service.Init(); + if (HandleInitResult(service, result)) { + return false; + } + } + + foreach (IAsyncInitializable service in AsyncInitializables) { + InitResult result = await service.InitAsync(); + if (HandleInitResult(service, result)) { + return false; + } + } + + return true; + } + + public readonly IReadOnlyCollection GetConfigLayouts() { + var configLayouts = Initializables.Select(x => x.ConfigLayout).Concat( + AsyncInitializables.Select(x => x.ConfigLayout)) + .Where(x => x != ConfigLayout.Empty && x.Keys.Length > 0) + .DistinctBy(x => x.Keys) + .ToImmutableArray(); + + return configLayouts; + } + + private readonly bool HandleInitResult(IInitializable service, InitResult result) => HandleInitResult(GetName(service), result); + private readonly bool HandleInitResult(IAsyncInitializable service, InitResult result) => HandleInitResult(GetName(service), result); + + private readonly bool HandleInitResult(string name, InitResult result) { + if (result == InitResult.Success) { + return false; + } + + if (result.ResultType == InitResultType.Warning) { + Logger?.LogInformation("Warning initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN)); + return false; + } + + if (result.ResultType == InitResultType.Error) { + Logger?.LogWarning("Error initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN)); + return false; + } + + if (result.ResultType == InitResultType.Critical) { + Logger?.LogCritical("Critical error initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN)); + Logger?.LogCritical("Stopping!"); + return true; + } + + Logger?.LogInformation("Unknown result from initializing {serviceName}: {message}", name, result.Message.GetText(LanguageCode.EN)); + return false; + } + + private static string GetName(IAsyncInitializable service) { + return TryGetNameFromConfig(service.ConfigLayout, out string? name) + ? name + : service.GetType().Name; + } + + private static string GetName(IInitializable service) { + return TryGetNameFromConfig(service.ConfigLayout, out string? name) + ? name + : service.GetType().Name; + } + + private static bool TryGetNameFromConfig(ConfigLayout configLayout, [NotNullWhen(true)] out string? name) { + if (configLayout is not null && !string.IsNullOrWhiteSpace(configLayout.ConfigName)) { + name = configLayout.ConfigName; + return true; + } + + name = null; + return false; + } +} diff --git a/src/MatrixWeatherDisplay/DependencyInjection/ServiceInizializer.cs b/src/MatrixWeatherDisplay/DependencyInjection/ServiceInizializer.cs deleted file mode 100644 index 195a893..0000000 --- a/src/MatrixWeatherDisplay/DependencyInjection/ServiceInizializer.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using MatrixWeb.Extensions; -using Microsoft.Extensions.DependencyInjection; -using System; - -namespace MatrixWeatherDisplay.DependencyInjection; -internal class ServiceInitializer { - private readonly IServiceProvider _services; - - public ServiceInitializer(IServiceProvider services) { - _services = services; - } - - public void Init() where T : IInitializable => Init(service => service.Init()); - public void Init(Action action) { - T? service = _services.GetService(); - if (service is null) { - return; - } - - action(service); - } - - public void Init(ServiceDescriptor t) { - var serviceRaw = _services.GetService(t.ServiceType); - if (serviceRaw is not IInitializable service) { - throw new InvalidOperationException("The type must implement the 'IInitializable' interface to be initializable by this method"); - } - - service.Init(); - } - - public async Task InitAsync() where T : IAsyncInitializable => await InitAsync(service => service.InitAsync()); - public async Task InitAsync(Func action) { - T? service = _services.GetService(); - if (service is null) { - return; - } - - await action(service); - } - - public async Task InitAsync(ServiceDescriptor t) { - if (_services.GetService(t.ServiceType) is not IAsyncInitializable service) { - throw new InvalidOperationException("The type must implement the 'IAsyncInitializable' interface to be initializable by this method"); - } - - await service.InitAsync(); - } -} diff --git a/src/MatrixWeatherDisplay/ScreenGenerators/ErrorScreen.cs b/src/MatrixWeatherDisplay/ScreenGenerators/ErrorScreen.cs index fe5ff9b..f38c761 100644 --- a/src/MatrixWeatherDisplay/ScreenGenerators/ErrorScreen.cs +++ b/src/MatrixWeatherDisplay/ScreenGenerators/ErrorScreen.cs @@ -34,7 +34,7 @@ public ErrorScreen(InternetService internetService, ErrorIconLoader errorIconLoa public async Task GenerateImageAsync() { - if(await _internetService.HasInternetConnection()) { + if(await _internetService.HasInternetConnectionAsync()) { return Screen.Empty; } diff --git a/src/MatrixWeatherDisplay/ScreenGenerators/TemperatureScreen.cs b/src/MatrixWeatherDisplay/ScreenGenerators/TemperatureScreen.cs index f709acf..4914405 100644 --- a/src/MatrixWeatherDisplay/ScreenGenerators/TemperatureScreen.cs +++ b/src/MatrixWeatherDisplay/ScreenGenerators/TemperatureScreen.cs @@ -37,7 +37,7 @@ public async Task GenerateImageAsync() { WeatherStatus weather = await _weather.GetWeatherAsync(); int temp = (int)Math.Round(weather.Temperature); - Color color = _colorHelper.MapTemperature(temp); + Color color = ColorHelper.MapTemperature(temp); Image image = GenerateTemperatureScreen(16, 16, temp, color); return new Screen(image, ScreenTime); diff --git a/src/MatrixWeatherDisplay/ScreenGenerators/TimeScreen.cs b/src/MatrixWeatherDisplay/ScreenGenerators/TimeScreen.cs index dfcab6e..103b211 100644 --- a/src/MatrixWeatherDisplay/ScreenGenerators/TimeScreen.cs +++ b/src/MatrixWeatherDisplay/ScreenGenerators/TimeScreen.cs @@ -37,8 +37,8 @@ public Task GenerateImageAsync() { int hours = now.Hour; int minutes = now.Minute; - Color colorHour = _colorHelper.MapHour(now.TotalHours()); - Color colorMinute = _colorHelper.MapMinute(now.MinutesOfHour()); + Color colorHour = ColorHelper.MapHour(now.TotalHours()); + Color colorMinute = ColorHelper.MapMinute(now.MinutesOfHour()); _symbolLoader.DrawNumber(image, hours, 2, 0, 4, colorHour); _symbolLoader.DrawNumber(image, minutes, 2, 9, 4, colorMinute); diff --git a/src/MatrixWeatherDisplay/Services/DeviceService.cs b/src/MatrixWeatherDisplay/Services/DeviceService.cs index ddc1564..a08374c 100644 --- a/src/MatrixWeatherDisplay/Services/DeviceService.cs +++ b/src/MatrixWeatherDisplay/Services/DeviceService.cs @@ -54,20 +54,20 @@ public async Task SendGifAsync(byte[] gifBytes) { await UpdateBrightnessAsync(); } - await PerformForAll(d => d.SendGifAsync(gifBytes)); + await PerformForAllAsync(d => d.SendGifAsync(gifBytes)); } public async Task SetBrightnessAsync(double newBrightness) { BrightnessPair brightness = _brightnessService.GetBrightness(newBrightness); Brightness = brightness; - await PerformForAll(d => d.SendBrightnessAsync(brightness.Real)); + await PerformForAllAsync(d => d.SendBrightnessAsync(brightness.Real)); } public async Task UpdateBrightnessAsync() { BrightnessPair brightness = _brightnessService.GetBrightness(Brightness.Display); Brightness = brightness; - await PerformForAll(d => d.SendBrightnessAsync(brightness.Real)); + await PerformForAllAsync(d => d.SendBrightnessAsync(brightness.Real)); } - private async Task PerformForAll(Func func) => await Task.WhenAll(_devices.Select(func)); + private async Task PerformForAllAsync(Func func) => await Task.WhenAll(_devices.Select(func)); } diff --git a/src/MatrixWeatherDisplay/Services/InternetService.cs b/src/MatrixWeatherDisplay/Services/InternetService.cs index 9519885..00f3cbb 100644 --- a/src/MatrixWeatherDisplay/Services/InternetService.cs +++ b/src/MatrixWeatherDisplay/Services/InternetService.cs @@ -70,20 +70,20 @@ public InitResult Init() { return InitResult.Success; } - public async Task HasInternetConnection() { + public async Task HasInternetConnectionAsync() { if(TicksTime.Now - _lastCheckTime > _updateFrequency) { - await Update(); + await UpdateAsync(); } return _lastCheckResult; } - private async Task Update() { - _lastCheckResult = await Ping(); + private async Task UpdateAsync() { + _lastCheckResult = await PingAsync(); _lastCheckTime = TicksTime.Now; } - private async Task Ping() { + private async Task PingAsync() { try { PingReply result = await _pingSender.SendPingAsync(_hostToPing, _timeout); return result.Status == IPStatus.Success; diff --git a/src/MatrixWeatherDisplay/Services/SpotifyService.cs b/src/MatrixWeatherDisplay/Services/SpotifyService.cs index 533f78f..1791353 100644 --- a/src/MatrixWeatherDisplay/Services/SpotifyService.cs +++ b/src/MatrixWeatherDisplay/Services/SpotifyService.cs @@ -70,7 +70,7 @@ public string GetSpotifyUrl(string baseUrl) { return request.ToUri().ToString(); } - public async Task AddToken(string code, string url) { + public async Task AddTokenAsync(string code, string url) { if (_clientId is null || _clientSecret is null) { throw new InvalidOperationException("The service 'SpotifyService' should be initialized and get all values through the config, to be used!"); } diff --git a/src/MatrixWeb.Extensions/MatrixWeb.Extensions.Weather/Services/CachedWeatherClient.cs b/src/MatrixWeb.Extensions/MatrixWeb.Extensions.Weather/Services/CachedWeatherClient.cs index dbba155..bd5b621 100644 --- a/src/MatrixWeb.Extensions/MatrixWeb.Extensions.Weather/Services/CachedWeatherClient.cs +++ b/src/MatrixWeb.Extensions/MatrixWeb.Extensions.Weather/Services/CachedWeatherClient.cs @@ -6,8 +6,7 @@ using MatrixWeb.Extensions.Weather.Data; namespace MatrixWeb.Extensions.Weather.Services; -public abstract class CachedWeatherClient : IInitializable, IService -{ +public abstract class CachedWeatherClient : IInitializable, IService { private static readonly TicksTimeSpan s_updateFrequency = TicksTimeSpan.FromTimeSpan(TimeSpan.FromMinutes(5)); private WeatherStatus? _currentWeather; @@ -20,19 +19,16 @@ public abstract class CachedWeatherClient : IInitializable, IService protected abstract Task UpdateWeather(); public abstract ConfigLayout ConfigLayout { get; } - private async Task PrivateUpdateWeather() - { + private async Task PrivateUpdateWeatherAsync() { WeatherStatus newWeather = await UpdateWeather(); _lastUpdate = TicksTime.Now; _currentWeather = newWeather; } - public async Task GetWeatherAsync() - { - if (TicksTime.Now - _lastUpdate >= s_updateFrequency || _currentWeather is null) - { - await PrivateUpdateWeather(); + public async Task GetWeatherAsync() { + if (TicksTime.Now - _lastUpdate >= s_updateFrequency || _currentWeather is null) { + await PrivateUpdateWeatherAsync(); } return _currentWeather ?? throw new UnreachableException("Current weather should always has a value as this point"); diff --git a/src/MatrixWeb.Extensions/MatrixWeb.Extensions.Weather/Services/WeatherService.cs b/src/MatrixWeb.Extensions/MatrixWeb.Extensions.Weather/Services/WeatherService.cs index b7edca0..2dd36d8 100644 --- a/src/MatrixWeb.Extensions/MatrixWeb.Extensions.Weather/Services/WeatherService.cs +++ b/src/MatrixWeb.Extensions/MatrixWeb.Extensions.Weather/Services/WeatherService.cs @@ -27,11 +27,7 @@ public InitResult Init() { public async Task GetWeatherAsync() { CachedWeatherClient provider = _clients[WeatherProvider]; - if (!provider.IsEnabled) { - return new WeatherStatus(); - } - - return await provider.GetWeatherAsync(); + return provider.IsEnabled ? await provider.GetWeatherAsync() : new WeatherStatus(); } public bool IsProviderEnabled(WeatherProvider weatherProvider) => _clients[weatherProvider].IsEnabled; diff --git a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Data/Config/ConfigLayout.cs b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Data/Config/ConfigLayout.cs index a9f614f..e8a4d74 100644 --- a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Data/Config/ConfigLayout.cs +++ b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Data/Config/ConfigLayout.cs @@ -6,11 +6,11 @@ using System; namespace MatrixWeb.Extensions.Data.Config; -public class ConfigLayout : IEquatable { +public sealed class ConfigLayout : IEquatable { public required string ConfigName { get; init; } public required ConfigKey[] Keys { get; init; } - public static readonly ConfigLayout Empty = new ConfigLayout() { + public static readonly ConfigLayout Empty = new() { ConfigName = "", Keys = Array.Empty() }; @@ -19,4 +19,6 @@ public class ConfigLayout : IEquatable { public bool Equals(ConfigLayout? other) => other is not null && ConfigName == other.ConfigName && EqualityComparer.Default.Equals(Keys, other.Keys); public static bool operator ==(ConfigLayout? left, ConfigLayout? right) => EqualityComparer.Default.Equals(left, right); public static bool operator !=(ConfigLayout? left, ConfigLayout? right) => !(left == right); + + public override int GetHashCode() => HashCode.Combine(ConfigName, Keys); } diff --git a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Data/RawConfig.cs b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Data/RawConfig.cs index bd598d1..c7b3868 100644 --- a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Data/RawConfig.cs +++ b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Data/RawConfig.cs @@ -30,8 +30,18 @@ public bool TryGetString(string key, [NotNullWhen(true)] out string? value) { public bool TryGetGuid(string key, out Guid value) => Get(key, Guid.TryParse, out value); private bool Get(string key, DataGetter func, out T? value) { - value = default; - return _data.ContainsKey(key) && _data[key] is not null && func(_data[key], CultureInfo.InvariantCulture, out value); + if (_data.ContainsKey(key)) { + value = default; + return false; + } + + string? valueAsString = _data[key]; + if(valueAsString is null) { + value = default; + return false; + } + + return func(valueAsString, CultureInfo.InvariantCulture, out value); } public void Set(string key, object value) => _data[key] = value.ToString(); diff --git a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Logging/Logger.cs b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Logging/Logger.cs index 563a3e4..e3b0547 100644 --- a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Logging/Logger.cs +++ b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Logging/Logger.cs @@ -39,7 +39,4 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except LogLevel.None => ConsoleColor.White, _ => ConsoleColor.White }; - - - // public static ILogger Create() => new Logger(typeof(T).Name, new Wrapped(LogLevel.Information)); } diff --git a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Logging/Provider.cs b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Logging/Provider.cs index cb6e2c6..a9f73c0 100644 --- a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Logging/Provider.cs +++ b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Logging/Provider.cs @@ -52,12 +52,9 @@ public InitResult Init() { } public ILogger CreateLogger(string categoryName) { - if (_disposedValue) { - throw new ObjectDisposedException(GetType().FullName); - } - - return _loggers.GetOrAdd(categoryName, name => new Logger(name.Split('.')[^1], _minLogLevel)); - + return _disposedValue + ? throw new ObjectDisposedException(GetType().FullName) + : (ILogger)_loggers.GetOrAdd(categoryName, name => new Logger(name.Split('.')[^1], _minLogLevel)); } public ILogger CreateLogger() => CreateLogger(typeof(T).Name); @@ -79,5 +76,4 @@ public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } - } \ No newline at end of file diff --git a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/ConfigService.cs b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/ConfigService.cs index c993970..2097b47 100644 --- a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/ConfigService.cs +++ b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/ConfigService.cs @@ -16,7 +16,7 @@ public class ConfigService: IService{ private Dictionary? _configs; - public IReadOnlyCollection Layouts { get; private set; } + public IReadOnlyCollection Layouts { get; private set; } = new List(0); public async Task InitAsync(IReadOnlyCollection layouts) { Layouts = layouts; @@ -36,11 +36,9 @@ public async Task InitAsync(IReadOnlyCollection layouts) { public RawConfig GetOrCreateConfig(string name) => GetConfig(name) ?? CreateConfig(name); public RawConfig? GetConfig(string name) { - if (_configs is null) { - return null; - } - - return !_configs.TryGetValue(name, out RawConfig? config) ? null : config; + return _configs is not null && _configs.TryGetValue(name, out RawConfig? config) + ? config + : null; } public RawConfig CreateConfig(string name) { diff --git a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/Loader/SymbolLoader.cs b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/Loader/SymbolLoader.cs index 450079f..5027bb9 100644 --- a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/Loader/SymbolLoader.cs +++ b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/Loader/SymbolLoader.cs @@ -27,7 +27,7 @@ public class SymbolLoader : IAsyncInitializable, IService { private readonly Dictionary _symbols = new(); - private static async Task LoadSymbol(string path) { + private static async Task LoadSymbolAsync(string path) { Image image = await Image.LoadAsync(path); bool[,] symbol = new bool[image.Width, image.Height]; @@ -46,7 +46,7 @@ public async Task InitAsync() { char character = symbol.Value; bool[,] symbolMatrix; try { - symbolMatrix = await LoadSymbol(Path.Combine(s_directory, file)); + symbolMatrix = await LoadSymbolAsync(Path.Combine(s_directory, file)); } catch(Exception ex) { return InitResult.Critical(new Text(new TextElement(LanguageCode.EN, $"Couldn't load file '{file}': {ex.Message}"), new TextElement(LanguageCode.DE, $"Konnte Datei nicht laden '{file}': {ex.Message}"))); diff --git a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/Translation/Text.cs b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/Translation/Text.cs index 9332b7d..e2d728f 100644 --- a/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/Translation/Text.cs +++ b/src/MatrixWeb.Extensions/MatrixWeb.Extensions/Services/Translation/Text.cs @@ -5,7 +5,7 @@ public record Text(params TextElement[] Texts) { public static readonly Text Empty = new(new TextElement(LanguageCode.EN, ""), new TextElement(LanguageCode.DE, "")); public string GetText(LanguageCode languageCode) { - return TryGetText(languageCode, out var text) + return TryGetText(languageCode, out string? text) ? text : string.Empty; } diff --git a/src/MatrixWeb/Pages/Settings.razor b/src/MatrixWeb/Pages/Settings.razor index eb0b5ee..e501549 100644 --- a/src/MatrixWeb/Pages/Settings.razor +++ b/src/MatrixWeb/Pages/Settings.razor @@ -18,9 +18,9 @@ @inject TextService textService - @foreach(var configLayout in configService.Layouts) { + @foreach (var configLayout in configService.Layouts) {

@configLayout.ConfigName

- @foreach(var key in configLayout.Keys) { + @foreach (var key in configLayout.Keys) { } } @@ -44,11 +44,11 @@

@if (_redTimeRange == TimeRange.Always) { - @textService[s_alwaysRedText] - } else if (_redTimeRange == TimeRange.Never) { - @textService[s_neverRedText] + @textService[s_alwaysRedText] + } else if (_redTimeRange == TimeRange.Never) { + @textService[s_neverRedText] } else { - @textService[s_redBetweenText] @_redTimeRange.Start @textService[s_andText] @_redTimeRange.End + @textService[s_redBetweenText] @_redTimeRange.Start @textService[s_andText] @_redTimeRange.End }

diff --git a/src/MatrixWeb/Pages/SpotifyCallback.razor b/src/MatrixWeb/Pages/SpotifyCallback.razor index 896dd6b..8995fcc 100644 --- a/src/MatrixWeb/Pages/SpotifyCallback.razor +++ b/src/MatrixWeb/Pages/SpotifyCallback.razor @@ -34,7 +34,7 @@ } try { - await spotify.AddToken(code, GetCallbackUrl()); + await spotify.AddTokenAsync(code, GetCallbackUrl()); } catch (Exception ex) { logger.LogError(ex.ToString()); _error = true; diff --git a/src/MatrixWeb/Program.cs b/src/MatrixWeb/Program.cs index c77ea09..f429bc3 100644 --- a/src/MatrixWeb/Program.cs +++ b/src/MatrixWeb/Program.cs @@ -34,7 +34,7 @@ public static async Task Main(string[] args) { displayApp.Services.MoveServiceTo(builder.Services); displayApp.Services.MoveLogger(builder.Services); - builder.Services.AddSingleton((p) => new DisplayService(displayApp, p.GetService>())); + builder.Services.AddSingleton((p) => new DisplayService(displayApp, p.GetRequiredService>())); displayApp.Services.MoveServiceTo(builder.Services); displayApp.Services.MoveServiceTo(builder.Services); diff --git a/src/MatrixWeb/Shared/ConfigInput.razor b/src/MatrixWeb/Shared/ConfigInput.razor index e381569..f190545 100644 --- a/src/MatrixWeb/Shared/ConfigInput.razor +++ b/src/MatrixWeb/Shared/ConfigInput.razor @@ -4,32 +4,40 @@ @inject ConfigService configService
- - + +
@code { - private Guid _inputId = Guid.NewGuid(); + private string _inputId = $"input-{Guid.NewGuid()}"; private RawConfig? _config = null; - [Parameter] - public ConfigKey ConfigKey { get; set; } + [Parameter, EditorRequired] + public ConfigKey? ConfigKey { get; set; } - [Parameter] - public ConfigLayout ConfigLayout { get; set; } + [Parameter, EditorRequired] + public ConfigLayout? ConfigLayout { get; set; } protected override void OnInitialized() { + if (ConfigKey is null || ConfigLayout is null) { + return; + } + _config = configService.GetOrCreateConfig(ConfigLayout.ConfigName); } - private string Getvalue() { + private string GetValue() { + if (ConfigKey is null || ConfigLayout is null) { + return ""; + } + if(_config is null) { return ""; } - if (_config.TryGetString(ConfigKey.Key, out string value)) { + if (_config.TryGetString(ConfigKey.Key, out string? value)) { return value; } @@ -37,6 +45,10 @@ } private string GetInputType() { + if (ConfigKey is null || ConfigLayout is null) { + return ""; + } + if(ConfigKey.Type == typeof(string) || ConfigKey.Type == typeof(Guid)) { return "text"; } @@ -49,6 +61,10 @@ } private void OnChange(ChangeEventArgs e) { + if (ConfigKey is null || ConfigLayout is null) { + return; + } + if(e.Value is not string str) { return; } diff --git a/src/MatrixWeb/Shared/Inputs/ExtendedInput.razor b/src/MatrixWeb/Shared/Inputs/ExtendedInput.razor index 4ea9eaa..312d5bc 100644 --- a/src/MatrixWeb/Shared/Inputs/ExtendedInput.razor +++ b/src/MatrixWeb/Shared/Inputs/ExtendedInput.razor @@ -5,7 +5,7 @@ @@ -29,7 +29,7 @@ [Parameter] public bool Disabled { get; set; } = false; - protected string Text { get; set; } + protected string Text { get; set; } = ""; protected int Multiplier { get; set; } = 1; diff --git a/src/MatrixWeb/Shared/Inputs/HourInput.cs b/src/MatrixWeb/Shared/Inputs/HourInput.cs index cebe8e1..bc34b33 100644 --- a/src/MatrixWeb/Shared/Inputs/HourInput.cs +++ b/src/MatrixWeb/Shared/Inputs/HourInput.cs @@ -6,13 +6,13 @@ namespace MatrixWeb.Shared.Inputs; public class HourInput : ExtendedInput { private static bool s_textIdsSet = false; - private static int _hourText = -1; + private static int s_hourText = -1; [Inject] - public TextService TextService { get; set; } + public required TextService TextService { get; set; } private static void InitTexts(TextService textService) { - _hourText = textService.AddText(new TextElement(LanguageCode.EN, "Hours"), new TextElement(LanguageCode.DE, "Stunden")); + s_hourText = textService.AddText(new TextElement(LanguageCode.EN, "Hours"), new TextElement(LanguageCode.DE, "Stunden")); s_textIdsSet = true; } @@ -21,7 +21,7 @@ protected override void OnParametersSet() { InitTexts(TextService); } - Text = TextService[_hourText]; + Text = TextService[s_hourText]; base.OnParametersSet(); } } diff --git a/src/MatrixWeb/Shared/Inputs/PercentInput.cs b/src/MatrixWeb/Shared/Inputs/PercentInput.cs index 01297bf..8abd500 100644 --- a/src/MatrixWeb/Shared/Inputs/PercentInput.cs +++ b/src/MatrixWeb/Shared/Inputs/PercentInput.cs @@ -5,13 +5,13 @@ namespace MatrixWeb.Shared.Inputs; public class PercentInput : ExtendedInput { private static bool s_textIdsSet = false; - private static int _percentText = -1; + private static int s_percentText = -1; [Inject] - public TextService TextService { get; set; } + public required TextService TextService { get; set; } private static void InitTexts(TextService textService) { - _percentText = textService.AddText(new TextElement(LanguageCode.EN, "%"), new TextElement(LanguageCode.DE, "%")); + s_percentText = textService.AddText(new TextElement(LanguageCode.EN, "%"), new TextElement(LanguageCode.DE, "%")); s_textIdsSet = true; } @@ -20,7 +20,7 @@ protected override void OnParametersSet() { InitTexts(TextService); } - Text = TextService[_percentText]; + Text = TextService[s_percentText]; Multiplier = 100; base.OnParametersSet(); } diff --git a/src/MatrixWeb/Shared/Inputs/SecondInput.cs b/src/MatrixWeb/Shared/Inputs/SecondInput.cs index 5585f9a..c58f9aa 100644 --- a/src/MatrixWeb/Shared/Inputs/SecondInput.cs +++ b/src/MatrixWeb/Shared/Inputs/SecondInput.cs @@ -5,13 +5,13 @@ namespace MatrixWeb.Shared.Inputs; public class SecondInput : ExtendedInput { private static bool s_textIdsSet = false; - private static int _secondsText = -1; + private static int s_secondsText = -1; [Inject] public TextService TextService { get; set; } private static void InitTexts(TextService textService) { - _secondsText = textService.AddText(new TextElement(LanguageCode.EN, "Sec"), new TextElement(LanguageCode.DE, "Sek.")); + s_secondsText = textService.AddText(new TextElement(LanguageCode.EN, "Sec"), new TextElement(LanguageCode.DE, "Sek.")); s_textIdsSet = true; } @@ -21,7 +21,7 @@ protected override void OnParametersSet() { InitTexts(TextService); } - Text = TextService[_secondsText]; + Text = TextService[s_secondsText]; base.OnParametersSet(); } } diff --git a/src/MatrixWeb/Shared/OverlayWindow.razor b/src/MatrixWeb/Shared/OverlayWindow.razor index cd43ef7..7d77799 100644 --- a/src/MatrixWeb/Shared/OverlayWindow.razor +++ b/src/MatrixWeb/Shared/OverlayWindow.razor @@ -14,5 +14,5 @@ public bool Visible { get; set; } [Parameter] - public RenderFragment ChildContent { get; set; } + public RenderFragment? ChildContent { get; set; } }