using Avalonia; using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Layout; using Avalonia.Platform.Storage; using Avalonia.Styling; using Avalonia.Threading; using System.ComponentModel; using System.IO; namespace ImageCatalog_2; public partial class AvaloniaMainWindow : Window { private readonly DataModel _model; private bool _isDarkTheme; public AvaloniaMainWindow(DataModel model) { InitializeComponent(); _model = model; DataContext = _model; Opened += (_, _) => SyncThemeStateFromCurrentTheme(); Closing += AvaloniaMainWindow_Closing; // Let DataModel marshal callbacks onto Avalonia UI thread. _model.UiInvoker = action => Dispatcher.UIThread.Invoke(action); _model.SelectSourceFolderRequested += async (_, _) => { var folders = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { Title = "Seleziona cartella sorgente" }); if (folders.Count > 0) { _model.SourcePath = folders[0].Path.LocalPath + Path.DirectorySeparatorChar; } }; _model.SelectDestinationFolderRequested += async (_, _) => { var folders = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { Title = "Seleziona cartella destinazione" }); if (folders.Count > 0) { _model.DestinationPath = folders[0].Path.LocalPath + Path.DirectorySeparatorChar; } }; _model.SelectLogoFileRequested += async (_, _) => { var files = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { Title = "Seleziona logo", FileTypeFilter = [ new FilePickerFileType("Immagini") { Patterns = ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif"] } ] }); if (files.Count > 0) { _model.LogoFile = files[0].Path.LocalPath; } }; _model.SelectModelsFolderRequested += async (_, _) => { var folders = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { Title = "Seleziona cartella modelli" }); if (folders.Count > 0) { _model.ModelsFolderPath = folders[0].Path.LocalPath + Path.DirectorySeparatorChar; } }; _model.SelectCsvOutputRequested += async (_, _) => { var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions { Title = "Salva CSV", DefaultExtension = "csv", FileTypeChoices = [new FilePickerFileType("CSV") { Patterns = ["*.csv"] }] }); if (file is not null) { _model.CsvOutputPath = file.Path.LocalPath; } }; _model.SaveSettingsRequested += async (_, _) => { var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions { Title = "Salva impostazioni", DefaultExtension = "xml", FileTypeChoices = [new FilePickerFileType("Setup") { Patterns = ["*.xml"] }] }); if (file is not null) { await _model.SaveSettingsToFileAsync(file.Path.LocalPath); } }; _model.LoadSettingsRequested += async (_, _) => { var files = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { Title = "Carica impostazioni", FileTypeFilter = [new FilePickerFileType("Setup") { Patterns = ["*.xml"] }] }); if (files.Count > 0) { await _model.LoadSettingsFromFileAsync(files[0].Path.LocalPath); } }; _model.SelectColorRequested += (_, _) => { // Color is set by typing hex directly in the TextBox. }; _model.SelectTransparentColorRequested += (_, _) => { // Color is set by typing hex directly in the TextBox. }; _model.ShowMessageRequested += async (_, args) => { await ShowMessageDialogAsync(args.Item1, args.Item2); }; } private bool _isStoppingFaceEncoderForClose; private async void AvaloniaMainWindow_Closing(object? sender, CancelEventArgs e) { if (_isStoppingFaceEncoderForClose || !_model.IsFaceEncoderRunning) { return; } e.Cancel = true; _isStoppingFaceEncoderForClose = true; try { await _model.StopFaceEncoderAsync("Arresto face encoder in chiusura...", waitForExit: true); } finally { _isStoppingFaceEncoderForClose = false; Close(); } } private void ToggleTheme_Click(object? sender, RoutedEventArgs e) { _isDarkTheme = !_isDarkTheme; if (Avalonia.Application.Current is not null) { Avalonia.Application.Current.RequestedThemeVariant = _isDarkTheme ? ThemeVariant.Dark : ThemeVariant.Light; } UpdateThemeToggleButtonContent(); } private void SyncThemeStateFromCurrentTheme() { _isDarkTheme = ActualThemeVariant == ThemeVariant.Dark; UpdateThemeToggleButtonContent(); } private void UpdateThemeToggleButtonContent() { _ = this.FindControl("ThemeToggleButton"); } private async Task ShowMessageDialogAsync(string title, string message) { var dialog = new Window { Title = title, Width = 480, CanResize = false, WindowStartupLocation = WindowStartupLocation.CenterOwner, SizeToContent = SizeToContent.Height }; dialog.Content = BuildMessageDialogContent(message, () => dialog.Close()); await dialog.ShowDialog(this); } private static Control BuildMessageDialogContent(string message, Action closeDialog) { var layout = new StackPanel { Margin = new Thickness(16), Spacing = 12 }; layout.Children.Add(new TextBlock { Text = message, TextWrapping = Avalonia.Media.TextWrapping.Wrap, MaxWidth = 420 }); var closeButton = new Button { Content = "OK", MinWidth = 88, HorizontalAlignment = HorizontalAlignment.Right }; closeButton.Click += (_, _) => closeDialog(); layout.Children.Add(closeButton); return layout; } }