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
+181
View File
@@ -0,0 +1,181 @@
using LehrerApp.Core.Models;
using LehrerApp.Data.Repositories;
using Xunit;
namespace LehrerApp.Data.Tests;
public sealed class TrashTests
{
private static LiteDbContext NewInMemoryContext() => new(new MemoryStream());
[Fact]
public void GradeRepository_DeleteVerschiebtInDenPapierkorbUndRestoreStelltWiederHer()
{
using var db = NewInMemoryContext();
var group = new LearningGroup { Name = "8a", SchoolYear = "2025/26" };
new GroupRepository(db).Save(group);
var student = new Student { FirstName = "Anna", LastName = "A" };
db.Students.Insert(student);
var repo = new GradeRepository(db);
var grade = new Grade
{
StudentId = student.Id, GroupId = group.Id, Category = GradeCategory.Oral,
Value = "2", Date = new DateOnly(2026, 3, 4),
};
repo.Save(grade);
repo.Delete(grade.Id);
Assert.Null(db.Grades.FindById(grade.Id));
var trashed = db.TrashedItems.FindAll().Single();
Assert.Equal(nameof(Grade), trashed.EntityType);
Assert.Equal("Note 2 (04.03.2026)", trashed.Summary);
repo.Restore(trashed.Id);
var restored = db.Grades.FindById(grade.Id);
Assert.NotNull(restored);
Assert.Equal("2", restored!.Value);
Assert.Empty(db.TrashedItems.FindAll());
}
[Fact]
public void GradeRepository_RestoreMitUnbekannterTrashIdTutNichts()
{
using var db = NewInMemoryContext();
var repo = new GradeRepository(db);
repo.Restore(Guid.NewGuid());
Assert.Empty(db.Grades.FindAll());
}
[Fact]
public void WorkTaskRepository_DeleteVerschiebtInDenPapierkorbUndRestoreStelltWiederHer()
{
using var db = NewInMemoryContext();
var repo = new WorkTaskRepository(db);
var task = new WorkTask { Title = "Elternbrief schreiben", Category = TaskCategory.Admin };
repo.Save(task);
repo.Delete(task.Id);
Assert.Null(db.Tasks.FindById(task.Id));
Assert.Equal("Elternbrief schreiben", db.TrashedItems.FindAll().Single().Summary);
repo.Restore(db.TrashedItems.FindAll().Single().Id);
Assert.NotNull(db.Tasks.FindById(task.Id));
}
[Fact]
public void TimeEntryRepository_DeleteVerschiebtInDenPapierkorbUndRestoreStelltWiederHer()
{
using var db = NewInMemoryContext();
var repo = new TimeEntryRepository(db);
var entry = new TimeEntry { Category = "Korrektur", Date = new DateOnly(2026, 3, 4), DurationMinutes = 45 };
repo.Save(entry);
repo.Delete(entry.Id);
Assert.Null(db.TimeEntries.FindById(entry.Id));
Assert.Equal("45 Min. Korrektur (04.03.2026)", db.TrashedItems.FindAll().Single().Summary);
repo.Restore(db.TrashedItems.FindAll().Single().Id);
Assert.NotNull(db.TimeEntries.FindById(entry.Id));
}
[Fact]
public void SeatingPlanRepository_DeleteVerschiebtInDenPapierkorbUndRestoreStelltWiederHer()
{
using var db = NewInMemoryContext();
var group = new LearningGroup { Name = "8a", SchoolYear = "2025/26" };
new GroupRepository(db).Save(group);
var repo = new SeatingPlanRepository(db);
var plan = new SeatingPlan { GroupId = group.Id, Name = "Standard", Room = "B204", Rows = 2, Columns = 2 };
repo.Save(plan);
repo.Delete(plan.Id);
Assert.Null(db.SeatingPlans.FindById(plan.Id));
Assert.Equal("Standard (Raum B204)", db.TrashedItems.FindAll().Single().Summary);
repo.Restore(db.TrashedItems.FindAll().Single().Id);
Assert.NotNull(db.SeatingPlans.FindById(plan.Id));
}
[Fact]
public void SeatingPlanRepository_DeleteOhneRaumNutztNurDenNamenAlsSummary()
{
using var db = NewInMemoryContext();
var group = new LearningGroup { Name = "8a", SchoolYear = "2025/26" };
new GroupRepository(db).Save(group);
var repo = new SeatingPlanRepository(db);
var plan = new SeatingPlan { GroupId = group.Id, Name = "Standard", Rows = 2, Columns = 2 };
repo.Save(plan);
repo.Delete(plan.Id);
Assert.Equal("Standard", db.TrashedItems.FindAll().Single().Summary);
}
[Fact]
public void GradingKeyTemplateRepository_DeleteVerschiebtInDenPapierkorbUndRestoreStelltWiederHer()
{
using var db = NewInMemoryContext();
var repo = new GradingKeyTemplateRepository(db);
var template = new GradingKeyTemplate { Name = "Standard 1-6", GradingSystem = GradingSystem.Grades1To6 };
repo.Save(template);
repo.Delete(template.Id);
Assert.Null(db.GradingKeyTemplates.FindById(template.Id));
Assert.Equal("Standard 1-6", db.TrashedItems.FindAll().Single().Summary);
repo.Restore(db.TrashedItems.FindAll().Single().Id);
Assert.NotNull(db.GradingKeyTemplates.FindById(template.Id));
}
[Fact]
public void TrashRepository_GetAllSortiertNeuesteZuerst()
{
using var db = NewInMemoryContext();
db.TrashedItems.Insert(new TrashedItem
{
EntityType = nameof(WorkTask), Summary = "Älter", DeletedAt = DateTime.UtcNow.AddDays(-2),
});
db.TrashedItems.Insert(new TrashedItem
{
EntityType = nameof(WorkTask), Summary = "Neuer", DeletedAt = DateTime.UtcNow,
});
var all = new TrashRepository(db).GetAll();
Assert.Equal(2, all.Count);
Assert.Equal("Neuer", all[0].Summary);
Assert.Equal("Älter", all[1].Summary);
}
[Fact]
public void TrashRepository_PurgeOlderThanEntferntNurAeltereEintraege()
{
using var db = NewInMemoryContext();
db.TrashedItems.Insert(new TrashedItem
{
EntityType = nameof(WorkTask), Summary = "Alt", DeletedAt = DateTime.UtcNow.AddDays(-40),
});
db.TrashedItems.Insert(new TrashedItem
{
EntityType = nameof(WorkTask), Summary = "Frisch", DeletedAt = DateTime.UtcNow,
});
new TrashRepository(db).PurgeOlderThan(DateTime.UtcNow.AddDays(-30));
var remaining = db.TrashedItems.FindAll().ToList();
Assert.Single(remaining);
Assert.Equal("Frisch", remaining[0].Summary);
}
}