Klausurtermine im Kalender (4.4.3) + Stundenplan: Ausnahme eintragen, Zahnrad-Settings-Link

- 4.4.3: Box "ANSTEHENDE KLAUSUREN" im Heute-Tab, gruppenübergreifend, nächste 21 Tage.
  IExamRepository um GetAll() erweitert.
- Nutzer-Feedback: "Vertretung eintragen" deckt auch Ausfall/Sondereinsatz ab, daher
  umbenannt in "Ausnahme eintragen". "Stundenplan bearbeiten" (redundant zum Bearbeiten-Tab)
  ersetzt durch Zahnrad-Button, der direkt in die Einstellungen springt.
This commit is contained in:
2026-08-15 22:24:04 +02:00
parent d6dee72acc
commit 0800832ae5
13 changed files with 189 additions and 21 deletions
@@ -67,6 +67,7 @@ public partial class TimetableViewModel : ObservableObject
public ObservableCollection<TodayLessonItem> TodayItems { get; } = [];
public ObservableCollection<TodaySupervisionItem> TodaySupervisions { get; } = [];
public ObservableCollection<TodaySpecialAssignmentItem> TodaySpecialAssignments { get; } = [];
public ObservableCollection<UpcomingExamItem> UpcomingExams { get; } = [];
[ObservableProperty] private int _activeTabIndex;
[ObservableProperty] private string _todayLabel = "";
@@ -77,6 +78,7 @@ 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 Action? OnNavigateToSettings { get; set; }
public TimetableViewModel(ITimetableSlotRepository slots, IGroupRepository groups,
ISubjectRepository subjects, ILessonRepository lessons, IExamRepository exams,
@@ -127,6 +129,31 @@ public partial class TimetableViewModel : ObservableObject
BuildWeekOverview(today, publicHolidayDates, duties);
BuildToday(today);
BuildHoursWarnings();
BuildUpcomingExams(today);
}
// ── Anstehende Klausurtermine (4.4.3) ────────────────────────────────────
/// <summary>
/// Mehrtägiger Vorausblick über alle Gruppen hinweg (nicht nur "heute", wie die Tagesliste,
/// und unabhängig von <see cref="WeekOffset"/>, anders als das Wochenraster) — Abgabefristen
/// sind bewusst nicht enthalten, dafür gibt es noch kein eigenes Datenmodell (siehe TODO.md).
/// </summary>
private const int UpcomingExamsHorizonDays = 21;
private void BuildUpcomingExams(DateOnly today)
{
UpcomingExams.Clear();
var groupNames = _groups.GetAll(includeInactive: true).ToDictionary(g => g.Id, g => g.Name);
var horizon = today.AddDays(UpcomingExamsHorizonDays);
var upcoming = _exams.GetAll()
.Where(e => e.Date >= today && e.Date <= horizon)
.OrderBy(e => e.Date)
.Take(10);
foreach (var exam in upcoming)
UpcomingExams.Add(new UpcomingExamItem(exam.Date, groupNames.GetValueOrDefault(exam.GroupId, "?"), exam.Title));
}
// ── "Heute": Tagesliste ──────────────────────────────────────────────────
@@ -207,7 +234,7 @@ public partial class TimetableViewModel : ObservableObject
}
[RelayCommand]
private void ShowEditor() => ActiveTabIndex = 1;
private void OpenSettings() => OnNavigateToSettings?.Invoke();
// ── "Heute": Wochenraster (Nutzer-Feedback) — wie das Bearbeiten-Raster, aber nur Anzeige ──
@@ -649,6 +676,14 @@ public class HoursWarningItem(string groupName, int assigned, int expected)
public string Text { get; } = $"{groupName}: {assigned} von {expected} Wochenstunden eingetragen";
}
public class UpcomingExamItem(DateOnly date, string groupName, string title)
{
public DateOnly Date { get; } = date;
public string DateDisplay { get; } = date.ToString("dd.MM.yyyy");
public string GroupName { get; } = groupName;
public string Title { get; } = title;
}
public class TodayLessonItem
{
public Guid GroupId { get; private init; }