using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Jugenddienst_Stunden.Models; using Jugenddienst_Stunden.Types; using System.ComponentModel; using System.Windows.Input; using static System.Runtime.InteropServices.JavaScript.JSType; using Jugenddienst_Stunden.Interfaces; using Jugenddienst_Stunden.Repositories; using Jugenddienst_Stunden.Services; using Jugenddienst_Stunden.Infrastructure; using Jugenddienst_Stunden.Validators; using System.Net.Http; namespace Jugenddienst_Stunden.ViewModels; /// /// Viewmodel für die einzelnen Stundeneinträge / Bearbeitung /// public partial class StundeViewModel : ObservableObject, IQueryAttributable { private readonly IHoursService _hoursService; public int Id { get; set; } public string Title { get; set; } = "Eintrag bearbeiten"; public string SubTitle { get; set; } = DateTime.Today.ToString("dddd, d. MMMM yyyy"); //private HoursBase HoursBase = new HoursBase(); internal Settings Settings = new Settings(); public event EventHandler AlertEvent; public event EventHandler InfoEvent; public event Func> ConfirmEvent; //public event Func> ConfirmEvent; //public event EventHandler ConfirmEvent; /// /// Gemeinden für die Auswahlliste /// [ObservableProperty] private List optionsGemeinde; /// /// Projekte für die Auswahlliste /// [ObservableProperty] private List optionsProjekt; /// /// Freistellungen für die Auswahlliste /// [ObservableProperty] private List optionsFreistellung; /// /// Vorhandene Zeiten anzeigen, wenn neuer Eintrag erstellt wird /// [ObservableProperty] private List dayTimes; /// /// Aktueller Stundeneintrag /// [ObservableProperty] private DayTime dayTime; /// /// Dürfen Gemeinden verwendet werden? /// [ObservableProperty] private bool gemeindeAktivSet; /// /// Dürfen Projekte verwendet werden? /// [ObservableProperty] private bool projektAktivSet; [ObservableProperty] private bool freistellungEnabled; public ICommand SaveCommand { get; private set; } public ICommand DeleteCommand { get; private set; } public ICommand DeleteConfirmCommand { get; private set; } //public ICommand LoadDataCommand { get; private set; } public StundeViewModel() : this(GetServiceOrCreate()) { LoadSettingsAsync(); } private static IHoursService GetServiceOrCreate() { // Fallback-Konstruktion, falls DI nicht injiziert wurde (z. B. im Designer) var http = new HttpClient(); var options = new Infrastructure.ApiOptions { BaseUrl = GlobalVar.ApiUrl, Timeout = TimeSpan.FromSeconds(15) }; var tokenProvider = new GlobalVarTokenProvider(); var api = new ApiClient(http, options, tokenProvider, new PreferencesAppSettings()); var repo = new HoursRepository(api); var validator = new HoursValidator(); return new HoursService(repo, validator); } internal StundeViewModel(IHoursService hoursService) { _hoursService = hoursService; SaveCommand = new AsyncRelayCommand(Save); //DeleteCommand = new AsyncRelayCommand(Delete); DeleteConfirmCommand = new Command(async () => await DeleteConfirm()); } // DI-Konstruktor, der den globalen Alert-Service abonniert und Alerts an das ViewModel weiterreicht. internal StundeViewModel(IHoursService hoursService, IAlertService alertService) : this(hoursService) { if (alertService is not null) { alertService.AlertRaised += (s, msg) => AlertEvent?.Invoke(this, msg); } } private async void LoadSettingsAsync() { try { Settings = await _hoursService.GetSettingsAsync(); GlobalVar.Settings = Settings; OptionsGemeinde = Settings.Gemeinden; OptionsProjekt = Settings.Projekte; OptionsFreistellung = Settings.Freistellungen; GemeindeAktivSet = Settings.GemeindeAktivSet; ProjektAktivSet = Settings.ProjektAktivSet; } catch (Exception e) { AlertEvent?.Invoke(this, e.Message); } } async Task Save() { bool exceptionOccurred = false; bool proceed = true; //Arbeitszeit sollte nicht null sein if (DayTime.TimeSpanVon == DayTime.TimeSpanBis && DayTime.FreistellungAktiv.Name == null) { proceed = false; AlertEvent?.Invoke(this, "Uhrzeiten sollten unterschiedlich sein"); } //Projekt ist ein Pflichtfeld if (Settings.ProjektAktivSet && DayTime.ProjektAktiv.Id == 0) { proceed = false; AlertEvent?.Invoke(this, "Projekt darf nicht leer sein"); } //Gemeinde ist ein Pflichtfeld if (Settings.GemeindeAktivSet && DayTime.GemeindeAktiv.Id == 0) { proceed = false; AlertEvent?.Invoke(this, "Gemeinde darf nicht leer sein"); } if (proceed) { try { await _hoursService.SaveEntryAsync(DayTime); } catch (Exception e) { AlertEvent?.Invoke(this, e.Message); exceptionOccurred = true; } if (!exceptionOccurred) { if (DayTime.Id != null) { await Shell.Current.GoToAsync($"..?saved={DayTime.Id}"); } else { await Shell.Current.GoToAsync($"..?date={DayTime.Day.ToString("yyyy-MM-dd")}"); } } } } /// /// Löschen ohne Bestätigung /// private async Task Delete() { await _hoursService.DeleteEntryAsync(DayTime); await Shell.Current.GoToAsync($"..?date={DayTime.Day.ToString("yyyy-MM-dd")}"); } /// /// Löschen mit Bestätigung /// private async Task DeleteConfirm() { if (ConfirmEvent != null) { bool answer = await ConfirmEvent.Invoke("Achtung", "Löschen kann nicht ungeschehen gemacht werden. Fortfahren?"); if (answer) { //Löschen await _hoursService.DeleteEntryAsync(DayTime); await Shell.Current.GoToAsync($"..?date={DayTime.Day.ToString("yyyy-MM-dd")}"); } else { //nicht Löschen } } } /// /// Anwenden der Query-Parameter /// async void IQueryAttributable.ApplyQueryAttributes(IDictionary query) { //load beinhaltet die ID: Eintrag bearbeiten //date beinhaltet einen Tag: Neuen Eintrag erstellen if (query.ContainsKey("load")) { //DateTime heute = DateTime.Now; try { var entry = await _hoursService.GetEntryAsync(Convert.ToInt32(query["load"])); // var settings = await _hoursService.GetSettingsAsync(); // GlobalVar.Settings = settings; // GemeindeAktivSet = settings.GemeindeAktivSet; // ProjektAktivSet = settings.ProjektAktivSet; DayTime = entry; DayTime.TimeSpanVon = entry.Begin.ToTimeSpan(); DayTime.TimeSpanBis = entry.End.ToTimeSpan(); // OptionsGemeinde = settings.Gemeinden ?? new List(); // OptionsProjekt = settings.Projekte ?? new List(); // OptionsFreistellung = settings.Freistellungen ?? new List(); DayTime.GemeindeAktiv = OptionsGemeinde.FirstOrDefault(Gemeinde => Gemeinde.Id == DayTime.Gemeinde) ?? new Gemeinde(); DayTime.ProjektAktiv = OptionsProjekt.FirstOrDefault(Projekt => Projekt.Id == DayTime.Projekt) ?? new Projekt(); DayTime.FreistellungAktiv = OptionsFreistellung.FirstOrDefault(Freistellung => Freistellung.Id == DayTime.Free) ?? new Freistellung(); //Evtl. noch die anderen Zeiten des gleichen Tages holen var day = await _hoursService.GetDayWithSettingsAsync(DayTime.Day); DayTimes = day.dayTimes; OnPropertyChanged(nameof(DayTime)); OnPropertyChanged(nameof(DayTimes)); } catch (Exception e) { AlertEvent?.Invoke(this, e.Message); } finally { } if (System.String.IsNullOrEmpty(DayTime.Description)) { InfoEvent?.Invoke(this, "Eintrag hat keinen Beschreibungstext"); } SubTitle = DayTime.Day.ToString("dddd, d. MMMM yyyy"); OnPropertyChanged(nameof(SubTitle)); FreistellungEnabled = !DayTime.Approved; //OnPropertyChanged(nameof(DayTime)); } else if (query.ContainsKey("date")) { Title = "Neuer Eintrag"; OnPropertyChanged(nameof(Title)); DateTime _date = DateTime.ParseExact((string)query["date"], "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture); //Bei neuem Eintrag die vorhandenen des gleichen Tages anzeigen try { var (list, settings) = await _hoursService.GetDayWithSettingsAsync(_date); GlobalVar.Settings = settings; DayTimes = list; OptionsGemeinde = settings.Gemeinden; OptionsProjekt = settings.Projekte; OptionsFreistellung = settings.Freistellungen; GemeindeAktivSet = settings.GemeindeAktivSet; ProjektAktivSet = settings.ProjektAktivSet; } catch (Exception) { //Ein Tag ohne Einträge gibt eine Fehlermeldung, //die soll aber ignoriert werden, weil beim Neueintrag ist das ja Wurscht //In dem Fall müssen die Settings aber nochmal geholt werden, weil die dann nicht geladen wurden // LoadSettingsAsync(); } finally { DayTime = new DayTime(); DayTime.Day = _date; DayTime.EmployeeId = GlobalVar.EmployeeId; DayTime.GemeindeAktiv = new Gemeinde(); DayTime.ProjektAktiv = new Projekt(); DayTime.FreistellungAktiv = new Freistellung(); SubTitle = _date.ToString("dddd, d. MMMM yyyy"); FreistellungEnabled = true; OnPropertyChanged(nameof(SubTitle)); //OnPropertyChanged(nameof(DayTime)); } } } }