- 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>
82 lines
2.7 KiB
C#
82 lines
2.7 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
|
|
{
|
|
// ── KI-Unterstützung (4.5.9) ──────────────────────────────────────────────
|
|
|
|
[ObservableProperty] private bool _aiEnabled;
|
|
[ObservableProperty] private string _aiUsername = "";
|
|
[ObservableProperty] private string _aiPassword = "";
|
|
[ObservableProperty] private string _aiLoginError = "";
|
|
[ObservableProperty] private bool _aiIsLoggedIn;
|
|
[ObservableProperty] private string _aiBalanceDisplay = "";
|
|
|
|
// ── KI-Unterstützung: Laden / Anmelden / Abmelden ────────────────────────
|
|
|
|
private void LoadAiSettings()
|
|
{
|
|
AiEnabled = _aiSettings.Enabled;
|
|
AiUsername = _aiSettings.Username;
|
|
AiIsLoggedIn = _aiSettings.IsLoggedIn;
|
|
if (AiIsLoggedIn) _ = RefreshAiBalance();
|
|
}
|
|
|
|
partial void OnAiEnabledChanged(bool value) => _aiSettings.SetEnabled(value);
|
|
|
|
private async Task RefreshAiBalance()
|
|
{
|
|
var token = _aiSettings.GetToken();
|
|
if (token is null) return;
|
|
try
|
|
{
|
|
var balance = await _aiPlanning.GetBalanceAsync(token);
|
|
AiBalanceDisplay = $"Guthaben: {balance:0.00} €";
|
|
}
|
|
catch (AiBackendException ex) { AiBalanceDisplay = ex.Message; }
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task AiLogin()
|
|
{
|
|
AiLoginError = "";
|
|
var valid = true;
|
|
if (string.IsNullOrWhiteSpace(AiUsername)) { AiLoginError = "Benutzername erforderlich."; valid = false; }
|
|
if (string.IsNullOrWhiteSpace(AiPassword)) { AiLoginError = "Passwort erforderlich."; valid = false; }
|
|
if (!valid) return;
|
|
|
|
try
|
|
{
|
|
var token = await _aiPlanning.LoginAsync(AiUsername, AiPassword);
|
|
_aiSettings.SetCredentialsAndToken(AiUsername, token);
|
|
AiPassword = "";
|
|
AiIsLoggedIn = true;
|
|
await RefreshAiBalance();
|
|
}
|
|
catch (AiBackendException ex) { AiLoginError = ex.Message; }
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void AiLogout()
|
|
{
|
|
_aiSettings.Logout();
|
|
AiIsLoggedIn = false;
|
|
AiBalanceDisplay = "";
|
|
}
|
|
}
|