Tagesflagge im Sitzplan, Leistungsüberblick mit Zielnoten-Rechner
CI / build-and-test (push) Canceled after 0s

- Mitarbeit: Tagesflagge (👑 Spitzentag / 😴 Schlaftag /  Schlechter Tag)
  je Schüler und Sitzung. Primär im Sitzplatz-Dialog (⇧1/2/3, ⇧X) mit
  Badge auf der Sitzplatz-Kachel; Fallback in der Schnelleingabe für
  Lerngruppen ohne Sitzplan.
- Noten: neuer Dialog "Überblick" in der Notenübersicht zeigt Klausuren,
  Mitarbeit- und sonstige Noten eines Schülers samt berechneter
  Zeugnisnote. Zielnoten-Rechner (ReportGradeTargetCalculator) beantwortet
  "was brauche ich noch für Note X", ein Was-wäre-wenn-Rechner simuliert
  eine zusätzliche Klausurnote. Bewerter-/Schülermodus per Umschalter im
  selben Fenster — Bewertermodus zeigt zusätzlich Kursdurchschnitt je
  Klausur und erlaubt das Bearbeiten von Mitarbeit-/Sonstige-Noten.
  Klausurverlauf als Balken-Sparkline wie die bestehende Notenentwicklung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-30 11:43:47 +02:00
