Stunde/Einheit-Dialog: Gruppe + Fach anzeigen, nicht nur Fach

Bei einer Klasse, die in mehreren Fächern unterrichtet wird (mehrere
LearningGroup-Datensätze mit gleichem Namen, z.B. zwei "10c"), zeigte
UnitDialog bisher nur das Fach ("Fach: Chemie"), LessonDialog gar keinen
Gruppen-/Fach-Hinweis. Beide zeigen jetzt "Gruppe · Fach" (z.B. "10c ·
Chemie") direkt unter dem Dialogtitel, nicht editierbar, nur zur Einordnung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 00:47:07 +02:00
co-authored by Claude Sonnet 5
parent 888df39f37
commit fbf70df439
7 changed files with 77 additions and 14 deletions
@@ -19,7 +19,17 @@ public sealed class LessonDialogViewModelTests
FakeTimetableSlots? slots = null, PeriodScheduleService? periodSchedule = null) =>
new(new FakeLessons(), new FakeShorthandCodes([]), new FakeAlternativeLessonPaths([]),
slots ?? new FakeTimetableSlots(), periodSchedule ?? NewPeriodSchedule(),
unitId, groupId, [], [], editing);
unitId, groupId, "10c", "Chemie", [], [], editing);
/// Nutzer-Feedback: bei einer Klasse, die in mehreren Fächern unterrichtet wird (mehrere
/// LearningGroup-Datensätze mit gleichem Namen), war im Stunden-Dialog nicht erkennbar,
/// welche der beiden Stunden man gerade bearbeitet.
[Fact]
public void GroupSubjectDisplay_ZeigtGruppeUndFachZusammen()
{
var vm = BuildVm(Guid.NewGuid(), Guid.NewGuid());
Assert.Equal("10c · Chemie", vm.GroupSubjectDisplay);
}
[Fact]
public void AddPhase_FuegtZeileMitStandardwertenHinzu()
@@ -83,7 +93,7 @@ public sealed class LessonDialogViewModelTests
var codes = new FakeShorthandCodes([new ShorthandCode { Code = "Tb" }, new ShorthandCode { Code = "SH" }]);
var vm = new LessonDialogViewModel(new FakeLessons(), codes, new FakeAlternativeLessonPaths([]),
new FakeTimetableSlots(), NewPeriodSchedule(),
Guid.NewGuid(), Guid.NewGuid(), [], ["Plenum", "LDE", "Tb"], null); // "Tb" doppelt (Katalog + Historie), soll nur einmal erscheinen
Guid.NewGuid(), Guid.NewGuid(), "10c", "Chemie", [], ["Plenum", "LDE", "Tb"], null); // "Tb" doppelt (Katalog + Historie), soll nur einmal erscheinen
Assert.Equal(["LDE", "Plenum", "SH", "Tb"], vm.ShorthandSuggestions);
}
@@ -145,7 +155,7 @@ public sealed class LessonDialogViewModelTests
var groupId = Guid.NewGuid();
var lessons = new FakeLessons();
var vm = new LessonDialogViewModel(lessons, new FakeShorthandCodes([]), new FakeAlternativeLessonPaths([]),
new FakeTimetableSlots(), NewPeriodSchedule(), unitId, groupId, [], [], null)
new FakeTimetableSlots(), NewPeriodSchedule(), unitId, groupId, "10c", "Chemie", [], [], null)
{
Topic = "Brechung", DateText = "01.09.2025", StartTimeText = "11:45",
};
@@ -242,7 +252,7 @@ public sealed class LessonDialogViewModelTests
};
var vm = new LessonDialogViewModel(new FakeLessons(), new FakeShorthandCodes([]), alternativePaths,
new FakeTimetableSlots(), NewPeriodSchedule(), Guid.NewGuid(), Guid.NewGuid(), [], [], editing);
new FakeTimetableSlots(), NewPeriodSchedule(), Guid.NewGuid(), Guid.NewGuid(), "10c", "Chemie", [], [], editing);
Assert.True(vm.Phases[0].HasAlternativePath);
Assert.Equal("Kurzversion", vm.Phases[0].AlternativePathName);
@@ -0,0 +1,28 @@
using LehrerApp.Desktop.ViewModels.Groups;
using Xunit;
namespace LehrerApp.Desktop.Tests;
/// Nutzer-Feedback: bei einer Klasse, die in mehreren Fächern unterrichtet wird (mehrere
/// LearningGroup-Datensätze mit gleichem Namen), war im Einheiten-Dialog nur das Fach sichtbar,
/// nicht welche Klasse gemeint ist — beides zusammen macht es eindeutig.
public sealed class UnitDialogViewModelTests
{
[Fact]
public void GroupSubjectDisplay_ZeigtGruppeUndFachZusammen()
{
var vm = new UnitDialogViewModel(new FakeUnits(), new FakeCompetencyDomains(),
Guid.NewGuid(), Guid.NewGuid(), 10, "10c", "Chemie", editingUnit: null);
Assert.Equal("10c · Chemie", vm.GroupSubjectDisplay);
}
[Fact]
public void GroupSubjectDisplay_OhneFach_WeistDaraufHin()
{
var vm = new UnitDialogViewModel(new FakeUnits(), new FakeCompetencyDomains(),
Guid.NewGuid(), null, 10, "10c", "", editingUnit: null);
Assert.Equal("10c · kein Fach hinterlegt (siehe Lerngruppe)", vm.GroupSubjectDisplay);
}
}
@@ -39,6 +39,7 @@ public partial class PlanningTabViewModel : ObservableObject
public Guid? SubjectId { get; private set; }
public int GradeLevel { get; private set; }
public string SubjectName { get; private set; } = "";
public string GroupLabel { get; private set; } = "";
[ObservableProperty] private UnitSummary? _selectedUnit;
[ObservableProperty] private LessonSummary? _selectedLesson;
@@ -88,6 +89,7 @@ public partial class PlanningTabViewModel : ObservableObject
SubjectId = group?.SubjectId;
GradeLevel = group?.GradeLevel ?? 0;
SubjectName = SubjectId is Guid sid ? _subjects.GetById(sid)?.Name ?? "" : "";
GroupLabel = group?.Name ?? "";
LoadUnits();
}
@@ -494,21 +496,23 @@ public partial class UnitDialogViewModel : ObservableObject
public string CompetencySummary => _competencyCodes.Count == 0
? "Keine Kompetenzen" : $"{_competencyCodes.Count} Kompetenz(en)";
/// Fach kommt von der Lerngruppe, nicht editierbar (jede Gruppe unterrichtet ein Fach).
public string SubjectDisplay { get; }
/// Gruppe + Fach kommen von der Lerngruppe, nicht editierbar (jede Gruppe unterrichtet ein
/// Fach) — beide zusammen zeigen, da dieselbe Klasse in mehreren Fächern (mehrere
/// Lerngruppen mit gleichem Namen) sonst nicht unterscheidbar wäre (Nutzer-Feedback).
public string GroupSubjectDisplay { get; }
public Unit? Result { get; private set; }
public string DialogTitle => _editingUnit is null ? "Neue Einheit anlegen" : "Einheit bearbeiten";
public string SaveButtonText => _editingUnit is null ? "Anlegen" : "Speichern";
public UnitDialogViewModel(IUnitRepository units, ICompetencyDomainRepository competencyDomains,
Guid groupId, Guid? subjectId, int gradeLevel, string subjectName, Unit? editingUnit)
Guid groupId, Guid? subjectId, int gradeLevel, string groupName, string subjectName, Unit? editingUnit)
{
_units = units; _competencyDomains = competencyDomains;
_groupId = groupId; _subjectId = subjectId; _gradeLevel = gradeLevel;
_editingUnit = editingUnit;
SubjectDisplay = string.IsNullOrWhiteSpace(subjectName)
? "Kein Fach hinterlegt (siehe Lerngruppe)" : $"Fach: {subjectName}";
GroupSubjectDisplay = string.IsNullOrWhiteSpace(subjectName)
? $"{groupName} · kein Fach hinterlegt (siehe Lerngruppe)" : $"{groupName} · {subjectName}";
_competencyCodes = editingUnit is not null ? [.. editingUnit.Competencies] : [];
BuildCompetencyTagGroups();
@@ -631,6 +635,12 @@ public partial class LessonDialogViewModel : ObservableObject
public string DialogTitle => _editingLesson is null ? "Neue Stunde anlegen" : "Stunde bearbeiten";
public string SaveButtonText => _editingLesson is null ? "Anlegen" : "Speichern";
/// Gruppe + Fach der Einheit, zu der diese Stunde gehört — nicht editierbar, nur zur
/// Einordnung. Ohne das war bei gleichnamigen Klassen in mehreren Fächern (mehrere
/// Lerngruppen mit gleichem Namen) nicht erkennbar, welche Stunde man gerade bearbeitet
/// (Nutzer-Feedback).
public string GroupSubjectDisplay { get; }
// Für die KI-Unterstützung mit Fokus auf genau diese Stunde (4.5.22) — nur für bereits
// gespeicherte Stunden sinnvoll, eine gerade erst angelegte, noch ungespeicherte Stunde hat
// keine echte Id, auf die sich die KI beziehen könnte.
@@ -645,12 +655,14 @@ public partial class LessonDialogViewModel : ObservableObject
public LessonDialogViewModel(ILessonRepository lessons, IShorthandCodeRepository shorthandCodes,
IAlternativeLessonPathRepository alternativePaths, ITimetableSlotRepository timetableSlots,
PeriodScheduleService periodSchedule, Guid unitId, Guid groupId,
PeriodScheduleService periodSchedule, Guid unitId, Guid groupId, string groupName, string subjectName,
List<string> materialSuggestions, List<string> shorthandHistorySuggestions, Lesson? editingLesson)
{
_lessons = lessons; _alternativePaths = alternativePaths;
_timetableSlots = timetableSlots; _periodSchedule = periodSchedule;
_unitId = unitId; _groupId = groupId; _editingLesson = editingLesson;
GroupSubjectDisplay = string.IsNullOrWhiteSpace(subjectName)
? $"{groupName} · kein Fach hinterlegt (siehe Lerngruppe)" : $"{groupName} · {subjectName}";
MaterialSuggestions = [.. materialSuggestions];
// Vorschläge kommen sowohl aus dem gepflegten Kürzel-Katalog (Einstellungen) als auch aus
@@ -10,7 +10,10 @@
<Grid RowDefinitions="*,Auto" Margin="24">
<ScrollViewer Grid.Row="0">
<StackPanel Spacing="14" Margin="0,0,12,0">
<StackPanel Spacing="2">
<TextBlock Text="{Binding DialogTitle}" Classes="dialogtitle"/>
<TextBlock Text="{Binding GroupSubjectDisplay}" FontSize="12" Opacity="0.6"/>
</StackPanel>
<Grid ColumnDefinitions="*,12,*,12,*,12,*">
<StackPanel Grid.Column="0" Spacing="4">
@@ -41,7 +41,7 @@ public partial class PlanningTabView : UserControl
var dialogVm = new UnitDialogViewModel(
App.Services.GetRequiredService<IUnitRepository>(),
App.Services.GetRequiredService<ICompetencyDomainRepository>(),
groupId, vm.SubjectId, vm.GradeLevel, vm.SubjectName, editingUnit);
groupId, vm.SubjectId, vm.GradeLevel, vm.GroupLabel, vm.SubjectName, editingUnit);
var dialog = new UnitDialog { DataContext = dialogVm };
var owner = TopLevel.GetTopLevel(this) as Window;
@@ -80,13 +80,16 @@ public partial class PlanningTabView : UserControl
private async Task<bool> ShowLessonDialog(Guid unitId, Guid groupId,
List<string> materialSuggestions, List<string> shorthandHistorySuggestions, Lesson? editingLesson)
{
if (DataContext is not PlanningTabViewModel vm) return false;
var dialogVm = new LessonDialogViewModel(
App.Services.GetRequiredService<ILessonRepository>(),
App.Services.GetRequiredService<IShorthandCodeRepository>(),
App.Services.GetRequiredService<IAlternativeLessonPathRepository>(),
App.Services.GetRequiredService<ITimetableSlotRepository>(),
App.Services.GetRequiredService<PeriodScheduleService>(),
unitId, groupId, materialSuggestions, shorthandHistorySuggestions, editingLesson);
unitId, groupId, vm.GroupLabel, vm.SubjectName,
materialSuggestions, shorthandHistorySuggestions, editingLesson);
var dialog = new LessonDialog { DataContext = dialogVm };
var owner = TopLevel.GetTopLevel(this) as Window;
@@ -12,7 +12,7 @@
<StackPanel Spacing="14" Margin="0,0,12,0">
<StackPanel Spacing="2">
<TextBlock Text="{Binding DialogTitle}" Classes="dialogtitle"/>
<TextBlock Text="{Binding SubjectDisplay}" FontSize="12" Opacity="0.6"/>
<TextBlock Text="{Binding GroupSubjectDisplay}" FontSize="12" Opacity="0.6"/>
</StackPanel>
<StackPanel Spacing="4">
+7
View File
@@ -286,6 +286,13 @@ gruppenspezifischen Tab "Planung" (`GroupDetailView`), siehe unten.
- [x] **4.1.1** Listenansicht der Einheiten je Gruppe mit Status und Zeitraum
(ersetzt den Platzhalter im Tab "Planung").
- [x] **4.1.2** Dialog Einheit anlegen/bearbeiten: Titel, Fach, Zeitraum, Status, Notizen.
**Nachtrag (Nutzer-Feedback, im Zuge des 4.3.3-Bugfixes):** Bei einer Klasse, die in
mehreren Fächern unterrichtet wird (mehrere `LearningGroup`-Datensätze mit gleichem Namen,
z.B. zwei "10c"), zeigte der Dialog bisher nur das Fach ("Fach: Chemie"), nicht welche
Klasse gemeint ist — beides zusammen war nirgends auf einen Blick zu sehen. Jetzt zeigen
sowohl `UnitDialog` (Einheit) als auch `LessonDialog` (Stunde) direkt unter dem Dialogtitel
"Gruppe · Fach" (z.B. "10c · Chemie"), nicht editierbar, nur zur Einordnung.
- [x] **4.1.3** Kompetenzen aus dem Katalog (siehe 8) einer Einheit zuordnen — Mehrfachauswahl.
- [x] **4.1.4** Einheit als Vorlage speichern und in eine andere Gruppe kopieren
(inkl. Stunden, ohne Datumsbezug).