From 988a293c424c79ec47697376de92b35e1db945ba Mon Sep 17 00:00:00 2001 From: Baddi86 Date: Wed, 2 Sep 2026 20:07:53 +0200 Subject: [PATCH] Planung: Stunde einer anderen Einheit zuweisen ("Einheit wechseln") MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bisher war die Einheit einer Stunde nach dem Anlegen fix - bei falscher Auswahl im Erstellen-Dialog blieb nur Löschen+Neuanlegen. Neuer Button öffnet einen Dialog zur Auswahl der Ziel-Einheit; die Ansicht springt danach automatisch dorthin mit der Stunde vorausgewählt. Co-Authored-By: Claude Sonnet 5 --- .../PlanningTabViewModelTests.cs | 24 +++++++++ .../ViewModels/Groups/PlanningViewModels.cs | 52 +++++++++++++++++++ .../Views/Groups/ChangeLessonUnitDialog.axaml | 47 +++++++++++++++++ .../Groups/ChangeLessonUnitDialog.axaml.cs | 21 ++++++++ .../Views/Groups/PlanningTabView.axaml | 2 + .../Views/Groups/PlanningTabView.axaml.cs | 15 ++++++ 6 files changed, 161 insertions(+) create mode 100644 LehrerApp.Desktop/Views/Groups/ChangeLessonUnitDialog.axaml create mode 100644 LehrerApp.Desktop/Views/Groups/ChangeLessonUnitDialog.axaml.cs diff --git a/LehrerApp.Desktop.Tests/PlanningTabViewModelTests.cs b/LehrerApp.Desktop.Tests/PlanningTabViewModelTests.cs index 6b478e7..ea6789f 100644 --- a/LehrerApp.Desktop.Tests/PlanningTabViewModelTests.cs +++ b/LehrerApp.Desktop.Tests/PlanningTabViewModelTests.cs @@ -93,6 +93,30 @@ public class PlanningTabViewModelTests Assert.Equal(new DateOnly(2025, 9, 8), byUnit[l2.Id].Date); // unverändert } + [Fact] + public async Task ChangeLessonUnit_OrdnetStundeDerZieleinheitZuUndWaehltSieAus() + { + var (vm, units, lessons, groupId) = BuildScenario(); + var unitA = new Unit { GroupId = groupId, Title = "Mechanik" }; + var unitB = new Unit { GroupId = groupId, Title = "Optik" }; + units.Add(unitA); units.Add(unitB); + var l1 = new Lesson { UnitId = unitA.Id, GroupId = groupId, Date = new DateOnly(2025, 9, 1), Status = LessonStatus.Planned, Topic = "1" }; + lessons.Add(l1); + + vm.Initialize(groupId); + vm.SelectedUnit = vm.Units.Single(u => u.Id == unitA.Id); + vm.SelectedLesson = vm.Lessons.Single(l => l.Id == l1.Id); + vm.OnPickUnitChange = _ => Task.FromResult(unitB); + + await vm.ChangeLessonUnitCommand.ExecuteAsync(null); + + Assert.Empty(lessons.GetByUnit(unitA.Id)); + var moved = Assert.Single(lessons.GetByUnit(unitB.Id)); + Assert.Equal(l1.Id, moved.Id); + Assert.Equal(unitB.Id, vm.SelectedUnit?.Id); + Assert.Equal(l1.Id, vm.SelectedLesson?.Id); + } + [Fact] public async Task CopyUnit_ErhaeltAbstaendeUndSetztGroupIdAufZielgruppe() { diff --git a/LehrerApp.Desktop/ViewModels/Groups/PlanningViewModels.cs b/LehrerApp.Desktop/ViewModels/Groups/PlanningViewModels.cs index deeec62..f90c505 100644 --- a/LehrerApp.Desktop/ViewModels/Groups/PlanningViewModels.cs +++ b/LehrerApp.Desktop/ViewModels/Groups/PlanningViewModels.cs @@ -5,6 +5,7 @@ using LehrerApp.Core.Interfaces; using LehrerApp.Core.Models; using LehrerApp.Core.Services; using LehrerApp.Desktop.Services; +using LehrerApp.Desktop.ViewModels.Planning; using LehrerApp.Desktop.ViewModels.Students; using System.Collections.ObjectModel; using System.Globalization; @@ -75,6 +76,7 @@ public partial class PlanningTabViewModel : ObservableObject public Func, List, Task>? OnEditLesson { get; set; } public Func>? OnConfirmDeleteLesson { get; set; } public Func>? OnPickMoveTarget { get; set; } + public Func>? OnPickUnitChange { get; set; } public Func? OnShowLesson { get; set; } public Func>? OnGenerateLessonSeries { get; set; } public Func>? OnAiAssist { get; set; } @@ -160,6 +162,7 @@ public partial class PlanningTabViewModel : ObservableObject EditLessonCommand.NotifyCanExecuteChanged(); DeleteLessonCommand.NotifyCanExecuteChanged(); MoveLessonCommand.NotifyCanExecuteChanged(); + ChangeLessonUnitCommand.NotifyCanExecuteChanged(); AdvanceLessonStatusCommand.NotifyCanExecuteChanged(); } @@ -349,6 +352,23 @@ public partial class PlanningTabViewModel : ObservableObject new LessonSchedulingService(_lessons).Move(moved, newDate, newPeriod, shiftFollowing); } + /// Ordnet eine bereits angelegte Stunde einer anderen Einheit derselben Gruppe zu (Korrektur + /// einer im Erstellen-Dialog falsch gewählten Einheit, Nutzer-Feedback) — bisher war das nur + /// über Löschen + Neuanlegen möglich. Datum/Stundennummer bleiben unverändert, nur UnitId ändert + /// sich. Nach dem Speichern springt die Ansicht direkt zur Ziel-Einheit mit der Stunde + /// vorausgewählt, damit sichtbar bleibt, wohin sie verschoben wurde. + [RelayCommand(CanExecute = nameof(HasSelectedLesson))] + private async Task ChangeLessonUnit() + { + if (OnPickUnitChange is null || SelectedLesson is null) return; + var lesson = SelectedLesson.Model; + var targetUnit = await OnPickUnitChange(lesson); + if (targetUnit is null) return; + lesson.UnitId = targetUnit.Id; + _lessons.Save(lesson); + RefreshPlanning(selectUnitId: targetUnit.Id, selectLessonId: lesson.Id); + } + [RelayCommand(CanExecute = nameof(HasSelectedLesson))] private void AdvanceLessonStatus() { @@ -1206,6 +1226,38 @@ public partial class MoveLessonDialogViewModel : ObservableObject } } +// ── Dialog: Stunde einer anderen Einheit zuweisen (Korrektur der Einheit) ──── + +public partial class ChangeLessonUnitDialogViewModel : ObservableObject +{ + [ObservableProperty] private TimetableUnitOption? _selectedUnit; + [ObservableProperty] private string _error = ""; + + public string CurrentUnitLabel { get; } + public ObservableCollection Units { get; } = []; + public bool HasUnits => Units.Count > 0; + public Unit? Result { get; private set; } + + public ChangeLessonUnitDialogViewModel(IUnitRepository units, Guid groupId, Guid currentUnitId, + string currentUnitTitle) + { + CurrentUnitLabel = currentUnitTitle; + foreach (var unit in units.GetByGroup(groupId).Where(u => u.Id != currentUnitId) + .OrderBy(u => u.Status == UnitStatus.Active ? 0 : u.Status == UnitStatus.Planned ? 1 : 2) + .ThenByDescending(u => u.StartDate) + .ThenBy(u => u.Title, StringComparer.CurrentCultureIgnoreCase)) + Units.Add(new TimetableUnitOption(unit)); + } + + [RelayCommand] + private void Save() + { + Error = ""; + if (SelectedUnit is null) { Error = "Bitte eine Ziel-Einheit auswählen."; return; } + Result = SelectedUnit.Model; + } +} + // ── Dialog: Stunden serienweise aus dem Stundenplan erzeugen (4.2.5) ──────── public partial class GenerateLessonSeriesDialogViewModel : ObservableObject diff --git a/LehrerApp.Desktop/Views/Groups/ChangeLessonUnitDialog.axaml b/LehrerApp.Desktop/Views/Groups/ChangeLessonUnitDialog.axaml new file mode 100644 index 0000000..5667d3d --- /dev/null +++ b/LehrerApp.Desktop/Views/Groups/ChangeLessonUnitDialog.axaml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +