Unterrichtsplanung: Serienerzeugung, Stundenraster, Aufsichten & Vertretung (Kapitel 4.2/4.3 Nachtrag)
Stunden serienweise aus dem Stundenplan erzeugen (4.2.5); Stundenraster (Uhrzeiten je Stunde) in den Einstellungen mit Zeitbedarf-Rückmeldung im Verlaufsplan-Editor; wiederkehrende Pausenaufsicht; neuer "Vertretung eintragen"-Dialog für einmalige Vertretungsaufsicht, Vertretungsstunde, Sondereinsätze (Ausflüge, Berufsmessen) und schlichten Stundenausfall. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -58,11 +58,15 @@ public partial class TimetableViewModel : ObservableObject
|
||||
private readonly SchoolCalendarSettingsService _calendarSettings;
|
||||
private readonly PublicHolidayService _publicHolidays;
|
||||
private readonly SchoolYearService _schoolYear;
|
||||
private readonly ISupervisionDutyRepository _supervisionDuties;
|
||||
private readonly ISubstitutionEntryRepository _substitutions;
|
||||
|
||||
public ObservableCollection<TimetableCellItem> Cells { get; } = [];
|
||||
public ObservableCollection<WeekCellItem> WeekItems { get; } = [];
|
||||
public ObservableCollection<HoursWarningItem> HoursWarnings { get; } = [];
|
||||
public ObservableCollection<TodayLessonItem> TodayItems { get; } = [];
|
||||
public ObservableCollection<TodaySupervisionItem> TodaySupervisions { get; } = [];
|
||||
public ObservableCollection<TodaySpecialAssignmentItem> TodaySpecialAssignments { get; } = [];
|
||||
|
||||
[ObservableProperty] private int _activeTabIndex;
|
||||
[ObservableProperty] private string _todayLabel = "";
|
||||
@@ -72,15 +76,18 @@ public partial class TimetableViewModel : ObservableObject
|
||||
|
||||
public Func<TimetableCellItem, Task>? OnEditSlot { get; set; }
|
||||
public Action<Guid>? OnNavigateToGroup { get; set; }
|
||||
public Func<Task>? OnAddSubstitution { get; set; }
|
||||
|
||||
public TimetableViewModel(ITimetableSlotRepository slots, IGroupRepository groups,
|
||||
ISubjectRepository subjects, ILessonRepository lessons, IExamRepository exams,
|
||||
ISchoolHolidayRepository schoolHolidays, SchoolCalendarSettingsService calendarSettings,
|
||||
PublicHolidayService publicHolidays, SchoolYearService schoolYear)
|
||||
PublicHolidayService publicHolidays, SchoolYearService schoolYear,
|
||||
ISupervisionDutyRepository supervisionDuties, ISubstitutionEntryRepository substitutions)
|
||||
{
|
||||
_slots = slots; _groups = groups; _subjects = subjects; _lessons = lessons; _exams = exams;
|
||||
_schoolHolidays = schoolHolidays; _calendarSettings = calendarSettings;
|
||||
_publicHolidays = publicHolidays; _schoolYear = schoolYear;
|
||||
_supervisionDuties = supervisionDuties; _substitutions = substitutions;
|
||||
Load();
|
||||
}
|
||||
|
||||
@@ -95,6 +102,14 @@ public partial class TimetableViewModel : ObservableObject
|
||||
[RelayCommand]
|
||||
private void CurrentWeek() { WeekOffset = 0; Load(); }
|
||||
|
||||
[RelayCommand]
|
||||
private async Task AddSubstitution()
|
||||
{
|
||||
if (OnAddSubstitution is null) return;
|
||||
await OnAddSubstitution();
|
||||
Load();
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
@@ -106,33 +121,90 @@ public partial class TimetableViewModel : ObservableObject
|
||||
|
||||
var holidayBadges = ComputeHolidayBadges(today, publicHolidayDates);
|
||||
var examProximity = ComputeExamProximity(today, publicHolidayDates);
|
||||
var duties = _supervisionDuties.GetAll();
|
||||
|
||||
BuildGrid(holidayBadges);
|
||||
BuildWeekOverview(today, publicHolidayDates);
|
||||
BuildGrid(holidayBadges, duties);
|
||||
BuildWeekOverview(today, publicHolidayDates, duties);
|
||||
BuildToday(today);
|
||||
BuildHoursWarnings();
|
||||
}
|
||||
|
||||
// ── "Heute": Tagesliste ──────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Vertretungsstunden (<see cref="SubstitutionEntry"/>, Kind Lesson) überschreiben für ihre
|
||||
/// Stunde die normale, aus dem Stundenplan abgeleitete Anzeige — sie beschreiben, was an
|
||||
/// diesem konkreten Tag tatsächlich stattfindet. Stunden ohne passenden Stundenplan-Slot (z.B.
|
||||
/// Vertretung in einer fremden Gruppe) werden zusätzlich angehängt.
|
||||
/// </summary>
|
||||
private void BuildToday(DateOnly today)
|
||||
{
|
||||
TodayItems.Clear();
|
||||
var slotsToday = _slots.GetAll().Where(s => s.Weekday == today.DayOfWeek).OrderBy(s => s.PeriodNumber).ToList();
|
||||
var substitutionsToday = _substitutions.GetByDate(today);
|
||||
var slotsToday = _slots.GetAll().Where(s => s.Weekday == today.DayOfWeek).ToList();
|
||||
var items = new List<TodayLessonItem>();
|
||||
var coveredPeriods = new HashSet<int>();
|
||||
|
||||
foreach (var slot in slotsToday)
|
||||
{
|
||||
coveredPeriods.Add(slot.PeriodNumber);
|
||||
var lessonSub = substitutionsToday.FirstOrDefault(s => s.Kind == SubstitutionKind.Lesson && s.PeriodNumber == slot.PeriodNumber);
|
||||
if (lessonSub is not null) { items.Add(TodayLessonItem.ForSubstitution(slot.PeriodNumber, lessonSub)); continue; }
|
||||
|
||||
var group = _groups.GetById(slot.GroupId);
|
||||
if (group is null) continue;
|
||||
|
||||
var cancelled = substitutionsToday.FirstOrDefault(s => s.Kind == SubstitutionKind.Cancelled && s.PeriodNumber == slot.PeriodNumber);
|
||||
if (cancelled is not null) { items.Add(TodayLessonItem.ForCancelled(slot.GroupId, slot.PeriodNumber, group.Name, cancelled)); continue; }
|
||||
|
||||
var lesson = _lessons.GetByGroupAndDate(slot.GroupId, today).FirstOrDefault();
|
||||
var exam = _exams.GetByGroup(slot.GroupId).FirstOrDefault(e => e.Date == today);
|
||||
TodayItems.Add(new TodayLessonItem(slot.GroupId, slot.PeriodNumber, group.Name,
|
||||
items.Add(new TodayLessonItem(slot.GroupId, slot.PeriodNumber, group.Name,
|
||||
slot.Room ?? "", ColorFor(group.Name), lesson?.Topic, exam?.Title));
|
||||
}
|
||||
|
||||
foreach (var sub in substitutionsToday.Where(s => s.Kind == SubstitutionKind.Lesson &&
|
||||
s.PeriodNumber is int p && !coveredPeriods.Contains(p)))
|
||||
items.Add(TodayLessonItem.ForSubstitution(sub.PeriodNumber!.Value, sub));
|
||||
|
||||
TodayItems.Clear();
|
||||
foreach (var item in items.OrderBy(i => i.PeriodNumber)) TodayItems.Add(item);
|
||||
|
||||
TodaySupervisions.Clear();
|
||||
foreach (var item in BuildTodaySupervisionItems(today, substitutionsToday)) TodaySupervisions.Add(item);
|
||||
|
||||
TodaySpecialAssignments.Clear();
|
||||
foreach (var sub in substitutionsToday.Where(s => s.Kind == SubstitutionKind.SpecialAssignment))
|
||||
{
|
||||
var periodLabel = sub.IsAllDay ? "Ganztägig" : $"{sub.FromPeriod}.–{sub.ToPeriod}. Stunde";
|
||||
TodaySpecialAssignments.Add(new TodaySpecialAssignmentItem(periodLabel, sub.Description, sub.GroupLabel));
|
||||
}
|
||||
}
|
||||
|
||||
private List<TodaySupervisionItem> BuildTodaySupervisionItems(DateOnly today, List<SubstitutionEntry> substitutionsToday)
|
||||
{
|
||||
var dutiesToday = _supervisionDuties.GetAll().Where(d => d.Weekday == today.DayOfWeek).ToList();
|
||||
var subsToday = substitutionsToday.Where(s => s.Kind == SubstitutionKind.Supervision).ToList();
|
||||
var afterPeriods = dutiesToday.Select(d => d.AfterPeriod)
|
||||
.Concat(subsToday.Select(s => s.AfterPeriod!.Value))
|
||||
.Distinct().OrderBy(p => p);
|
||||
|
||||
var result = new List<TodaySupervisionItem>();
|
||||
foreach (var afterPeriod in afterPeriods)
|
||||
{
|
||||
var sub = subsToday.FirstOrDefault(s => s.AfterPeriod == afterPeriod);
|
||||
if (sub is not null) { result.Add(new TodaySupervisionItem(afterPeriod, sub.Description, isSubstitution: true)); continue; }
|
||||
var duty = dutiesToday.First(d => d.AfterPeriod == afterPeriod);
|
||||
result.Add(new TodaySupervisionItem(afterPeriod, duty.Location, isSubstitution: false));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenGroup(Guid groupId) => OnNavigateToGroup?.Invoke(groupId);
|
||||
private void OpenGroup(Guid groupId)
|
||||
{
|
||||
if (groupId == Guid.Empty) return; // Vertretung in fremder Gruppe ohne echte GroupId
|
||||
OnNavigateToGroup?.Invoke(groupId);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ShowEditor() => ActiveTabIndex = 1;
|
||||
@@ -146,9 +218,11 @@ public partial class TimetableViewModel : ObservableObject
|
||||
/// parallele Kurs oder die nächste Stunde in der Woche auf einen Blick sichtbar sind. Die
|
||||
/// Badges (Ferien-Nähe, Klausur-Nähe) werden je Zelle am dort angezeigten Datum ausgerichtet,
|
||||
/// nicht am realen "heute" — sonst würde beim Blättern in andere Wochen ein Badge angezeigt,
|
||||
/// das eigentlich zu einer ganz anderen Woche gehört.
|
||||
/// das eigentlich zu einer ganz anderen Woche gehört. Aufsicht-Zeilen (wiederkehrend + einmalige
|
||||
/// Vertretungsaufsicht) werden zwischen den betroffenen Stundenzeilen eingefügt, Vertretungsstunden
|
||||
/// ersetzen für ihre Stunde die sonst aus dem Stundenplan abgeleitete Anzeige.
|
||||
/// </summary>
|
||||
private void BuildWeekOverview(DateOnly today, HashSet<DateOnly> publicHolidayDates)
|
||||
private void BuildWeekOverview(DateOnly today, HashSet<DateOnly> publicHolidayDates, List<SupervisionDuty> duties)
|
||||
{
|
||||
WeekItems.Clear();
|
||||
var currentWeekMonday = today.AddDays(-((int)today.DayOfWeek + 6) % 7);
|
||||
@@ -160,22 +234,54 @@ public partial class TimetableViewModel : ObservableObject
|
||||
var groups = _groups.GetAll(includeInactive: true).ToDictionary(g => g.Id);
|
||||
var schoolHolidays = _schoolHolidays.GetAll();
|
||||
var dateByWeekday = Weekdays.ToDictionary(w => w, w => monday.AddDays((int)w - (int)DayOfWeek.Monday));
|
||||
var dutiesByPeriod = duties.ToLookup(d => d.AfterPeriod);
|
||||
var substitutionsThisWeek = dateByWeekday.Values.SelectMany(d => _substitutions.GetByDate(d)).ToList();
|
||||
|
||||
WeekItems.Add(WeekCellItem.Corner());
|
||||
foreach (var weekday in Weekdays)
|
||||
WeekItems.Add(WeekCellItem.WeekdayHeader(weekday, dateByWeekday[weekday], dateByWeekday[weekday] == today));
|
||||
|
||||
AddWeekSupervisionRowIfAny(0, dutiesByPeriod, substitutionsThisWeek, dateByWeekday);
|
||||
|
||||
for (var period = FirstPeriod; period <= LastPeriod; period++)
|
||||
{
|
||||
WeekItems.Add(WeekCellItem.PeriodLabel(period));
|
||||
foreach (var weekday in Weekdays)
|
||||
{
|
||||
var date = dateByWeekday[weekday];
|
||||
var lessonSub = substitutionsThisWeek.FirstOrDefault(s =>
|
||||
s.Kind == SubstitutionKind.Lesson && s.Date == date && s.PeriodNumber == period);
|
||||
if (lessonSub is not null)
|
||||
{
|
||||
WeekItems.Add(WeekCellItem.ForSubstitutionLesson(weekday, period, date == today, lessonSub));
|
||||
continue;
|
||||
}
|
||||
|
||||
var specialAssignment = substitutionsThisWeek.FirstOrDefault(s =>
|
||||
s.Kind == SubstitutionKind.SpecialAssignment && s.Date == date &&
|
||||
(s.IsAllDay || (period >= s.FromPeriod && period <= s.ToPeriod)));
|
||||
if (specialAssignment is not null)
|
||||
{
|
||||
WeekItems.Add(WeekCellItem.ForSpecialAssignment(weekday, period, date == today, specialAssignment));
|
||||
continue;
|
||||
}
|
||||
|
||||
var slot = allSlots.FirstOrDefault(s => s.Weekday == weekday && s.PeriodNumber == period);
|
||||
if (slot is null) { WeekItems.Add(WeekCellItem.Empty(weekday, period)); continue; }
|
||||
|
||||
var date = dateByWeekday[weekday];
|
||||
var group = groups.GetValueOrDefault(slot.GroupId);
|
||||
var subject = group?.SubjectId is { } subjectId ? _subjects.GetById(subjectId) : null;
|
||||
|
||||
var cancelled = substitutionsThisWeek.FirstOrDefault(s =>
|
||||
s.Kind == SubstitutionKind.Cancelled && s.Date == date && s.PeriodNumber == period);
|
||||
if (cancelled is not null)
|
||||
{
|
||||
WeekItems.Add(WeekCellItem.ForCancelled(weekday, period, date == today, cancelled,
|
||||
subject?.ShortName is { Length: > 0 } csn ? csn : subject?.Name ?? "",
|
||||
group?.Name ?? "?", slot.GroupId));
|
||||
continue;
|
||||
}
|
||||
|
||||
var lesson = _lessons.GetByGroupAndDate(slot.GroupId, date).FirstOrDefault();
|
||||
var hasExam = _exams.GetByGroup(slot.GroupId).Any(e => e.Date == date);
|
||||
var isHoliday = IsFreeDay(date, schoolHolidays, publicHolidayDates);
|
||||
@@ -189,6 +295,30 @@ public partial class TimetableViewModel : ObservableObject
|
||||
colorHex, holidayBadge, hasExam, isLastBeforeExam,
|
||||
MentionsExperiment(lesson), slot.GroupId, isHoliday));
|
||||
}
|
||||
AddWeekSupervisionRowIfAny(period, dutiesByPeriod, substitutionsThisWeek, dateByWeekday);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddWeekSupervisionRowIfAny(int afterPeriod, ILookup<int, SupervisionDuty> dutiesByPeriod,
|
||||
List<SubstitutionEntry> substitutionsThisWeek, Dictionary<DayOfWeek, DateOnly> dateByWeekday)
|
||||
{
|
||||
var hasAny = dutiesByPeriod.Contains(afterPeriod) ||
|
||||
substitutionsThisWeek.Any(s => s.Kind == SubstitutionKind.Supervision && s.AfterPeriod == afterPeriod);
|
||||
if (!hasAny) return;
|
||||
|
||||
WeekItems.Add(WeekCellItem.SupervisionRowLabel(afterPeriod));
|
||||
foreach (var weekday in Weekdays)
|
||||
{
|
||||
var date = dateByWeekday[weekday];
|
||||
var substitution = substitutionsThisWeek.FirstOrDefault(s =>
|
||||
s.Kind == SubstitutionKind.Supervision && s.Date == date && s.AfterPeriod == afterPeriod);
|
||||
if (substitution is not null)
|
||||
{
|
||||
WeekItems.Add(WeekCellItem.SupervisionCell(substitution.Description, isSubstitution: true));
|
||||
continue;
|
||||
}
|
||||
var duty = dutiesByPeriod[afterPeriod].FirstOrDefault(d => d.Weekday == weekday);
|
||||
WeekItems.Add(WeekCellItem.SupervisionCell(duty?.Location ?? "", isSubstitution: false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,16 +356,19 @@ public partial class TimetableViewModel : ObservableObject
|
||||
|
||||
// ── Bearbeiten-Raster ─────────────────────────────────────────────────────
|
||||
|
||||
private void BuildGrid(Dictionary<(DayOfWeek Weekday, Guid GroupId), string> badges)
|
||||
private void BuildGrid(Dictionary<(DayOfWeek Weekday, Guid GroupId), string> badges, List<SupervisionDuty> duties)
|
||||
{
|
||||
Cells.Clear();
|
||||
var allSlots = _slots.GetAll();
|
||||
var groupNames = _groups.GetAll(includeInactive: true).ToDictionary(g => g.Id, g => g.Name);
|
||||
var dutiesByPeriod = duties.ToLookup(d => d.AfterPeriod);
|
||||
|
||||
Cells.Add(TimetableCellItem.Corner());
|
||||
foreach (var weekday in Weekdays)
|
||||
Cells.Add(TimetableCellItem.WeekdayHeader(weekday));
|
||||
|
||||
AddGridSupervisionRowIfAny(0, dutiesByPeriod);
|
||||
|
||||
for (var period = FirstPeriod; period <= LastPeriod; period++)
|
||||
{
|
||||
Cells.Add(TimetableCellItem.PeriodLabel(period));
|
||||
@@ -246,6 +379,21 @@ public partial class TimetableViewModel : ObservableObject
|
||||
var badge = slot is not null ? badges.GetValueOrDefault((weekday, slot.GroupId), "") : "";
|
||||
Cells.Add(TimetableCellItem.ForSlot(weekday, period, slot, groupName, ColorFor(groupName), badge));
|
||||
}
|
||||
AddGridSupervisionRowIfAny(period, dutiesByPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Aufsicht wird nur in den Einstellungen gepflegt (siehe SettingsView) — im
|
||||
/// Bearbeiten-Raster ist die Zeile bewusst nur Anzeige, kein weiterer Klick-Dialog nötig für
|
||||
/// eine so kleine, seltene Pflegeaufgabe.</summary>
|
||||
private void AddGridSupervisionRowIfAny(int afterPeriod, ILookup<int, SupervisionDuty> dutiesByPeriod)
|
||||
{
|
||||
if (!dutiesByPeriod.Contains(afterPeriod)) return;
|
||||
Cells.Add(TimetableCellItem.SupervisionRowLabel(afterPeriod));
|
||||
foreach (var weekday in Weekdays)
|
||||
{
|
||||
var duty = dutiesByPeriod[afterPeriod].FirstOrDefault(d => d.Weekday == weekday);
|
||||
Cells.Add(TimetableCellItem.SupervisionCell(duty?.Location ?? ""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,6 +493,8 @@ public class TimetableCellItem
|
||||
{
|
||||
public bool IsHeader { get; private init; }
|
||||
public bool IsPeriodLabel { get; private init; }
|
||||
public bool IsSupervisionRow { get; private init; }
|
||||
public bool IsSupervisionCell { get; private init; }
|
||||
public string Text { get; private init; } = "";
|
||||
public DayOfWeek? Weekday { get; private init; }
|
||||
public int PeriodNumber { get; private init; }
|
||||
@@ -352,9 +502,11 @@ public class TimetableCellItem
|
||||
public string GroupName { get; private init; } = "";
|
||||
public string ColorHex { get; private init; } = "#9E9E9E";
|
||||
public string BadgeText { get; private init; } = "";
|
||||
public string SupervisionLocation { get; private init; } = "";
|
||||
public bool HasSupervision => SupervisionLocation.Length > 0;
|
||||
public bool HasBadge => BadgeText.Length > 0;
|
||||
public bool IsAssigned => Slot is not null;
|
||||
public bool IsSlotCell => !IsHeader && !IsPeriodLabel;
|
||||
public bool IsSlotCell => !IsHeader && !IsPeriodLabel && !IsSupervisionRow && !IsSupervisionCell;
|
||||
|
||||
public static TimetableCellItem Corner() => new() { IsHeader = true, Text = "" };
|
||||
|
||||
@@ -370,6 +522,18 @@ public class TimetableCellItem
|
||||
|
||||
public static TimetableCellItem PeriodLabel(int period) => new() { IsPeriodLabel = true, Text = period.ToString() };
|
||||
|
||||
public static TimetableCellItem SupervisionRowLabel(int afterPeriod) => new()
|
||||
{
|
||||
IsSupervisionRow = true,
|
||||
Text = afterPeriod == 0 ? "Aufsicht (vor 1.)" : $"Aufsicht (n. {afterPeriod}.)",
|
||||
};
|
||||
|
||||
public static TimetableCellItem SupervisionCell(string location) => new()
|
||||
{
|
||||
IsSupervisionCell = true,
|
||||
SupervisionLocation = location,
|
||||
};
|
||||
|
||||
public static TimetableCellItem ForSlot(DayOfWeek day, int period, TimetableSlot? slot, string groupName,
|
||||
string colorHex, string badgeText) => new()
|
||||
{
|
||||
@@ -384,8 +548,14 @@ public class WeekCellItem
|
||||
{
|
||||
public bool IsHeader { get; private init; }
|
||||
public bool IsPeriodLabel { get; private init; }
|
||||
public bool IsSlotCell => !IsHeader && !IsPeriodLabel;
|
||||
public bool IsSupervisionRow { get; private init; }
|
||||
public bool IsSupervisionCell { get; private init; }
|
||||
public bool IsSlotCell => !IsHeader && !IsPeriodLabel && !IsSupervisionRow && !IsSupervisionCell;
|
||||
public bool IsAssigned { get; private init; }
|
||||
public bool IsSubstitutionLesson { get; private init; }
|
||||
public bool IsSubstitutionSupervision { get; private init; }
|
||||
public bool IsSpecialAssignment { get; private init; }
|
||||
public bool IsCancelled { get; private init; }
|
||||
public string Text { get; private init; } = "";
|
||||
public DayOfWeek? Weekday { get; private init; }
|
||||
public int PeriodNumber { get; private init; }
|
||||
@@ -402,6 +572,8 @@ public class WeekCellItem
|
||||
public bool IsLastBeforeExam { get; private init; }
|
||||
public bool HasExperiment { get; private init; }
|
||||
public bool IsHoliday { get; private init; }
|
||||
public string SupervisionLocation { get; private init; } = "";
|
||||
public bool HasSupervision => SupervisionLocation.Length > 0;
|
||||
public bool HasRoom => !string.IsNullOrWhiteSpace(Room);
|
||||
public bool HasTopic => !string.IsNullOrWhiteSpace(Topic);
|
||||
|
||||
@@ -422,6 +594,19 @@ public class WeekCellItem
|
||||
|
||||
public static WeekCellItem Empty(DayOfWeek day, int period) => new() { Weekday = day, PeriodNumber = period };
|
||||
|
||||
public static WeekCellItem SupervisionRowLabel(int afterPeriod) => new()
|
||||
{
|
||||
IsSupervisionRow = true,
|
||||
Text = afterPeriod == 0 ? "Aufsicht (vor 1.)" : $"Aufsicht (n. {afterPeriod}.)",
|
||||
};
|
||||
|
||||
public static WeekCellItem SupervisionCell(string location, bool isSubstitution) => new()
|
||||
{
|
||||
IsSupervisionCell = true,
|
||||
SupervisionLocation = location,
|
||||
IsSubstitutionSupervision = isSubstitution,
|
||||
};
|
||||
|
||||
public static WeekCellItem ForSlot(DayOfWeek day, int period, bool isToday, string subjectLabel,
|
||||
string groupName, string room, string topic, string colorHex, string holidayBadge,
|
||||
bool hasExam, bool isLastBeforeExam, bool hasExperiment, Guid groupId, bool isHoliday) => new()
|
||||
@@ -432,6 +617,30 @@ public class WeekCellItem
|
||||
IsLastBeforeExam = isLastBeforeExam, HasExperiment = hasExperiment, GroupId = groupId,
|
||||
IsHoliday = isHoliday,
|
||||
};
|
||||
|
||||
public static WeekCellItem ForSubstitutionLesson(DayOfWeek day, int period, bool isToday, SubstitutionEntry entry) => new()
|
||||
{
|
||||
Weekday = day, PeriodNumber = period, IsAssigned = true, IsToday = isToday, IsSubstitutionLesson = true,
|
||||
SubjectLabel = "Vertretung", GroupName = entry.GroupLabel, Topic = entry.Description,
|
||||
ColorHex = "#8E24AA", GroupId = entry.GroupId ?? Guid.Empty,
|
||||
};
|
||||
|
||||
public static WeekCellItem ForSpecialAssignment(DayOfWeek day, int period, bool isToday, SubstitutionEntry entry) => new()
|
||||
{
|
||||
Weekday = day, PeriodNumber = period, IsAssigned = true, IsToday = isToday, IsSpecialAssignment = true,
|
||||
SubjectLabel = "Sondereinsatz",
|
||||
GroupName = string.IsNullOrWhiteSpace(entry.GroupLabel) ? "" : entry.GroupLabel,
|
||||
Topic = entry.Description,
|
||||
ColorHex = "#00838F", GroupId = entry.GroupId ?? Guid.Empty,
|
||||
};
|
||||
|
||||
public static WeekCellItem ForCancelled(DayOfWeek day, int period, bool isToday, SubstitutionEntry entry,
|
||||
string subjectLabel, string groupName, Guid groupId) => new()
|
||||
{
|
||||
Weekday = day, PeriodNumber = period, IsAssigned = true, IsToday = isToday, IsCancelled = true,
|
||||
SubjectLabel = subjectLabel, GroupName = groupName, Topic = entry.Description,
|
||||
ColorHex = "#757575", GroupId = groupId,
|
||||
};
|
||||
}
|
||||
|
||||
public class HoursWarningItem(string groupName, int assigned, int expected)
|
||||
@@ -440,17 +649,53 @@ public class HoursWarningItem(string groupName, int assigned, int expected)
|
||||
public string Text { get; } = $"{groupName}: {assigned} von {expected} Wochenstunden eingetragen";
|
||||
}
|
||||
|
||||
public class TodayLessonItem(Guid groupId, int periodNumber, string groupName, string room,
|
||||
string colorHex, string? lessonTopic, string? examTitle)
|
||||
public class TodayLessonItem
|
||||
{
|
||||
public Guid GroupId { get; } = groupId;
|
||||
public int PeriodNumber { get; } = periodNumber;
|
||||
public string GroupName { get; } = groupName;
|
||||
public string Room { get; } = room;
|
||||
public string ColorHex { get; } = colorHex;
|
||||
public string? LessonTopic { get; } = lessonTopic;
|
||||
public string? ExamTitle { get; } = examTitle;
|
||||
public Guid GroupId { get; private init; }
|
||||
public int PeriodNumber { get; private init; }
|
||||
public string GroupName { get; private init; } = "";
|
||||
public string Room { get; private init; } = "";
|
||||
public string ColorHex { get; private init; } = "#9E9E9E";
|
||||
public string? LessonTopic { get; private init; }
|
||||
public string? ExamTitle { get; private init; }
|
||||
public bool IsSubstitution { get; private init; }
|
||||
public bool IsCancelled { get; private init; }
|
||||
public bool HasRoom => !string.IsNullOrWhiteSpace(Room);
|
||||
public bool HasLessonTopic => !string.IsNullOrWhiteSpace(LessonTopic);
|
||||
public bool HasExam => ExamTitle is not null;
|
||||
public bool HasGroupId => GroupId != Guid.Empty;
|
||||
|
||||
public TodayLessonItem(Guid groupId, int periodNumber, string groupName, string room,
|
||||
string colorHex, string? lessonTopic, string? examTitle)
|
||||
{
|
||||
GroupId = groupId; PeriodNumber = periodNumber; GroupName = groupName; Room = room;
|
||||
ColorHex = colorHex; LessonTopic = lessonTopic; ExamTitle = examTitle;
|
||||
}
|
||||
|
||||
public static TodayLessonItem ForSubstitution(int periodNumber, SubstitutionEntry entry) => new(
|
||||
entry.GroupId ?? Guid.Empty, periodNumber, entry.GroupLabel, "", "#8E24AA", entry.Description, null)
|
||||
{ IsSubstitution = true };
|
||||
|
||||
public static TodayLessonItem ForCancelled(Guid groupId, int periodNumber, string groupName, SubstitutionEntry entry) => new(
|
||||
groupId, periodNumber, groupName, "", "#757575",
|
||||
string.IsNullOrWhiteSpace(entry.Description) ? null : entry.Description, null)
|
||||
{ IsCancelled = true };
|
||||
}
|
||||
|
||||
public class TodaySupervisionItem(int afterPeriod, string description, bool isSubstitution)
|
||||
{
|
||||
public int AfterPeriod { get; } = afterPeriod;
|
||||
public string PeriodLabel { get; } = afterPeriod == 0 ? "Vor der 1. Stunde" : $"Nach der {afterPeriod}. Stunde";
|
||||
public string Description { get; } = description;
|
||||
public bool IsSubstitution { get; } = isSubstitution;
|
||||
}
|
||||
|
||||
public class TodaySpecialAssignmentItem(string periodLabel, string description, string groupLabel)
|
||||
{
|
||||
public string PeriodLabel { get; } = periodLabel;
|
||||
public string Description { get; } = description;
|
||||
public string GroupLabel { get; } = groupLabel;
|
||||
public bool HasGroupLabel => !string.IsNullOrWhiteSpace(GroupLabel);
|
||||
public string DisplayText { get; } =
|
||||
$"{periodLabel} — {description}" + (string.IsNullOrWhiteSpace(groupLabel) ? "" : $" ({groupLabel})");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user