feat: AvaloniaUi GSS2.Test

This commit is contained in:
2026-01-16 14:17:19 +03:00
parent af828a407d
commit 2ce8d3e966
11 changed files with 210 additions and 40 deletions
+2 -2
View File
@@ -58,7 +58,7 @@ public static class DependencyInjectionHelper
return new IlluminatorService(logger, serviceConfiguration); return new IlluminatorService(logger, serviceConfiguration);
} }
); );
public static IServiceCollection AddCameraService(this IServiceCollection services, string section) => services public static IServiceCollection AddCameraService(this IServiceCollection services, string section, bool autoInitialize = false) => services
.AddSingleton( .AddSingleton(
serviceProvider => serviceProvider =>
{ {
@@ -71,7 +71,7 @@ public static class DependencyInjectionHelper
var logger = serviceProvider.GetService<ILogger<CameraService>>(); var logger = serviceProvider.GetService<ILogger<CameraService>>();
if (logger is null) if (logger is null)
throw new Exception("Cannot get logger"); throw new Exception("Cannot get logger");
return new CameraService(logger, serviceConfiguration); return new CameraService(logger, serviceConfiguration, autoInitialize);
} }
); );
+1 -1
View File
@@ -21,7 +21,7 @@
<PackageReference Include="OpenCvSharp4.runtime.linux-arm" Version="4.11.0.20250506" /> <PackageReference Include="OpenCvSharp4.runtime.linux-arm" Version="4.11.0.20250506" />
<PackageReference Include="System.Device.Gpio" Version="4.0.1" /> <PackageReference Include="System.Device.Gpio" Version="4.0.1" />
<PackageReference Include="Iot.Device.Bindings" Version="4.0.1" /> <PackageReference Include="Iot.Device.Bindings" Version="4.0.1" />
<PackageReference Include="LibCameraSharp" Version="0.5.2-20260114" /> <PackageReference Include="LibCameraSharp" Version="0.5.2-20260116" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+8
View File
@@ -0,0 +1,8 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="GSS2.Test.App"
RequestedThemeVariant="Dark">
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>
+83
View File
@@ -0,0 +1,83 @@
using System.Drawing;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using GSS2.Core;
using GSS2.Core.Analysis.AmineContent.Database;
using GSS2.Core.Hardware;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging.Console;
namespace GSS2.Test;
public partial class App : Application
{
private readonly IHost _host = BuildHostApp();
public override void Initialize()
{
_host.Start();
AvaloniaXamlLoader.Load(this);
}
private static IHost BuildHostApp()
{
var builder = Host.CreateApplicationBuilder();
builder.Logging.ClearProviders();
builder.Logging.AddConsole(options => options.FormatterName = nameof(ConsoleFormatter));
builder.Logging.AddConsoleFormatter<ConsoleFormatter, ConsoleFormatterOptions>();
builder.Logging.AddProvider(new FileLoggerProvider("app.log"));
builder.Services.AddSingleton<LibCameraLogSink>();
builder.Services.AddAmineContentCalibrationContext(builder.Configuration);
builder.Services.AddAmineContentResultsContext(builder.Configuration);
builder.Services.AddLightsService("Hardware:Lights");
builder.Services.AddTemperatureHumidityService("Hardware:TemperatureHumidity");
builder.Services.AddIlluminatorService("Hardware:Illuminator");
builder.Services.AddCameraService("Hardware:Camera", true);
var host = builder.Build();
host.Services.GetRequiredService<LibCameraLogSink>();
using (var scope = host.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<AmineContentCalibrationContext>();
context.Database.Migrate();
}
using (var scope = host.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<AmineContentResultsContext>();
context.Database.Migrate();
}
return host;
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
var lightsService = _host.Services.GetRequiredService<LightsService>();
_ = lightsService.Run(CancellationToken.None);
_ = lightsService.SnowfallAsync(0.3, 1, Color.Aqua);
var cameraService = _host.Services.GetRequiredService<CameraService>();
var illuminatorService = _host.Services.GetRequiredService<IlluminatorService>();
desktop.MainWindow = new MainWindow(cameraService, illuminatorService, lightsService);
desktop.MainWindow.Closed += async (_, _) =>
{
await lightsService.DisconnectAsync();
await _host.StopAsync();
_host.Dispose();
};
}
base.OnFrameworkInitializationCompleted();
}
}
+13
View File
@@ -1,14 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk.Worker"> <Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>dotnet-GSS2.Test-191ece0a-855d-46ec-9ecb-44378fc3db83</UserSecretsId> <UserSecretsId>dotnet-GSS2.Test-191ece0a-855d-46ec-9ecb-44378fc3db83</UserSecretsId>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
<PackageReference Include="Avalonia" Version="11.3.9" />
<PackageReference Include="Avalonia.Desktop" Version="11.3.9" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.9" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.9" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.9">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+9
View File
@@ -0,0 +1,9 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="GSS2.Test.MainWindow"
Title="GSS2.Test">
<Image x:Name="image"/>
</Window>
+60
View File
@@ -0,0 +1,60 @@
using Avalonia.Controls;
using Avalonia.Media.Imaging;
using GSS2.Core.Hardware;
namespace GSS2.Test;
public partial class MainWindow : Window
{
private readonly CameraService _cameraService;
private readonly IlluminatorService _illuminatorService;
private readonly LightsService _lightsService;
public MainWindow(CameraService cameraService, IlluminatorService illuminatorService, LightsService lightsService)
{
_cameraService = cameraService;
_illuminatorService = illuminatorService;
_lightsService = lightsService;
InitializeComponent();
PointerPressed += async (_, _) =>
{
_lightsService.CpuLoad(0.5, 1, System.Drawing.Color.Aqua);
try
{
_illuminatorService.SetIntensity(0.01, 0, 0);
_illuminatorService.TurnOn();
using var img = await _cameraService.CaptureImage(CancellationToken.None, 5);
if (img is not null)
{
var bytes = img.ToBytes(".png");
using var stream = new MemoryStream(bytes);
image.Source = new Bitmap(stream);
}
_lightsService.Flash(0.5, 2, System.Drawing.Color.Green);
}
catch
{
_lightsService.Flash(0.5, 2, System.Drawing.Color.Red);
}
finally
{
_illuminatorService.TurnOff();
}
var snowfallTimer = new System.Timers.Timer(3000);
snowfallTimer.Elapsed += (_, _) =>
{
lightsService.Snowfall(0.3, 1, System.Drawing.Color.Aqua);
snowfallTimer.Dispose();
};
snowfallTimer.Start();
};
}
}
+12 -33
View File
@@ -1,46 +1,25 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging.Console;
using GSS2.Core; using GSS2.Core;
using GSS2.Core.Analysis.AmineContent.Database; using GSS2.Core.Analysis.AmineContent.Database;
using Microsoft.Extensions.Logging.Console;
using Avalonia;
namespace GSS2.Test; namespace GSS2.Test;
public class Program public class Program
{ {
[STAThread]
public static void Main(string[] args) public static void Main(string[] args)
{ {
var builder = Host.CreateApplicationBuilder(args); BuildAvaloniaApp()
.UseStandardRuntimePlatformSubsystem()
builder.Logging.ClearProviders(); .StartWithClassicDesktopLifetime(args);
builder.Logging.AddConsole(options => options.FormatterName = nameof(ConsoleFormatter));
builder.Logging.AddConsoleFormatter<ConsoleFormatter, ConsoleFormatterOptions>();
builder.Logging.AddProvider(new FileLoggerProvider("app.log"));
builder.Services.AddSingleton<LibCameraLogSink>();
builder.Services.AddAmineContentCalibrationContext(builder.Configuration);
builder.Services.AddAmineContentResultsContext(builder.Configuration);
builder.Services.AddLightsService("Hardware:Lights");
builder.Services.AddTemperatureHumidityService("Hardware:TemperatureHumidity");
builder.Services.AddIlluminatorService("Hardware:Illuminator");
builder.Services.AddCameraService("Hardware:Camera");
builder.Services.AddHostedService<Worker>();
var host = builder.Build();
host.Services.GetRequiredService<LibCameraLogSink>();
using (var scope = host.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<AmineContentCalibrationContext>();
context.Database.Migrate();
}
using (var scope = host.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<AmineContentResultsContext>();
context.Database.Migrate();
} }
host.Run(); public static AppBuilder BuildAvaloniaApp()
} => AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
} }
+2 -2
View File
@@ -29,12 +29,12 @@ public class Worker(
_ = _lightsService.Run(cancellationToken); _ = _lightsService.Run(cancellationToken);
_ = _lightsService.SnowfallAsync(0.3, 1, Color.Aqua, cancellationToken); _ = _lightsService.SnowfallAsync(0.3, 1, Color.Aqua, cancellationToken);
_illuminatorService.SetIntensity(0.5, 0, 0); _illuminatorService.SetIntensity(0.01, 0, 0);
_illuminatorService.TurnOn(); _illuminatorService.TurnOn();
await Task.Delay(1000); await Task.Delay(1000);
var img = await _cameraService.CaptureImage(cancellationToken); var img = await _cameraService.CaptureImage(cancellationToken, 50);
img?.SaveImage("IMAGE.png"); img?.SaveImage("IMAGE.png");
await Task.Delay(1000); await Task.Delay(1000);
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="GSS2.Test.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>
+1 -1
View File
@@ -40,7 +40,7 @@
"ViewFinderWidth": 1920, "ViewFinderWidth": 1920,
"ViewFinderHeight": 1080, "ViewFinderHeight": 1080,
"ViewFinderFps": 30, "ViewFinderFps": 30,
"ImageCaptureFrameBufferCount": 2, "ImageCaptureFrameBufferCount": 5,
"ImageCaptureWidth": 4056, "ImageCaptureWidth": 4056,
"ImageCaptureHeight": 3040 "ImageCaptureHeight": 3040
}, },