feat: Enhance Face AI upload functionality and UI
Some checks failed
Build Windows Avalonia / build (push) Failing after 1m48s
Release Windows Avalonia / build (push) Failing after 1m41s
Release Windows Avalonia / release (push) Has been skipped

- Updated MainWindow.axaml to increase height and add new UI elements for SSH upload configuration.
- Implemented commands for opening source and destination paths in file explorer.
- Added FaceUploadPath and SSH configuration properties to DataModel and AiSettingsViewModel.
- Introduced validation for FaceUploadPath format and commands for uploading face encoder output.
- Enhanced PickerPreferenceService to manage SSH credentials and upload preferences.
- Updated settings persistence to include FaceUploadPath and SSH preferences.
- Added tests for FaceUploadPath validation and upload command enabling logic.
This commit is contained in:
Maddo 2026-06-06 11:54:21 +02:00
commit e9142df97c
22 changed files with 1477 additions and 84 deletions

View file

@ -1,4 +1,5 @@
using System.Globalization;
using System.Reflection;
using System.Xml.Linq;
using MaddoShared;
using SixLabors.ImageSharp;
@ -8,6 +9,9 @@ namespace CatalogLite;
public sealed class CatalogConfigurationLoader
{
private const string EmbeddedConfigResourceName = "CatalogLite.Assets.Config.xml";
private const string EmbeddedLogoResourceName = "CatalogLite.Assets.Logo_RUS_ETS_tricolore_OK.png";
public CatalogLiteConfiguration Load(string filePath, PicSettings picSettings)
{
if (string.IsNullOrWhiteSpace(filePath))
@ -21,7 +25,7 @@ public sealed class CatalogConfigurationLoader
}
var values = ConfigurationValues.Load(filePath);
ApplyPicSettings(values, picSettings);
ApplyPicSettings(values, picSettings);
var sourcePath = LiteCatalogViewModel.NormalizeDirectoryPath(values.GetString("DirSorgente"));
var destinationPath = LiteCatalogViewModel.NormalizeDirectoryPath(values.GetString("DirDestinazione"));
@ -41,6 +45,32 @@ public sealed class CatalogConfigurationLoader
};
}
public CatalogLiteConfiguration LoadEmbedded(PicSettings picSettings)
{
using var configStream = OpenEmbeddedResource(EmbeddedConfigResourceName);
var values = ConfigurationValues.Load(configStream);
ApplyPicSettings(values, picSettings);
picSettings.LogoData = ReadAllBytes(OpenEmbeddedResource(EmbeddedLogoResourceName));
picSettings.LogoNomeFile = string.Empty;
var sourcePath = LiteCatalogViewModel.NormalizeDirectoryPath(values.GetString("DirSorgente"));
var destinationPath = LiteCatalogViewModel.NormalizeDirectoryPath(values.GetString("DirDestinazione"));
picSettings.DirectorySorgente = sourcePath;
picSettings.DirectoryDestinazione = destinationPath;
picSettings.DestDir = string.IsNullOrWhiteSpace(destinationPath)
? new DirectoryInfo(Environment.CurrentDirectory)
: new DirectoryInfo(destinationPath);
return new CatalogLiteConfiguration
{
FilePath = "Configurazione incorporata",
SourcePath = sourcePath,
DestinationPath = destinationPath,
Options = BuildOptions(values, sourcePath, destinationPath)
};
}
public static ImageCreationService.Options CloneOptions(ImageCreationService.Options options, string sourcePath, string destinationPath)
{
return new ImageCreationService.Options
@ -150,6 +180,22 @@ public sealed class CatalogConfigurationLoader
return string.Equals(values.GetString("MiniatureModalita"), mode, StringComparison.OrdinalIgnoreCase);
}
private static Stream OpenEmbeddedResource(string resourceName)
{
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
return stream ?? throw new InvalidOperationException($"Risorsa incorporata non trovata: {resourceName}");
}
private static byte[] ReadAllBytes(Stream stream)
{
using (stream)
{
using var memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
private static Rgba32 ParseColor(string value, Rgba32 fallback)
{
if (string.IsNullOrWhiteSpace(value))
@ -193,7 +239,13 @@ public sealed class CatalogConfigurationLoader
public static ConfigurationValues Load(string filePath)
{
var document = XDocument.Load(filePath);
using var stream = File.OpenRead(filePath);
return Load(stream);
}
public static ConfigurationValues Load(Stream stream)
{
var document = XDocument.Load(stream);
var values = document
.Descendants("Setup")
.Where(element => element.Element("Nome") is not null)