feat: MainView

This commit is contained in:
2026-04-13 09:29:03 +03:00
parent 8cf1c89863
commit 16c5b5d42f
9 changed files with 518 additions and 3 deletions
+128 -2
View File
@@ -1,5 +1,17 @@
using System.CommandLine;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Avalonia;
using Avalonia.OpenGL.Egl;
using GSS2.Core.Logging;
using GSS2.Core;
using GSS2.Core.Analysis.AmineContent.Database.Calibration;
using GSS2.Core.Analysis.AmineContent.Database.Results;
namespace GSS2.Commands;
public static class UI
@@ -31,7 +43,6 @@ public static class UI
RenderingMode = new("--mode", ["--rendering-mode", "-m"])
{
Description = "Режим рендеринга",
DefaultValueFactory = (_) => RenderingModes.X11
};
HideConsole = new("--hide-console", ["--no-console", "-c"])
@@ -53,7 +64,6 @@ public static class UI
Command.Add(RenderingMode);
Command.Add(HideConsole);
Command.SetAction(CommandAction);
}
/// <summary>
@@ -69,6 +79,122 @@ public static class UI
private static void CommandAction(ParseResult result)
{
/// Получаем значения аргументов командной строки
var fullscreen = result.GetValue(Fullscreen);
var renderingMode = result.GetValue(RenderingMode);
var hideConsole = result.GetValue(HideConsole);
// Если выбран режим рендеринга DRM, то приложение будет рисоваться вместе с консолью,
// поэтому если не перехватить консоль, то вывод в неё будет рисоваться вместе с интерфейсом
if (hideConsole)
SilenceConsole();
// Собираем хост
var host = BuildHost();
// Запускаем хост асинхронно без блокировки потока
_ = host.RunAsync();
// Собираем графическое приложение
var ui = BuildApplication(host, fullscreen);
switch (renderingMode)
{
case RenderingModes.X11:
// Если мы запускаемся под X11,
// то очевидно у нас есть полноценный рабочий стол,
// поэтому запускаем графический интерфейс в классическом режиме с главным окном
ui.StartWithClassicDesktopLifetime(Program.Args);
break;
case RenderingModes.DRM:
// Если мы запускаемся в DRM (Direct Rendering Mode),
// то у нас нет рабочего стола и окон,
// потому что отрисовка (вроде как) идёт напрямую в кадровый буфер,
// поэтому запускаем графический интерфейс в DRM.
// Если работает X11, или любая другая графическая система,
// то запустить приложение в DRM не получится,
// потому что DRI (Direct Rendering Interface) занят этой графической системой
// TODO: Подумать над тем, чтобы брать DRI и scale для DRM рендеринга из переменных среды
// TODO: Подумать над тем, чтобы при запуске в DRM убивать приложения, которые занимают DRI
ui.StartLinuxDrm(Program.Args, "/dev/dri/card1", 1.0);
break;
}
}
private static void SilenceConsole()
{
var start = new ThreadStart(() =>
{
Console.CursorVisible = false;
while (true)
Console.ReadKey(true);
});
var thread = new Thread(start)
{
IsBackground = true
};
thread.Start();
}
private static IHost BuildHost()
{
// Создаём хост
var builder = Host.CreateApplicationBuilder();
// Добавляем конфигурацию из appsettings.json
builder.Configuration.AddAppSettingsJson();
// Конфигурируем логгер
builder.Logging.ConfigureLogging();
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);
builder.Services.AddComputeResourcesService();
builder.Services.AddImageStorageService(new DirectoryInfo("images"));
// Добавляем элементы интерфейса как сервисы
builder.Services.AddViewsAndModels();
// Собираем хост
var host = builder.Build();
// Поскольку LibCameraLogSink, который перенаправляет логи из libcamera в хост,
// не будет создан ни одним из других сервисов, его необходимо создать превентивно
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;
}
private static AppBuilder BuildApplication(IHost host, bool fullscreen) =>
AppBuilder.Configure(() => new Application(host.Services, fullscreen))
.UsePlatformDetect()
.UseSkia()
.LogToTrace()
.With(new X11PlatformOptions
{
RenderingMode = [X11RenderingMode.Egl]
})
.With(new EglDisplayOptions
{
SupportsContextSharing = true
});
}