WIP (unstable): Klassenlehrer-Feature auf Einstellungen/eigenen Bereich umgestellt
Nutzer-Feedback: Klassenlehrer ist eine Rolle für die ganze Klasse, unabhängig vom eigenen Unterricht - die Anbindung an ein LearningGroup.IsClassTeacher-Flag mit Tab in der Gruppendetailansicht war deshalb der falsche Ort. Ersetzt durch: - Klassenauswahl in den WebUntis-Einstellungen (WebUntisSettingsService.HomeroomClassName), über den bestehenden WebUntis-Klassenpicker. - Eigener Sidebar-Bereich "Klassenlehrer" statt Gruppen-Tab. - Zwei Ebenen: kompakte Roster-Übersicht mit Ampel-Symbolen (Fehlzeiten heute, Klassenbuch-Badge) und Details (die bisherigen Rohdaten-Listen, jetzt gefiltert auf einzelne Schüler*innen anspringbar). Noch nicht mit echtem WebUntis-Zugang gegengeprüft (siehe TODO.md). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+17
-11
@@ -1,10 +1,10 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="clr-namespace:LehrerApp.Desktop.ViewModels.Groups"
|
||||
x:Class="LehrerApp.Desktop.Views.Groups.ClassTeacherTabView"
|
||||
x:DataType="vm:ClassTeacherTabViewModel">
|
||||
xmlns:vm="clr-namespace:LehrerApp.Desktop.ViewModels.ClassTeacher"
|
||||
x:Class="LehrerApp.Desktop.Views.ClassTeacher.ClassTeacherDetailsView"
|
||||
x:DataType="vm:ClassTeacherDetailsViewModel">
|
||||
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,Auto,1*,Auto,Auto,1*,Auto" Margin="16" RowSpacing="6">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,1*,Auto,Auto,1*,Auto" Margin="16" RowSpacing="6">
|
||||
<TextBlock Grid.Row="0" TextWrapping="Wrap" FontSize="12" Opacity="0.65"
|
||||
Text="Klassenbucheinträge anderer Lehrkräfte und Fehlzeiten der Klasse über alle Fächer (nur Ansicht, keine Übernahme in eigene Daten)."/>
|
||||
|
||||
@@ -15,8 +15,14 @@
|
||||
<Button Content="Laden" Command="{Binding LoadCommand}" IsEnabled="{Binding !Busy}"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="2" Text="Klassenbucheinträge anderer Lehrkräfte" FontWeight="SemiBold" FontSize="13" Margin="0,4,0,0"/>
|
||||
<Grid Grid.Row="3" ColumnDefinitions="70,1*,1.1*,0.8*,1*,1.3*" ColumnSpacing="8" Margin="4,0">
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" Spacing="8"
|
||||
IsVisible="{Binding StudentFilter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
|
||||
<TextBlock Text="{Binding StudentFilter, StringFormat='Gefiltert auf: {0}'}" FontSize="12" VerticalAlignment="Center"/>
|
||||
<Button Content="Filter zurücksetzen" FontSize="11" Padding="8,3" Click="OnClearStudentFilterClick"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="3" Text="Klassenbucheinträge anderer Lehrkräfte" FontWeight="SemiBold" FontSize="13" Margin="0,4,0,0"/>
|
||||
<Grid Grid.Row="4" ColumnDefinitions="70,1*,1.1*,0.8*,1*,1.3*" ColumnSpacing="8" Margin="4,0">
|
||||
<TextBlock Grid.Column="0" Text="Datum" FontSize="11" Opacity="0.6"/>
|
||||
<TextBlock Grid.Column="1" Text="Schüler*in" FontSize="11" Opacity="0.6"/>
|
||||
<TextBlock Grid.Column="2" Text="Fach / Lehrkraft" FontSize="11" Opacity="0.6"/>
|
||||
@@ -24,7 +30,7 @@
|
||||
<TextBlock Grid.Column="4" Text="Gruppe" FontSize="11" Opacity="0.6"/>
|
||||
<TextBlock Grid.Column="5" Text="Text" FontSize="11" Opacity="0.6"/>
|
||||
</Grid>
|
||||
<ScrollViewer Grid.Row="4">
|
||||
<ScrollViewer Grid.Row="5">
|
||||
<ItemsControl ItemsSource="{Binding Entries}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:ClassTeacherClassRegisterRow">
|
||||
@@ -44,9 +50,9 @@
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
<TextBlock Grid.Row="5" Text="Fehlzeiten der Klasse (alle Fächer, pro Schüler*in und Tag zusammengefasst)"
|
||||
<TextBlock Grid.Row="6" Text="Fehlzeiten der Klasse (alle Fächer, pro Schüler*in und Tag zusammengefasst)"
|
||||
FontWeight="SemiBold" FontSize="13" Margin="0,8,0,0"/>
|
||||
<Grid Grid.Row="6" ColumnDefinitions="70,1*,1.3*,0.5*,0.6*,0.6*,0.8*,1.5*" ColumnSpacing="8" Margin="4,0">
|
||||
<Grid Grid.Row="7" ColumnDefinitions="70,1*,1.3*,0.5*,0.6*,0.6*,0.8*,1.5*" ColumnSpacing="8" Margin="4,0">
|
||||
<TextBlock Grid.Column="0" Text="Datum" FontSize="11" Opacity="0.6"/>
|
||||
<TextBlock Grid.Column="1" Text="Schüler*in" FontSize="11" Opacity="0.6"/>
|
||||
<TextBlock Grid.Column="2" Text="Fächer" FontSize="11" Opacity="0.6"/>
|
||||
@@ -56,7 +62,7 @@
|
||||
<TextBlock Grid.Column="6" Text="Status" FontSize="11" Opacity="0.6"/>
|
||||
<TextBlock Grid.Column="7" Text="Grund / Notiz" FontSize="11" Opacity="0.6"/>
|
||||
</Grid>
|
||||
<ScrollViewer Grid.Row="7">
|
||||
<ScrollViewer Grid.Row="8">
|
||||
<ItemsControl ItemsSource="{Binding AbsenceEntries}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:ClassAbsenceDaySummaryRow">
|
||||
@@ -79,6 +85,6 @@
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
<TextBlock Grid.Row="8" Text="{Binding Status}" FontSize="12" TextWrapping="Wrap"/>
|
||||
<TextBlock Grid.Row="9" Text="{Binding Status}" FontSize="12" TextWrapping="Wrap"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,17 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using LehrerApp.Desktop.ViewModels.ClassTeacher;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.ClassTeacher;
|
||||
|
||||
public partial class ClassTeacherDetailsView : UserControl
|
||||
{
|
||||
public ClassTeacherDetailsView() => InitializeComponent();
|
||||
|
||||
private void OnClearStudentFilterClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is not ClassTeacherDetailsViewModel vm) return;
|
||||
vm.StudentFilter = "";
|
||||
vm.LoadCommand.Execute(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="clr-namespace:LehrerApp.Desktop.ViewModels.ClassTeacher"
|
||||
xmlns:views="clr-namespace:LehrerApp.Desktop.Views.ClassTeacher"
|
||||
x:Class="LehrerApp.Desktop.Views.ClassTeacher.ClassTeacherOverviewView"
|
||||
x:DataType="vm:ClassTeacherOverviewViewModel">
|
||||
|
||||
<Grid>
|
||||
<!-- Hinweis, solange in den Einstellungen keine Klasse ausgewählt ist -->
|
||||
<StackPanel IsVisible="{Binding !HomeroomClassConfigured}" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" Spacing="12" MaxWidth="360">
|
||||
<TextBlock Text="🎓" FontSize="40" HorizontalAlignment="Center"/>
|
||||
<TextBlock Text="Noch keine Klasse ausgewählt" FontSize="16" FontWeight="SemiBold" HorizontalAlignment="Center"/>
|
||||
<TextBlock TextWrapping="Wrap" TextAlignment="Center" FontSize="13" Opacity="0.7"
|
||||
Text="Wähle in den WebUntis-Einstellungen die Klasse aus, deren Klassenlehrer/-in du bist."/>
|
||||
<Button Content="Zu den Einstellungen" Command="{Binding GoToSettingsCommand}" HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
<TabbedPage IsVisible="{Binding HomeroomClassConfigured}" TabPlacement="Top"
|
||||
SelectedIndex="{Binding ActiveTabIndex}">
|
||||
|
||||
<ContentPage Header="Übersicht">
|
||||
<Grid RowDefinitions="Auto,Auto,*" Margin="16" RowSpacing="8">
|
||||
<TextBlock Grid.Row="0" Text="{Binding HomeroomClassName, StringFormat='Klasse {0}'}"
|
||||
FontSize="18" FontWeight="SemiBold"/>
|
||||
<TextBlock Grid.Row="1" Text="{Binding Status}" FontSize="12" Opacity="0.7"/>
|
||||
<ScrollViewer Grid.Row="2">
|
||||
<ItemsControl ItemsSource="{Binding Roster}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:ClassTeacherRosterRow">
|
||||
<Button HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Background="Transparent" BorderThickness="0" Padding="8,6"
|
||||
Command="{Binding $parent[ItemsControl].((vm:ClassTeacherOverviewViewModel)DataContext).ShowDetailsForStudentCommand}"
|
||||
CommandParameter="{Binding}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<TextBlock Grid.Column="0" Text="{Binding StatusIcon}" FontSize="16" Width="28"
|
||||
ToolTip.Tip="{Binding AbsenceTooltip}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding StudentName}" VerticalAlignment="Center"/>
|
||||
<Border Grid.Column="2" Background="#1976D2" CornerRadius="8" Padding="6,1"
|
||||
IsVisible="{Binding HasRecentClassRegisterEntry}"
|
||||
ToolTip.Tip="Klassenbucheintrag einer anderen Lehrkraft in den letzten 7 Tagen">
|
||||
<TextBlock Text="Klassenbuch" Foreground="White" FontSize="10"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
|
||||
<ContentPage Header="Details">
|
||||
<views:ClassTeacherDetailsView DataContext="{Binding DetailsTab}"/>
|
||||
</ContentPage>
|
||||
|
||||
</TabbedPage>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,8 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.ClassTeacher;
|
||||
|
||||
public partial class ClassTeacherOverviewView : UserControl
|
||||
{
|
||||
public ClassTeacherOverviewView() => InitializeComponent();
|
||||
}
|
||||
@@ -71,9 +71,6 @@
|
||||
<CheckBox Content="Gehört zu meiner Klasse" IsChecked="{Binding IsOwnClass}"
|
||||
ToolTip.Tip="Für die farbliche Hervorhebung im Dashboard-Kalender. Mehrere Gruppen (Klasse + zugehörige Kurse) können markiert werden."/>
|
||||
|
||||
<CheckBox Content="Klassenlehrer/-in dieser Klasse" IsChecked="{Binding IsClassTeacher}"
|
||||
ToolTip.Tip="Blendet den Klassenlehrer-Tab ein (Klassenbucheinträge anderer Lehrkräfte zu dieser Klasse). Sollte nur an genau einer Gruppe gesetzt werden."/>
|
||||
|
||||
<CheckBox Content="Niveaudifferenzierung (E/G/Förder)" IsChecked="{Binding IsDifferentiated}"
|
||||
ToolTip.Tip="Blendet im Schüler-Tab eine Niveau-Zuordnung je Schüler ein und erlaubt in Klausuren die Zuordnung zu einem Niveau."/>
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.Groups;
|
||||
|
||||
public partial class ClassTeacherTabView : UserControl
|
||||
{
|
||||
public ClassTeacherTabView() => InitializeComponent();
|
||||
}
|
||||
@@ -205,11 +205,6 @@
|
||||
<views:GroupDocumentationTabView DataContext="{Binding GroupDocumentationTab}"/>
|
||||
</ContentPage>
|
||||
|
||||
<!-- Tab: Klassenlehrer, nur sichtbar für Gruppen mit IsClassTeacher -->
|
||||
<ContentPage Header="Klassenlehrer" IsVisible="{Binding IsClassTeacher}">
|
||||
<views:ClassTeacherTabView DataContext="{Binding ClassTeacherTab}"/>
|
||||
</ContentPage>
|
||||
|
||||
</TabbedPage>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
xmlns:vmp="clr-namespace:LehrerApp.Desktop.ViewModels.Planning"
|
||||
xmlns:vw="clr-namespace:LehrerApp.Desktop.Views.Workload"
|
||||
xmlns:vmw="clr-namespace:LehrerApp.Desktop.ViewModels.Workload"
|
||||
xmlns:vct="clr-namespace:LehrerApp.Desktop.Views.ClassTeacher"
|
||||
xmlns:vmct="clr-namespace:LehrerApp.Desktop.ViewModels.ClassTeacher"
|
||||
xmlns:svc="clr-namespace:LehrerApp.Desktop.Services"
|
||||
x:Class="LehrerApp.Desktop.Views.MainWindow"
|
||||
x:DataType="vm:MainWindowViewModel"
|
||||
@@ -58,6 +60,9 @@
|
||||
<DataTemplate DataType="vmw:WorkloadViewModel">
|
||||
<vw:WorkloadView/>
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="vmct:ClassTeacherOverviewViewModel">
|
||||
<vct:ClassTeacherOverviewView/>
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="vm:PlaceholderViewModel">
|
||||
<views:PlaceholderView/>
|
||||
</DataTemplate>
|
||||
@@ -209,6 +214,16 @@
|
||||
<TextBlock Classes="navlabel" Text="Arbeitszeit"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Classes="navitem" Classes.active="{Binding IsClassTeacherActive}" HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
CornerRadius="6"
|
||||
Command="{Binding NavigateToCommand}"
|
||||
CommandParameter="{x:Static vm:NavItem.ClassTeacher}">
|
||||
<StackPanel Classes="navcontent" Orientation="Horizontal" Spacing="10">
|
||||
<TextBlock Classes="navicon" Text="🎓" TextAlignment="Center"/>
|
||||
<TextBlock Classes="navlabel" Text="Klassenlehrer"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Classes="navitem" Classes.active="{Binding IsSettingsActive}" HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
CornerRadius="6"
|
||||
|
||||
@@ -1000,6 +1000,19 @@
|
||||
IsVisible="{Binding UntisApiIsConfigured}" IsEnabled="{Binding !UntisApiBusy}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="8" IsVisible="{Binding UntisApiIsConfigured}">
|
||||
<Separator Margin="0,8"/>
|
||||
<TextBlock Text="Klassenlehrer" FontSize="16" FontWeight="SemiBold"/>
|
||||
<TextBlock FontSize="12" Opacity="0.6" TextWrapping="Wrap"
|
||||
Text="Die Klasse, deren Klassenlehrer/-in du bist — unabhängig von deinem eigenen Unterricht. Schaltet den Klassenlehrer-Bereich in der Seitenleiste frei."/>
|
||||
<TextBlock FontSize="13" Text="{Binding UntisHomeroomClassDisplay}"/>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Button Content="Klasse auswählen…" Command="{Binding UntisPickHomeroomClassCommand}"/>
|
||||
<Button Content="Entfernen" Command="{Binding UntisClearHomeroomClassCommand}"
|
||||
IsVisible="{Binding UntisHomeroomClassName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<Separator Margin="0,8"/>
|
||||
|
||||
<TextBlock Text="WebUntis-Stundenplan-Abgleich" FontSize="16" FontWeight="SemiBold"/>
|
||||
|
||||
@@ -4,8 +4,10 @@ using Avalonia.Platform.Storage;
|
||||
using LehrerApp.Core.Interfaces;
|
||||
using LehrerApp.Desktop.Services;
|
||||
using LehrerApp.Desktop.ViewModels;
|
||||
using LehrerApp.Desktop.ViewModels.Groups;
|
||||
using LehrerApp.Desktop.ViewModels.Planning;
|
||||
using LehrerApp.Desktop.ViewModels.Settings;
|
||||
using LehrerApp.Desktop.Views.Groups;
|
||||
using LehrerApp.Desktop.Views.Planning;
|
||||
using LehrerApp.Desktop.Views.Shared;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -31,6 +33,7 @@ public partial class SettingsView : UserControl
|
||||
vm.OnConfirmRecoveryRestore = ShowRecoveryRestoreConfirmDialog;
|
||||
vm.OnThemeChanged = App.ApplyTheme;
|
||||
vm.OnReviewUntisMapping = ShowUntisMappingReviewDialog;
|
||||
vm.OnPickHomeroomClass = PickHomeroomClassAsync;
|
||||
_ = vm.LoadSchoolLocationCommand.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
@@ -51,6 +54,20 @@ public partial class SettingsView : UserControl
|
||||
await dialog.ShowDialog<bool>(owner);
|
||||
}
|
||||
|
||||
private async Task<(int UntisId, string Name)?> PickHomeroomClassAsync()
|
||||
{
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
if (owner is null) return null;
|
||||
|
||||
var untis = App.Services.GetRequiredService<WebUntisIntegrationService>();
|
||||
var selectionVm = new WebUntisClassSelectionViewModel(untis);
|
||||
var selection = new WebUntisClassSelectionDialog { DataContext = selectionVm };
|
||||
await selectionVm.InitializeAsync();
|
||||
if (!await selection.ShowDialog<bool>(owner) || selectionVm.SelectedClass is null) return null;
|
||||
|
||||
return (selectionVm.SelectedClass.UntisId, selectionVm.SelectedClass.Name);
|
||||
}
|
||||
|
||||
private async Task<bool> SaveRecoveryFile(string content)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(this);
|
||||
|
||||
Reference in New Issue
Block a user