Files
admin 6af4bee1f0 refactor: Dashboard-Handlungsbedarf zu einer Karte zusammenfassen
Fasst die sieben Kacheln, die tatsaechlich "wo muss ich reagieren" beantworten
(Entschuldigungen, Fehlzeiten-Warnung, Foerderplan-Wiedervorlage, Korrekturen,
ungeplante Stunden, Auffaelligkeiten, Unterrichtszeit-Nacherfassung), zu einer
Karte "Handlungsbedarf" mit Filter-Chips zusammen statt sieben eigener
Sichtbarkeits-Schalter.

Neues gemeinsames Modell AttentionItem/AttentionGroup/AttentionAction traegt nur
Anzeigedaten - die Datenbeschaffung bleibt unveraendert in den jeweiligen
DashboardViewModel.LoadXxx-Methoden, die am Ende ein AttentionItem statt ihrer
eigenen Item-Klasse erzeugen. RebuildAttention() gruppiert nach Art (feste
Reihenfolge) und wendet Filter an, ohne die Repos erneut abzufragen.

SupportPlanDueItem, CorrectionProgressItem, UnplannedLessonItem und
DashboardAlertItem entfallen (nur dashboard-intern verwendet); OpenExcuseItem
und AttendanceWarningItem bleiben bestehen, da GroupOverviewViewModel sie
weiterhin nutzt. Fuenf Navigations-Commands wurden durch ein einziges
OpenAttentionItemCommand ersetzt.

Bewusste Verhaltensaenderung: LoadAlerts dupliziert Fehlzeiten-Ueberschreitungen
nicht mehr in die Auffaelligkeiten-Gruppe, da dieselbe Zahl sonst zweimal in
derselben Karte erschiene (vorher durch zwei getrennte Kacheln nicht sichtbar).

Details und Testanpassungen siehe TODO.md, Abschnitt 9 (Dashboard).
2026-09-11 00:40:58 +02:00