co-authored by Claude Sonnet 5
parent 84c03962ef
commit 1215d4ac22
20 changed files with 1087 additions and 4 deletions
@@ -0,0 +1,184 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:LehrerApp.Desktop.ViewModels.Groups"
xmlns:students="clr-namespace:LehrerApp.Desktop.ViewModels.Students"
x:Class="LehrerApp.Desktop.Views.Groups.StudentPerformanceOverviewDialog"
x:DataType="vm:StudentPerformanceOverviewViewModel"
Title="Leistungsüberblick"
Width="920" Height="720" MinWidth="700" MinHeight="520"
CanResize="True" WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,Auto,*,Auto" Margin="24">
<Grid Grid.Row="0" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" Spacing="2">
<TextBlock Text="{Binding StudentName}" Classes="dialogtitle"/>
<TextBlock Text="{Binding GroupLabel}" FontSize="12" Opacity="0.6"/>
</StackPanel>
<Button Grid.Column="1" Content="{Binding ModeButtonLabel}"
Command="{Binding ToggleModeCommand}" VerticalAlignment="Top"
ToolTip.Tip="Zwischen Bewerter- und Schülermodus umschalten"/>
</Grid>
<StackPanel Grid.Row="1" Orientation="Horizontal" Spacing="12" Margin="0,12,0,10">
<StackPanel Orientation="Horizontal" Spacing="6">
<TextBlock Text="Zeitraum:" VerticalAlignment="Center"/>
<ComboBox ItemsSource="{Binding PeriodOptions}" SelectedItem="{Binding SelectedPeriod}" MinWidth="170"/>
</StackPanel>
<TextBlock Text="{Binding SchemeSummary}" FontSize="12" Opacity="0.6" VerticalAlignment="Center"
IsVisible="{Binding IsTeacherMode}"/>
</StackPanel>
<ScrollViewer Grid.Row="2">
<Grid ColumnDefinitions="*,300">
<StackPanel Grid.Column="0" Spacing="18" Margin="0,0,16,0">
<StackPanel Spacing="6">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Text="KLAUSUREN" FontSize="11" FontWeight="Bold" Opacity="0.5"/>
<TextBlock Grid.Column="1" Text="{Binding ExamsAverageDisplay, StringFormat='Ø {0}'}"
FontSize="12" Opacity="0.7" IsVisible="{Binding ExamsAverageDisplay, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</Grid>
<ItemsControl ItemsSource="{Binding ExamRows}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:StudentExamRow">
<Grid ColumnDefinitions="Auto,*,80,80" Margin="0,4">
<TextBlock Grid.Column="0" Text="{Binding DateDisplay}" FontSize="12" Opacity="0.6" Width="80"/>
<TextBlock Grid.Column="1" Text="{Binding Title}" FontSize="13"/>
<TextBlock Grid.Column="2" Text="{Binding OwnGradeDisplay}" FontWeight="SemiBold"
HorizontalAlignment="Right"/>
<TextBlock Grid.Column="3" Text="{Binding ClassAverageDisplay}" Opacity="0.55"
HorizontalAlignment="Right"
IsVisible="{Binding $parent[ItemsControl].((vm:StudentPerformanceOverviewViewModel)DataContext).IsTeacherMode}"
ToolTip.Tip="Kursdurchschnitt dieser Klausur"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Keine Klausuren im gewählten Zeitraum." Classes="emptyhint"
IsVisible="{Binding !ExamRows.Count}"/>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled"
IsVisible="{Binding !!ExamHistory.Points.Count}">
<ItemsControl ItemsSource="{Binding ExamHistory.Points}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><StackPanel Orientation="Horizontal" Spacing="10"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="students:GradeHistoryPoint">
<StackPanel Width="46" VerticalAlignment="Bottom" ToolTip.Tip="{Binding TooltipText}">
<Border Classes="historybar" Height="{Binding BarHeight}" Width="16" CornerRadius="2"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Classes.warning="{Binding IsWarning}"/>
<TextBlock Text="{Binding Value}" FontSize="11" FontWeight="SemiBold"
HorizontalAlignment="Center" Margin="0,3,0,0"/>
<TextBlock Text="{Binding DateDisplay}" FontSize="9" Opacity="0.5"
HorizontalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Styles>
<Style Selector="Border.historybar">
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundAccentBrush}"/>
</Style>
<Style Selector="Border.historybar.warning">
<Setter Property="Background" Value="#E53935"/>
</Style>
</ItemsControl.Styles>
</ItemsControl>
</ScrollViewer>
</StackPanel>
<StackPanel Spacing="6">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Text="MITARBEIT" FontSize="11" FontWeight="Bold" Opacity="0.5"/>
<TextBlock Grid.Column="1" Text="{Binding ParticipationAverageDisplay, StringFormat='Ø {0}'}"
FontSize="12" Opacity="0.7" IsVisible="{Binding ParticipationAverageDisplay, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</Grid>
<ItemsControl ItemsSource="{Binding ParticipationRows}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:StudentSimpleGradeRow">
<Grid ColumnDefinitions="Auto,*,70,Auto" Margin="0,4">
<TextBlock Grid.Column="0" Text="{Binding DateDisplay}" FontSize="12" Opacity="0.6" Width="80"/>
<TextBlock Grid.Column="1" Text="{Binding CategoryLabel}" FontSize="13"/>
<TextBox Grid.Column="2" Text="{Binding Value}"
IsVisible="{Binding $parent[ItemsControl].((vm:StudentPerformanceOverviewViewModel)DataContext).IsTeacherMode}"/>
<TextBlock Grid.Column="2" Text="{Binding Value}" FontWeight="SemiBold" HorizontalAlignment="Right"
IsVisible="{Binding !$parent[ItemsControl].((vm:StudentPerformanceOverviewViewModel)DataContext).IsTeacherMode}"/>
<Button Grid.Column="3" Content="Speichern" Command="{Binding SaveCommand}" FontSize="11" Padding="8,3" Margin="6,0,0,0"
IsVisible="{Binding $parent[ItemsControl].((vm:StudentPerformanceOverviewViewModel)DataContext).IsTeacherMode}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Keine Mitarbeitsnote im gewählten Zeitraum." Classes="emptyhint"
IsVisible="{Binding !ParticipationRows.Count}"/>
</StackPanel>
<StackPanel Spacing="6">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Text="SONSTIGE" FontSize="11" FontWeight="Bold" Opacity="0.5"/>
<TextBlock Grid.Column="1" Text="{Binding OtherAverageDisplay, StringFormat='Ø {0}'}"
FontSize="12" Opacity="0.7" IsVisible="{Binding OtherAverageDisplay, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</Grid>
<ItemsControl ItemsSource="{Binding OtherRows}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:StudentSimpleGradeRow">
<Grid ColumnDefinitions="Auto,*,70,Auto" Margin="0,4">
<TextBlock Grid.Column="0" Text="{Binding DateDisplay}" FontSize="12" Opacity="0.6" Width="80"/>
<TextBlock Grid.Column="1" Text="{Binding CategoryLabel}" FontSize="13"/>
<TextBox Grid.Column="2" Text="{Binding Value}"
IsVisible="{Binding $parent[ItemsControl].((vm:StudentPerformanceOverviewViewModel)DataContext).IsTeacherMode}"/>
<TextBlock Grid.Column="2" Text="{Binding Value}" FontWeight="SemiBold" HorizontalAlignment="Right"
IsVisible="{Binding !$parent[ItemsControl].((vm:StudentPerformanceOverviewViewModel)DataContext).IsTeacherMode}"/>
<Button Grid.Column="3" Content="Speichern" Command="{Binding SaveCommand}" FontSize="11" Padding="8,3" Margin="6,0,0,0"
IsVisible="{Binding $parent[ItemsControl].((vm:StudentPerformanceOverviewViewModel)DataContext).IsTeacherMode}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Keine sonstigen Noten im gewählten Zeitraum." Classes="emptyhint"
IsVisible="{Binding !OtherRows.Count}"/>
</StackPanel>
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}" CornerRadius="8" Padding="14">
<StackPanel Spacing="2">
<TextBlock Text="ZEUGNISNOTE (BERECHNET)" FontSize="11" FontWeight="Bold" Opacity="0.5"/>
<TextBlock Text="{Binding CurrentReportGradeDisplay}" FontSize="18" FontWeight="SemiBold"/>
</StackPanel>
</Border>
</StackPanel>
<StackPanel Grid.Column="1" Spacing="16">
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}" CornerRadius="8" Padding="14">
<StackPanel Spacing="8">
<TextBlock Text="ZIELNOTE: WAS BRAUCHE ICH NOCH?" FontSize="11" FontWeight="Bold" Opacity="0.5"/>
<StackPanel Orientation="Horizontal" Spacing="6">
<TextBlock Text="Ziel:" VerticalAlignment="Center"/>
<TextBox Text="{Binding TargetGradeText}" Width="70" PlaceholderText="z.B. 2"/>
<TextBlock Text="in" VerticalAlignment="Center"/>
<ComboBox ItemsSource="{Binding TargetBucketOptions}" SelectedItem="{Binding TargetBucketName}" MinWidth="110"/>
</StackPanel>
<TextBlock Text="{Binding TargetResultDisplay}" TextWrapping="Wrap" FontSize="13"/>
</StackPanel>
</Border>
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}" CornerRadius="8" Padding="14">
<StackPanel Spacing="8">
<TextBlock Text="WAS-WÄRE-WENN" FontSize="11" FontWeight="Bold" Opacity="0.5"/>
<StackPanel Orientation="Horizontal" Spacing="6">
<TextBlock Text="Zusätzliche Klausurnote:" VerticalAlignment="Center" TextWrapping="Wrap"/>
<TextBox Text="{Binding WhatIfExamGradeText}" Width="70" PlaceholderText="z.B. 3"/>
</StackPanel>
<TextBlock Text="{Binding WhatIfResultDisplay}" TextWrapping="Wrap" FontSize="13"/>
</StackPanel>
</Border>
</StackPanel>
</Grid>
</ScrollViewer>
<Grid Grid.Row="3" ColumnDefinitions="*,Auto" Margin="0,16,0,0">
<Button Grid.Column="1" Content="Schließen" Click="OnClose"/>
</Grid>
</Grid>
</Window>