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
+55 -4
View File
@@ -161,11 +161,18 @@ public class SeatingPlanRepository(LiteDbContext db) : ISeatingPlanRepository
public void Delete(Guid id)
{
if (db.SeatingPlans.FindById(id) is { } plan)
ArchivedGroupWriteGuard.EnsureActive(db, plan.GroupId);
if (db.SeatingPlans.FindById(id) is not { } plan) return;
ArchivedGroupWriteGuard.EnsureActive(db, plan.GroupId);
db.MoveToTrash(nameof(SeatingPlan), id, plan,
string.IsNullOrWhiteSpace(plan.Room) ? plan.Name : $"{plan.Name} (Raum {plan.Room})");
db.SeatingPlans.Delete(id);
db.OnChange?.Invoke(nameof(SeatingPlan), id.ToString(), "Delete", null);
}
public void Restore(Guid trashId)
{
if (db.RestoreFromTrash<SeatingPlan>(trashId) is { } plan) Save(plan);
}
}
public class GroupMembershipRepository(LiteDbContext db) : IGroupMembershipRepository
@@ -260,9 +267,16 @@ public class GradingKeyTemplateRepository(LiteDbContext db) : IGradingKeyTemplat
}
public void Delete(Guid id)
{
if (db.GradingKeyTemplates.FindById(id) is { } template)
db.MoveToTrash(nameof(GradingKeyTemplate), id, template, template.Name);
db.GradingKeyTemplates.Delete(id);
db.OnChange?.Invoke(nameof(GradingKeyTemplate), id.ToString(), "Delete", null);
}
public void Restore(Guid trashId)
{
if (db.RestoreFromTrash<GradingKeyTemplate>(trashId) is { } template) Save(template);
}
}
public class GradeRepository(LiteDbContext db) : IGradeRepository
@@ -279,11 +293,18 @@ public class GradeRepository(LiteDbContext db) : IGradeRepository
}
public void Delete(Guid id)
{
if (db.Grades.FindById(id) is { } grade)
ArchivedGroupWriteGuard.EnsureActive(db, grade.GroupId);
if (db.Grades.FindById(id) is not { } grade) return;
ArchivedGroupWriteGuard.EnsureActive(db, grade.GroupId);
db.MoveToTrash(nameof(Grade), id, grade,
$"Note {grade.Value} ({grade.Date:dd.MM.yyyy})");
db.Grades.Delete(id);
db.OnChange?.Invoke(nameof(Grade), id.ToString(), "Delete", null);
}
public void Restore(Guid trashId)
{
if (db.RestoreFromTrash<Grade>(trashId) is { } grade) Save(grade);
}
}
public class GradingSchemeRepository(LiteDbContext db) : IGradingSchemeRepository
@@ -421,9 +442,16 @@ public class WorkTaskRepository(LiteDbContext db) : IWorkTaskRepository
}
public void Delete(Guid id)
{
if (db.Tasks.FindById(id) is { } task)
db.MoveToTrash(nameof(WorkTask), id, task, task.Title);
db.Tasks.Delete(id);
db.OnChange?.Invoke(nameof(WorkTask), id.ToString(), "Delete", null);
}
public void Restore(Guid trashId)
{
if (db.RestoreFromTrash<WorkTask>(trashId) is { } task) Save(task);
}
}
public class TimeEntryRepository(LiteDbContext db) : ITimeEntryRepository
@@ -441,9 +469,17 @@ public class TimeEntryRepository(LiteDbContext db) : ITimeEntryRepository
}
public void Delete(Guid id)
{
if (db.TimeEntries.FindById(id) is { } entry)
db.MoveToTrash(nameof(TimeEntry), id, entry,
$"{entry.DurationMinutes} Min. {entry.Category} ({entry.Date:dd.MM.yyyy})");
db.TimeEntries.Delete(id);
db.OnChange?.Invoke(nameof(TimeEntry), id.ToString(), "Delete", null);
}
public void Restore(Guid trashId)
{
if (db.RestoreFromTrash<TimeEntry>(trashId) is { } entry) Save(entry);
}
}
public class ParticipationSessionRepository(LiteDbContext db) : IParticipationSessionRepository
@@ -764,3 +800,18 @@ public class CompetencyDomainRepository(LiteDbContext db) : ICompetencyDomainRep
});
}
}
/// <summary>Papierkorb (14.3) — bewusst nicht sync-fähig: TrashedItem wird nie über
/// db.OnChange gemeldet, bleibt also rein lokal auf dem Gerät, auf dem gelöscht wurde. Ein
/// "Fehlklick sofort rückgängig machen"-Werkzeug, kein geräteübergreifendes Archiv.</summary>
public class TrashRepository(LiteDbContext db) : ITrashRepository
{
public List<TrashedItem> GetAll() =>
db.TrashedItems.FindAll().OrderByDescending(t => t.DeletedAt).ToList();
public void PurgeOlderThan(DateTime cutoffUtc)
{
foreach (var item in db.TrashedItems.Find(t => t.DeletedAt < cutoffUtc).ToList())
db.TrashedItems.Delete(item.Id);
}
}