Anwesenheit und Hausaufgaben revision

This commit is contained in:
2026-08-13 09:49:10 +02:00
parent 741586846a
commit 4ab82c6bbe
4 changed files with 106 additions and 42 deletions
@@ -468,7 +468,7 @@ public static class HomeworkDisplay
public static string Label(HomeworkStatus? status) => status switch public static string Label(HomeworkStatus? status) => status switch
{ {
null => "Keine Hausaufgabe erfasst", null => "Keine Hausaufgabe aufgegeben",
HomeworkStatus.Completed => "Hausaufgabe gemacht", HomeworkStatus.Completed => "Hausaufgabe gemacht",
HomeworkStatus.PartiallyCompleted => "Teilweise angefertigt Rest offen", HomeworkStatus.PartiallyCompleted => "Teilweise angefertigt Rest offen",
HomeworkStatus.PartialSubmittedLate => "Teilweise angefertigt Rest nachgereicht", HomeworkStatus.PartialSubmittedLate => "Teilweise angefertigt Rest nachgereicht",
@@ -476,7 +476,7 @@ public static class HomeworkDisplay
HomeworkStatus.MissingOpen => "Nicht gemacht Nachreichen offen", HomeworkStatus.MissingOpen => "Nicht gemacht Nachreichen offen",
HomeworkStatus.MissingOverdue => "Nicht gemacht nicht mehr nachgereicht", HomeworkStatus.MissingOverdue => "Nicht gemacht nicht mehr nachgereicht",
HomeworkStatus.SubmittedLate => "Hausaufgabe nachgereicht", HomeworkStatus.SubmittedLate => "Hausaufgabe nachgereicht",
_ => "Keine Hausaufgabe erfasst", _ => "Keine Hausaufgabe aufgegeben",
}; };
public static string Symbol(HomeworkStatus? status) => status switch public static string Symbol(HomeworkStatus? status) => status switch
@@ -28,9 +28,9 @@
<Grid Grid.Row="2" RowDefinitions="Auto,Auto" ColumnDefinitions="*,Auto" Margin="0,12,0,0"> <Grid Grid.Row="2" RowDefinitions="Auto,Auto" ColumnDefinitions="*,Auto" Margin="0,12,0,0">
<StackPanel Grid.Row="0" Grid.Column="0" Spacing="3"> <StackPanel Grid.Row="0" Grid.Column="0" Spacing="3">
<TextBlock FontSize="10" Opacity="0.55" TextWrapping="Wrap" <TextBlock FontSize="10" Opacity="0.55" TextWrapping="Wrap"
Text="Anwesenheit: A anwesend · K Entschuldigung offen · E entschuldigt · U unentschuldigt · G geschwänzt · V Schulveranstaltung · 0 nicht kontrolliert"/> Text="Anwesenheit: 1 anwesend · 2 Entschuldigung offen · 5 krank/entschuldigt · 7 andere Schulveranstaltung · 9 geschwänzt · 0 unentschuldigt · X nicht kontrolliert"/>
<TextBlock FontSize="10" Opacity="0.55" TextWrapping="Wrap" <TextBlock FontSize="10" Opacity="0.55" TextWrapping="Wrap"
Text="Hausaufgaben mit Alt/⌥: M gemacht · T teilweise · R Rest nachgereicht · X Rest nicht nachgereicht · O Nachreichen offen · F endgültig nicht nachgereicht · S nachgereicht · 0 keine"/> Text="Hausaufgaben mit Alt/⌥: 1 gemacht · 3 teilweise/Rest offen · 4 Rest nachgereicht · 5 Rest nicht nachgereicht · 7 nicht gemacht/offen · 8 vollständig nachgereicht · 0 endgültig nicht nachgereicht · X keine aufgegeben"/>
<TextBlock FontSize="10" Opacity="0.55" <TextBlock FontSize="10" Opacity="0.55"
Text="↑/↓ Zeile wählen · Enter nächste Zeile · Esc schließen"/> Text="↑/↓ Zeile wählen · Enter nächste Zeile · Esc schließen"/>
</StackPanel> </StackPanel>
@@ -13,10 +13,16 @@ namespace LehrerApp.Desktop.Views.Groups;
public partial class AttendanceHomeworkQuickInputDialog : Window public partial class AttendanceHomeworkQuickInputDialog : Window
{ {
private bool _leftAltDown;
private bool _rightAltDown;
public AttendanceHomeworkQuickInputDialog() public AttendanceHomeworkQuickInputDialog()
{ {
InitializeComponent(); InitializeComponent();
BuildColumns(); BuildColumns();
// Im Tunnel lauschen, bevor DataGrid/Button einen Modifier-Event konsumieren können.
AddHandler(KeyDownEvent, OnPreviewKeyDown, RoutingStrategies.Tunnel, handledEventsToo: true);
AddHandler(KeyUpEvent, OnPreviewKeyUp, RoutingStrategies.Tunnel, handledEventsToo: true);
} }
protected override void OnOpened(EventArgs e) protected override void OnOpened(EventArgs e)
@@ -55,13 +61,13 @@ public partial class AttendanceHomeworkQuickInputDialog : Window
if (row is null) return new TextBlock(); if (row is null) return new TextBlock();
var button = StatusButton(185); var button = StatusButton(185);
var flyout = new MenuFlyout { Placement = PlacementMode.BottomEdgeAlignedLeft }; var flyout = new MenuFlyout { Placement = PlacementMode.BottomEdgeAlignedLeft };
AddAttendanceItem(flyout, row, "· Nicht kontrolliert", null); AddAttendanceItem(flyout, row, "[1] ✓ Anwesend", AttendanceStatus.Present);
AddAttendanceItem(flyout, row, "✓ Anwesend", AttendanceStatus.Present); AddAttendanceItem(flyout, row, "[2] ? Entschuldigung offen", AttendanceStatus.ExcusePending);
AddAttendanceItem(flyout, row, "? Entschuldigung offen", AttendanceStatus.ExcusePending); AddAttendanceItem(flyout, row, "[5] ⊘ Krank, entschuldigt", AttendanceStatus.Excused);
AddAttendanceItem(flyout, row, "⊘ Krank, entschuldigt", AttendanceStatus.Excused); AddAttendanceItem(flyout, row, "[7] ◇ Andere Schulveranstaltung", AttendanceStatus.OtherSchoolEvent);
AddAttendanceItem(flyout, row, "! Unentschuldigt", AttendanceStatus.Unexcused); AddAttendanceItem(flyout, row, "[9] ✕ Geschwänzt", AttendanceStatus.Truant);
AddAttendanceItem(flyout, row, "✕ Geschwänzt", AttendanceStatus.Truant); AddAttendanceItem(flyout, row, "[0] ! Unentschuldigt", AttendanceStatus.Unexcused);
AddAttendanceItem(flyout, row, "◇ Andere Schulveranstaltung", AttendanceStatus.OtherSchoolEvent); AddAttendanceItem(flyout, row, "[X] · Nicht kontrolliert", null);
button.Flyout = flyout; button.Flyout = flyout;
void Refresh() void Refresh()
@@ -84,14 +90,14 @@ public partial class AttendanceHomeworkQuickInputDialog : Window
if (row is null) return new TextBlock(); if (row is null) return new TextBlock();
var button = StatusButton(245); var button = StatusButton(245);
var flyout = new MenuFlyout { Placement = PlacementMode.BottomEdgeAlignedLeft }; var flyout = new MenuFlyout { Placement = PlacementMode.BottomEdgeAlignedLeft };
AddHomeworkItem(flyout, row, "· Keine Hausaufgabe", null); AddHomeworkItem(flyout, row, "[⌥1] ✓ Gemacht", HomeworkStatus.Completed);
AddHomeworkItem(flyout, row, "✓ Gemacht", HomeworkStatus.Completed); AddHomeworkItem(flyout, row, "[⌥3] ◐ Teilweise, Rest offen", HomeworkStatus.PartiallyCompleted);
AddHomeworkItem(flyout, row, "◐ Teilweise, Rest offen", HomeworkStatus.PartiallyCompleted); AddHomeworkItem(flyout, row, "[⌥4] ◕ Rest nachgereicht", HomeworkStatus.PartialSubmittedLate);
AddHomeworkItem(flyout, row, "◕ Rest nachgereicht", HomeworkStatus.PartialSubmittedLate); AddHomeworkItem(flyout, row, "[⌥5] ◒ Rest nicht nachgereicht", HomeworkStatus.PartialMissingOverdue);
AddHomeworkItem(flyout, row, "◒ Rest nicht nachgereicht", HomeworkStatus.PartialMissingOverdue); AddHomeworkItem(flyout, row, "[⌥7] ! Nicht gemacht, Nachreichen offen", HomeworkStatus.MissingOpen);
AddHomeworkItem(flyout, row, "! Nicht gemacht, Nachreichen offen", HomeworkStatus.MissingOpen); AddHomeworkItem(flyout, row, "[⌥8] ↺ Vollständig nachgereicht", HomeworkStatus.SubmittedLate);
AddHomeworkItem(flyout, row, "✕ Nicht mehr nachgereicht", HomeworkStatus.MissingOverdue); AddHomeworkItem(flyout, row, "[⌥0] ✕ Nicht mehr nachgereicht", HomeworkStatus.MissingOverdue);
AddHomeworkItem(flyout, row, "↺ Nachgereicht", HomeworkStatus.SubmittedLate); AddHomeworkItem(flyout, row, "[⌥X] · Keine Hausaufgabe aufgegeben", null);
button.Flyout = flyout; button.Flyout = flyout;
void Refresh() => UpdateButton(button, row.HomeworkSymbol, row.HomeworkTooltip, void Refresh() => UpdateButton(button, row.HomeworkSymbol, row.HomeworkTooltip,
@@ -154,27 +160,41 @@ public partial class AttendanceHomeworkQuickInputDialog : Window
} }
} }
protected override void OnKeyDown(KeyEventArgs e) private void OnPreviewKeyDown(object? sender, KeyEventArgs e)
{ {
if (e.PhysicalKey == PhysicalKey.AltLeft)
{
_leftAltDown = true;
return;
}
if (e.PhysicalKey == PhysicalKey.AltRight)
{
_rightAltDown = true;
return;
}
var vm = ViewModel; var vm = ViewModel;
var row = vm?.SelectedRow; var row = vm?.SelectedRow;
if (vm is null || row is null) { base.OnKeyDown(e); return; } if (vm is null || row is null) return;
if (e.KeyModifiers.HasFlag(KeyModifiers.Alt)) var digit = DigitFromEvent(e);
var isX = e.Key == Key.X || e.PhysicalKey == PhysicalKey.X;
var altDown = _leftAltDown || _rightAltDown ||
e.KeyModifiers.HasFlag(KeyModifiers.Alt);
if (altDown)
{ {
var homework = e.Key switch HomeworkStatus? homework = isX ? null : digit switch
{ {
Key.D0 or Key.NumPad0 => (HomeworkStatus?)null, 1 => HomeworkStatus.Completed,
Key.M => HomeworkStatus.Completed, 3 => HomeworkStatus.PartiallyCompleted,
Key.T => HomeworkStatus.PartiallyCompleted, 4 => HomeworkStatus.PartialSubmittedLate,
Key.R => HomeworkStatus.PartialSubmittedLate, 5 => HomeworkStatus.PartialMissingOverdue,
Key.X => HomeworkStatus.PartialMissingOverdue, 7 => HomeworkStatus.MissingOpen,
Key.O => HomeworkStatus.MissingOpen, 8 => HomeworkStatus.SubmittedLate,
Key.F => HomeworkStatus.MissingOverdue, 0 => HomeworkStatus.MissingOverdue,
Key.S => HomeworkStatus.SubmittedLate,
_ => null, _ => 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; var recognized = isX || digit is 0 or 1 or 3 or 4 or 5 or 7 or 8;
if (recognized) if (recognized)
{ {
vm.ApplyHomework(row, homework); vm.ApplyHomework(row, homework);
@@ -182,19 +202,27 @@ public partial class AttendanceHomeworkQuickInputDialog : Window
e.Handled = true; e.Handled = true;
return; return;
} }
// Eine mit Alt/Option gedrückte Ziffer darf niemals in den
// Anwesenheitszweig durchfallen, auch wenn sie nicht belegt ist.
if (digit is not null)
{
e.Handled = true;
return;
}
} }
AttendanceStatus? attendance = e.Key switch AttendanceStatus? attendance = isX ? null : digit switch
{ {
Key.A => AttendanceStatus.Present, 1 => AttendanceStatus.Present,
Key.K => AttendanceStatus.ExcusePending, 2 => AttendanceStatus.ExcusePending,
Key.E => AttendanceStatus.Excused, 5 => AttendanceStatus.Excused,
Key.U => AttendanceStatus.Unexcused, 7 => AttendanceStatus.OtherSchoolEvent,
Key.G => AttendanceStatus.Truant, 9 => AttendanceStatus.Truant,
Key.V => AttendanceStatus.OtherSchoolEvent, 0 => AttendanceStatus.Unexcused,
_ => null, _ => 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; var attendanceRecognized = isX || digit is 0 or 1 or 2 or 5 or 7 or 9;
if (attendanceRecognized) if (attendanceRecognized)
{ {
vm.ApplyAttendance(row, attendance); vm.ApplyAttendance(row, attendance);
@@ -208,13 +236,49 @@ public partial class AttendanceHomeworkQuickInputDialog : Window
case Key.Up: vm.MoveSelection(-1); BringSelectionIntoView(); e.Handled = true; break; 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.Down or Key.Enter: vm.MoveSelection(1); BringSelectionIntoView(); e.Handled = true; break;
case Key.Escape: Close(); e.Handled = true; break; case Key.Escape: Close(); e.Handled = true; break;
default: base.OnKeyDown(e); break; default: break;
} }
} }
private void OnPreviewKeyUp(object? sender, KeyEventArgs e)
{
if (e.PhysicalKey == PhysicalKey.AltLeft) _leftAltDown = false;
if (e.PhysicalKey == PhysicalKey.AltRight) _rightAltDown = false;
}
private AttendanceHomeworkQuickInputViewModel? ViewModel => private AttendanceHomeworkQuickInputViewModel? ViewModel =>
DataContext as AttendanceHomeworkQuickInputViewModel; DataContext as AttendanceHomeworkQuickInputViewModel;
private static int? DigitFromEvent(KeyEventArgs e) => e.PhysicalKey switch
{
PhysicalKey.Digit0 => 0,
PhysicalKey.Digit1 => 1,
PhysicalKey.Digit2 => 2,
PhysicalKey.Digit3 => 3,
PhysicalKey.Digit4 => 4,
PhysicalKey.Digit5 => 5,
PhysicalKey.Digit6 => 6,
PhysicalKey.Digit7 => 7,
PhysicalKey.Digit8 => 8,
PhysicalKey.Digit9 => 9,
_ => DigitFromKey(e.Key),
};
private static int? DigitFromKey(Key key) => key switch
{
Key.D0 or Key.NumPad0 => 0,
Key.D1 or Key.NumPad1 => 1,
Key.D2 or Key.NumPad2 => 2,
Key.D3 or Key.NumPad3 => 3,
Key.D4 or Key.NumPad4 => 4,
Key.D5 or Key.NumPad5 => 5,
Key.D6 or Key.NumPad6 => 6,
Key.D7 or Key.NumPad7 => 7,
Key.D8 or Key.NumPad8 => 8,
Key.D9 or Key.NumPad9 => 9,
_ => null,
};
private void BringSelectionIntoView() private void BringSelectionIntoView()
{ {
if (ViewModel?.SelectedRow is { } row) if (ViewModel?.SelectedRow is { } row)
@@ -34,7 +34,7 @@
<Flyout Placement="BottomEdgeAlignedRight"> <Flyout Placement="BottomEdgeAlignedRight">
<StackPanel Width="310" Spacing="6" Margin="12"> <StackPanel Width="310" Spacing="6" Margin="12">
<TextBlock Text="Hausaufgaben" FontWeight="SemiBold" FontSize="11"/> <TextBlock Text="Hausaufgaben" FontWeight="SemiBold" FontSize="11"/>
<TextBlock Text="· keine Hausaufgabe erfasst" FontSize="10" Opacity="0.65"/> <TextBlock Text="· keine Hausaufgabe aufgegeben" FontSize="10" Opacity="0.65"/>
<TextBlock Text="✓ gemacht" FontSize="10" Foreground="#2E9D57"/> <TextBlock Text="✓ gemacht" FontSize="10" Foreground="#2E9D57"/>
<TextBlock Text="◐ teilweise angefertigt Rest offen" FontSize="10" Foreground="#D98200"/> <TextBlock Text="◐ teilweise angefertigt Rest offen" FontSize="10" Foreground="#D98200"/>
<TextBlock Text="◕ teilweise angefertigt Rest nachgereicht" FontSize="10" Foreground="#7F77DD"/> <TextBlock Text="◕ teilweise angefertigt Rest nachgereicht" FontSize="10" Foreground="#7F77DD"/>