Catalog Lite
This commit is contained in:
parent
398cfa310e
commit
181229aa41
18 changed files with 1435 additions and 0 deletions
350
CatalogLite/LiteCatalogViewModel.cs
Normal file
350
CatalogLite/LiteCatalogViewModel.cs
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
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);
|
||||
_picSettings.ImageCreatorProvider = "ImageSharp";
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue