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,81 @@
|
||||
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
|
||||
{
|
||||
// ── Stundenraster: Uhrzeiten je Einzelstunde (4.2.2 Nachtrag) ────────────
|
||||
|
||||
[ObservableProperty] private string _periodTimesError = "";
|
||||
[ObservableProperty] private string _periodTimesStatus = "";
|
||||
|
||||
public ObservableCollection<PeriodTimeEditItem> PeriodTimes { get; } = [];
|
||||
|
||||
// ── Stundenraster: Laden / Speichern ─────────────────────────────────────
|
||||
|
||||
private void LoadPeriodTimes()
|
||||
{
|
||||
PeriodTimes.Clear();
|
||||
for (var period = 1; period <= 10; period++)
|
||||
{
|
||||
var times = _periodSchedule.GetTimes(period);
|
||||
PeriodTimes.Add(new PeriodTimeEditItem(period, times?.Start, times?.End));
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SavePeriodTimes()
|
||||
{
|
||||
PeriodTimesError = ""; PeriodTimesStatus = "";
|
||||
var entries = new List<PeriodTimeEntry>();
|
||||
|
||||
foreach (var item in PeriodTimes)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(item.StartText) && string.IsNullOrWhiteSpace(item.EndText))
|
||||
continue; // Stunde bewusst nicht konfiguriert — ok, keine Pflicht für alle 10.
|
||||
|
||||
if (!TimeOnly.TryParseExact(item.StartText, "HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out var start) ||
|
||||
!TimeOnly.TryParseExact(item.EndText, "HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out var end))
|
||||
{ PeriodTimesError = $"{item.PeriodLabel}: Format HH:MM."; return; }
|
||||
|
||||
if (end <= start)
|
||||
{ PeriodTimesError = $"{item.PeriodLabel}: Ende muss nach dem Beginn liegen."; return; }
|
||||
|
||||
entries.Add(new PeriodTimeEntry { PeriodNumber = item.PeriodNumber, Start = start, End = end });
|
||||
}
|
||||
|
||||
_periodSchedule.SetPeriods(entries);
|
||||
PeriodTimesStatus = "Gespeichert.";
|
||||
}
|
||||
}
|
||||
|
||||
public partial class PeriodTimeEditItem : ObservableObject
|
||||
{
|
||||
public int PeriodNumber { get; }
|
||||
public string PeriodLabel { get; }
|
||||
|
||||
[ObservableProperty] private string _startText;
|
||||
[ObservableProperty] private string _endText;
|
||||
|
||||
public PeriodTimeEditItem(int periodNumber, TimeOnly? start, TimeOnly? end)
|
||||
{
|
||||
PeriodNumber = periodNumber;
|
||||
PeriodLabel = $"{periodNumber}. Stunde";
|
||||
_startText = start?.ToString("HH:mm") ?? "";
|
||||
_endText = end?.ToString("HH:mm") ?? "";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user