using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using LehrerApp.Core.Interfaces; using LehrerApp.Core.Models; using LehrerApp.Core.Services; using LehrerApp.Data; using LehrerApp.Desktop.Services; using LehrerApp.Desktop.ViewModels.Planning; using LehrerApp.Sync; using LehrerApp.Sync.Crypto; using System.Collections.ObjectModel; using System.Globalization; using System.Security.Cryptography; using System.Text.Json; using System.Text.Json.Serialization; namespace LehrerApp.Desktop.ViewModels.Settings; public partial class SettingsViewModel { // ── Notenschlüssel-Vorlagen (1.3.2) ────────────────────────────────────── [ObservableProperty] private string _newTemplateName = ""; [ObservableProperty] private string _newTemplateGradingSystemName = "Noten 1–6"; [ObservableProperty] private string _newTemplateNameError = ""; public List GradingSystemOptions { get; } = ["Noten 1–6", "Punkte 0–15"]; public ObservableCollection GradingKeyTemplateList { get; } = []; // ── Notenschlüssel-Vorlagen: Laden / Hinzufügen / Löschen ──────────────── private void LoadGradingKeyTemplates() { GradingKeyTemplateList.Clear(); foreach (var t in _gradingKeyTemplates.GetAll()) GradingKeyTemplateList.Add(new GradingKeyTemplateEditItem(t, _gradingKeyTemplates, _grading)); } [RelayCommand] private void AddGradingKeyTemplate() { if (string.IsNullOrWhiteSpace(NewTemplateName)) { NewTemplateNameError = "Vorlagenname erforderlich."; return; } var system = NewTemplateGradingSystemName == "Punkte 0–15" ? GradingSystem.Points0To15 : GradingSystem.Grades1To6; var defaults = system == GradingSystem.Grades1To6 ? GradingService.DefaultKey1To6() : GradingService.DefaultKey0To15(); var template = new GradingKeyTemplate { Name = NewTemplateName.Trim(), GradingSystem = system, Entries = defaults.Select(e => new GradingKeyEntry { Grade = e.Grade, MinPercent = e.MinPercent }).ToList(), }; _gradingKeyTemplates.Save(template); GradingKeyTemplateList.Add(new GradingKeyTemplateEditItem(template, _gradingKeyTemplates, _grading)); NewTemplateName = ""; NewTemplateNameError = ""; } [RelayCommand] private void DeleteGradingKeyTemplate(GradingKeyTemplateEditItem? item) { if (item is null) return; _gradingKeyTemplates.Delete(item.Id); GradingKeyTemplateList.Remove(item); } } public partial class GradingKeyTemplateEditItem : ObservableObject { private readonly GradingKeyTemplate _template; private readonly IGradingKeyTemplateRepository _repo; private readonly GradingService _grading; public Guid Id { get; } public string Name { get; } public string GradingSystemLabel { get; } [ObservableProperty] private string _newGrade = ""; [ObservableProperty] private double _newMinPercent; [ObservableProperty] private string _newGradeError = ""; [ObservableProperty] private string _newMinPercentError = ""; [ObservableProperty] private string _completenessWarning = ""; public ObservableCollection Entries { get; } = []; public GradingKeyTemplateEditItem(GradingKeyTemplate template, IGradingKeyTemplateRepository repo, GradingService grading) { _template = template; _repo = repo; _grading = grading; Id = template.Id; Name = template.Name; GradingSystemLabel = template.GradingSystem == GradingSystem.Grades1To6 ? "Noten 1–6" : "Punkte 0–15"; foreach (var e in template.Entries.OrderByDescending(e => e.MinPercent)) Entries.Add(new GradingKeyEntryVm(e, DeleteEntry)); RecomputeCompleteness(); } [RelayCommand] private void AddEntry() { NewGradeError = ""; NewMinPercentError = ""; var valid = true; if (string.IsNullOrWhiteSpace(NewGrade)) { NewGradeError = "Bezeichnung erforderlich."; valid = false; } if (NewMinPercent is < 0 or > 100) { NewMinPercentError = "Muss zwischen 0 und 100 liegen."; valid = false; } else if (_template.Entries.Any(e => Math.Abs(e.MinPercent - NewMinPercent) < 0.0001)) { NewMinPercentError = "Diese Prozentgrenze existiert bereits."; valid = false; } if (!valid) return; var entry = new GradingKeyEntry { Grade = NewGrade.Trim(), MinPercent = NewMinPercent }; _template.Entries.Add(entry); _template.Entries = _template.Entries.OrderByDescending(e => e.MinPercent).ToList(); _repo.Save(_template); Entries.Clear(); foreach (var e in _template.Entries) Entries.Add(new GradingKeyEntryVm(e, DeleteEntry)); NewGrade = ""; NewMinPercent = 0; RecomputeCompleteness(); } private void DeleteEntry(GradingKeyEntryVm vm) { _template.Entries.RemoveAll(e => e.Grade == vm.Grade && Math.Abs(e.MinPercent - vm.MinPercent) < 0.0001); _repo.Save(_template); Entries.Remove(vm); RecomputeCompleteness(); } private void RecomputeCompleteness() => CompletenessWarning = _grading.ValidateGradingKey(_template.Entries) ?? ""; } // ── GradingKeyEntryVm ───────────────────────────────────────────────────────── public class GradingKeyEntryVm { public string Grade { get; } public double MinPercent { get; } public string Display { get; } public IRelayCommand DeleteCommand { get; } public GradingKeyEntryVm(GradingKeyEntry e, Action onDelete) { Grade = e.Grade; MinPercent = e.MinPercent; Display = $"{Grade} — ab {MinPercent.ToString("0.##")} %"; DeleteCommand = new RelayCommand(() => onDelete(this)); } }