595 lines
36 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:LehrerApp.Desktop.ViewModels"
x:Class="LehrerApp.Desktop.Views.Dashboard.DashboardView"
x:DataType="vm:DashboardViewModel">
<UserControl.Styles>
<Style Selector="TextBlock.overdue">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
<Style Selector="Button.webuntishealth">
<Setter Property="Foreground" Value="{DynamicResource AppStatusOkBrush}"/>
</Style>
<Style Selector="Button.webuntishealth.warning">
<Setter Property="Foreground" Value="{DynamicResource AppStatusWarningBrush}"/>
</Style>
<Style Selector="Border.daycell.selected">
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundAccentBrush}"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{DynamicResource SystemAccentColor}"/>
</Style>
<!-- Handlungsbedarf-Karte: Schweregrad-Streifen (nur Auffälligkeiten) und die rot
hervorgehobene Fehlzeitenquote — ersetzen die früheren fest kodierten Hex-Farben
(#D32F2F/#F59E0B, Foreground="Red") durch die validierte Status-Palette. -->
<Style Selector="Border.severitybar">
<Setter Property="Width" Value="4"/>
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Border.severitybar.high">
<Setter Property="Background" Value="{DynamicResource AppStatusDangerBrush}"/>
</Style>
<Style Selector="Border.severitybar.medium">
<Setter Property="Background" Value="{DynamicResource AppStatusWarningBrush}"/>
</Style>
<Style Selector="TextBlock.attentionTrailing">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Opacity" Value="0.6"/>
</Style>
<Style Selector="TextBlock.attentionTrailing.warning">
<Setter Property="FontSize" Value="12"/>
<Setter Property="Opacity" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource AppStatusDangerBrush}"/>
</Style>
</UserControl.Styles>
<ScrollViewer Padding="24">
<StackPanel Spacing="20">
<!-- Begrüßung -->
<Grid RowDefinitions="Auto,Auto">
<StackPanel>
<TextBlock Text="{Binding Greeting}" FontSize="14" Opacity="0.6"/>
<TextBlock Text="{Binding CurrentDate}" FontSize="24" FontWeight="SemiBold"/>
</StackPanel>
<WrapPanel Grid.Row="1" Orientation="Horizontal" ItemSpacing="8" LineSpacing="8" Margin="0,10,0,0">
<!-- Fasst die vier WebUntis-Abgleiche zusammen, die jetzt nur noch im Menü "WebUntis"
erreichbar sind (siehe TODO.md, Untis-Hub) - Klick öffnet den Hub. -->
<Button Content="{Binding WebUntisHealthLabel}" Click="OnOpenUntisHubClick"
IsVisible="{Binding IsWebUntisHealthVisible}"
Classes="webuntishealth" Classes.warning="{Binding IsWebUntisHealthWarning}"
VerticalAlignment="Center"/>
<Button Content="Bereiche anpassen" Command="{Binding ToggleDashboardSettingsCommand}"
VerticalAlignment="Center"/>
</WrapPanel>
</Grid>
<!-- Der Tagesfokus beantwortet zuerst die vier Fragen, die beim Öffnen der App zählen:
Was unterrichte ich, was ist zu tun, wo muss ich reagieren und was steht an? -->
<Border Background="{DynamicResource AppCardBackgroundBrush}"
BorderBrush="{DynamicResource AppCardBorderBrush}" BorderThickness="1"
CornerRadius="10" Padding="16,14">
<Grid ColumnDefinitions="*,*,*,*">
<StackPanel Grid.Column="0" Spacing="3">
<TextBlock Text="UNTERRICHT HEUTE" FontSize="10" FontWeight="Bold" Opacity="0.5"/>
<TextBlock Text="{Binding TodayLessonSummary}" FontSize="18" FontWeight="SemiBold"/>
</StackPanel>
<StackPanel Grid.Column="1" Spacing="3" Margin="18,0,0,0">
<TextBlock Text="AUFGABEN" FontSize="10" FontWeight="Bold" Opacity="0.5"/>
<TextBlock Text="{Binding OpenTaskSummary}" FontSize="18" FontWeight="SemiBold"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="3" Margin="18,0,0,0">
<TextBlock Text="HANDLUNGSBEDARF" FontSize="10" FontWeight="Bold" Opacity="0.5"/>
<TextBlock Text="{Binding AttentionSummary}" FontSize="18" FontWeight="SemiBold"
Foreground="{DynamicResource AppStatusWarningBrush}"/>
</StackPanel>
<StackPanel Grid.Column="3" Spacing="3" Margin="18,0,0,0">
<TextBlock Text="NÄCHSTE 30 TAGE" FontSize="10" FontWeight="Bold" Opacity="0.5"/>
<TextBlock Text="{Binding UpcomingSummary}" FontSize="18" FontWeight="SemiBold"/>
</StackPanel>
</Grid>
</Border>
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}" CornerRadius="8"
Padding="12" IsVisible="{Binding IsDashboardSettingsOpen}">
<ItemsControl ItemsSource="{Binding DashboardCards}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel Orientation="Horizontal"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:DashboardCardOption">
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}"
BorderThickness="1" CornerRadius="6" Padding="8" Margin="4">
<StackPanel Orientation="Horizontal" Spacing="6">
<CheckBox Content="{Binding Title}" IsChecked="{Binding IsVisible}" VerticalAlignment="Center"/>
<Button Content="↑" Padding="6,2"
ToolTip.Tip="Bereich nach oben verschieben"
AutomationProperties.Name="Dashboard-Bereich nach oben verschieben"
Command="{Binding $parent[ItemsControl].((vm:DashboardViewModel)DataContext).MoveCardUpCommand}"
CommandParameter="{Binding}"/>
<Button Content="↓" Padding="6,2"
ToolTip.Tip="Bereich nach unten verschieben"
AutomationProperties.Name="Dashboard-Bereich nach unten verschieben"
Command="{Binding $parent[ItemsControl].((vm:DashboardViewModel)DataContext).MoveCardDownCommand}"
CommandParameter="{Binding}"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
<!-- Serverseitig gecachte DWD-Daten für den in den Einstellungen hinterlegten Schulstandort. -->
<Expander Header="{Binding WeatherSummary}" IsExpanded="{Binding HasWeatherWarnings}"
IsVisible="{Binding IsWeatherPanelVisible}"
Background="{DynamicResource AppCardBackgroundBrush}"
BorderBrush="{DynamicResource AppCardBorderBrush}" BorderThickness="1"
CornerRadius="8" Padding="12,6">
<StackPanel Spacing="10" Margin="6,8,6,6">
<Grid ColumnDefinitions="*,Auto">
<StackPanel>
<TextBlock Text="WETTER AM SCHULSTANDORT" FontSize="11" FontWeight="Bold" Opacity="0.5"/>
<TextBlock Text="{Binding WeatherDetails}" FontSize="11" Opacity="0.65" TextWrapping="Wrap"
IsVisible="{Binding WeatherDetails, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
<Button Grid.Column="1" Content="Aktualisieren" FontSize="11" Padding="8,3"
Command="{Binding RefreshCommand}" VerticalAlignment="Top"/>
</Grid>
<TextBlock Text="{Binding WeatherStatus}" FontSize="11" Opacity="0.65" TextWrapping="Wrap"
IsVisible="{Binding WeatherStatus, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
<ItemsControl ItemsSource="{Binding WeatherWarnings}" IsVisible="{Binding HasWeatherWarnings}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:DashboardWeatherWarningItem">
<Border BorderBrush="{Binding SeverityColor}" BorderThickness="4,0,0,0"
Background="#14D32F2F" Padding="10" Margin="0,3" CornerRadius="4">
<StackPanel Spacing="3">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Text="{Binding Headline}" FontSize="13" FontWeight="SemiBold" TextWrapping="Wrap"/>
<TextBlock Grid.Column="1" Text="{Binding PeriodDisplay}" FontSize="10" Opacity="0.65"
Margin="10,0,0,0"/>
</Grid>
<TextBlock Text="{Binding Description}" FontSize="11" TextWrapping="Wrap"/>
<TextBlock Text="{Binding Instruction}" FontSize="11" Opacity="0.75" TextWrapping="Wrap"
IsVisible="{Binding Instruction, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Wetterdaten © Deutscher Wetterdienst" FontSize="10" Opacity="0.5"/>
</StackPanel>
</Expander>
<TextBlock Text="HEUTE UND HANDLUNGSBEDARF" FontSize="11" FontWeight="Bold" Opacity="0.5"
Margin="2,2,0,-8"/>
<!-- 7 Kacheln (today/tasks/calendar/examload/upcoming/groups/attention) auf 2 Spalten -> 4 Zeilen. -->
<Grid ColumnDefinitions="3*,2*" RowDefinitions="Auto,Auto,Auto,Auto">
<!-- Heutige Stunden -->
<Border Grid.Column="{Binding TodayCard.Column}" Grid.Row="{Binding TodayCard.Row}"
IsVisible="{Binding TodayCard.EffectiveIsVisible}" Margin="{Binding TodayCard.Margin}"
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="8" Padding="16">
<StackPanel>
<TextBlock Text="Heute" FontSize="14" FontWeight="SemiBold"
Opacity="0.5" Margin="0,0,0,10"/>
<ItemsControl ItemsSource="{Binding TodaysLessons}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:LessonItem">
<Button Command="{Binding $parent[ItemsControl].((vm:DashboardViewModel)DataContext).OpenLessonCommand}"
CommandParameter="{Binding}"
Background="Transparent" BorderThickness="0" Padding="0" Margin="0,4"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
<Grid ColumnDefinitions="4,*,Auto">
<Border Grid.Column="0" Width="4" CornerRadius="2"
Background="{DynamicResource SystemAccentColor}"
Margin="0,0,10,0"/>
<StackPanel Grid.Column="1">
<TextBlock Text="{Binding GroupName}" FontWeight="SemiBold" FontSize="13"/>
<TextBlock Text="{Binding Topic}" FontSize="12" Opacity="0.7"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
<StackPanel Grid.Column="2" HorizontalAlignment="Right" Margin="8,0,0,0">
<TextBlock Text="{Binding TimeDisplay}" FontSize="12" Opacity="0.7"
HorizontalAlignment="Right"
IsVisible="{Binding TimeDisplay, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
<TextBlock Text="{Binding Room}" FontSize="11" Opacity="0.6"
HorizontalAlignment="Right" IsVisible="{Binding HasRoom}"/>
</StackPanel>
</Grid>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Keine Stunden heute" Classes="emptyhint"
IsVisible="{Binding !TodaysLessons.Count}"/>
</StackPanel>
</Border>
<!-- Offene Aufgaben -->
<Border Grid.Column="{Binding TasksCard.Column}" Grid.Row="{Binding TasksCard.Row}"
IsVisible="{Binding TasksCard.EffectiveIsVisible}" Margin="{Binding TasksCard.Margin}"
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="8" Padding="16">
<StackPanel>
<Grid ColumnDefinitions="*,Auto,Auto" Margin="0,0,0,10">
<TextBlock Grid.Column="0" Text="Offene Aufgaben" FontSize="14" FontWeight="SemiBold"
Opacity="0.5" VerticalAlignment="Center"/>
<Button Grid.Column="1" Content="🔔+" FontSize="12" Padding="7,2" Margin="0,0,4,0"
ToolTip.Tip="Erinnerung anlegen" Command="{Binding AddReminderCommand}"/>
<Button Grid.Column="2" Content="" FontSize="12" Padding="8,2"
ToolTip.Tip="Aufgabe anlegen" Command="{Binding AddTaskCommand}"/>
</Grid>
<ItemsControl ItemsSource="{Binding OpenTasks}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:TaskItem">
<Grid ColumnDefinitions="4,Auto,*,Auto" Margin="0,3">
<Border Grid.Column="0" Background="#D32F2F" CornerRadius="2" Margin="0,0,6,0"
IsVisible="{Binding IsHighPriority}" ToolTip.Tip="Hohe Priorität"/>
<TextBlock Grid.Column="1" Text="🔔" FontSize="12" Margin="0,0,4,0"
IsVisible="{Binding IsReminder}"
ToolTip.Tip="Erinnerung — kein Zeitbezug"/>
<TextBlock Grid.Column="2" Text="{Binding Title}"
FontSize="13" TextTrimming="CharacterEllipsis"/>
<TextBlock Grid.Column="3" Text="{Binding DueDate}"
FontSize="12" Opacity="0.6" Margin="8,0,0,0"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Keine offenen Aufgaben" Classes="emptyhint"
IsVisible="{Binding !OpenTasks.Count}"/>
</StackPanel>
</Border>
<!-- Kalender: feste Position direkt unter Heute/Aufgaben, damit die wachsende
Lerngruppen-Liste darunter ihn nicht nach unten verdrängt. -->
<Border Grid.Column="{Binding CalendarCard.Column}" Grid.Row="{Binding CalendarCard.Row}"
IsVisible="{Binding CalendarCard.EffectiveIsVisible}" Margin="{Binding CalendarCard.Margin}"
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="8" Padding="16" HorizontalAlignment="Left" MaxWidth="320">
<StackPanel Spacing="8">
<StackPanel.Styles>
<!-- Basiswerte als Style (nicht lokal), damit die spezifischeren Selektoren
(z.B. .daycell.ownclass) sie überschreiben können. -->
<Style Selector="Border.daycell">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Opacity" Value="1"/>
</Style>
<Style Selector="Border.daycell.haslesson">
<Setter Property="Background" Value="#14808080"/>
</Style>
<Style Selector="Border.daycell.ownclass">
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlBackgroundAccentBrush}"/>
</Style>
<Style Selector="Border.daycell.outside">
<Setter Property="Opacity" Value="0.35"/>
</Style>
<Style Selector="TextBlock.daynum">
<Setter Property="FontWeight" Value="Normal"/>
</Style>
<Style Selector="TextBlock.daynum.today">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="{DynamicResource SystemControlForegroundAccentBrush}"/>
</Style>
</StackPanel.Styles>
<Grid ColumnDefinitions="Auto,*,Auto,Auto,Auto">
<TextBlock Grid.Column="0" Text="KALENDER" FontSize="11" FontWeight="Bold"
Opacity="0.5" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="{Binding CalendarMonthLabel}" FontSize="13"
FontWeight="SemiBold" TextAlignment="Center" VerticalAlignment="Center"
Width="130" Margin="12,0"/>
<Button Grid.Column="2" Content="Heute" FontSize="11" Padding="8,2"
Command="{Binding CalendarTodayCommand}" Margin="0,0,4,0"/>
<Button Grid.Column="3" Content="" Padding="8,2" Command="{Binding PrevMonthCommand}"
ToolTip.Tip="Vorheriger Monat" AutomationProperties.Name="Vorheriger Monat"/>
<Button Grid.Column="4" Content="" Padding="8,2" Command="{Binding NextMonthCommand}" Margin="4,0,0,0"
ToolTip.Tip="Nächster Monat" AutomationProperties.Name="Nächster Monat"/>
</Grid>
<ItemsControl ItemsSource="{Binding CalendarWeekdayHeaders}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><UniformGrid Columns="7"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontSize="10" Opacity="0.5" FontWeight="Bold"
HorizontalAlignment="Center" Width="32"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl ItemsSource="{Binding CalendarDays}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><UniformGrid Columns="7"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:CalendarDayCell">
<Button Background="Transparent" BorderThickness="0" Padding="0" Margin="1"
HorizontalAlignment="Center"
Command="{Binding $parent[ItemsControl].((vm:DashboardViewModel)DataContext).SelectCalendarDayCommand}"
CommandParameter="{Binding}" ToolTip.Tip="{Binding Tooltip}">
<Border Classes="daycell" Classes.ownclass="{Binding IsOwnClassDay}"
Classes.haslesson="{Binding HasLesson}"
Classes.outside="{Binding !IsCurrentMonth}"
Classes.selected="{Binding IsSelected}"
Width="32" Height="32" CornerRadius="6">
<Grid>
<TextBlock Classes="daynum" Classes.today="{Binding IsToday}"
Text="{Binding DayNumber}" FontSize="12"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal" Spacing="2" Margin="0,0,0,3"
HorizontalAlignment="Center" VerticalAlignment="Bottom">
<Ellipse Width="5" Height="5" Fill="#1E88E5" IsVisible="{Binding HasSession}"/>
<Ellipse Width="5" Height="5" Fill="#E53935" IsVisible="{Binding HasExam}"/>
<Ellipse Width="5" Height="5" Fill="#FF8A00" IsVisible="{Binding HasAnnualPlanEvent}"/>
</StackPanel>
</Grid>
</Border>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<WrapPanel Orientation="Horizontal" Margin="0,4,0,0">
<StackPanel Orientation="Horizontal" Spacing="4" Margin="0,0,14,4">
<Border Width="10" Height="10" CornerRadius="3" Background="#14808080"/>
<TextBlock Text="Unterricht" FontSize="10" Opacity="0.6"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="4" Margin="0,0,14,4">
<Ellipse Width="7" Height="7" Fill="#E53935"/>
<TextBlock Text="Klausur" FontSize="10" Opacity="0.6"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="4" Margin="0,0,14,4">
<Ellipse Width="7" Height="7" Fill="#1E88E5"/>
<TextBlock Text="Sitzung" FontSize="10" Opacity="0.6"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="4" Margin="0,0,14,4">
<Ellipse Width="7" Height="7" Fill="#FF8A00"/>
<TextBlock Text="Jahresplan" FontSize="10" Opacity="0.6"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="4" Margin="0,0,14,4">
<Border Width="10" Height="10" CornerRadius="3" BorderThickness="2"
BorderBrush="{DynamicResource SystemControlBackgroundAccentBrush}"/>
<TextBlock Text="Meine Klasse" FontSize="10" Opacity="0.6"/>
</StackPanel>
</WrapPanel>
<Separator Margin="0,4"/>
<TextBlock Text="{Binding SelectedDayLabel}" FontWeight="SemiBold" FontSize="12"/>
<ItemsControl ItemsSource="{Binding SelectedDayEvents}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:CalendarEventItem">
<Button Background="Transparent" BorderThickness="0" Padding="0" Margin="0,3"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
Command="{Binding $parent[ItemsControl].((vm:DashboardViewModel)DataContext).OpenCalendarEventCommand}"
CommandParameter="{Binding}">
<Grid ColumnDefinitions="Auto,*">
<TextBlock Text="{Binding KindLabel}" FontSize="10" Opacity="0.55" Width="58"/>
<StackPanel Grid.Column="1">
<TextBlock Text="{Binding Title}" FontSize="12" FontWeight="SemiBold"/>
<TextBlock Text="{Binding Subtitle}" FontSize="10" Opacity="0.6"/>
<TextBlock Text="{Binding Description}" FontSize="10" Opacity="0.6"
TextWrapping="Wrap"
IsVisible="{Binding Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
</Grid>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Keine Termine an diesem Tag." Classes="emptyhint"
IsVisible="{Binding !SelectedDayEvents.Count}"/>
</StackPanel>
</Border>
<!-- Klausurwochen (Nutzer-Feedback): eigene Klausurlast über alle Kurse hinweg -->
<Border Grid.Column="{Binding ExamLoadCard.Column}" Grid.Row="{Binding ExamLoadCard.Row}"
IsVisible="{Binding ExamLoadCard.EffectiveIsVisible}" Margin="{Binding ExamLoadCard.Margin}" VerticalAlignment="Top"
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="8" Padding="16">
<StackPanel>
<TextBlock Text="KLAUSURWOCHEN" FontSize="11" FontWeight="Bold"
Opacity="0.5" Margin="0,0,0,10"/>
<ItemsControl ItemsSource="{Binding ExamWeekLoads}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:ExamWeekLoadItem">
<Grid ColumnDefinitions="*,Auto" Margin="0,4">
<TextBlock Grid.Column="0" Text="{Binding Label}" FontSize="13"/>
<TextBlock Grid.Column="1" Text="{Binding CountDisplay}" Foreground="#F59E0B"
FontSize="12" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Keine Woche mit auffälliger Klausurhäufung." Classes="emptyhint"
IsVisible="{Binding !ExamWeekLoads.Count}"/>
</StackPanel>
</Border>
<!-- Anstehende Termine (9.3) -->
<Border Grid.Column="{Binding UpcomingCard.Column}" Grid.Row="{Binding UpcomingCard.Row}"
IsVisible="{Binding UpcomingCard.EffectiveIsVisible}" Margin="{Binding UpcomingCard.Margin}" VerticalAlignment="Top"
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="8" Padding="16">
<StackPanel>
<TextBlock Text="ANSTEHENDE TERMINE" FontSize="11" FontWeight="Bold"
Opacity="0.5" Margin="0,0,0,10"/>
<ItemsControl ItemsSource="{Binding UpcomingDates}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:UpcomingDateItem">
<Button Background="Transparent" BorderThickness="0" Padding="0" Margin="0,4"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
Command="{Binding $parent[ItemsControl].((vm:DashboardViewModel)DataContext).OpenUpcomingDateCommand}"
CommandParameter="{Binding}">
<Grid ColumnDefinitions="Auto,*,Auto">
<Border Background="{DynamicResource SystemAccentColorLight2}" CornerRadius="4"
Padding="5,2" VerticalAlignment="Center">
<TextBlock Text="{Binding KindLabel}" FontSize="10"/>
</Border>
<StackPanel Grid.Column="1" Margin="8,0">
<TextBlock Text="{Binding Title}" FontSize="13" FontWeight="SemiBold"
TextTrimming="CharacterEllipsis"/>
<TextBlock Text="{Binding Subtitle}" FontSize="11" Opacity="0.6"/>
</StackPanel>
<TextBlock Grid.Column="2" Text="{Binding DateDisplay}" FontSize="12"
VerticalAlignment="Center" Classes.overdue="{Binding IsOverdue}"/>
</Grid>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Keine Termine in den nächsten 30 Tagen." Classes="emptyhint"
IsVisible="{Binding !UpcomingDates.Count}"/>
</StackPanel>
</Border>
<!-- Handlungsbedarf: zusammengefasste Karte für die frueheren sieben Kacheln
(Entschuldigungen, Fehlzeiten, Foerderplan, Korrekturen, ungeplante Stunden,
Auffaelligkeiten, Unterrichtszeit-Nacherfassung) — siehe AttentionItem.cs.
Filter-Chips ersetzen die vorherige Sichtbarkeit je Einzelkachel. x:Name traegt den
Weg zum DashboardViewModel durch zwei ItemsControl-Verschachtelungen (Gruppe -> Item)
hindurch, ohne $parent[ItemsControl] mit Ancestor-Level zaehlen zu muessen. -->
<Border Grid.Column="{Binding AttentionCard.Column}" Grid.Row="{Binding AttentionCard.Row}"
IsVisible="{Binding AttentionCard.EffectiveIsVisible}" Margin="{Binding AttentionCard.Margin}" VerticalAlignment="Top"
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="8" Padding="16">
<StackPanel Spacing="10">
<TextBlock Text="HANDLUNGSBEDARF" FontSize="11" FontWeight="Bold" Opacity="0.5"/>
<ItemsControl ItemsSource="{Binding AttentionFilters}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel Orientation="Horizontal" ItemSpacing="6" LineSpacing="6"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:AttentionFilterOption">
<ToggleButton Content="{Binding Label}" IsChecked="{Binding IsActive}"
FontSize="11" Padding="8,3"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl x:Name="AttentionGroupsList" ItemsSource="{Binding Attention}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:AttentionGroup">
<StackPanel Margin="0,6,0,0" Spacing="4">
<TextBlock FontSize="11" FontWeight="SemiBold" Opacity="0.7">
<Run Text="{Binding Header}"/>
<Run Text=" ("/>
<Run Text="{Binding Count}"/>
<Run Text=")"/>
</TextBlock>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:AttentionItem">
<StackPanel Margin="0,4">
<Grid ColumnDefinitions="4,*">
<Border Grid.Column="0" Classes="severitybar"
Classes.high="{Binding IsHighSeverity}"
Classes.medium="{Binding IsMediumSeverity}" Margin="0,0,9,0"/>
<!-- Bewusst immer als Button (statt je nach IsClickable ein anderes Root-Element):
ein einheitliches Template für alle sieben Arten. Bei Excuse/MissingTeachingTime
ist Navigate null, der Klick auf die Zeile selbst ist dann folgenlos — die
eigentliche Aktion liegt dort in Actions (Entschuldigt/Erfassen) darunter. -->
<Button Grid.Column="1" Background="Transparent" BorderThickness="0" Padding="0"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
Command="{Binding #AttentionGroupsList.((vm:DashboardViewModel)DataContext).OpenAttentionItemCommand}"
CommandParameter="{Binding}">
<StackPanel Spacing="3">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Text="{Binding Title}" FontSize="13" FontWeight="SemiBold"
TextTrimming="CharacterEllipsis"/>
<TextBlock Grid.Column="1" Text="{Binding TrailingText}"
Classes="attentionTrailing" Classes.warning="{Binding IsWarningTrailing}"
VerticalAlignment="Center" Margin="8,0,0,0"
IsVisible="{Binding HasTrailingText}"/>
<TextBlock Grid.Column="1" Text="{Binding DateDisplay}" FontSize="12"
VerticalAlignment="Center" Margin="8,0,0,0"
Classes.overdue="{Binding IsOverdue}"
IsVisible="{Binding HasDate}"/>
</Grid>
<TextBlock Text="{Binding Subtitle}" FontSize="11" Opacity="0.6"
IsVisible="{Binding HasSubtitle}"/>
<ProgressBar Minimum="0" Maximum="100" Value="{Binding ProgressPercent}"
Height="6" IsVisible="{Binding HasProgress}"/>
<TextBlock Text="{Binding ProgressLabel}" FontSize="10" Opacity="0.65"
IsVisible="{Binding HasProgress}"/>
</StackPanel>
</Button>
</Grid>
<ItemsControl ItemsSource="{Binding Actions}" Margin="13,4,0,0"
IsVisible="{Binding HasActions}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><StackPanel Orientation="Horizontal" Spacing="4"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:AttentionAction">
<Button Content="{Binding Label}" FontSize="11" Padding="7,3"
Command="{Binding Command}" CommandParameter="{Binding Parameter}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Keine offenen Punkte." Classes="emptyhint"
IsVisible="{Binding !Attention.Count}"/>
</StackPanel>
</Border>
<!-- Meine Lerngruppen -->
<Border Grid.Column="{Binding GroupsCard.Column}" Grid.Row="{Binding GroupsCard.Row}"
IsVisible="{Binding GroupsCard.EffectiveIsVisible}" Margin="{Binding GroupsCard.Margin}"
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="8" Padding="16">
<StackPanel>
<TextBlock Text="MEINE LERNGRUPPEN" FontSize="11" FontWeight="Bold"
Opacity="0.5" Margin="0,0,0,10"/>
<ItemsControl ItemsSource="{Binding CurrentGroups}" HorizontalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" ItemSpacing="8" LineSpacing="8"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:GroupChip">
<Button Command="{Binding $parent[ItemsControl].((vm:DashboardViewModel)DataContext).OpenGroupCommand}"
CommandParameter="{Binding}"
Background="{DynamicResource SystemAccentColorLight2}"
CornerRadius="6" Padding="12,6" MinWidth="150"
ToolTip.Tip="Kurs öffnen">
<StackPanel>
<StackPanel Orientation="Horizontal" Spacing="6">
<Border Width="6" Height="6" CornerRadius="3"
Background="{DynamicResource SystemAccentColor}"
IsVisible="{Binding IsOnSelectedDay}" VerticalAlignment="Center"/>
<TextBlock Text="{Binding Name}" FontWeight="SemiBold" FontSize="13"/>
</StackPanel>
<TextBlock Text="{Binding Subject}" FontSize="11" Opacity="0.7"
IsVisible="{Binding Subject, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Noch keine Lerngruppen." Classes="emptyhint"
IsVisible="{Binding !CurrentGroups.Count}"/>
</StackPanel>
</Border>
</Grid>
</StackPanel>
</ScrollViewer>
</UserControl>