fix: Klassenlehrer-Übersicht rief Schülerreport bislang live statt gecacht ab

Die Übersicht wirkte beim Öffnen spürbar zeitverzögert, obwohl Fehlzeiten
und Klassenbuch schon lokal gecacht waren (Nutzer-Feedback: "fühlt sich an
wie ein Live-Pull mit CSV-Parsing"). Grund: genau das passierte - der
Schülerreport (Namen fürs Roster) lief komplett am Cache vorbei bei jedem
Öffnen live gegen WebUntis.

Neues UntisStudentRosterCacheEntry/UntisStudentRosterCacheRepository
(gleiches "kein db.OnChange"-Prinzip wie die bestehenden Caches) plus
UntisReportCacheService.GetStudentRosterAsync - ohne heißes/kaltes Fenster,
da eine Klassenliste keine Historie hat, nur dieselbe Stundenschwelle
"gilt der letzte Abruf noch als frisch".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-26 22:18:53 +02:00
co-authored by Claude Sonnet 5
parent 69cc16bbd2
commit 0c8bb58e1b
12 changed files with 149 additions and 14 deletions
@@ -1,6 +1,7 @@
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LehrerApp.Core.Models;
using LehrerApp.Desktop.Services;
namespace LehrerApp.Desktop.ViewModels.ClassTeacher;
@@ -22,7 +23,7 @@ public sealed record ClassTeacherRosterRow(string StudentName, int? ExternKey, b
/// (siehe UntisForeignClassRegisterEventDto) — WebUntis liefert Namen dort in anderer
/// Reihenfolge als im Schülerreport.</summary>
public static IReadOnlyList<ClassTeacherRosterRow> Build(
IReadOnlyList<UntisStudentDto> students,
IReadOnlyList<UntisStudentRosterCacheEntry> students,
IReadOnlyList<ClassAbsenceDaySummaryRow> todayAbsences,
IReadOnlyList<UntisForeignClassRegisterEventDto> recentClassRegisterEntries)
{
@@ -64,7 +65,6 @@ public sealed record ClassTeacherRosterRow(string StudentName, int? ExternKey, b
public partial class ClassTeacherOverviewViewModel : ObservableObject
{
private readonly WebUntisSettingsService _settings;
private readonly WebUntisIntegrationService _untis;
private readonly UntisReportCacheService _cache;
public ClassTeacherDetailsViewModel DetailsTab { get; }
@@ -81,10 +81,10 @@ public partial class ClassTeacherOverviewViewModel : ObservableObject
/// keine Klasse gewählt ist.
public Func<Task>? OnNavigateToSettings { get; set; }
public ClassTeacherOverviewViewModel(WebUntisSettingsService settings, WebUntisIntegrationService untis,
public ClassTeacherOverviewViewModel(WebUntisSettingsService settings,
UntisReportCacheService cache, ClassTeacherDetailsViewModel detailsTab)
{
_settings = settings; _untis = untis; _cache = cache; DetailsTab = detailsTab;
_settings = settings; _cache = cache; DetailsTab = detailsTab;
}
partial void OnHomeroomClassNameChanged(string? value) => OnPropertyChanged(nameof(HomeroomClassConfigured));
@@ -107,13 +107,13 @@ public partial class ClassTeacherOverviewViewModel : ObservableObject
try
{
var today = DateOnly.FromDateTime(DateTime.Today);
var studentsTask = _untis.GetStudentsAsync(className);
var studentsTask = _cache.GetStudentRosterAsync(className);
var absencesTask = _cache.GetAbsencesAsync(className, today, today);
var classRegisterTask = _cache.GetClassRegisterEventsAsync(className, today.AddDays(-7), today);
await Task.WhenAll(studentsTask, absencesTask, classRegisterTask);
var todayAbsences = ClassAbsenceDaySummaryRow.GroupByStudentAndDay(absencesTask.Result);
foreach (var row in ClassTeacherRosterRow.Build(studentsTask.Result.Students, todayAbsences,
foreach (var row in ClassTeacherRosterRow.Build(studentsTask.Result, todayAbsences,
classRegisterTask.Result))
Roster.Add(row);
Status = $"{Roster.Count} Schüler*innen · Stand heute.";