Catalog/CatalogLite/LiteCatalogViewModel.cs

349 lines
10 KiB
C#
Raw Permalink Normal View History

2026-05-26 21:47:55 +02:00
using MaddoShared;
using Microsoft.Extensions.Logging;
namespace CatalogLite;
public sealed class LiteCatalogViewModel : ViewModelBase
{
private readonly CatalogConfigurationLoader _configurationLoader;
private readonly PicSettings _picSettings;
private readonly ImageCreationService _imageCreationService;
private readonly ImageProcessingCoordinator _imageProcessingCoordinator;
private readonly ILogger<LiteCatalogViewModel> _logger;
private CatalogLiteConfiguration? _configuration;
private CancellationTokenSource? _processingTokenSource;
private string _configurationPath = string.Empty;
private string _sourcePath = string.Empty;
private string _destinationPath = string.Empty;
private string _processingStatus = "Carica una configurazione XML.";
private string _speedCounter = "-";
private int _processedImagesCount;
private int _totalImagesCount;
private int _progressBarValue;
private int _progressBarMaximum = 100;
private bool _isProcessing;
public LiteCatalogViewModel(
CatalogConfigurationLoader configurationLoader,
PicSettings picSettings,
ImageCreationService imageCreationService,
ImageProcessingCoordinator imageProcessingCoordinator,
ILogger<LiteCatalogViewModel> logger)
{
_configurationLoader = configurationLoader;
_picSettings = picSettings;
_imageCreationService = imageCreationService;
_imageProcessingCoordinator = imageProcessingCoordinator;
_logger = logger;
LoadConfigurationCommand = new AsyncCommand(RequestLoadConfigurationAsync, () => !IsProcessing);
SelectSourceFolderCommand = new AsyncCommand(RequestSourceFolderAsync, () => !IsProcessing);
SelectDestinationFolderCommand = new AsyncCommand(RequestDestinationFolderAsync, () => !IsProcessing);
StartProcessingCommand = new AsyncCommand(StartProcessingAsync, CanStartProcessing);
StopProcessingCommand = new AsyncCommand(StopProcessingAsync, () => IsProcessing);
}
public event EventHandler? LoadConfigurationRequested;
public event EventHandler? SelectSourceFolderRequested;
public event EventHandler? SelectDestinationFolderRequested;
public event EventHandler<LiteMessageEventArgs>? ShowMessageRequested;
public Action<Action>? UiInvoker { get; set; }
public AsyncCommand LoadConfigurationCommand { get; }
public AsyncCommand SelectSourceFolderCommand { get; }
public AsyncCommand SelectDestinationFolderCommand { get; }
public AsyncCommand StartProcessingCommand { get; }
public AsyncCommand StopProcessingCommand { get; }
public string ConfigurationPath
{
get => _configurationPath;
private set
{
_configurationPath = value;
NotifyPropertyChanged();
}
}
public string SourcePath
{
get => _sourcePath;
set
{
_sourcePath = NormalizeDirectoryPath(value);
NotifyPropertyChanged();
RaiseCommandStates();
}
}
public string DestinationPath
{
get => _destinationPath;
set
{
_destinationPath = NormalizeDirectoryPath(value);
NotifyPropertyChanged();
RaiseCommandStates();
}
}
public string ProcessingStatus
{
get => _processingStatus;
private set
{
_processingStatus = value;
NotifyPropertyChanged();
}
}
public string SpeedCounter
{
get => _speedCounter;
private set
{
_speedCounter = value;
NotifyPropertyChanged();
}
}
public int ProcessedImagesCount
{
get => _processedImagesCount;
private set
{
_processedImagesCount = value;
NotifyPropertyChanged();
}
}
public int TotalImagesCount
{
get => _totalImagesCount;
private set
{
_totalImagesCount = value;
NotifyPropertyChanged();
}
}
public int ProgressBarValue
{
get => _progressBarValue;
private set
{
_progressBarValue = value;
NotifyPropertyChanged();
}
}
public int ProgressBarMaximum
{
get => _progressBarMaximum;
private set
{
_progressBarMaximum = Math.Max(1, value);
NotifyPropertyChanged();
}
}
public bool IsProcessing
{
get => _isProcessing;
private set
{
_isProcessing = value;
NotifyPropertyChanged();
RaiseCommandStates();
}
}
public async Task LoadConfigurationFromFileAsync(string filePath)
{
try
{
var configuration = await Task.Run(() => _configurationLoader.Load(filePath, _picSettings)).ConfigureAwait(false);
RunOnUiThread(() =>
{
_configuration = configuration;
ConfigurationPath = configuration.FilePath;
SourcePath = configuration.SourcePath;
DestinationPath = configuration.DestinationPath;
ResetProgress("Configurazione caricata.");
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore durante il caricamento della configurazione");
ShowMessage("Configurazione", $"Impossibile caricare la configurazione: {ex.GetBaseException().Message}");
}
}
public static string NormalizeDirectoryPath(string? path)
{
if (string.IsNullOrWhiteSpace(path))
{
return string.Empty;
}
var trimmed = path.Trim().TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
return trimmed + Path.DirectorySeparatorChar;
}
private Task RequestLoadConfigurationAsync()
{
LoadConfigurationRequested?.Invoke(this, EventArgs.Empty);
return Task.CompletedTask;
}
private Task RequestSourceFolderAsync()
{
SelectSourceFolderRequested?.Invoke(this, EventArgs.Empty);
return Task.CompletedTask;
}
private Task RequestDestinationFolderAsync()
{
SelectDestinationFolderRequested?.Invoke(this, EventArgs.Empty);
return Task.CompletedTask;
}
private bool CanStartProcessing()
{
return !IsProcessing
&& _configuration is not null
&& !string.IsNullOrWhiteSpace(SourcePath)
&& !string.IsNullOrWhiteSpace(DestinationPath);
}
private async Task StartProcessingAsync()
{
if (_configuration is null)
{
ShowMessage("Configurazione", "Carica prima una configurazione XML.");
return;
}
if (!Directory.Exists(SourcePath))
{
ShowMessage("Sorgente", "La cartella sorgente non esiste.");
return;
}
try
{
Directory.CreateDirectory(DestinationPath);
}
catch (Exception ex)
{
ShowMessage("Destinazione", $"Impossibile usare la cartella destinazione: {ex.GetBaseException().Message}");
return;
}
_processingTokenSource?.Dispose();
_processingTokenSource = new CancellationTokenSource();
var token = _processingTokenSource.Token;
var options = CatalogConfigurationLoader.CloneOptions(_configuration.Options, SourcePath, DestinationPath);
_picSettings.DirectorySorgente = SourcePath;
_picSettings.DirectoryDestinazione = DestinationPath;
_picSettings.DestDir = new DirectoryInfo(DestinationPath);
IsProcessing = true;
ResetProgress("Analisi immagini...");
try
{
var total = await Task.Run(() => _imageCreationService.GetFilesToProcessPublic(options).Count, token).ConfigureAwait(false);
RunOnUiThread(() =>
{
TotalImagesCount = total;
ProgressBarMaximum = Math.Max(1, total);
ProcessingStatus = total == 0 ? "Nessuna immagine trovata." : "Elaborazione in corso...";
});
if (total == 0)
{
return;
}
var result = await _imageProcessingCoordinator.RunAsync(
options,
token,
update => RunOnUiThread(() =>
{
ProcessedImagesCount = update.Processed;
TotalImagesCount = update.Total;
ProgressBarMaximum = update.Total;
ProgressBarValue = update.Processed;
ProcessingStatus = update.Status;
}),
speed => RunOnUiThread(() => SpeedCounter = speed)).ConfigureAwait(false);
RunOnUiThread(() =>
{
SpeedCounter = result.FinalSpeedCounter;
ProcessingStatus = "Finito.";
});
}
catch (OperationCanceledException)
{
RunOnUiThread(() => ProcessingStatus = "Operazione annullata.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore durante l'elaborazione");
RunOnUiThread(() => ProcessingStatus = $"Errore: {ex.GetBaseException().Message}");
}
finally
{
_processingTokenSource?.Dispose();
_processingTokenSource = null;
RunOnUiThread(() => IsProcessing = false);
}
}
private Task StopProcessingAsync()
{
_processingTokenSource?.Cancel();
ProcessingStatus = "Arresto in corso...";
return Task.CompletedTask;
}
private void ResetProgress(string status)
{
ProcessingStatus = status;
ProcessedImagesCount = 0;
TotalImagesCount = 0;
ProgressBarValue = 0;
ProgressBarMaximum = 100;
SpeedCounter = "-";
}
private void RunOnUiThread(Action action)
{
if (UiInvoker is null)
{
action();
return;
}
UiInvoker(action);
}
private void ShowMessage(string title, string message)
{
RunOnUiThread(() => ShowMessageRequested?.Invoke(this, new LiteMessageEventArgs(title, message)));
}
private void RaiseCommandStates()
{
LoadConfigurationCommand.RaiseCanExecuteChanged();
SelectSourceFolderCommand.RaiseCanExecuteChanged();
SelectDestinationFolderCommand.RaiseCanExecuteChanged();
StartProcessingCommand.RaiseCanExecuteChanged();
StopProcessingCommand.RaiseCanExecuteChanged();
}
}