aufräumen
This commit is contained in:
@@ -12,7 +12,7 @@ namespace LehrerApp.Desktop.ViewModels.Groups;
|
||||
public partial class GroupListViewModel : ObservableObject
|
||||
{
|
||||
private readonly IGroupRepository _groups;
|
||||
private readonly SchoolYearService _sy;
|
||||
private readonly ISubjectRepository _subjects;
|
||||
|
||||
public Action<Guid, int>? OnNavigateToDetail { get; set; }
|
||||
public Func<Task>? OnAddGroup { get; set; }
|
||||
@@ -37,9 +37,9 @@ public partial class GroupListViewModel : ObservableObject
|
||||
public ObservableCollection<string> SchoolYears { get; } = [];
|
||||
public ObservableCollection<GroupListItem> Groups { get; } = [];
|
||||
|
||||
public GroupListViewModel(IGroupRepository groups, SchoolYearService sy)
|
||||
public GroupListViewModel(IGroupRepository groups, ISubjectRepository subjects, SchoolYearService sy)
|
||||
{
|
||||
_groups = groups; _sy = sy;
|
||||
_groups = groups; _subjects = subjects;
|
||||
foreach (var y in sy.RecentSchoolYears()) SchoolYears.Add(y);
|
||||
SelectedSchoolYear = sy.CurrentSchoolYear();
|
||||
}
|
||||
@@ -63,11 +63,13 @@ public partial class GroupListViewModel : ObservableObject
|
||||
Groups.Clear();
|
||||
var all = _groups.GetBySchoolYear(SelectedSchoolYear, includeInactive: ShowArchived)
|
||||
.Where(g => g.IsActive != ShowArchived);
|
||||
var subjectNames = _subjects.GetAll().ToDictionary(s => s.Id, s => s.Name);
|
||||
var filtered = string.IsNullOrWhiteSpace(SearchText) ? all
|
||||
: all.Where(g => g.Name.Contains(SearchText, StringComparison.OrdinalIgnoreCase)
|
||||
|| (g.Subject?.Contains(SearchText, StringComparison.OrdinalIgnoreCase) ?? false));
|
||||
|| (g.SubjectId is Guid id && subjectNames.GetValueOrDefault(id, "")
|
||||
.Contains(SearchText, StringComparison.OrdinalIgnoreCase)));
|
||||
foreach (var g in filtered.OrderBy(g => g.Name))
|
||||
Groups.Add(new GroupListItem(g));
|
||||
Groups.Add(new GroupListItem(g, g.SubjectId is Guid id ? subjectNames.GetValueOrDefault(id, "") : ""));
|
||||
SelectedGroup = Groups.FirstOrDefault(g => g.Id == selectedId);
|
||||
OnPropertyChanged(nameof(ListSummary));
|
||||
OnPropertyChanged(nameof(HasNoGroups));
|
||||
@@ -136,15 +138,15 @@ public class GroupListItem
|
||||
public bool IsActive { get; }
|
||||
public string ArchiveActionLabel => IsActive ? "Archivieren" : "Wieder aktivieren";
|
||||
|
||||
public GroupListItem(LearningGroup g)
|
||||
public GroupListItem(LearningGroup g, string subjectName)
|
||||
{
|
||||
Id = g.Id;
|
||||
IsActive = g.IsActive;
|
||||
Name = g.Name;
|
||||
Subject = g.Subject ?? "";
|
||||
Subject = subjectName;
|
||||
TypeLabel = g.Type == GroupType.Class ? "Klasse" : "Kurs";
|
||||
GradingLabel = g.GradingSystem == GradingSystem.Grades1To6 ? "1–6" : "0–15";
|
||||
DisplayName = string.IsNullOrEmpty(g.Subject) ? g.Name : $"{g.Name} · {g.Subject}";
|
||||
DisplayName = string.IsNullOrEmpty(subjectName) ? g.Name : $"{g.Name} · {subjectName}";
|
||||
Subtitle = $"{TypeLabel} · Stufe {g.GradeLevel} · Noten {GradingLabel} · {g.SchoolYear}";
|
||||
}
|
||||
}
|
||||
@@ -155,7 +157,8 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
{
|
||||
private readonly IGroupRepository _groups;
|
||||
private readonly IStudentRepository _students;
|
||||
private readonly IEnrollmentRepository _enrollments;
|
||||
private readonly IGroupMembershipRepository _memberships;
|
||||
private readonly ISubjectRepository _subjects;
|
||||
private readonly IExamRepository _exams;
|
||||
private readonly IGradeRepository _grades;
|
||||
|
||||
@@ -171,6 +174,7 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
// bevor LoadGroup() läuft (siehe MainWindowViewModel.NavigateToGroupDetail), Group ist dann
|
||||
// kurzzeitig null — ein verschachtelter Pfad würde dafür jedes Mal einen Binding-Fehler loggen.
|
||||
public bool IsDifferentiated => Group?.IsDifferentiated ?? false;
|
||||
public string SubjectName { get; private set; } = "";
|
||||
|
||||
partial void OnGroupChanged(LearningGroup? value) => OnPropertyChanged(nameof(IsDifferentiated));
|
||||
|
||||
@@ -187,10 +191,11 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
public Func<Exam, Task>? OnEvaluateExam { get; set; }
|
||||
|
||||
public GroupDetailViewModel(IGroupRepository groups, IStudentRepository students,
|
||||
IEnrollmentRepository enrollments, IExamRepository exams, IGradeRepository grades,
|
||||
IGroupMembershipRepository memberships, ISubjectRepository subjects,
|
||||
IExamRepository exams, IGradeRepository grades,
|
||||
ParticipationTabViewModel participationTab)
|
||||
{
|
||||
_groups = groups; _students = students; _enrollments = enrollments;
|
||||
_groups = groups; _students = students; _memberships = memberships; _subjects = subjects;
|
||||
_exams = exams; _grades = grades;
|
||||
ParticipationTab = participationTab;
|
||||
}
|
||||
@@ -199,6 +204,9 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
{
|
||||
Group = _groups.GetById(id);
|
||||
if (Group is null) return;
|
||||
SubjectName = Group.SubjectId is Guid subjectId
|
||||
? _subjects.GetById(subjectId)?.Name ?? ""
|
||||
: "";
|
||||
GroupTitle = Group.Name;
|
||||
GroupSubtitle = $"{Group.SchoolYear} · " +
|
||||
$"{(Group.Type == GroupType.Class ? "Klasse" : "Kurs")} · " +
|
||||
@@ -221,14 +229,13 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
{
|
||||
if (Group is null) return;
|
||||
Students.Clear();
|
||||
var enrolled = _students.GetByGroup(Group.Id, Group.SchoolYear);
|
||||
var enrollments = _enrollments.GetByGroupAndYear(Group.Id, Group.SchoolYear)
|
||||
.ToDictionary(e => e.StudentId);
|
||||
var enrolled = _students.GetByGroup(Group.Id);
|
||||
var memberships = _memberships.GetByGroup(Group.Id).ToDictionary(e => e.StudentId);
|
||||
StudentCount = enrolled.Count;
|
||||
foreach (var s in enrolled)
|
||||
{
|
||||
enrollments.TryGetValue(s.Id, out var enr);
|
||||
var summary = new StudentSummary(s, enr) { OnChanged = SaveStudentNiveau };
|
||||
memberships.TryGetValue(s.Id, out var membership);
|
||||
var summary = new StudentSummary(s, membership) { OnChanged = SaveStudentNiveau };
|
||||
Students.Add(summary);
|
||||
}
|
||||
}
|
||||
@@ -236,11 +243,10 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
private void SaveStudentNiveau(StudentSummary summary)
|
||||
{
|
||||
if (Group is null) return;
|
||||
var enrollment = _enrollments.GetByGroupAndYear(Group.Id, Group.SchoolYear)
|
||||
.FirstOrDefault(e => e.StudentId == summary.Id);
|
||||
if (enrollment is null) return;
|
||||
enrollment.Niveau = summary.Niveau;
|
||||
_enrollments.Save(enrollment);
|
||||
var membership = _memberships.GetByStudentAndGroup(summary.Id, Group.Id);
|
||||
if (membership is null) return;
|
||||
membership.Niveau = summary.Niveau;
|
||||
_memberships.Save(membership);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -259,10 +265,9 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
private void RemoveStudent()
|
||||
{
|
||||
if (Group is null || SelectedStudent is null) return;
|
||||
var enrollment = _enrollments.GetByGroupAndYear(Group.Id, Group.SchoolYear)
|
||||
.FirstOrDefault(e => e.StudentId == SelectedStudent.Id);
|
||||
if (enrollment is null) return;
|
||||
_enrollments.Delete(enrollment.Id);
|
||||
var membership = _memberships.GetByStudentAndGroup(SelectedStudent.Id, Group.Id);
|
||||
if (membership is null) return;
|
||||
_memberships.Delete(membership.Id);
|
||||
LoadStudents();
|
||||
SelectedStudent = null;
|
||||
ParticipationTab.RefreshCurrentGrid();
|
||||
@@ -422,18 +427,18 @@ public partial class StudentSummary : ObservableObject
|
||||
|
||||
public Action<StudentSummary>? OnChanged { get; set; }
|
||||
|
||||
public StudentSummary(Core.Models.Student s, Enrollment? e)
|
||||
public StudentSummary(Core.Models.Student s, GroupMembership? membership)
|
||||
{
|
||||
Id = s.Id;
|
||||
FullName = s.FullName;
|
||||
PeriodLabel = e?.Period switch
|
||||
PeriodLabel = membership?.Period switch
|
||||
{
|
||||
EnrollmentPeriod.H1Only => "H1",
|
||||
EnrollmentPeriod.H2Only => "H2",
|
||||
EnrollmentPeriod.Custom => BuildCustomLabel(e),
|
||||
MembershipPeriod.H1Only => "H1",
|
||||
MembershipPeriod.H2Only => "H2",
|
||||
MembershipPeriod.Custom => BuildCustomLabel(membership),
|
||||
_ => "",
|
||||
};
|
||||
_niveau = e?.Niveau;
|
||||
_niveau = membership?.Niveau;
|
||||
}
|
||||
|
||||
partial void OnNiveauChanged(Niveau? value)
|
||||
@@ -442,11 +447,11 @@ public partial class StudentSummary : ObservableObject
|
||||
OnChanged?.Invoke(this);
|
||||
}
|
||||
|
||||
private static string BuildCustomLabel(Enrollment e)
|
||||
private static string BuildCustomLabel(GroupMembership membership)
|
||||
{
|
||||
if (e.JoinedAt.HasValue && e.LeftAt.HasValue) return $"{e.JoinedAt:dd.MM.}–{e.LeftAt:dd.MM.}";
|
||||
if (e.JoinedAt.HasValue) return $"ab {e.JoinedAt:dd.MM.}";
|
||||
if (e.LeftAt.HasValue) return $"bis {e.LeftAt:dd.MM.}";
|
||||
if (membership.JoinedAt.HasValue && membership.LeftAt.HasValue) return $"{membership.JoinedAt:dd.MM.}–{membership.LeftAt:dd.MM.}";
|
||||
if (membership.JoinedAt.HasValue) return $"ab {membership.JoinedAt:dd.MM.}";
|
||||
if (membership.LeftAt.HasValue) return $"bis {membership.LeftAt:dd.MM.}";
|
||||
return "Datum";
|
||||
}
|
||||
}
|
||||
@@ -491,35 +496,34 @@ public class ExamSummary
|
||||
public partial class AddStudentToGroupDialogViewModel : ObservableObject
|
||||
{
|
||||
private readonly IStudentRepository _students;
|
||||
private readonly IEnrollmentRepository _enrollments;
|
||||
private readonly IGroupMembershipRepository _memberships;
|
||||
private readonly Guid _groupId;
|
||||
private readonly string _schoolYear;
|
||||
|
||||
[ObservableProperty] private string _searchText = "";
|
||||
[ObservableProperty] private StudentPickerItem? _selectedStudent;
|
||||
[ObservableProperty] private string _validationMessage = "";
|
||||
[ObservableProperty] private EnrollmentPeriod _period = EnrollmentPeriod.FullYear;
|
||||
[ObservableProperty] private MembershipPeriod _period = MembershipPeriod.FullYear;
|
||||
[ObservableProperty] private string _joinedAtText = "";
|
||||
[ObservableProperty] private string _leftAtText = "";
|
||||
|
||||
public bool IsFullYear { get => Period == EnrollmentPeriod.FullYear; set { if (value) Period = EnrollmentPeriod.FullYear; } }
|
||||
public bool IsH1Only { get => Period == EnrollmentPeriod.H1Only; set { if (value) Period = EnrollmentPeriod.H1Only; } }
|
||||
public bool IsH2Only { get => Period == EnrollmentPeriod.H2Only; set { if (value) Period = EnrollmentPeriod.H2Only; } }
|
||||
public bool IsCustom { get => Period == EnrollmentPeriod.Custom; set { if (value) Period = EnrollmentPeriod.Custom; } }
|
||||
public bool IsCustomPeriod => Period == EnrollmentPeriod.Custom;
|
||||
public bool IsFullYear { get => Period == MembershipPeriod.FullYear; set { if (value) Period = MembershipPeriod.FullYear; } }
|
||||
public bool IsH1Only { get => Period == MembershipPeriod.H1Only; set { if (value) Period = MembershipPeriod.H1Only; } }
|
||||
public bool IsH2Only { get => Period == MembershipPeriod.H2Only; set { if (value) Period = MembershipPeriod.H2Only; } }
|
||||
public bool IsCustom { get => Period == MembershipPeriod.Custom; set { if (value) Period = MembershipPeriod.Custom; } }
|
||||
public bool IsCustomPeriod => Period == MembershipPeriod.Custom;
|
||||
|
||||
public ObservableCollection<StudentPickerItem> AvailableStudents { get; } = [];
|
||||
public Enrollment? Result { get; private set; }
|
||||
public GroupMembership? Result { get; private set; }
|
||||
|
||||
public AddStudentToGroupDialogViewModel(IStudentRepository students,
|
||||
IEnrollmentRepository enrollments, Guid groupId, string schoolYear)
|
||||
IGroupMembershipRepository memberships, Guid groupId)
|
||||
{
|
||||
_students = students; _enrollments = enrollments;
|
||||
_groupId = groupId; _schoolYear = schoolYear;
|
||||
_students = students; _memberships = memberships;
|
||||
_groupId = groupId;
|
||||
LoadAvailableStudents();
|
||||
}
|
||||
|
||||
partial void OnPeriodChanged(EnrollmentPeriod value)
|
||||
partial void OnPeriodChanged(MembershipPeriod value)
|
||||
{
|
||||
OnPropertyChanged(nameof(IsFullYear));
|
||||
OnPropertyChanged(nameof(IsH1Only));
|
||||
@@ -532,11 +536,11 @@ public partial class AddStudentToGroupDialogViewModel : ObservableObject
|
||||
|
||||
private void LoadAvailableStudents()
|
||||
{
|
||||
var alreadyEnrolled = _enrollments.GetByGroupAndYear(_groupId, _schoolYear)
|
||||
var alreadyAssigned = _memberships.GetByGroup(_groupId)
|
||||
.Select(e => e.StudentId).ToHashSet();
|
||||
var all = _students.GetAll();
|
||||
var available = all
|
||||
.Where(s => !alreadyEnrolled.Contains(s.Id))
|
||||
.Where(s => !alreadyAssigned.Contains(s.Id))
|
||||
.Where(s => string.IsNullOrWhiteSpace(SearchText) ||
|
||||
s.FullName.Contains(SearchText, StringComparison.OrdinalIgnoreCase));
|
||||
AvailableStudents.Clear();
|
||||
@@ -549,7 +553,7 @@ public partial class AddStudentToGroupDialogViewModel : ObservableObject
|
||||
if (SelectedStudent is null) { ValidationMessage = "Bitte einen Schüler auswählen."; return; }
|
||||
|
||||
DateOnly? joinedAt = null, leftAt = null;
|
||||
if (Period == EnrollmentPeriod.Custom)
|
||||
if (Period == MembershipPeriod.Custom)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(JoinedAtText) &&
|
||||
DateOnly.TryParseExact(JoinedAtText, "dd.MM.yyyy",
|
||||
@@ -561,16 +565,15 @@ public partial class AddStudentToGroupDialogViewModel : ObservableObject
|
||||
leftAt = l;
|
||||
}
|
||||
|
||||
Result = new Enrollment
|
||||
Result = new GroupMembership
|
||||
{
|
||||
StudentId = SelectedStudent.Id,
|
||||
GroupId = _groupId,
|
||||
SchoolYear = _schoolYear,
|
||||
Period = Period,
|
||||
JoinedAt = joinedAt,
|
||||
LeftAt = leftAt,
|
||||
};
|
||||
_enrollments.Save(Result);
|
||||
_memberships.Save(Result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,11 +590,8 @@ public partial class AddGroupDialogViewModel : ObservableObject
|
||||
{
|
||||
private readonly IGroupRepository _groups;
|
||||
private readonly ISubjectRepository _subjects;
|
||||
private readonly SchoolYearService _sy;
|
||||
private readonly IEnrollmentRepository _enrollments;
|
||||
private List<Subject> _allSubjects = [];
|
||||
private LearningGroup? _editingGroup;
|
||||
private string? _originalSchoolYear;
|
||||
|
||||
public List<string> TypeOptions { get; } = ["Klasse", "Kurs"];
|
||||
[ObservableProperty] private string _selectedTypeName = "Kurs";
|
||||
@@ -625,9 +625,9 @@ public partial class AddGroupDialogViewModel : ObservableObject
|
||||
public string SaveButtonText => _editingGroup is null ? "Anlegen" : "Speichern";
|
||||
|
||||
public AddGroupDialogViewModel(IGroupRepository groups, ISubjectRepository subjects,
|
||||
SchoolYearService sy, IEnrollmentRepository enrollments)
|
||||
SchoolYearService sy)
|
||||
{
|
||||
_groups = groups; _subjects = subjects; _sy = sy; _enrollments = enrollments;
|
||||
_groups = groups; _subjects = subjects;
|
||||
_allSubjects = subjects.GetAll();
|
||||
KnownSubjectNames = _allSubjects.Select(s => s.Name).ToList();
|
||||
SchoolYears = sy.RecentSchoolYears(3);
|
||||
@@ -642,10 +642,9 @@ public partial class AddGroupDialogViewModel : ObservableObject
|
||||
public void LoadForEdit(LearningGroup group)
|
||||
{
|
||||
_editingGroup = group;
|
||||
_originalSchoolYear = group.SchoolYear;
|
||||
SelectedTypeName = group.Type == GroupType.Class ? "Klasse" : "Kurs";
|
||||
Name = group.Name;
|
||||
Subject = group.Subject ?? "";
|
||||
Subject = group.SubjectId is Guid subjectId ? _subjects.GetById(subjectId)?.Name ?? "" : "";
|
||||
GradeLevel = group.GradeLevel;
|
||||
SelectedGradingName = group.GradingSystem == GradingSystem.Grades1To6
|
||||
? "Noten 1–6" : "Punkte 0–15";
|
||||
@@ -684,7 +683,6 @@ public partial class AddGroupDialogViewModel : ObservableObject
|
||||
|
||||
Result = _editingGroup ?? new LearningGroup();
|
||||
Result.Name = Name.Trim();
|
||||
Result.Subject = subjectName;
|
||||
Result.SubjectId = subjectId;
|
||||
Result.Type = IsKurs ? GroupType.Course : GroupType.Class;
|
||||
Result.GradeLevel = GradeLevel;
|
||||
@@ -695,14 +693,5 @@ public partial class AddGroupDialogViewModel : ObservableObject
|
||||
Result.IsOwnClass = IsOwnClass;
|
||||
Result.IsDifferentiated = IsDifferentiated;
|
||||
_groups.Save(Result);
|
||||
|
||||
if (_editingGroup is not null && _originalSchoolYear != SelectedSchoolYear)
|
||||
{
|
||||
foreach (var enrollment in _enrollments.GetByGroup(Result.Id))
|
||||
{
|
||||
enrollment.SchoolYear = SelectedSchoolYear;
|
||||
_enrollments.Save(enrollment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user