CI / build-and-test (push) Canceled after 0s
Dashboard warnings (attendance, homework, lateness) get a "Details" flyout with key figures, a list of dates and the compact month calendar from the class teacher overview, now extracted as a shared control. The calendar now aligns days under their weekday (Mo-So header, blank leading cells). Creating Vorgänge and documentation is supported by quick blocks with the current figures, dated standard phrases (e.g. "Klassenleitung informiert") and documentation templates (status snapshot, conversation, informing the class/subject teachers, parent call, parent letter). The class teacher Vorgänge tab uses WebUntis figures (absences across all subjects, class register) for the same blocks and templates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
79 lines
3.5 KiB
C#
79 lines
3.5 KiB
C#
using System.Collections;
|
||
using System.Collections.Specialized;
|
||
using Avalonia;
|
||
using Avalonia.Controls;
|
||
using LehrerApp.Desktop.ViewModels.ClassTeacher;
|
||
|
||
namespace LehrerApp.Desktop.Views.Shared;
|
||
|
||
/// <summary>Eine Rasterzelle des kompakten Monatskalenders; <see cref="Day"/> ist null für die
|
||
/// Leerzellen vor dem Monatsersten.</summary>
|
||
public sealed record CompactMonthCell(ClassTeacherCompactCalendarDay? Day)
|
||
{
|
||
public bool IsPlaceholder => Day is null;
|
||
public bool IsDay => Day is not null;
|
||
}
|
||
|
||
/// <summary>Kompakter Monatskalender (eine Zelle je Tag, Statuskürzel statt Tageszahl) — erwartet
|
||
/// <see cref="ClassTeacherCompactCalendarDay"/>-Einträge in <see cref="Days"/>, genau einen je
|
||
/// Kalendertag ab dem Monatsersten. Genutzt von der Klassenlehrer-Übersicht und dem Detail-Popup der
|
||
/// Dashboard-Warnungen.
|
||
/// Nutzer-Feedback: vorher begann jeder Monat oben links, der 1. stand also unabhängig vom
|
||
/// Wochentag in der Montags-Spalte. Die Ausrichtung passiert bewusst hier in der Anzeige (Leerzellen
|
||
/// vor dem Monatsersten + Kopfzeile Mo–So) statt in den beiden Buildern — deren Ergebnis bleibt
|
||
/// "ein Eintrag je Kalendertag" und damit für Tests/Aufrufer unverändert.</summary>
|
||
public partial class CompactMonthCalendar : UserControl
|
||
{
|
||
public static readonly StyledProperty<IEnumerable?> DaysProperty =
|
||
AvaloniaProperty.Register<CompactMonthCalendar, IEnumerable?>(nameof(Days));
|
||
|
||
public static readonly DirectProperty<CompactMonthCalendar, IReadOnlyList<CompactMonthCell>> CellsProperty =
|
||
AvaloniaProperty.RegisterDirect<CompactMonthCalendar, IReadOnlyList<CompactMonthCell>>(nameof(Cells), c => c.Cells);
|
||
|
||
public static string[] WeekdayHeaders { get; } = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"];
|
||
|
||
private IReadOnlyList<CompactMonthCell> _cells = [];
|
||
private INotifyCollectionChanged? _observed;
|
||
|
||
public IEnumerable? Days
|
||
{
|
||
get => GetValue(DaysProperty);
|
||
set => SetValue(DaysProperty, value);
|
||
}
|
||
|
||
public IReadOnlyList<CompactMonthCell> Cells
|
||
{
|
||
get => _cells;
|
||
private set => SetAndRaise(CellsProperty, ref _cells, value);
|
||
}
|
||
|
||
public CompactMonthCalendar() => InitializeComponent();
|
||
|
||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||
{
|
||
base.OnPropertyChanged(change);
|
||
if (change.Property != DaysProperty) return;
|
||
// Beide Aufrufer befüllen eine ObservableCollection per Clear/Add neu (Monat blättern,
|
||
// Schülerauswahl) — deshalb auf Änderungen der Sammlung selbst lauschen, nicht nur auf
|
||
// einen neuen Days-Wert.
|
||
if (_observed is not null) _observed.CollectionChanged -= OnDaysCollectionChanged;
|
||
_observed = Days as INotifyCollectionChanged;
|
||
if (_observed is not null) _observed.CollectionChanged += OnDaysCollectionChanged;
|
||
RebuildCells();
|
||
}
|
||
|
||
private void OnDaysCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) => RebuildCells();
|
||
|
||
private void RebuildCells() => Cells = BuildCells(Days?.OfType<ClassTeacherCompactCalendarDay>() ?? []);
|
||
|
||
public static IReadOnlyList<CompactMonthCell> BuildCells(IEnumerable<ClassTeacherCompactCalendarDay> days)
|
||
{
|
||
var list = days.ToList();
|
||
if (list.Count == 0) return [];
|
||
var leading = ((int)list[0].Date.DayOfWeek + 6) % 7; // Montag = 0 … Sonntag = 6
|
||
return Enumerable.Repeat(new CompactMonthCell(null), leading)
|
||
.Concat(list.Select(d => new CompactMonthCell(d)))
|
||
.ToList();
|
||
}
|
||
}
|