- 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>
91 lines
2.8 KiB
C#
91 lines
2.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;
|
|
|
|
namespace LehrerApp.Desktop.ViewModels.Settings;
|
|
|
|
public partial class SettingsViewModel
|
|
{
|
|
// ── Schulweiter Jahresplan (ClassyPlan-iCal) ─────────────────────────────
|
|
|
|
[ObservableProperty] private bool _annualPlanIsConfigured;
|
|
[ObservableProperty] private string _annualPlanIcalUrlInput = "";
|
|
[ObservableProperty] private string _annualPlanUrlError = "";
|
|
[ObservableProperty] private string _annualPlanStatusDisplay = "";
|
|
[ObservableProperty] private bool _annualPlanFetchBusy;
|
|
|
|
// ── Schulweiter Jahresplan: Laden / Speichern / Entfernen / Jetzt abrufen ─
|
|
|
|
private void LoadAnnualPlanSettings()
|
|
{
|
|
AnnualPlanIsConfigured = _annualPlanSettings.IsConfigured;
|
|
AnnualPlanStatusDisplay = _annualPlanSettings.LastSyncAt is { } at
|
|
? $"Letzter Abgleich: {at.ToLocalTime():dd.MM.yyyy HH:mm} — {_annualPlanSettings.LastSyncStatus}"
|
|
: "Noch kein Abgleich durchgeführt.";
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void AnnualPlanSaveUrl()
|
|
{
|
|
AnnualPlanUrlError = "";
|
|
if (string.IsNullOrWhiteSpace(AnnualPlanIcalUrlInput))
|
|
{
|
|
AnnualPlanUrlError = "iCal-URL erforderlich.";
|
|
return;
|
|
}
|
|
if (!Uri.TryCreate(AnnualPlanIcalUrlInput, UriKind.Absolute, out var uri) ||
|
|
uri.Scheme is not ("http" or "https"))
|
|
{
|
|
AnnualPlanUrlError = "Ungültige HTTP(S)-URL.";
|
|
return;
|
|
}
|
|
|
|
_annualPlanSettings.SetIcalUrl(AnnualPlanIcalUrlInput.Trim());
|
|
_annualPlanSettings.SetEnabled(true);
|
|
AnnualPlanIcalUrlInput = "";
|
|
AppBootstrapper.RestartApplication();
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void AnnualPlanRemove()
|
|
{
|
|
_annualPlanSync?.Clear();
|
|
_annualPlanSettings.ClearIcalUrl();
|
|
LoadAnnualPlanSettings();
|
|
AppBootstrapper.RestartApplication();
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task AnnualPlanFetchNow()
|
|
{
|
|
if (_annualPlanSync is null)
|
|
{
|
|
AnnualPlanStatusDisplay = "Abgleich nicht aktiv — App neu starten.";
|
|
return;
|
|
}
|
|
|
|
AnnualPlanFetchBusy = true;
|
|
try
|
|
{
|
|
await _annualPlanSync.PollAsync();
|
|
LoadAnnualPlanSettings();
|
|
}
|
|
finally
|
|
{
|
|
AnnualPlanFetchBusy = false;
|
|
}
|
|
}
|
|
}
|