Fasst die sieben Kacheln, die tatsaechlich "wo muss ich reagieren" beantworten (Entschuldigungen, Fehlzeiten-Warnung, Foerderplan-Wiedervorlage, Korrekturen, ungeplante Stunden, Auffaelligkeiten, Unterrichtszeit-Nacherfassung), zu einer Karte "Handlungsbedarf" mit Filter-Chips zusammen statt sieben eigener Sichtbarkeits-Schalter. Neues gemeinsames Modell AttentionItem/AttentionGroup/AttentionAction traegt nur Anzeigedaten - die Datenbeschaffung bleibt unveraendert in den jeweiligen DashboardViewModel.LoadXxx-Methoden, die am Ende ein AttentionItem statt ihrer eigenen Item-Klasse erzeugen. RebuildAttention() gruppiert nach Art (feste Reihenfolge) und wendet Filter an, ohne die Repos erneut abzufragen. SupportPlanDueItem, CorrectionProgressItem, UnplannedLessonItem und DashboardAlertItem entfallen (nur dashboard-intern verwendet); OpenExcuseItem und AttendanceWarningItem bleiben bestehen, da GroupOverviewViewModel sie weiterhin nutzt. Fuenf Navigations-Commands wurden durch ein einziges OpenAttentionItemCommand ersetzt. Bewusste Verhaltensaenderung: LoadAlerts dupliziert Fehlzeiten-Ueberschreitungen nicht mehr in die Auffaelligkeiten-Gruppe, da dieselbe Zahl sonst zweimal in derselben Karte erschiene (vorher durch zwei getrennte Kacheln nicht sichtbar). Details und Testanpassungen siehe TODO.md, Abschnitt 9 (Dashboard).
107 lines
5.7 KiB
C#
107 lines
5.7 KiB
C#
using CommunityToolkit.Mvvm.ComponentModel;
|
||
using System.Windows.Input;
|
||
|
||
namespace LehrerApp.Desktop.ViewModels;
|
||
|
||
/// <summary>Die sieben Dashboard-Kacheln, die tatsächlich "wo muss ich reagieren" beantworten
|
||
/// (siehe <see cref="DashboardViewModel.AttentionCount"/>), zusammengefasst zu einer Karte mit
|
||
/// Filter-Chips statt sieben eigenen Sichtbarkeits-Schaltern. Reihenfolge hier ist die Reihenfolge
|
||
/// der Gruppen in der zusammengefassten Ansicht (siehe DashboardViewModel.RebuildAttention) — sie
|
||
/// übernimmt bewusst die frühere Sortierung aus DashboardSettingsService.DefaultCardOrder, damit
|
||
/// sich nichts, was Nutzer bereits kennen, unvorhersehbar umsortiert.
|
||
/// "Klausurwochen" (examload) bleibt bewusst außen vor: die Einträge dort sind Wochen-Aggregate,
|
||
/// keine Einzelvorgänge, die sich abhaken oder anklicken lassen — sie passen nicht ins Item-Modell.</summary>
|
||
public enum AttentionKind { MissingTeachingTime, Excuse, Correction, Unplanned, Alert, Attendance, SupportPlan }
|
||
|
||
/// <summary>Eine Inline-Aktion auf einem Handlungsbedarf-Eintrag (z.B. "Entschuldigt"/"Unentschuldigt",
|
||
/// "Erfassen"). Verwendet ICommand statt Action, damit die bereits vorhandenen generierten
|
||
/// RelayCommands (OpenExcuseItem.MarkExcusedCommand, DashboardViewModel.AddMissingTeachingTimeCommand)
|
||
/// direkt weiterverwendet werden können, statt sie in einen zweiten Delegate-Typ zu verpacken.</summary>
|
||
public sealed record AttentionAction(string Label, ICommand Command, object? Parameter = null);
|
||
|
||
/// <summary>Gemeinsame Projektion für die sieben Handlungsbedarf-Arten. Trägt nur Anzeigedaten —
|
||
/// die eigentliche Beschaffung bleibt unverändert in den jeweiligen DashboardViewModel.LoadXxx-
|
||
/// Methoden; sie erzeugen am Ende ein AttentionItem statt (wie vorher) ihre eigene Item-Klasse in
|
||
/// ihre eigene ObservableCollection einzutragen.</summary>
|
||
public sealed class AttentionItem
|
||
{
|
||
public AttentionKind Kind { get; }
|
||
public string Title { get; }
|
||
public string Subtitle { get; }
|
||
/// <summary>Kurztext rechts neben dem Titel — Fehlzeitenquote, Alert-Kind-Label. Meist leer.</summary>
|
||
public string TrailingText { get; }
|
||
public string DateDisplay { get; }
|
||
public bool IsOverdue { get; }
|
||
public AlertSeverity? Severity { get; }
|
||
/// <summary>Nur bei Korrekturen gesetzt (0–100); steuert die ProgressBar. Eigenes HasProgress statt
|
||
/// Nullability, damit die ProgressBar-Bindung ein einfaches int (kompatibel mit Value:double) bleibt.</summary>
|
||
public int ProgressPercent { get; }
|
||
public bool HasProgress { get; }
|
||
/// <summary>Text unter der ProgressBar, z.B. "3 von 5 Arbeiten bewertet". Nur bei Korrekturen gesetzt.</summary>
|
||
public string ProgressLabel { get; }
|
||
/// <summary>Färbt TrailingText wie die frühere Fehlzeiten-Warnung (fest "Foreground=Red") ein —
|
||
/// nur bei Attendance gesetzt, weil ein AttentionItem dieser Art per Konstruktion nur entsteht,
|
||
/// wenn die Fehlzeitenquote den Schwellenwert bereits überschreitet.</summary>
|
||
public bool IsWarningTrailing { get; }
|
||
public IReadOnlyList<AttentionAction> Actions { get; }
|
||
public Action? Navigate { get; }
|
||
|
||
public AttentionItem(AttentionKind kind, string title, string subtitle = "", string trailingText = "",
|
||
string dateDisplay = "", bool isOverdue = false, AlertSeverity? severity = null,
|
||
int progressPercent = 0, string progressLabel = "", bool hasProgress = false,
|
||
bool isWarningTrailing = false, IReadOnlyList<AttentionAction>? actions = null, Action? navigate = null)
|
||
{
|
||
Kind = kind;
|
||
Title = title;
|
||
Subtitle = subtitle;
|
||
TrailingText = trailingText;
|
||
DateDisplay = dateDisplay;
|
||
IsOverdue = isOverdue;
|
||
Severity = severity;
|
||
ProgressPercent = progressPercent;
|
||
ProgressLabel = progressLabel;
|
||
HasProgress = hasProgress;
|
||
IsWarningTrailing = isWarningTrailing;
|
||
Actions = actions ?? [];
|
||
Navigate = navigate;
|
||
}
|
||
|
||
public bool HasSubtitle => !string.IsNullOrWhiteSpace(Subtitle);
|
||
public bool HasTrailingText => !string.IsNullOrWhiteSpace(TrailingText);
|
||
public bool HasDate => !string.IsNullOrWhiteSpace(DateDisplay);
|
||
public bool HasActions => Actions.Count > 0;
|
||
public bool HasSeverity => Severity is not null;
|
||
public bool IsHighSeverity => Severity == AlertSeverity.High;
|
||
public bool IsMediumSeverity => Severity == AlertSeverity.Medium;
|
||
}
|
||
|
||
/// <summary>Eine Kind-Gruppe innerhalb der zusammengefassten Handlungsbedarf-Liste. Items behalten
|
||
/// die Sortierung, die ihre jeweilige LoadXxx-Methode schon immer produziert hat (z.B. Fehlzeiten
|
||
/// nach Quote absteigend, Korrekturen nach Datum) — ein zweites, generisches "Importance"-Sortieren
|
||
/// quer über alle Arten würde diese bewusst gewählten Reihenfolgen wieder zerstören.</summary>
|
||
public sealed class AttentionGroup(AttentionKind kind, string header, IReadOnlyList<AttentionItem> items)
|
||
{
|
||
public AttentionKind Kind { get; } = kind;
|
||
public string Header { get; } = header;
|
||
public IReadOnlyList<AttentionItem> Items { get; } = items;
|
||
public int Count => Items.Count;
|
||
}
|
||
|
||
/// <summary>Ein Filter-Chip für eine Handlungsbedarf-Art in der zusammengefassten Karte — ersetzt
|
||
/// die frühere Sichtbarkeit je Einzelkachel (siehe DashboardViewModel.LoadAttentionFilters).</summary>
|
||
public partial class AttentionFilterOption : ObservableObject
|
||
{
|
||
[ObservableProperty] private bool _isActive = true;
|
||
public AttentionKind Kind { get; }
|
||
public string Label { get; }
|
||
public Action? OnChanged { get; set; }
|
||
|
||
public AttentionFilterOption(AttentionKind kind, string label)
|
||
{
|
||
Kind = kind;
|
||
Label = label;
|
||
}
|
||
|
||
partial void OnIsActiveChanged(bool value) => OnChanged?.Invoke();
|
||
}
|