Dashboard-Performance, CI-Workflow, Settings-Aufteilung, Backup-Härtung
- 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>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
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
|
||||
{
|
||||
// ── Sicherheit: App-Sperre nach Inaktivität (13.3.5) ─────────────────────
|
||||
|
||||
[ObservableProperty] private bool _appLockEnabled;
|
||||
[ObservableProperty] private int _appLockTimeoutMinutes = 10;
|
||||
[ObservableProperty] private string _appLockNewPassword = "";
|
||||
[ObservableProperty] private string _appLockNewPasswordConfirm = "";
|
||||
[ObservableProperty] private string _appLockPasswordError = "";
|
||||
[ObservableProperty] private string _appLockStatus = "";
|
||||
|
||||
public bool AppLockHasPassword => _appLock.HasPassword;
|
||||
|
||||
/// Vom Code-Behind gesetzt: aktualisiert den laufenden Inaktivitäts-Timer sofort,
|
||||
/// ohne dass die App neu gestartet werden muss.
|
||||
public Action? OnAppLockChanged { get; set; }
|
||||
|
||||
// ── App-Sperre: Speichern ─────────────────────────────────────────────────
|
||||
|
||||
[RelayCommand]
|
||||
private void SaveAppLockSettings()
|
||||
{
|
||||
AppLockPasswordError = "";
|
||||
var valid = true;
|
||||
var wantsNewPassword = !string.IsNullOrWhiteSpace(AppLockNewPassword) || !string.IsNullOrWhiteSpace(AppLockNewPasswordConfirm);
|
||||
|
||||
if (AppLockEnabled && !_appLock.HasPassword && !wantsNewPassword)
|
||||
{
|
||||
AppLockPasswordError = "Bitte ein Passwort für die App-Sperre festlegen.";
|
||||
valid = false;
|
||||
}
|
||||
else if (wantsNewPassword)
|
||||
{
|
||||
if (AppLockNewPassword != AppLockNewPasswordConfirm)
|
||||
{
|
||||
AppLockPasswordError = "Passwörter stimmen nicht überein.";
|
||||
valid = false;
|
||||
}
|
||||
else if (AppLockNewPassword.Length < 4)
|
||||
{
|
||||
AppLockPasswordError = "Mindestens 4 Zeichen.";
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) return;
|
||||
|
||||
if (wantsNewPassword) _appLock.SetPassword(AppLockNewPassword.Trim());
|
||||
_appLock.Configure(AppLockEnabled, AppLockTimeoutMinutes);
|
||||
|
||||
AppLockNewPassword = ""; AppLockNewPasswordConfirm = "";
|
||||
OnPropertyChanged(nameof(AppLockHasPassword));
|
||||
AppLockStatus = "Gespeichert.";
|
||||
OnAppLockChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user