TodaysLessons löst je Stunde den Raum über den passenden TimetableSlot auf und die Uhrzeit aus Lesson.StartTime bzw. dem Stundenraster - gleiche Quellen wie im Verlaufsplan-Editor und Stundenplan. Bewusst nicht dupliziert: die Vertretung/Ausfall-Logik der Stundenplan-eigenen "Heute"-Ansicht bleibt dort, das Dashboard zeigt nur die einfache geplante Stunde. Klick auf eine Stunde springt in die Mitarbeitserfassung der Gruppe - bewusst anderes Ziel als der bestehende Stundenplan-Sprung (dort "Planung"), da vom Dashboard aus morgens eher die Mitarbeitserfassung naheliegt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
124 lines
4.8 KiB
C#
124 lines
4.8 KiB
C#
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<AppLogger>().Info("Anwendung gestartet.");
|
|
GlobalExceptionHandler.AttachNotifications(Services.GetRequiredService<NotificationService>());
|
|
|
|
if (!_exitHandlerAttached)
|
|
{
|
|
desktop.Exit += (_, _) => DisposeServices();
|
|
_exitHandlerAttached = true;
|
|
}
|
|
|
|
var mainVm = Services.GetRequiredService<MainWindowViewModel>();
|
|
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<LiteDbContext>()?.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<GroupListViewModel>();
|
|
gl.OnNavigateToDetail = (id, tab) => main.NavigateToGroupDetail(id, tab);
|
|
|
|
// Dashboard → GroupDetail (Chips) / StudentDetail (Fehlzeiten-/Förderplan-Hinweise)
|
|
var dash = Services.GetRequiredService<DashboardViewModel>();
|
|
dash.OnNavigateToGroup = id => main.NavigateToGroupDetail(id);
|
|
dash.OnNavigateToStudent = id => main.NavigateToStudent(id);
|
|
dash.OnNavigateToLesson = id => main.NavigateToGroupDetail(id, 2); // Tab "Mitarbeit"
|
|
|
|
// StudentList → StudentDetail + Anlegen
|
|
var sl = Services.GetRequiredService<StudentListViewModel>();
|
|
sl.OnNavigateToDetail = id => main.NavigateToStudent(id);
|
|
sl.OnAddStudent = () => ShowAddStudentDialog();
|
|
|
|
// Stundenplan "Heute" → GroupDetail (Tab "Planung") / Einstellungen (Zahnrad, Tab "Ferien & Feiertage")
|
|
var timetable = Services.GetRequiredService<TimetableViewModel>();
|
|
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<Core.Interfaces.IStudentRepository>());
|
|
var dialog = new Views.Students.AddStudentDialog { DataContext = vm };
|
|
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
|
|
await dialog.ShowDialog<bool>(owner);
|
|
}
|
|
}
|