Files
LehrerApp/LehrerApp.Desktop/ViewModels/Settings/SettingsViewModel.cs
T
adminandClaude Sonnet 5 55fba2cadb feat: lokaler MCP-Server, Phase 4 (Elternbrief-Vorlagen + Claude-Desktop-Registrierung)
Schließt die MCP-Server-Spec ab. "Worksheets" aus der Spec entsprechen
im tatsächlichen Datenmodell den .lavorlage-Elternbrief-Vorlagen
(LehrerApp.Templating) - es gibt kein separates Arbeitsblatt-Konzept mit
Fach/Klassenstufe-Metadaten. Neue Tools list_letter_templates (Read) und
render_letter (Read, liefert Base64-PDF, kein DB-Schreibzugriff).

upload_worksheet/update_worksheet bewusst nicht umgesetzt: das
Seitenlayout ist eine eigene positionsbasierte DSL mit eigenem
visuellen Editor (LehrerApp.TemplateDesigner) - ein LLM müsste sie
blind erzeugen, mit hohem Risiko für kaputte Layouts. Platzhalter-Logik
aus CreateLetterDialogViewModel nach LetterPlaceholderBuilder extrahiert,
damit Dialog und MCP-Tool nicht auseinanderdriften.

Neuer McpClientRegistrationService trägt den Bridge-Pfad in Claude
Desktops claude_desktop_config.json ein (Button in den Einstellungen,
nie automatisch), ohne bestehende Fremdeinträge zu verlieren und ohne
eine nicht lesbare Konfigurationsdatei zu überschreiben.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 22:53:46 +02:00

