using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using LehrerApp.Core.Services; using LehrerApp.Data; using LehrerApp.Desktop.Services; using LehrerApp.Desktop.ViewModels; using LehrerApp.Desktop.ViewModels.Groups; using LehrerApp.Desktop.ViewModels.Planning; using LehrerApp.Desktop.ViewModels.Students; using LehrerApp.Desktop.Views; using Microsoft.Extensions.DependencyInjection; namespace LehrerApp.Desktop; public class App : Application { public static IServiceProvider Services { get; private set; } = null!; private static ServiceProvider? _serviceProvider; private static bool _exitHandlerAttached; public override void Initialize() => AvaloniaXamlLoader.Load(this); public override void OnFrameworkInitializationCompleted() { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { // Verschlüsselte Datenbank (13.3.4): Passwort abfragen, bevor die Datenbank // (und damit BuildServices, das sie öffnet) angefasst wird. if (AppBootstrapper.IsDbEncrypted()) { var promptVm = new DbPasswordPromptViewModel( new DatabaseEncryptionService(), AppBootstrapper.ResolveDbPath()); var promptWindow = new DbPasswordPromptWindow { DataContext = promptVm }; promptVm.OnUnlocked = password => { AppBootstrapper.DbPassword = password; StartMainApp(desktop, showImmediately: true); promptWindow.Close(); }; desktop.MainWindow = promptWindow; } else { StartMainApp(desktop, showImmediately: false); } } base.OnFrameworkInitializationCompleted(); } private static void StartMainApp( IClassicDesktopStyleApplicationLifetime desktop, bool showImmediately) { _serviceProvider = AppBootstrapper.BuildServices(); Services = _serviceProvider; Services.GetRequiredService().Info("Anwendung gestartet."); GlobalExceptionHandler.AttachNotifications(Services.GetRequiredService()); if (!_exitHandlerAttached) { desktop.Exit += (_, _) => DisposeServices(); _exitHandlerAttached = true; } var mainVm = Services.GetRequiredService(); WireCallbacks(mainVm); var main = new MainWindow { DataContext = mainVm }; desktop.MainWindow = main; if (showImmediately) main.Show(); } private static void DisposeServices() { if (_serviceProvider is null) return; try { _serviceProvider.GetService()?.Checkpoint(); } catch (Exception ex) { AppBootstrapper.Logger.Error("Datenbank-Checkpoint beim Beenden fehlgeschlagen.", ex); } finally { _serviceProvider.Dispose(); _serviceProvider = null; } } private static void WireCallbacks(MainWindowViewModel main) { // GroupList → GroupDetail (OnAddGroup wird in GroupListView.axaml.cs verdrahtet) var gl = Services.GetRequiredService(); gl.OnNavigateToDetail = (id, tab) => main.NavigateToGroupDetail(id, tab); // Dashboard → GroupDetail (Chips) / StudentDetail (Fehlzeiten-/Förderplan-Hinweise) var dash = Services.GetRequiredService(); dash.OnNavigateToGroup = id => main.NavigateToGroupDetail(id); dash.OnNavigateToStudent = id => main.NavigateToStudent(id); // StudentList → StudentDetail + Anlegen var sl = Services.GetRequiredService(); sl.OnNavigateToDetail = id => main.NavigateToStudent(id); sl.OnAddStudent = () => ShowAddStudentDialog(); // Stundenplan "Heute" → GroupDetail (Tab "Planung") / Einstellungen (Zahnrad, Tab "Ferien & Feiertage") var timetable = Services.GetRequiredService(); timetable.OnNavigateToSettings = () => main.NavigateToSettings(7); timetable.OnNavigateToGroup = id => main.NavigateToGroupDetail(id, 5); } private static async Task ShowAddStudentDialog() { var vm = new ViewModels.Students.AddStudentDialogViewModel( Services.GetRequiredService()); var dialog = new Views.Students.AddStudentDialog { DataContext = vm }; if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner }) await dialog.ShowDialog(owner); } }