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 { // ── Ferien & Feiertage (4.3.5, aus dem Stundenplan hierher verschoben) ─── [ObservableProperty] private string _selectedStateName = ""; [ObservableProperty] private string _newHolidayName = ""; [ObservableProperty] private string _newHolidayStartText = ""; [ObservableProperty] private string _newHolidayEndText = ""; [ObservableProperty] private string _holidayNameError = ""; [ObservableProperty] private string _holidayDateError = ""; [ObservableProperty] private string _schoolName = ""; [ObservableProperty] private string _schoolStreet = ""; [ObservableProperty] private string _schoolPostalCode = ""; [ObservableProperty] private string _schoolCity = ""; [ObservableProperty] private string _schoolNameError = ""; [ObservableProperty] private string _schoolStreetError = ""; [ObservableProperty] private string _schoolPostalCodeError = ""; [ObservableProperty] private string _schoolCityError = ""; [ObservableProperty] private string _schoolLocationStatus = ""; [ObservableProperty] private string _resolvedSchoolAddress = ""; public List StateOptions { get; } = GermanStateDisplay.Options.ToList(); public ObservableCollection SchoolHolidayEntries { get; } = []; // ── Ferien & Feiertage: Bundesland / Schulferien pflegen ───────────────── partial void OnSelectedStateNameChanged(string value) => _calendarSettings.SetState(GermanStateDisplay.FromLabel(value)); [RelayCommand] private async Task LoadSchoolLocation() { if (_schoolWeather is null) return; try { var location = await _schoolWeather.GetLocationAsync(); if (location is null) return; SchoolName = location.SchoolName; SchoolStreet = location.Street; SchoolPostalCode = location.PostalCode; SchoolCity = location.City; SelectedStateName = GermanStateDisplay.Label(location.State); ResolvedSchoolAddress = location.ResolvedAddress; } catch (SchoolWeatherException ex) { SchoolLocationStatus = ex.Message; } } [RelayCommand] private async Task SaveSchoolLocation() { SchoolNameError = ""; SchoolStreetError = ""; SchoolPostalCodeError = ""; SchoolCityError = ""; SchoolLocationStatus = ""; var valid = true; if (string.IsNullOrWhiteSpace(SchoolName)) { SchoolNameError = "Name der Schule erforderlich."; valid = false; } if (string.IsNullOrWhiteSpace(SchoolStreet)) { SchoolStreetError = "Straße und Hausnummer erforderlich."; valid = false; } if (!System.Text.RegularExpressions.Regex.IsMatch(SchoolPostalCode.Trim(), @"^\d{5}$")) { SchoolPostalCodeError = "Bitte eine fünfstellige PLZ angeben."; valid = false; } if (string.IsNullOrWhiteSpace(SchoolCity)) { SchoolCityError = "Ort erforderlich."; valid = false; } if (!valid) return; if (_schoolWeather is null) { SchoolLocationStatus = "Der Wetterdienst ist nicht verfügbar."; return; } SchoolLocationStatus = "Adresse wird geprüft …"; try { var profile = await _schoolWeather.SaveLocationAsync(new SchoolLocationRequest { SchoolName = SchoolName.Trim(), Street = SchoolStreet.Trim(), PostalCode = SchoolPostalCode.Trim(), City = SchoolCity.Trim(), State = GermanStateDisplay.FromLabel(SelectedStateName), }); ResolvedSchoolAddress = profile.ResolvedAddress; SchoolLocationStatus = "Schulstandort gespeichert. Wetterdaten werden serverseitig abgerufen."; } catch (SchoolWeatherException ex) { SchoolLocationStatus = ex.Message; } } private void LoadSchoolHolidays() { SchoolHolidayEntries.Clear(); foreach (var h in _schoolHolidays.GetAll().OrderBy(h => h.StartDate)) SchoolHolidayEntries.Add(new SchoolHolidayItem(h)); } [RelayCommand] private void AddSchoolHoliday() { HolidayNameError = ""; HolidayDateError = ""; var valid = true; if (string.IsNullOrWhiteSpace(NewHolidayName)) { HolidayNameError = "Name erforderlich."; valid = false; } var hasStart = DateOnly.TryParseExact(NewHolidayStartText, "dd.MM.yyyy", CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var start); var hasEnd = DateOnly.TryParseExact(NewHolidayEndText, "dd.MM.yyyy", CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var end); if (!hasStart || !hasEnd) { HolidayDateError = "Bitte Beginn und Ende im Format TT.MM.JJJJ angeben."; valid = false; } else if (end < start) { HolidayDateError = "Das Ende darf nicht vor dem Beginn liegen."; valid = false; } if (!valid) return; _schoolHolidays.Save(new SchoolHoliday { Name = NewHolidayName.Trim(), StartDate = start, EndDate = end }); NewHolidayName = ""; NewHolidayStartText = ""; NewHolidayEndText = ""; LoadSchoolHolidays(); } [RelayCommand] private void RemoveSchoolHoliday(SchoolHolidayItem? item) { if (item is null) return; _schoolHolidays.Delete(item.Id); SchoolHolidayEntries.Remove(item); } } public class SchoolHolidayItem(SchoolHoliday h) { public Guid Id { get; } = h.Id; public string Name { get; } = h.Name; public string RangeDisplay { get; } = $"{h.StartDate:dd.MM.yyyy} – {h.EndDate:dd.MM.yyyy}"; }