182 lines
7.8 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;
using LehrerApp.Templating;
namespace LehrerApp.Desktop.ViewModels.Settings;
/// <summary>
/// Reihenfolge MUSS exakt der Reihenfolge der ContentPage-Elemente in SettingsView.axaml
/// entsprechen (ActiveTabIndex bindet per Index, nicht per Name) — beim Umsortieren eines
/// Tabs in der XAML immer auch hier den Enum-Wert verschieben.
/// </summary>
public enum SettingsTab
{
Subjects = 0,
ShorthandCodes = 1,
Competencies = 2,
GradingKeyTemplates = 3,
GradingScheme = 4,
LetterTemplates = 5,
Holidays = 6,
PeriodSchedule = 7,
SupervisionDuties = 8,
Security = 9,
Privacy = 10,
Sync = 11,
Ai = 12,
WebUntis = 13,
Appearance = 14,
Trash = 15,
Mcp = 16,
}
// ── Haupt-ViewModel ───────────────────────────────────────────────────────────
public partial class SettingsViewModel : ObservableObject
{
private readonly ISubjectRepository _subjects;
private readonly ICompetencyDomainRepository _domainRepo;
private readonly IGradingKeyTemplateRepository _gradingKeyTemplates;
private readonly IGradingSchemeRepository _gradingSchemes;
private readonly GradingService _grading;
private readonly BackupService _backups;
private readonly BackupSettingsService _backupSettings;
private readonly DatabaseEncryptionService _dbEncryption;
private readonly AppLockService _appLock;
private readonly LiteDbContext _dbContext;
private readonly PrivacySettingsService _privacy;
private readonly IDocumentationRepository _documentation;
private readonly IStudentRepository _students;
private readonly IShorthandCodeRepository _shorthandCodes;
private readonly TemplateStore _letterTemplates;
[ObservableProperty] private int _activeTabIndex;
// ── Konstruktor ───────────────────────────────────────────────────────────
private readonly ISchoolHolidayRepository _schoolHolidays;
private readonly SchoolCalendarSettingsService _calendarSettings;
private readonly SchoolWeatherService? _schoolWeather;
private readonly PeriodScheduleService _periodSchedule;
private readonly ISupervisionDutyRepository _supervisionDuties;
private readonly AiSettingsService _aiSettings;
private readonly AiPlanningService _aiPlanning;
private readonly McpSettingsService _mcpSettings;
private readonly Services.Mcp.McpClientRegistrationService _mcpRegistration;
private readonly WebUntisSettingsService _untisSettings;
private readonly WebUntisIntegrationService? _untisIntegration;
private readonly UntisSyncService? _untisSync;
private readonly AnnualPlanSettingsService _annualPlanSettings;
private readonly AnnualPlanSyncService? _annualPlanSync;
private readonly SyncSettingsService _syncSettings;
private readonly SyncAuthService _syncAuth;
private readonly EventQueue _eventQueue;
private readonly SyncEngine? _syncEngine;
private readonly SnapshotService? _snapshotService;
private readonly SyncKeyRecoveryService _syncKeyRecovery;
private readonly AppearanceSettingsService _appearance;
private readonly CompetencyCatalogImportService _catalogImport;
private readonly AppLogger _logger;
public TrashViewModel TrashTab { get; }
public SettingsViewModel(ISubjectRepository subjects, ICompetencyDomainRepository domainRepo,
IGradingKeyTemplateRepository gradingKeyTemplates, IGradingSchemeRepository gradingSchemes,
GradingService grading, BackupService backups, BackupSettingsService backupSettings,
DatabaseEncryptionService dbEncryption,
AppLockService appLock, LiteDbContext dbContext, PrivacySettingsService privacy,
IDocumentationRepository documentation, IStudentRepository students,
IShorthandCodeRepository shorthandCodes, ISchoolHolidayRepository schoolHolidays,
SchoolCalendarSettingsService calendarSettings, PeriodScheduleService periodSchedule,
ISupervisionDutyRepository supervisionDuties, TemplateStore letterTemplates,
AiSettingsService aiSettings, AiPlanningService aiPlanning, McpSettingsService mcpSettings,
Services.Mcp.McpClientRegistrationService mcpRegistration,
WebUntisSettingsService untisSettings,
AnnualPlanSettingsService annualPlanSettings,
SyncSettingsService syncSettings, SyncAuthService syncAuth, EventQueue eventQueue,
AppLogger logger, SyncKeyStatus syncKeyStatus, SyncKeyRecoveryService syncKeyRecovery,
AppearanceSettingsService appearance, TrashViewModel trashTab,
SnapshotService? snapshotService = null, SyncEngine? syncEngine = null,
UntisSyncService? untisSync = null, AnnualPlanSyncService? annualPlanSync = null,
SchoolWeatherService? schoolWeather = null, WebUntisIntegrationService? untisIntegration = null)
{
_logger = logger;
_syncKeyRecovery = syncKeyRecovery;
SyncKeyWasRegenerated = syncKeyStatus.KeyWasRegenerated;
_appearance = appearance;
_selectedTheme = appearance.Load();
TrashTab = trashTab;
_subjects = subjects;
_domainRepo = domainRepo;
_gradingKeyTemplates = gradingKeyTemplates;
_gradingSchemes = gradingSchemes;
_grading = grading;
_backups = backups;
_backupSettings = backupSettings;
_dbEncryption = dbEncryption;
_appLock = appLock;
_dbContext = dbContext;
_privacy = privacy;
_documentation = documentation;
_students = students;
_shorthandCodes = shorthandCodes;
_schoolHolidays = schoolHolidays;
_calendarSettings = calendarSettings;
_schoolWeather = schoolWeather;
_periodSchedule = periodSchedule;
_supervisionDuties = supervisionDuties;
_letterTemplates = letterTemplates;
_aiSettings = aiSettings;
_aiPlanning = aiPlanning;
_mcpSettings = mcpSettings;
_mcpRegistration = mcpRegistration;
_untisSettings = untisSettings;
_untisIntegration = untisIntegration;
_untisSync = untisSync;
_annualPlanSettings = annualPlanSettings;
_annualPlanSync = annualPlanSync;
_syncSettings = syncSettings;
_syncAuth = syncAuth;
_eventQueue = eventQueue;
_snapshotService = snapshotService;
_syncEngine = syncEngine;
_catalogImport = new CompetencyCatalogImportService(domainRepo);
LoadSubjects();
LoadShorthandCodes();
LoadGradingKeyTemplates();
LoadGradingSchemes();
LoadBackups();
IsDbEncrypted = _dbEncryption.IsEncrypted(AppBootstrapper.DbPath);
AppLockEnabled = _appLock.IsEnabled;
AppLockTimeoutMinutes = _appLock.TimeoutMinutes;
RetentionYears = _privacy.RetentionYears;
LoadExpiredDocuments();
SelectedStateName = GermanStateDisplay.Label(_calendarSettings.State);
LoadSchoolHolidays();
LoadPeriodTimes();
LoadSupervisionDuties();
LoadLetterTemplates();
LoadAiSettings();
LoadMcpSettings();
LoadMcpRegistrationStatus();
LoadUntisSettings();
LoadAnnualPlanSettings();
LoadSyncSettings();
LoadSyncConflicts();
}
}