feat: Dunkelmodus, Fenstergröße merken, Papierkorb für Löschvorgänge (12.4, 14.3, 14.6)

Dunkelmodus über neuen Einstellungen-Tab "Darstellung" (Systemvorgabe/Hell/Dunkel),
Fenstergröße/Maximiert-Status wird über Sitzungen hinweg gemerkt (bewusst ohne
Fensterposition), und ein generischer Snapshot-basierter Papierkorb (30 Tage) für
Sitzpläne, Noten, Notenschlüssel-Vorlagen, Aufgaben und Zeiteinträge. Details und
bewusste Scope-Entscheidungen (Spaltenbreiten zurückgestellt, Farb-Audit für
Dunkelmodus offen, welche Entitäten der Papierkorb abdeckt) in TODO.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 16:26:10 +02:00
co-authored by Claude Sonnet 5
parent d9d007cd4b
commit 331033db5c
20 changed files with 1023 additions and 12 deletions
@@ -25,6 +25,9 @@ public interface ISeatingPlanRepository
List<SeatingPlan> GetByGroup(Guid groupId);
void Save(SeatingPlan plan);
void Delete(Guid id);
/// <summary>Stellt einen über <see cref="Delete"/> in den Papierkorb verschobenen Sitzplan
/// wieder her (14.3). Tut nichts, falls der Papierkorb-Eintrag nicht (mehr) existiert.</summary>
void Restore(Guid trashId);
}
public interface IGroupMembershipRepository
{
@@ -57,6 +60,8 @@ public interface IGradingKeyTemplateRepository
GradingKeyTemplate? GetById(Guid id);
void Save(GradingKeyTemplate template);
void Delete(Guid id);
/// <summary>Siehe ISeatingPlanRepository.Restore (14.3).</summary>
void Restore(Guid trashId);
}
public interface IGradeRepository
{
@@ -64,6 +69,8 @@ public interface IGradeRepository
List<Grade> GetByGroup(Guid groupId);
void Save(Grade grade);
void Delete(Guid id);
/// <summary>Siehe ISeatingPlanRepository.Restore (14.3).</summary>
void Restore(Guid trashId);
}
public interface IGradingSchemeRepository
{
@@ -138,6 +145,8 @@ public interface IWorkTaskRepository
List<WorkTask> GetAll();
void Save(WorkTask task);
void Delete(Guid id);
/// <summary>Siehe ISeatingPlanRepository.Restore (14.3).</summary>
void Restore(Guid trashId);
}
public interface ITimeEntryRepository
{
@@ -146,6 +155,8 @@ public interface ITimeEntryRepository
List<TimeEntry> GetByTask(Guid taskId);
void Save(TimeEntry entry);
void Delete(Guid id);
/// <summary>Siehe ISeatingPlanRepository.Restore (14.3).</summary>
void Restore(Guid trashId);
}
public interface IParticipationSessionRepository
{
@@ -209,3 +220,11 @@ public interface IAlternativeLessonPathRepository
void Save(AlternativeLessonPath path);
void Delete(Guid id);
}
/// <summary>Papierkorb (14.3) — reine Übersicht/Aufräumen; das eigentliche Wiederherstellen läuft
/// über die jeweilige Fach-Repository (z.B. IGradeRepository.Restore), da nur die kennt, wie ein
/// Schnappschuss ihres Modells korrekt gespeichert wird (Validierung, OnChange-Ereignis).</summary>
public interface ITrashRepository
{
List<TrashedItem> GetAll();
void PurgeOlderThan(DateTime cutoffUtc);
}
+21
View File
@@ -0,0 +1,21 @@
namespace LehrerApp.Core.Models;
/// <summary>
/// Papierkorb-Eintrag (14.3): ein gelöschter Datensatz, als vollständiger JSON-Schnappschuss
/// aufbewahrt, damit er wiederhergestellt werden kann. Deckt bewusst nur Löschvorgänge OHNE
/// Kaskade ab (z.B. eine einzelne Note, keine ganze Lerngruppe) — Details siehe
/// <c>LiteDbContext.MoveToTrash</c>/<c>RestoreFromTrash</c> und TODO.md 14.3.
/// </summary>
public class TrashedItem
{
public Guid Id { get; set; } = Guid.NewGuid();
/// <summary>Modellname (<c>nameof(Grade)</c> etc.) — bestimmt, wie der Schnappschuss beim
/// Wiederherstellen deserialisiert und welche Repository-Methode aufgerufen wird.</summary>
public string EntityType { get; set; } = "";
public Guid EntityId { get; set; }
/// <summary>Vollständiger JSON-Schnappschuss der gelöschten Entität.</summary>
public string Snapshot { get; set; } = "";
/// <summary>Kurze, für die Papierkorb-Liste lesbare Beschreibung (z.B. "Note 2 (12.09.2026)").</summary>
public string Summary { get; set; } = "";
public DateTime DeletedAt { get; set; } = DateTime.UtcNow;
}