using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Media; using LehrerApp.Core.Models; using LehrerApp.Desktop.ViewModels.Groups; namespace LehrerApp.Desktop.Views.Groups; public partial class AttendanceHomeworkQuickInputDialog : Window { public AttendanceHomeworkQuickInputDialog() { InitializeComponent(); BuildColumns(); } protected override void OnOpened(EventArgs e) { base.OnOpened(e); StatusGrid.Focus(); if (ViewModel?.SelectedRow is { } row) StatusGrid.ScrollIntoView(row, null); } private void BuildColumns() { StatusGrid.Columns.Add(new DataGridTextColumn { Header = "Schüler", Binding = new Binding(nameof(ParticipationStudentRow.Name)), Width = new DataGridLength(1, DataGridLengthUnitType.Star), }); StatusGrid.Columns.Add(new DataGridTemplateColumn { Header = "Anwesenheit", Width = new DataGridLength(210, DataGridLengthUnitType.Pixel), CellTemplate = BuildAttendanceTemplate(), }); StatusGrid.Columns.Add(new DataGridTemplateColumn { Header = "Hausaufgaben", Width = new DataGridLength(270, DataGridLengthUnitType.Pixel), CellTemplate = BuildHomeworkTemplate(), }); } private IDataTemplate BuildAttendanceTemplate() => new FuncDataTemplate((row, _) => { if (row is null) return new TextBlock(); var button = StatusButton(185); var flyout = new MenuFlyout { Placement = PlacementMode.BottomEdgeAlignedLeft }; AddAttendanceItem(flyout, row, "· Nicht kontrolliert", null); AddAttendanceItem(flyout, row, "✓ Anwesend", AttendanceStatus.Present); AddAttendanceItem(flyout, row, "? Entschuldigung offen", AttendanceStatus.ExcusePending); AddAttendanceItem(flyout, row, "⊘ Krank, entschuldigt", AttendanceStatus.Excused); AddAttendanceItem(flyout, row, "! Unentschuldigt", AttendanceStatus.Unexcused); AddAttendanceItem(flyout, row, "✕ Geschwänzt", AttendanceStatus.Truant); AddAttendanceItem(flyout, row, "◇ Andere Schulveranstaltung", AttendanceStatus.OtherSchoolEvent); button.Flyout = flyout; void Refresh() { UpdateButton(button, string.IsNullOrEmpty(row.AttendanceLabel) ? "·" : row.AttendanceLabel, row.AttendanceTooltip, AttendanceDisplay.Color(row.Attendance)); } Refresh(); row.PropertyChanged += (_, args) => { if (args.PropertyName == nameof(ParticipationStudentRow.AttendanceLabel)) Refresh(); }; return Center(button); }); private IDataTemplate BuildHomeworkTemplate() => new FuncDataTemplate((row, _) => { if (row is null) return new TextBlock(); var button = StatusButton(245); var flyout = new MenuFlyout { Placement = PlacementMode.BottomEdgeAlignedLeft }; AddHomeworkItem(flyout, row, "· Keine Hausaufgabe", null); AddHomeworkItem(flyout, row, "✓ Gemacht", HomeworkStatus.Completed); AddHomeworkItem(flyout, row, "◐ Teilweise, Rest offen", HomeworkStatus.PartiallyCompleted); AddHomeworkItem(flyout, row, "◕ Rest nachgereicht", HomeworkStatus.PartialSubmittedLate); AddHomeworkItem(flyout, row, "◒ Rest nicht nachgereicht", HomeworkStatus.PartialMissingOverdue); AddHomeworkItem(flyout, row, "! Nicht gemacht, Nachreichen offen", HomeworkStatus.MissingOpen); AddHomeworkItem(flyout, row, "✕ Nicht mehr nachgereicht", HomeworkStatus.MissingOverdue); AddHomeworkItem(flyout, row, "↺ Nachgereicht", HomeworkStatus.SubmittedLate); button.Flyout = flyout; void Refresh() => UpdateButton(button, row.HomeworkSymbol, row.HomeworkTooltip, HomeworkDisplay.Color(row.Homework)); Refresh(); row.PropertyChanged += (_, args) => { if (args.PropertyName == nameof(ParticipationStudentRow.HomeworkSymbol)) Refresh(); }; return Center(button); }); private void AddAttendanceItem(MenuFlyout flyout, ParticipationStudentRow row, string header, AttendanceStatus? status) { var item = new MenuItem { Header = header }; item.Click += (_, _) => ViewModel?.ApplyAttendance(row, status); flyout.Items.Add(item); } private void AddHomeworkItem(MenuFlyout flyout, ParticipationStudentRow row, string header, HomeworkStatus? status) { var item = new MenuItem { Header = header }; item.Click += (_, _) => ViewModel?.ApplyHomework(row, status); flyout.Items.Add(item); } private static Button StatusButton(double width) => new() { Width = width, Height = 29, Padding = new Thickness(8, 2), FontSize = 12, HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Center, }; private static Control Center(Control child) => new Grid { Margin = new Thickness(0, 2), HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, Children = { child }, }; private static void UpdateButton(Button button, string symbol, string tooltip, string color) { button.Content = $"{symbol} {tooltip}"; ToolTip.SetTip(button, tooltip + " – klicken, um Status auszuwählen"); if (Color.TryParse(color, out var parsed)) { button.Background = new SolidColorBrush(parsed); button.Foreground = Brushes.White; button.Opacity = 1; } else { button.ClearValue(Button.BackgroundProperty); button.ClearValue(Button.ForegroundProperty); button.Opacity = 0.48; } } protected override void OnKeyDown(KeyEventArgs e) { var vm = ViewModel; var row = vm?.SelectedRow; if (vm is null || row is null) { base.OnKeyDown(e); return; } if (e.KeyModifiers.HasFlag(KeyModifiers.Alt)) { var homework = e.Key switch { Key.D0 or Key.NumPad0 => (HomeworkStatus?)null, Key.M => HomeworkStatus.Completed, Key.T => HomeworkStatus.PartiallyCompleted, Key.R => HomeworkStatus.PartialSubmittedLate, Key.X => HomeworkStatus.PartialMissingOverdue, Key.O => HomeworkStatus.MissingOpen, Key.F => HomeworkStatus.MissingOverdue, Key.S => HomeworkStatus.SubmittedLate, _ => null, }; var recognized = e.Key is Key.D0 or Key.NumPad0 or Key.M or Key.T or Key.R or Key.X or Key.O or Key.F or Key.S; if (recognized) { vm.ApplyHomework(row, homework); BringSelectionIntoView(); e.Handled = true; return; } } AttendanceStatus? attendance = e.Key switch { Key.A => AttendanceStatus.Present, Key.K => AttendanceStatus.ExcusePending, Key.E => AttendanceStatus.Excused, Key.U => AttendanceStatus.Unexcused, Key.G => AttendanceStatus.Truant, Key.V => AttendanceStatus.OtherSchoolEvent, _ => null, }; var attendanceRecognized = e.Key is Key.D0 or Key.NumPad0 or Key.A or Key.K or Key.E or Key.U or Key.G or Key.V; if (attendanceRecognized) { vm.ApplyAttendance(row, attendance); BringSelectionIntoView(); e.Handled = true; return; } switch (e.Key) { case Key.Up: vm.MoveSelection(-1); BringSelectionIntoView(); e.Handled = true; break; case Key.Down or Key.Enter: vm.MoveSelection(1); BringSelectionIntoView(); e.Handled = true; break; case Key.Escape: Close(); e.Handled = true; break; default: base.OnKeyDown(e); break; } } private AttendanceHomeworkQuickInputViewModel? ViewModel => DataContext as AttendanceHomeworkQuickInputViewModel; private void BringSelectionIntoView() { if (ViewModel?.SelectedRow is { } row) StatusGrid.ScrollIntoView(row, null); } private void OnClose(object? sender, RoutedEventArgs e) => Close(); }