feat: Sitzungsfreigabe für MCP-Bestätigungen + LessonStatus.Cancelled

Sitzungsfreigabe: McpConfirmDialog bietet zwei Checkboxen ("diese Art
von Aktion" / "alle KI-Aktionen für den Rest der Sitzung nicht mehr
nachfragen"), nur beim Bestätigen wirksam. IMcpConfirmationService.
ConfirmAsync bekommt einen per [CallerMemberName] automatisch
befüllten operationKey - kein bestehender Aufruf musste geändert
werden. Freigaben leben als In-Memory-Bookkeeping auf der
Confirmation-Service-Instanz, gelten bis App-Ende, werden aber trotzdem
geloggt, damit stillschweigende Bestätigungen nicht spurlos bleiben.
Grund: 17 identische Bestätigungen in Folge für eine neu generierte
Unterrichtseinheit sind unzumutbar.

LessonStatus.Cancelled ("Ausgefallen") als Alternative zu
delete_lesson für Stunden, die nur ausgefallen sind (Exkursion,
Feiertag), aber als Ereignis dokumentiert bleiben sollen. Als
Cancelled=4 angehängt (bestehende LiteDB-Werte 0/1 sind fix). Konsistent
wie "bereits durchgeführt" behandelt an allen Stellen, die bisher nur
auf Conducted prüften: Terminverschiebung, Fortschrittsanzeige,
Hausaufgabe-kontrollieren-Erinnerung, "nächste Stunde"-Vorschlag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-12 02:25:45 +02:00
co-authored by Claude Sonnet 5
parent a4733c156b
commit 19aa302487
16 changed files with 231 additions and 25 deletions
@@ -376,7 +376,7 @@ public partial class PlanningTabViewModel : ObservableObject
[RelayCommand(CanExecute = nameof(HasSelectedLesson))]
private void AdvanceLessonStatus()
{
if (SelectedLesson is null || SelectedLesson.Model.Status == LessonStatus.Conducted) return;
if (SelectedLesson is null || SelectedLesson.Model.Status is LessonStatus.Conducted or LessonStatus.Cancelled) return;
var lesson = SelectedLesson.Model;
lesson.Status = lesson.Status == LessonStatus.Ready
? LessonStatus.Conducted
@@ -467,8 +467,11 @@ public class UnitSummary
};
CompetencyCountLabel = u.Competencies.Count == 0 ? "" : $"{u.Competencies.Count} Kompetenz(en)";
TotalCount = lessons.Count;
ConductedCount = lessons.Count(l => l.Status == LessonStatus.Conducted);
// Ausgefallene Stunden zählen weder als gehalten noch als noch zu haltendes Pensum -
// sie fallen komplett aus dem Fortschritt heraus, statt den Nenner künstlich zu erhöhen.
var countableLessons = lessons.Where(l => l.Status != LessonStatus.Cancelled).ToList();
TotalCount = countableLessons.Count;
ConductedCount = countableLessons.Count(l => l.Status == LessonStatus.Conducted);
ProgressFraction = TotalCount == 0 ? 0 : (double)ConductedCount / TotalCount;
ProgressText = TotalCount == 0 ? "Keine Stunden" : $"{ConductedCount} / {TotalCount} Stunden gehalten";
}
@@ -507,6 +510,7 @@ public class LessonSummary
LessonStatus.Draft => "#78909C",
LessonStatus.Ready => "#1976D2",
LessonStatus.Conducted => "#43A047",
LessonStatus.Cancelled => "#C62828",
_ => "#9E9E9E",
};
PhaseCountLabel = l.Phases.Count == 0 ? "" : $"{l.Phases.Count} Phasen";
@@ -543,13 +547,14 @@ public static class UnitStatusDisplay
public static class LessonStatusDisplay
{
public static string[] Options { get; } = ["Entwurf", "Geplant", "Bereit", "Durchgeführt"];
public static string[] Options { get; } = ["Entwurf", "Geplant", "Bereit", "Durchgeführt", "Ausgefallen"];
public static string ToName(LessonStatus s) => s switch
{
LessonStatus.Draft => "Entwurf",
LessonStatus.Ready => "Bereit",
LessonStatus.Conducted => "Durchgeführt",
LessonStatus.Cancelled => "Ausgefallen",
_ => "Geplant",
};
@@ -558,6 +563,7 @@ public static class LessonStatusDisplay
"Entwurf" => LessonStatus.Draft,
"Bereit" => LessonStatus.Ready,
"Durchgeführt" => LessonStatus.Conducted,
"Ausgefallen" => LessonStatus.Cancelled,
_ => LessonStatus.Planned,
};
}