diff --git a/Jugenddienst Stunden/Jugenddienst Stunden.csproj b/Jugenddienst Stunden/Jugenddienst Stunden.csproj index 2b484cb..df8a87f 100644 --- a/Jugenddienst Stunden/Jugenddienst Stunden.csproj +++ b/Jugenddienst Stunden/Jugenddienst Stunden.csproj @@ -87,6 +87,8 @@ $(TargetFrameworks);net8.0-windows10.0.26100.0 + True + snupkg @@ -97,6 +99,7 @@ 1.0.4 5 + True diff --git a/Jugenddienst Stunden/Models/Stunde.cs b/Jugenddienst Stunden/Models/Stunde.cs index 836113f..13e6484 100644 --- a/Jugenddienst Stunden/Models/Stunde.cs +++ b/Jugenddienst Stunden/Models/Stunde.cs @@ -1,6 +1,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using Newtonsoft.Json; using Jugenddienst_Stunden.Types; +using System.Collections.ObjectModel; namespace Jugenddienst_Stunden.Models; @@ -31,7 +32,7 @@ internal class Stunde : ObservableObject { name = Preferences.Default.Get("name", "Johannes"); surname = Preferences.Default.Get("surname", "Fink"); apiUrl = Preferences.Default.Get("apiUrl", "http://hours.dauni.mine.nu:81/appapi"); - + if (string.IsNullOrEmpty(apiKey)) { throw new Exception("Kein APIKEY, bitte zuerst Login durchführen"); @@ -107,39 +108,38 @@ internal class Stunde : ObservableObject { /// /// /// - public static async Task> LoadDay(DateTime date) { + public static async Task> LoadDay(DateTime date) { if (string.IsNullOrEmpty(apiKey)) { throw new Exception("Kein APIKEY, bitte zuerst Login durchführen"); } - List daytimes = new List(); if (Connectivity.Current.NetworkAccess == NetworkAccess.None) { throw new Exception("Bitte überprüfen Sie Ihre Internetverbindung und versuchen Sie es erneut."); //await App.Current.MainPage.DisplayAlert("Keine Internetverbindung", // "Bitte überprüfen Sie Ihre Internetverbindung und versuchen Sie es erneut.", // "OK"); - } else { - var tokendata = new TokenData(apiKey); - - //string data = await Auth.GetApiDataWithAuthAsync(requestUrl, apiKey); - string? data = await Auth.GetApiDataWithAuthAsync(tokendata.url + "?date=" + date.ToString("yyyy-MM-dd"), tokendata.apiKey); - - if (data == "null") { - throw new Exception("Keine Daten für " + date.ToString("ddd. dd. MMM") + " erhalten"); - } - if (data == "\"Lalala\"") { - throw new Exception("Problem mit Token"); - } - if (data == null) { - throw new Exception("Keine Daten erhalten"); - } - //daytimes = System.Text.Json.JsonSerializer.Deserialize>(data); - daytimes = JsonConvert.DeserializeObject>(data) ?? throw new Exception("Fehler beim Deserialisieren der Daten"); - - } - //Hours = hours; + + var tokendata = new TokenData(apiKey); + string? data = await Auth.GetApiDataWithAuthAsync(tokendata.url + "?date=" + date.ToString("yyyy-MM-dd"), tokendata.apiKey); + + if (data == "null") { + throw new Exception("Keine Daten für " + date.ToString("ddd. dd. MMM") + " erhalten"); + } + if (data == "\"Lalala\"") { + throw new Exception("Problem mit Token"); + } + if (data == null) { + throw new Exception("Keine Daten erhalten"); + } + + + ObservableCollection daytimes = System.Text.Json.JsonSerializer.Deserialize>(data) ?? throw new Exception("Fehler beim Deserialisieren der Daten"); + //daytimes = JsonConvert.DeserializeObject>(data); + //List daytimes = JsonConvert.DeserializeObject>(data) ?? throw new Exception("Fehler beim Deserialisieren der Daten"); + return daytimes; + } /// diff --git a/Jugenddienst Stunden/Types/DayTime.cs b/Jugenddienst Stunden/Types/DayTime.cs index 70813d0..46ec941 100644 --- a/Jugenddienst Stunden/Types/DayTime.cs +++ b/Jugenddienst Stunden/Types/DayTime.cs @@ -7,38 +7,38 @@ namespace Jugenddienst_Stunden.Types; /// public class DayTime { public int? id { get; set; } - public int? EmployeeId { get; set; } + public int EmployeeId { get; set; } public DateTime day { get; set; } - public int? wday { get; set; } + public int wday { get; set; } public TimeOnly begin { get; set; } public TimeOnly end { get; set; } - public string? description { get; set; } + public string description { get; set; } public string? free { get; set; } public bool? approved { get; set; } public int? type { get; set; } public int? projekt { get; set; } public int? gemeinde { get; set; } - public TimeOnly? night { get; set; } - public Dictionary? total { get; set; } - public TimeOnly? end_print { get; set; } - public TimeSpan? TimeSpanVon { get; set; } - public TimeSpan? TimeSpanBis { get; set; } - public Collection? Projekte { get; set; } - public Collection? Gemeinden { get; set; } - public Collection? Freistellungen { get; set; } + public TimeOnly night { get; set; } + public Dictionary total { get; set; } + public TimeOnly end_print { get; set; } + public TimeSpan TimeSpanVon { get; set; } + public TimeSpan TimeSpanBis { get; set; } + public Collection Projekte { get; set; } + public Collection Gemeinden { get; set; } + public Collection Freistellungen { get; set; } /// /// Gets the active Gemeinde based on the gemeinde ID. /// - public Gemeinde? GemeindeAktiv { get; set; } + public Gemeinde GemeindeAktiv { get; set; } /// /// Gets the active Projekt based on the projekt ID. /// - public Projekt? ProjektAktiv { get; set; } + public Projekt ProjektAktiv { get; set; } /// /// Gets the active Freistellung based on the Freistellung ID /// - public Freistellung? FreistellungAktiv { get; set; } + public Freistellung FreistellungAktiv { get; set; } } diff --git a/Jugenddienst Stunden/Types/Hours.cs b/Jugenddienst Stunden/Types/Hours.cs index ae7b5ba..28b2411 100644 --- a/Jugenddienst Stunden/Types/Hours.cs +++ b/Jugenddienst Stunden/Types/Hours.cs @@ -20,7 +20,7 @@ public class Hours : ObservableObject { //public Dictionary zeit_total_daily; public List zeit_total_daily_api; - public List daytime; + public List? daytime; //public List wochensumme; public string overtime_month; public string overtime; diff --git a/Jugenddienst Stunden/ViewModels/StundeViewModel.cs b/Jugenddienst Stunden/ViewModels/StundeViewModel.cs index a9d578e..466b56d 100644 --- a/Jugenddienst Stunden/ViewModels/StundeViewModel.cs +++ b/Jugenddienst Stunden/ViewModels/StundeViewModel.cs @@ -26,6 +26,7 @@ internal class StundeViewModel : ObservableObject, IQueryAttributable { public ObservableCollection OptionsGemeinde { get; private set; } public ObservableCollection OptionsProjekt { get; private set; } public ObservableCollection OptionsFreistellung { get; private set; } + public ObservableCollection DayTimes { get; set; } //private Gemeinde _selectedGemeinde; public Gemeinde SelectedOptionGemeinde { @@ -62,7 +63,7 @@ internal class StundeViewModel : ObservableObject, IQueryAttributable { } } - public List DayTimes { get; set; } + public ICommand SaveCommand { get; private set; } @@ -78,7 +79,6 @@ internal class StundeViewModel : ObservableObject, IQueryAttributable { //DeleteCommand = new AsyncRelayCommand(Delete); DeleteConfirmCommand = new Command(async () => await DeleteConfirm()); - } public StundeViewModel(DayTime stunde) { diff --git a/Jugenddienst Stunden/ViewModels/StundenViewModel.cs b/Jugenddienst Stunden/ViewModels/StundenViewModel.cs index 4ff0685..7419e94 100644 --- a/Jugenddienst Stunden/ViewModels/StundenViewModel.cs +++ b/Jugenddienst Stunden/ViewModels/StundenViewModel.cs @@ -1,89 +1,72 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using System.Windows.Input; -using Microsoft.Maui.Controls; -using Microsoft.Maui.Networking; -using ZXing.Net.Maui; +using Jugenddienst_Stunden.Types; using System.Collections.ObjectModel; using System.ComponentModel; -using Jugenddienst_Stunden.Types; -using System.Globalization; -using System; +using System.Runtime.CompilerServices; +using System.Windows.Input; namespace Jugenddienst_Stunden.ViewModels; -internal class StundenViewModel : ObservableObject, IQueryAttributable { +internal class StundenViewModel : ObservableObject, IQueryAttributable, INotifyPropertyChanged { public string Name => AppInfo.Name; public string Surname => AppInfo.VersionString; public string MoreInfoUrl => "https://aka.ms/maui"; public string Message => "Hier werden deine geleisteten Arbeitsstunden aufgelistet"; public string LoadOverview => "Lade Summen für " + DateTime.Today.ToString("MMMM"); public static DateTime GetDay = DateTime.Today; - public string ShowDay => "Zeit an Tag " + GetDay.ToString("ddd d. MMM") + ": "; + //public string ShowDay => "Zeit an Tag " + GetDay.ToString("ddd d. MMM") + ": "; - public int id { get; set; } public ICommand NewEntryCommand { get; } public ICommand SelectEntryCommand { get; } - public ICommand LoadDataCommand { get; private set; } public event EventHandler AlertEvent; public event EventHandler InfoEvent; - public object Stunden { get; } - - - private List _stunde; - public List Stunde { - get => _stunde; + private string _title = Preferences.Default.Get("name", "") + " " + Preferences.Default.Get("surname", ""); + public string Title { + get => _title; + set => SetProperty(ref _title, value); } + private Hours _hour; public Hours Hours { get => _hour; } - public string ZeitDone { - get => _hour.zeit; - } - public string ZeitCalculated { - get => _hour.zeit_total; - } - public string Nominal { - get => _hour.nominal; - } - public string Overtime { - get => _hour.overtime; - } - public string OvertimeMonth { - get => _hour.overtime_month; - } - public string Holiday { - get => _hour.holiday; - } + /// + /// Gesamtstunden an einem Tag + /// public TimeOnly DayTotal { get; set; } - public List DayTimes { - get => _hour.daytime; - set { - if (_hour.daytime != value) { - _hour.daytime = value; - OnPropertyChanged(); - } - } + /// + /// Liste der Tageszeiten + /// + private ObservableCollection _dayTimes = new ObservableCollection(); + public ObservableCollection DayTimes { + get => _dayTimes; + set => SetProperty(ref _dayTimes, value); } - public DateTime MinimumDate { - //get => _hour.MinDate; - //get => DateTime.Today.AddDays(-21); + /// + /// Mindest-Datum für den Datepicker + /// + public static DateTime MinimumDate { get => DateTime.Today.AddDays(-365); } - public DateTime MaximumDate { - //get => _hour.MaxDate; + /// + /// Höchst-Datum für den Datepicker + /// + public static DateTime MaximumDate { get => DateTime.Today.AddDays(60); } + /// + /// Heutiges Datum, wenn das Datum geändert wird, wird auch der Tag geladen + /// private DateTime dateToday = DateTime.Today; public DateTime DateToday { get => dateToday; @@ -91,62 +74,96 @@ internal class StundenViewModel : ObservableObject, IQueryAttributable { if (dateToday != value) { dateToday = value; GetDay = value; - OnPropertyChanged(); - _ = LoadDay(value); // Use discard operator to explicitly ignore the returned Task - //RefreshProperties(); - OnPropertyChanged(nameof(TimeDay)); - OnPropertyChanged(nameof(ShowDay)); - OnPropertyChanged(nameof(DayTimes)); + //OnPropertyChanged(); + _ = LoadDay(value); } } } - public DateTime Date { - get => _hour.Date; + /// + /// Monatsübersicht: Geleistete Stunden + /// + public string? ZeitCalculated { + get => _hour.zeit_total; } - - public List ZeitTotalDaily { - get => _hour.zeit_total_daily_api; + /// + /// Monatsübersicht: Sollstunden + /// + public string? Nominal { + get => _hour.nominal; } - public string Title { get; set; } = Preferences.Default.Get("name", "") + " " + Preferences.Default.Get("surname", ""); + /// + /// Monatsübersicht: Differenz zwischen Soll und geleisteten Stunden + /// + public string? Overtime { + get => _hour.overtime; + } + + /// + /// Monatsübersicht: Restüberstunden insgesamt + /// + public string OvertimeMonth { + get => _hour.overtime_month; + } + + /// + /// Monatsübersicht: Resturlaub + /// + public string Holiday { + get => _hour.holiday; + } + + - public List TimeDay { get; set; } + - public static string apiKey = Preferences.Default.Get("apiKey", ""); - + /// + /// CTOR + /// public StundenViewModel() { - _hour = new Types.Hours(); LoadDataCommand = new AsyncRelayCommand(LoadData); NewEntryCommand = new AsyncRelayCommand(NewEntryAsync); SelectEntryCommand = new AsyncRelayCommand(SelectEntryAsync); - _ = LoadDay(DateTime.Today); - OnPropertyChanged(nameof(DayTimes)); + Task task = LoadDay(DateTime.Today); + } + /// + /// Öffnet eine neue Stundeneingabe + /// + /// private async Task NewEntryAsync() { //Hier muss das Datum übergeben werden //await Shell.Current.GoToAsync(nameof(Views.StundePage)); - await Shell.Current.GoToAsync($"{nameof(Views.StundePage)}?date={dateToday.ToString("yyyy-MM-dd")}"); + await Shell.Current.GoToAsync($"{nameof(Views.StundePage)}?date={dateToday:yyyy-MM-dd}"); } + /// + /// Öffnet eine bestehende Stundeneingabe + /// + /// + /// private async Task SelectEntryAsync(DayTime entry) { if (entry != null && entry.id != null) { - var navigationParameters = new Dictionary {{ "load", entry.id }}; + var navigationParameters = new Dictionary { { "load", entry.id } }; //await Shell.Current.GoToAsync($"{nameof(Views.StundePage)}?load={entry.id}"); await Shell.Current.GoToAsync($"{nameof(Views.StundePage)}", navigationParameters); } else AlertEvent?.Invoke(this, "Auswahl enthält keine Daten"); } - + /// + /// Lädt die Monatssummen für die Übersicht + /// + /// private async Task LoadData() { try { _hour = await Models.Stunde.LoadData(); @@ -156,54 +173,67 @@ internal class StundenViewModel : ObservableObject, IQueryAttributable { } } + /// + /// Lädt die Arbeitszeiten für einen Tag + /// + /// + /// public async Task LoadDay(DateTime date) { - try { - _hour.daytime = await Models.Stunde.LoadDay(date); - ////if (_hour.zeit_total_daily_api != null) { - ////TimeDay = _hour.zeit_total_daily_api.Where(static p => p.Day == GetDay.Day).ToList() ?? new List { new TimeDay { Day = GetDay.Day, Hours = 0 } }; - //RefreshProperties(); + DayTotal = new TimeOnly(0); + try { + DayTimes = await Models.Stunde.LoadDay(date); + + //TODO: Hier muss noch die Berechnung der Stunden erfolgen //Hier werden im Moment noch nur die eingetragenen Stunden gezählt //Auf der Website bekommt der Benutzer die berechneten Stunden angezeigt (Nachstunden außerhalb des Stundenplanes zählen mehr ...) + TimeSpan span = TimeSpan.Zero; - foreach (DayTime dt in _hour.daytime) { + foreach (DayTime dt in DayTimes) { span += dt.end - dt.begin; } DayTotal = TimeOnly.FromTimeSpan(span); - OnPropertyChanged(nameof(ShowDay)); - OnPropertyChanged(nameof(TimeDay)); + + } catch (Exception e) { + DayTimes = new ObservableCollection(); + //TODO: hier könnte auch ein Fehler kommen, dann wäre InfoEvent falsch. + InfoEvent?.Invoke(this, e.Message); + } finally { OnPropertyChanged(nameof(DayTotal)); OnPropertyChanged(nameof(DayTimes)); - ////} - } catch (Exception e) { - DayTimes = new List(); - DayTotal = new TimeOnly(0); - OnPropertyChanged(nameof(DayTotal)); - InfoEvent?.Invoke(this, e.Message); } + } + async void IQueryAttributable.ApplyQueryAttributes(IDictionary query) { if (query.ContainsKey("date")) { await LoadDay(Convert.ToDateTime(query["date"])); } } + /// + /// Refreshes all properties + /// private void RefreshProperties() { OnPropertyChanged(nameof(Nominal)); OnPropertyChanged(nameof(Overtime)); OnPropertyChanged(nameof(OvertimeMonth)); OnPropertyChanged(nameof(ZeitCalculated)); - OnPropertyChanged(nameof(ZeitDone)); OnPropertyChanged(nameof(Holiday)); OnPropertyChanged(nameof(Hours)); OnPropertyChanged(nameof(Title)); - OnPropertyChanged(nameof(ZeitTotalDaily)); - OnPropertyChanged(nameof(TimeDay)); OnPropertyChanged(nameof(MinimumDate)); OnPropertyChanged(nameof(MaximumDate)); - OnPropertyChanged(nameof(ShowDay)); - //OnPropertyChanged(nameof(DateToday)); + } + + protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { + try { + base.OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); + } catch (Exception ex) { + AlertEvent?.Invoke(this, ex.Message); + //Console.WriteLine($"Fehler bei OnPropertyChanged: {ex.Message}"); + } } diff --git a/Jugenddienst Stunden/Views/StundenPage.xaml b/Jugenddienst Stunden/Views/StundenPage.xaml index bf8254a..ebc7702 100644 --- a/Jugenddienst Stunden/Views/StundenPage.xaml +++ b/Jugenddienst Stunden/Views/StundenPage.xaml @@ -46,10 +46,7 @@ - - - @@ -84,7 +81,6 @@ diff --git a/Jugenddienst Stunden/Views/StundenPage.xaml.cs b/Jugenddienst Stunden/Views/StundenPage.xaml.cs index 2a78906..5db423d 100644 --- a/Jugenddienst Stunden/Views/StundenPage.xaml.cs +++ b/Jugenddienst Stunden/Views/StundenPage.xaml.cs @@ -2,6 +2,9 @@ using Jugenddienst_Stunden.ViewModels; namespace Jugenddienst_Stunden.Views; +/// +/// Code-Behind für die Stunden-Übersicht +/// public partial class StundenPage : ContentPage { ///