using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Threading; using LehrerApp.Desktop.Views.Shared; namespace LehrerApp.Desktop.Services.Mcp; /// /// Produktive -Implementierung: zeigt den bestehenden /// (Views/Shared) über dem Hauptfenster an. Der aufrufende Tool-Handler /// läuft auf einem Hintergrund-Thread (MCP-Pipe-Session in ), /// deshalb Marshalling über . /// /// Ohne Reaktion des Nutzers würde die Pipe-Session (und damit der wartende KI-Client) unbegrenzt /// hängen bleiben — nach wird der Dialog automatisch geschlossen und die /// Änderung als abgelehnt gewertet. /// public sealed class AvaloniaMcpConfirmationService : IMcpConfirmationService { private static readonly TimeSpan Timeout = TimeSpan.FromMinutes(2); public async Task ConfirmAsync(string title, string message, CancellationToken ct) { if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner }) return false; // Die gesamte Warte-/Timeout-Logik läuft als ein Stück innerhalb des UI-Thread-Callbacks: // Avalonias Dispatcher-Synchronisationskontext sorgt dafür, dass die Fortsetzung nach // "await Task.WhenAny(...)" wieder auf dem UI-Thread läuft, sodass dialog.Close() dort // sicher aufgerufen werden kann. return await Dispatcher.UIThread.InvokeAsync(async () => { var dialog = new ConfirmDialog { DataContext = new ConfirmDialogInfo { Title = title, Message = message, ConfirmText = "Übernehmen" }, }; var dialogTask = dialog.ShowDialog(owner); var timeoutTask = Task.Delay(Timeout, ct); var completed = await Task.WhenAny(dialogTask, timeoutTask); if (completed != dialogTask) { dialog.Close(false); return false; } return await dialogTask; }); } }