using System.Collections.ObjectModel; using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Platform.Storage; using CommunityToolkit.Mvvm.ComponentModel; using LehrerApp.Templating; using System.Runtime.Versioning; namespace LehrerApp.TemplateDesigner; public partial class PdfImportDialogViewModel : ObservableObject { [ObservableProperty] private string _examplePath = ""; [ObservableProperty] private string _templatePath = ""; [ObservableProperty] private bool _useAi = true; [ObservableProperty] private string _username = ""; [ObservableProperty] private string _password = ""; [ObservableProperty] private string _status = "Bitte mindestens ein ausgefülltes Beispiel-PDF auswählen."; [ObservableProperty] private bool _isBusy; [ObservableProperty] private bool _hasResult; public ObservableCollection Candidates { get; } = []; public IReadOnlyList PlaceholderTypes { get; } = [PlaceholderType.Text, PlaceholderType.Multiline, PlaceholderType.Date, PlaceholderType.Number]; public bool CanAnalyze => !IsBusy && File.Exists(ExamplePath) && (!UseAi || (!string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(Password))); partial void OnExamplePathChanged(string value) => OnPropertyChanged(nameof(CanAnalyze)); partial void OnUseAiChanged(bool value) => OnPropertyChanged(nameof(CanAnalyze)); partial void OnUsernameChanged(string value) => OnPropertyChanged(nameof(CanAnalyze)); partial void OnPasswordChanged(string value) => OnPropertyChanged(nameof(CanAnalyze)); partial void OnIsBusyChanged(bool value) => OnPropertyChanged(nameof(CanAnalyze)); } [SupportedOSPlatform("windows")] [SupportedOSPlatform("linux")] [SupportedOSPlatform("macos")] public partial class PdfImportDialog : Window { private readonly PdfImportDialogViewModel _viewModel = new(); private PdfImportResult? _result; public PdfImportResult? Result { get; private set; } public PdfImportDialog() { InitializeComponent(); DataContext = _viewModel; } private async void OnChooseExample(object? sender, RoutedEventArgs e) { var file = await ChoosePdf("Ausgefülltes Beispiel-PDF auswählen"); if (file is not null) _viewModel.ExamplePath = file; } private async void OnChooseTemplate(object? sender, RoutedEventArgs e) { var file = await ChoosePdf("Leeres Template-PDF auswählen"); if (file is not null) _viewModel.TemplatePath = file; } private async Task ChoosePdf(string title) { var files = await StorageProvider.OpenFilePickerAsync(new() { Title = title, AllowMultiple = false, FileTypeFilter = [new("PDF-Dateien") { Patterns = ["*.pdf"] }] }); return files.Count == 0 ? null : files[0].Path.LocalPath; } private async void OnAnalyze(object? sender, RoutedEventArgs e) { _viewModel.IsBusy = true; _viewModel.HasResult = false; _viewModel.Status = "PDF wird lokal analysiert …"; try { _result = await new PdfImportPipeline().BuildAsync(_viewModel.ExamplePath, string.IsNullOrWhiteSpace(_viewModel.TemplatePath) ? null : _viewModel.TemplatePath, _viewModel.UseAi ? _viewModel.Username : null, _viewModel.UseAi ? _viewModel.Password : null); _viewModel.Candidates.Clear(); foreach (var candidate in _result.Candidates) _viewModel.Candidates.Add(candidate); _viewModel.HasResult = true; _viewModel.Status = $"{_viewModel.Candidates.Count} variable Textbereiche erkannt. Bitte Zuordnung prüfen und bestätigen."; } catch (Exception ex) { _viewModel.Status = $"Import fehlgeschlagen: {ex.Message}"; } finally { _viewModel.IsBusy = false; } } private void OnAccept(object? sender, RoutedEventArgs e) { if (_result is null) return; var document = new PdfImportPipeline().Extract(_viewModel.ExamplePath); Result = new PdfImportPipeline().BuildResult(_viewModel.ExamplePath, document, _viewModel.Candidates); Close(true); } private void OnCancel(object? sender, RoutedEventArgs e) => Close(false); }