diff --git a/LehrerApp.Desktop.Tests/QuickInputViewModelTests.cs b/LehrerApp.Desktop.Tests/QuickInputViewModelTests.cs new file mode 100644 index 0000000..27d8ebd --- /dev/null +++ b/LehrerApp.Desktop.Tests/QuickInputViewModelTests.cs @@ -0,0 +1,48 @@ +using LehrerApp.Core.Models; +using LehrerApp.Desktop.ViewModels.Groups; +using Xunit; + +namespace LehrerApp.Desktop.Tests; + +public sealed class QuickInputViewModelTests +{ + [Fact] + public void ZurueckZuVorherigemSchueler_ZeigtBereitsGesetzteBewertung() + { + var aspects = new List + { + new(new ParticipationAspect { Key = "mitarbeit", Label = "Mitarbeit" }), + }; + var rows = new List + { + new(Guid.NewGuid(), "Anna", new ParticipationEntry(), aspects, []), + new(Guid.NewGuid(), "Ben", new ParticipationEntry(), aspects, []), + }; + var vm = new QuickInputViewModel(rows, aspects); + + vm.SetRatingByNumber(4); // Scale5, 4. Stufe -> Rohwert 1 ("+"), Anna bewerten + vm.NextStudent(); // zu Ben + vm.PreviousStudent(); // zurück zu Anna + + Assert.Equal(1, vm.AspectRows[0].Value); + } + + [Fact] + public void VorherigerAspekt_SpringtRueckwaertsMitUmlauf() + { + var aspects = new List + { + new(new ParticipationAspect { Key = "a", Label = "A" }), + new(new ParticipationAspect { Key = "b", Label = "B" }), + }; + var rows = new List + { + new(Guid.NewGuid(), "Anna", new ParticipationEntry(), aspects, []), + }; + var vm = new QuickInputViewModel(rows, aspects); + + vm.PreviousAspect(); // von Index 0 rückwärts -> letzter Aspekt (Umlauf) + + Assert.Equal(1, vm.AspectIndex); + } +} diff --git a/LehrerApp.Desktop/ViewModels/Groups/ParticipationViewModels.cs b/LehrerApp.Desktop/ViewModels/Groups/ParticipationViewModels.cs index 19a7831..d146f91 100644 --- a/LehrerApp.Desktop/ViewModels/Groups/ParticipationViewModels.cs +++ b/LehrerApp.Desktop/ViewModels/Groups/ParticipationViewModels.cs @@ -351,7 +351,6 @@ public partial class ParticipationStudentRow : ObservableObject public Guid StudentId { get; } public string Name { get; } - private readonly ParticipationEntry _entry; private readonly IReadOnlyList _aspectDefs; public ObservableCollection Cells { get; } = []; @@ -375,7 +374,6 @@ public partial class ParticipationStudentRow : ObservableObject { StudentId = id; Name = name; - _entry = entry; _aspectDefs = aspects; _homework = HomeworkDisplay.Effective(entry); _attendance = entry.Attendance; @@ -397,8 +395,12 @@ public partial class ParticipationStudentRow : ObservableObject } } + // Liest aus Cells (per SetValue laufend aktuell gehalten), NICHT aus dem ursprünglichen + // ParticipationEntry-Snapshot: SetRating() schreibt nur in Cells + feuert OnRatingChanged + // (der Callback speichert über eine EIGENE, neu aus dem Repository geladene Entry-Instanz — + // der hier ursprünglich referenzierte Entry-Snapshot bekommt diese Änderung nie zu sehen). public int? GetRating(string key) => - _entry.Ratings.FirstOrDefault(r => r.Key == key)?.Value; + Cells.FirstOrDefault(c => c.AspectKey == key)?.Value; public void SetRating(string key, int? value) { @@ -743,8 +745,8 @@ public partial class QuickInputViewModel : ObservableObject AspectValueType.Points => $"0–9 Punkte eingeben (bis {CurrentAspectMaxPoints()})", _ => "1–5 bewerten", }; - return $"{ratingHint} · Q/W/E/R/T Aspekt wählen · Leertaste nächster Aspekt · " + - "Enter nächster Schüler · Backspace vorheriger · +/− anpassen · Esc schließen"; + return $"{ratingHint} · Q/W/E/R/T Aspekt wählen · Leertaste/↓ nächster Aspekt · ↑ vorheriger Aspekt · " + + "Enter/→ nächster Schüler · Backspace/← vorheriger Schüler · +/− anpassen · Esc schließen"; } } @@ -862,6 +864,12 @@ public partial class QuickInputViewModel : ObservableObject UpdateCurrentAspect(); } + public void PreviousAspect() + { + AspectIndex = (AspectIndex - 1 + _aspects.Count) % _aspects.Count; + UpdateCurrentAspect(); + } + public void NextStudent() { if (StudentIndex >= _rows.Count - 1) return; diff --git a/LehrerApp.Desktop/Views/Groups/ParticipationQuickInputDialog.axaml.cs b/LehrerApp.Desktop/Views/Groups/ParticipationQuickInputDialog.axaml.cs index 84a5662..ba2a8c5 100644 --- a/LehrerApp.Desktop/Views/Groups/ParticipationQuickInputDialog.axaml.cs +++ b/LehrerApp.Desktop/Views/Groups/ParticipationQuickInputDialog.axaml.cs @@ -47,6 +47,15 @@ public partial class ParticipationQuickInputDialog : Window break; case Key.Back: vm.PreviousStudent(); e.Handled = true; break; + // Rechtsseitiges Pendant zu Q/W/E/R/T (links)/Enter/Backspace/Leertaste: ohne diese + // Fälle fallen Pfeiltasten auf Avalonias Standard-Fokusnavigation durch und der Fokus + // springt auf den Schließen-Button — ein Enter danach schließt dann den Dialog statt + // zum nächsten Schüler zu springen. + case Key.Up: vm.PreviousAspect(); e.Handled = true; break; + case Key.Down: vm.NextAspect(); e.Handled = true; break; + case Key.Right: vm.NextStudent(); e.Handled = true; break; + case Key.Left: vm.PreviousStudent(); e.Handled = true; break; + case Key.OemPlus or Key.Add: vm.IncrementRating(); e.Handled = true; break; case Key.OemMinus or Key.Subtract: vm.DecrementRating(); e.Handled = true; break;