using Avalonia; using Avalonia.Controls; using LehrerApp.Desktop.Services; using LehrerApp.WebUntis; using Microsoft.Extensions.DependencyInjection; namespace LehrerApp.Desktop.Views; public sealed class OpenUntisPeriodsDialog : Window { private readonly WebUntisIntegrationService _service = App.Services.GetRequiredService(); private readonly WebUntisSettingsService _settings = App.Services.GetRequiredService(); private readonly CancellationTokenSource _closed = new(); private readonly ComboBox _mode = new() { ItemsSource = new[] { "Mein Unterricht", "Meine Klasse" }, SelectedIndex = 0 }; private readonly ComboBox _element = new() { MinWidth = 150 }; private readonly DatePicker _start = new(); private readonly DatePicker _end = new() { SelectedDate = DateTimeOffset.Now }; private readonly Button _load = new() { Content = "Abrufen" }; private readonly Button _schoolYear = new() { Content = "Seit Schuljahresbeginn" }; private readonly TextBlock _status = new() { TextWrapping = Avalonia.Media.TextWrapping.Wrap }; private readonly StackPanel _rows = new() { Spacing = 12 }; private readonly StackPanel _filters = new() { Spacing = 10, IsEnabled = false }; private UntisOpenPeriodsMeta? _meta; private int _yearId; public OpenUntisPeriodsDialog() { Title = "Offene WebUntis-Stunden"; Width = 850; Height = 650; MinWidth = 600; MinHeight = 450; WindowStartupLocation = WindowStartupLocation.CenterOwner; var root = new DockPanel { Margin = new Thickness(20) }; var header = new StackPanel { Spacing = 12 }; header.Children.Add(new TextBlock { Text = Title, FontSize = 22 }); var selection = new StackPanel { Orientation = Avalonia.Layout.Orientation.Horizontal, Spacing = 12 }; selection.Children.Add(_mode); selection.Children.Add(_element); _filters.Children.Add(selection); var dates = new WrapPanel { Orientation = Avalonia.Layout.Orientation.Horizontal }; dates.Children.Add(new TextBlock { Text = "Von ", VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center }); dates.Children.Add(_start); dates.Children.Add(new TextBlock { Text = " bis ", VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center }); dates.Children.Add(_end); _filters.Children.Add(dates); var actions = new StackPanel { Orientation = Avalonia.Layout.Orientation.Horizontal, Spacing = 12 }; actions.Children.Add(_schoolYear); actions.Children.Add(_load); _filters.Children.Add(actions); header.Children.Add(_filters); header.Children.Add(_status); DockPanel.SetDock(header, Dock.Top); root.Children.Add(header); root.Children.Add(new ScrollViewer { Content = _rows, Margin = new Thickness(0, 20, 0, 0) }); Content = root; _mode.SelectionChanged += (_, _) => SelectMode(); _element.SelectionChanged += (_, _) => ClearResults(); _start.SelectedDateChanged += (_, _) => ClearResults(); _end.SelectedDateChanged += (_, _) => ClearResults(); _schoolYear.Click += (_, _) => { if (_meta is not null) _start.SelectedDate = new DateTimeOffset(_meta.SchoolYearStart.ToDateTime(TimeOnly.MinValue)); }; _load.Click += async (_, _) => await LoadAsync(); Opened += async (_, _) => await InitializeAsync(); Closed += (_, _) => _closed.Cancel(); } private void ClearResults() { _rows.Children.Clear(); _status.Text = "Auswahl festlegen und Abrufen wählen."; } private void SelectMode() { if (_meta is null) return; var own = _mode.SelectedIndex == 0; var elements = own ? _meta.Teachers : _meta.Classes; _element.ItemsSource = elements; var preferred = own ? _settings.TeacherUntisId ?? _meta.OwnTeacherId : _settings.HomeroomClassUntisId ?? _meta.MyClassIds.Cast().FirstOrDefault(); _element.SelectedItem = elements.FirstOrDefault(x => x.Id == preferred) ?? (!own ? elements.FirstOrDefault(x => _meta.MyClassIds.Contains(x.Id)) : null); ClearResults(); } private async Task InitializeAsync() { _status.Text = "WebUntis-Auswahl wird geladen …"; try { var today = DateOnly.FromDateTime(DateTime.Today); var date = today.Year * 10000 + today.Month * 100 + today.Day; var years = await _service.GetSchoolYearsAsync(_closed.Token); var year = years.FirstOrDefault(x => x.StartDate <= date && date <= x.EndDate) ?? throw new InvalidDataException("Kein aktuelles WebUntis-Schuljahr gefunden."); _yearId = year.UntisId; _meta = await _service.GetOpenPeriodsMetaAsync(_yearId, _closed.Token); _start.SelectedDate = new DateTimeOffset(_meta.SchoolYearStart.ToDateTime(TimeOnly.MinValue)); SelectMode(); _filters.IsEnabled = true; if (_element.SelectedItem is not null) await LoadAsync(); } catch (OperationCanceledException) when (_closed.IsCancellationRequested) { } catch (Exception ex) { _status.Text = $"Abruf fehlgeschlagen: {ex.Message}"; } } private async Task LoadAsync() { _rows.Children.Clear(); if (_element.SelectedItem is not UntisOpenElement element || _start.SelectedDate is null || _end.SelectedDate is null) { _status.Text = "Bitte Lehrkraft oder Klasse und Zeitraum auswählen."; return; } var start = DateOnly.FromDateTime(_start.SelectedDate.Value.DateTime); var end = DateOnly.FromDateTime(_end.SelectedDate.Value.DateTime); if (start > end || start < _meta!.SchoolYearStart || end > _meta.SchoolYearEnd) { _status.Text = "Bitte einen gültigen Zeitraum innerhalb des Schuljahres auswählen."; return; } _filters.IsEnabled = false; _status.Text = "Offene Stunden werden geladen …"; try { var own = _mode.SelectedIndex == 0; var periods = await _service.GetOpenPeriodsAsync(_yearId, own ? element.Id : null, own ? null : element.Id, start, end, _closed.Token); foreach (var period in periods) _rows.Children.Add(new TextBlock { Text = $"{period.When}\n{period.Classes} · {period.Subject} · {period.Teachers}\n{period.Missing}", TextWrapping = Avalonia.Media.TextWrapping.Wrap }); _status.Text = periods.Count == 0 ? "Keine offenen Stunden im gewählten Zeitraum." : $"{periods.Count} offene Stunde(n) · Stand {DateTime.Now:HH:mm}"; } catch (OperationCanceledException) when (_closed.IsCancellationRequested) { } catch (Exception ex) { _status.Text = $"Abruf fehlgeschlagen: {ex.Message}"; } finally { _filters.IsEnabled = true; } } }