226 lines
8.7 KiB
C#
226 lines
8.7 KiB
C#
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<ParticipationStudentRow>((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<ParticipationStudentRow>((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();
|
||
}
|