- Dashboard: Fehlzeiten-Warnung lädt Mitarbeitssitzungen einmal vorab statt pro Schüler/Eintrag einzeln nachzuschlagen (N+1 vermieden); neues IParticipationSessionRepository.GetAll() dafür. - CI: .gitea/workflows/ci.yml baut und testet bei jedem Push/PR. Dabei fehlende Release|Any CPU-Konfiguration für 6 Projekte in der .sln behoben (LehrerApp.Data.Tests wurde bei Release-Builds der Solution bislang stillschweigend übersprungen). TreatWarningsAsErrors jetzt aktiv. - SettingsViewModel (1986 Zeilen) als partial class auf 20 Themen- dateien aufgeteilt, Verhalten unverändert. - Backup: optionaler zweiter Sicherungsordner (USB-Stick/Netzlaufwerk, best-effort) und Integritätsprüfung nach jedem Backup (DatabaseEncryptionService.CanOpenAndRead). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
115 lines
4.3 KiB
C#
115 lines
4.3 KiB
C#
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
|
|
{
|
|
// ── Word-Briefvorlagen (7.1.4 / 11.5) ───────────────────────────────────
|
|
|
|
[ObservableProperty] private string _letterTemplateStatus = "";
|
|
public ObservableCollection<LetterTemplateListItem> LetterTemplateList { get; } = [];
|
|
public IReadOnlyList<LetterPlaceholder> SupportedLetterPlaceholders =>
|
|
LetterTemplateService.SupportedPlaceholders;
|
|
|
|
// ── Word-Briefvorlagen: Import und Validierung ──────────────────────────
|
|
|
|
private void LoadLetterTemplates()
|
|
{
|
|
LetterTemplateList.Clear();
|
|
foreach (var template in _letterTemplates.GetTemplates())
|
|
LetterTemplateList.Add(new LetterTemplateListItem(template, _letterTemplates.Validate(template)));
|
|
}
|
|
|
|
public void ImportLetterTemplate(string path)
|
|
{
|
|
LetterTemplateStatus = "";
|
|
try
|
|
{
|
|
var template = _letterTemplates.Import(path);
|
|
var validation = _letterTemplates.Validate(template);
|
|
LoadLetterTemplates();
|
|
LetterTemplateStatus = validation.Issues.Count == 0
|
|
? "Vorlage importiert und ohne Auffälligkeiten geprüft."
|
|
: $"Vorlage importiert. Die Prüfung meldet {validation.Issues.Count} Hinweis(e).";
|
|
}
|
|
catch (Exception ex) when (ex is IOException or InvalidDataException or UnauthorizedAccessException)
|
|
{
|
|
LetterTemplateStatus = $"Import fehlgeschlagen: {ex.Message}";
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void ValidateLetterTemplate(LetterTemplateListItem? item)
|
|
{
|
|
if (item is null) return;
|
|
var index = LetterTemplateList.IndexOf(item);
|
|
var refreshed = new LetterTemplateListItem(item.Model, _letterTemplates.Validate(item.Model));
|
|
if (index >= 0) LetterTemplateList[index] = refreshed;
|
|
LetterTemplateStatus = refreshed.Validation.Issues.Count == 0
|
|
? $"„{item.Name}“ ist ohne Auffälligkeiten."
|
|
: $"„{item.Name}“: {refreshed.Validation.Issues.Count} Hinweis(e).";
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void DeleteLetterTemplate(LetterTemplateListItem? item)
|
|
{
|
|
if (item is null) return;
|
|
_letterTemplates.Delete(item.Id);
|
|
LetterTemplateList.Remove(item);
|
|
LetterTemplateStatus = "Vorlage gelöscht.";
|
|
}
|
|
}
|
|
|
|
public sealed class LetterTemplateListItem
|
|
{
|
|
public LetterTemplateInfo Model { get; }
|
|
public TemplateValidationResult Validation { get; }
|
|
public Guid Id => Model.Id;
|
|
public string Name => Model.Name;
|
|
public string OriginalFileName => Model.OriginalFileName;
|
|
public bool HasIssues => Validation.Issues.Count > 0;
|
|
public bool HasNoIssues => !HasIssues;
|
|
public string ValidationSummary => HasNoIssues
|
|
? $"{Validation.Tags.Count} Feld(er) · keine Auffälligkeiten"
|
|
: $"{Validation.Tags.Count} Feld(er) · {Validation.Issues.Count} Hinweis(e)";
|
|
public ObservableCollection<LetterTemplateIssueItem> Issues { get; }
|
|
|
|
public LetterTemplateListItem(LetterTemplateInfo model, TemplateValidationResult validation)
|
|
{
|
|
Model = model;
|
|
Validation = validation;
|
|
Issues = new(validation.Issues.Select(i => new LetterTemplateIssueItem(i)));
|
|
}
|
|
}
|
|
|
|
public sealed class LetterTemplateIssueItem(TemplateValidationIssue issue)
|
|
{
|
|
public string Icon => issue.Severity switch
|
|
{
|
|
TemplateIssueSeverity.Error => "⛔",
|
|
TemplateIssueSeverity.StrongWarning => "⚠",
|
|
_ => "ⓘ",
|
|
};
|
|
public string Message => issue.Message;
|
|
public string Color => issue.Severity switch
|
|
{
|
|
TemplateIssueSeverity.Error => "#DC2626",
|
|
TemplateIssueSeverity.StrongWarning => "#D97706",
|
|
_ => "#6B7280",
|
|
};
|
|
}
|