Unterrichtsplanung: Einheiten, Verlaufsplan-Editor, Kürzel-Katalog (Kapitel 4.1/4.2)
Neuer Tab "Planung" in GroupDetailView ersetzt den Platzhalter: Einheiten anlegen/bearbeiten/ als Vorlage in andere Gruppe kopieren, Stunden je Einheit mit Verschieben (inkl. Nachrücken der Folgestunden). Stundeneditor als tabellarischer Verlaufsplan (Phase/Dauer/Tätigkeit/ Material/Kurzsymbol je Zeile, Uhrzeit aus optionalem Stundenbeginn abgeleitet) statt eines einzelnen Phase-Felds mit Methoden-/Materialien-Chips — Kurzsymbol als Freitext mit Vorschlägen aus neuem Kürzel-Katalog (Einstellungen) plus bisher verwendeten Werten. Schema-Migrationen v1-v3 überführen bestehende Daten verlustfrei. 4.2.5 bewusst offen gelassen (hängt an Stundenplan, Kapitel 4.3). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="clr-namespace:LehrerApp.Desktop.ViewModels.Groups"
|
||||
xmlns:models="clr-namespace:LehrerApp.Core.Models;assembly=LehrerApp.Core"
|
||||
x:Class="LehrerApp.Desktop.Views.Groups.CopyUnitDialog"
|
||||
x:DataType="vm:CopyUnitDialogViewModel"
|
||||
Title="Einheit als Vorlage kopieren"
|
||||
Width="440" Height="320" MinWidth="380" MinHeight="280"
|
||||
CanResize="False" WindowStartupLocation="CenterOwner">
|
||||
|
||||
<Grid RowDefinitions="*,Auto" Margin="24">
|
||||
<StackPanel Grid.Row="0" Spacing="14">
|
||||
<TextBlock Text="Einheit als Vorlage kopieren" Classes="dialogtitle"/>
|
||||
<TextBlock Text="Titel, Aufbau und die zeitlichen Abstände der Stunden zueinander werden übernommen, alle Kalendertage neu ab dem gewählten Startdatum berechnet."
|
||||
FontSize="12" Opacity="0.6" TextWrapping="Wrap"/>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Zielgruppe *" FontSize="12" Opacity="0.7"/>
|
||||
<ComboBox ItemsSource="{Binding AvailableGroups}" SelectedItem="{Binding SelectedGroup}"
|
||||
HorizontalAlignment="Stretch" PlaceholderText="Gruppe auswählen">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="models:LearningGroup">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<TextBlock Text="{Binding SelectedGroupError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding SelectedGroupError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Neues Startdatum *" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding NewStartDateText}" PlaceholderText="TT.MM.JJJJ"/>
|
||||
<TextBlock Text="{Binding NewStartDateTextError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding NewStartDateTextError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Grid.Row="1" ColumnDefinitions="*,8,*" Margin="0,20,0,0">
|
||||
<Button Grid.Column="0" Content="Abbrechen" HorizontalAlignment="Stretch" Click="OnCancel"/>
|
||||
<Button Grid.Column="2" Content="Kopieren" HorizontalAlignment="Stretch" Click="OnSave"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,21 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using LehrerApp.Desktop.ViewModels.Groups;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.Groups;
|
||||
|
||||
public partial class CopyUnitDialog : Window
|
||||
{
|
||||
public CopyUnitDialog() => InitializeComponent();
|
||||
|
||||
private void OnSave(object? s, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is CopyUnitDialogViewModel vm && vm.SaveCommand.CanExecute(null))
|
||||
{
|
||||
vm.SaveCommand.Execute(null);
|
||||
if (vm.Result is not null) Close(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCancel(object? s, RoutedEventArgs e) => Close(false);
|
||||
}
|
||||
@@ -154,12 +154,7 @@
|
||||
|
||||
<!-- Tab: Planung -->
|
||||
<ContentPage Header="Planung">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock Text="Unterrichtseinheiten" FontSize="16" Opacity="0.4"
|
||||
HorizontalAlignment="Center"/>
|
||||
<TextBlock Text="Wird implementiert." FontSize="12" Opacity="0.3"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<views:PlanningTabView DataContext="{Binding PlanningTab}"/>
|
||||
</ContentPage>
|
||||
|
||||
<!-- Tab: Dokumentation -->
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
<Window 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.LessonDialog"
|
||||
x:DataType="vm:LessonDialogViewModel"
|
||||
Title="{Binding DialogTitle}"
|
||||
Width="960" Height="760" MinWidth="720" MinHeight="480"
|
||||
CanResize="True" WindowStartupLocation="CenterOwner">
|
||||
|
||||
<Grid RowDefinitions="*,Auto" Margin="24">
|
||||
<ScrollViewer Grid.Row="0">
|
||||
<StackPanel Spacing="14" Margin="0,0,12,0">
|
||||
<TextBlock Text="{Binding DialogTitle}" Classes="dialogtitle"/>
|
||||
|
||||
<Grid ColumnDefinitions="*,12,*,12,*,12,*">
|
||||
<StackPanel Grid.Column="0" Spacing="4">
|
||||
<TextBlock Text="Datum *" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding DateText}" PlaceholderText="TT.MM.JJJJ"/>
|
||||
<TextBlock Text="{Binding DateTextError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding DateTextError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Spacing="4">
|
||||
<TextBlock Text="Stunde Nr." FontSize="12" Opacity="0.7"/>
|
||||
<NumericUpDown Value="{Binding LessonNumber}" Minimum="1" Maximum="20" FormatString="0"
|
||||
ShowButtonSpinner="False"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="4" Spacing="4">
|
||||
<TextBlock Text="Beginn" FontSize="12" Opacity="0.7"
|
||||
ToolTip.Tip="Optional. Solange es noch keinen Stundenplan gibt: von Hand eintragen, damit die Uhrzeiten je Phase unten abgeleitet werden können."/>
|
||||
<TextBox Text="{Binding StartTimeText}" PlaceholderText="HH:MM"/>
|
||||
<TextBlock Text="{Binding StartTimeTextError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding StartTimeTextError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="6" Spacing="4">
|
||||
<TextBlock Text="Status" FontSize="12" Opacity="0.7"/>
|
||||
<ComboBox ItemsSource="{Binding StatusOptions}" SelectedItem="{Binding StatusName}"
|
||||
HorizontalAlignment="Stretch"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Thema *" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding Topic}" PlaceholderText="z.B. Brechung an planparallelen Platten"/>
|
||||
<TextBlock Text="{Binding TopicError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding TopicError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<Separator Margin="0,4"/>
|
||||
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="10" VerticalAlignment="Center">
|
||||
<TextBlock Text="Verlaufsplan" FontSize="14" FontWeight="SemiBold"/>
|
||||
<TextBlock Text="{Binding TotalDurationDisplay}" FontSize="12" Opacity="0.6"/>
|
||||
</StackPanel>
|
||||
<Button Grid.Column="1" Content="+ Phase" Command="{Binding AddPhaseCommand}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Tabellenkopf -->
|
||||
<Grid ColumnDefinitions="140,130,*,110,100,26,26,26" Margin="4,0,0,0">
|
||||
<TextBlock Grid.Column="0" Text="Phase" FontSize="11" FontWeight="SemiBold" Opacity="0.6"/>
|
||||
<TextBlock Grid.Column="1" Text="Dauer / Zeit" FontSize="11" FontWeight="SemiBold" Opacity="0.6"/>
|
||||
<TextBlock Grid.Column="2" Text="Tätigkeit" FontSize="11" FontWeight="SemiBold" Opacity="0.6"/>
|
||||
<TextBlock Grid.Column="3" Text="Material" FontSize="11" FontWeight="SemiBold" Opacity="0.6"/>
|
||||
<TextBlock Grid.Column="4" Text="Kurzsymbol" FontSize="11" FontWeight="SemiBold" Opacity="0.6"/>
|
||||
</Grid>
|
||||
<Separator/>
|
||||
|
||||
<!-- Eine Zeile je Phase, echte Tabellenspalten nebeneinander statt gestapelter Karten. -->
|
||||
<ItemsControl ItemsSource="{Binding Phases}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:PhaseStepEditItem">
|
||||
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}"
|
||||
BorderThickness="0,0,0,1" Padding="0,8">
|
||||
<Grid ColumnDefinitions="140,130,*,110,100,26,26,26">
|
||||
<TextBox Grid.Column="0" Text="{Binding Name}" PlaceholderText="z.B. Erarbeitung"
|
||||
VerticalAlignment="Top" Margin="0,0,6,0"/>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="6"
|
||||
VerticalAlignment="Top" Margin="0,0,6,0">
|
||||
<NumericUpDown Value="{Binding DurationMinutes}" Minimum="0" Maximum="180" Width="62"
|
||||
FormatString="0" ShowButtonSpinner="False" ToolTip.Tip="Dauer in Minuten"/>
|
||||
<TextBlock Text="{Binding ComputedTimeDisplay}" FontSize="12" Opacity="0.6"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<TextBox Grid.Column="2" Text="{Binding Activity}" AcceptsReturn="True" TextWrapping="Wrap"
|
||||
Height="56" VerticalAlignment="Top" Margin="0,0,6,0"
|
||||
PlaceholderText="Lehrer-/Schüler-Tätigkeit"
|
||||
ToolTip.Tip="Bei mehr Text scrollt das Feld intern."/>
|
||||
<AutoCompleteBox Grid.Column="3" Text="{Binding Material}"
|
||||
ItemsSource="{Binding $parent[ItemsControl].((vm:LessonDialogViewModel)DataContext).MaterialSuggestions}"
|
||||
FilterMode="Contains" MinimumPrefixLength="0" VerticalAlignment="Top"
|
||||
Margin="0,0,6,0" PlaceholderText="z.B. AB01"/>
|
||||
<AutoCompleteBox Grid.Column="4" Text="{Binding Shorthand}"
|
||||
ItemsSource="{Binding $parent[ItemsControl].((vm:LessonDialogViewModel)DataContext).ShorthandSuggestions}"
|
||||
FilterMode="Contains" MinimumPrefixLength="0" VerticalAlignment="Top"
|
||||
Margin="0,0,6,0" PlaceholderText="z.B. AB001->S, Plenum, LDE"
|
||||
ToolTip.Tip="Freitext für den schnellen Überblick — mal ein Materialfluss-Pfeil (AB001->S), mal nur eine Sozialform (Plenum, LDE)."/>
|
||||
<Button Grid.Column="5" Content="↑" Command="{Binding MoveUpCommand}" Padding="4,2"
|
||||
VerticalAlignment="Top" ToolTip.Tip="Nach oben"/>
|
||||
<Button Grid.Column="6" Content="↓" Command="{Binding MoveDownCommand}" Padding="4,2"
|
||||
VerticalAlignment="Top" Margin="2,0,0,0" ToolTip.Tip="Nach unten"/>
|
||||
<Button Grid.Column="7" Content="✕" Command="{Binding RemoveCommand}" Padding="4,2"
|
||||
VerticalAlignment="Top" Margin="2,0,0,0" ToolTip.Tip="Entfernen"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<Separator Margin="0,4"/>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Hausaufgabe" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding Homework}" AcceptsReturn="True" Height="48" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Reflexion" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding Reflection}" AcceptsReturn="True" Height="56" TextWrapping="Wrap"
|
||||
PlaceholderText="Nach der Stunde: was lief gut, was nicht?"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid Grid.Row="1" ColumnDefinitions="*,8,*" Margin="0,20,0,0">
|
||||
<Button Grid.Column="0" Content="Abbrechen" HorizontalAlignment="Stretch" Click="OnCancel"/>
|
||||
<Button Grid.Column="2" Content="{Binding SaveButtonText}"
|
||||
HorizontalAlignment="Stretch" Click="OnSave"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,21 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using LehrerApp.Desktop.ViewModels.Groups;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.Groups;
|
||||
|
||||
public partial class LessonDialog : Window
|
||||
{
|
||||
public LessonDialog() => InitializeComponent();
|
||||
|
||||
private void OnSave(object? s, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is LessonDialogViewModel vm && vm.SaveCommand.CanExecute(null))
|
||||
{
|
||||
vm.SaveCommand.Execute(null);
|
||||
if (vm.Result is not null) Close(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCancel(object? s, RoutedEventArgs e) => Close(false);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<Window 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.MoveLessonDialog"
|
||||
x:DataType="vm:MoveLessonDialogViewModel"
|
||||
Title="Stunde verschieben"
|
||||
Width="400" Height="260" MinWidth="360" MinHeight="240"
|
||||
CanResize="False" WindowStartupLocation="CenterOwner">
|
||||
|
||||
<Grid RowDefinitions="*,Auto" Margin="24">
|
||||
<StackPanel Grid.Row="0" Spacing="14">
|
||||
<TextBlock Text="Stunde verschieben" Classes="dialogtitle"/>
|
||||
<TextBlock FontSize="12" Opacity="0.6">
|
||||
<Run Text="Bisheriges Datum: "/>
|
||||
<Run Text="{Binding CurrentDateDisplay}"/>
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Neues Datum *" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding NewDateText}" PlaceholderText="TT.MM.JJJJ"/>
|
||||
<TextBlock Text="{Binding NewDateTextError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding NewDateTextError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Content="Folgestunden automatisch verschieben"
|
||||
IsChecked="{Binding ShiftFollowingPlanned}"
|
||||
ToolTip.Tip="Verschiebt alle noch geplanten Stunden derselben Einheit, die nach dieser Stunde liegen, um denselben Zeitraum. Bereits durchgeführte Stunden bleiben unverändert."/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Grid.Row="1" ColumnDefinitions="*,8,*" Margin="0,20,0,0">
|
||||
<Button Grid.Column="0" Content="Abbrechen" HorizontalAlignment="Stretch" Click="OnCancel"/>
|
||||
<Button Grid.Column="2" Content="Verschieben" HorizontalAlignment="Stretch" Click="OnSave"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,21 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using LehrerApp.Desktop.ViewModels.Groups;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.Groups;
|
||||
|
||||
public partial class MoveLessonDialog : Window
|
||||
{
|
||||
public MoveLessonDialog() => InitializeComponent();
|
||||
|
||||
private void OnSave(object? s, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is MoveLessonDialogViewModel vm && vm.SaveCommand.CanExecute(null))
|
||||
{
|
||||
vm.SaveCommand.Execute(null);
|
||||
if (vm.Result is not null) Close(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCancel(object? s, RoutedEventArgs e) => Close(false);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<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.PlanningTabView"
|
||||
x:DataType="vm:PlanningTabViewModel">
|
||||
|
||||
<Grid RowDefinitions="Auto,2*,Auto,Auto,2*" Margin="16">
|
||||
|
||||
<!-- Einheiten-Toolbar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="*,Auto" Margin="0,0,0,8">
|
||||
<TextBlock Grid.Column="0" Text="Unterrichtseinheiten" FontSize="14" FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"/>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="8">
|
||||
<Button Content="+ Einheit" Command="{Binding AddUnitCommand}"/>
|
||||
<Button Content="Bearbeiten" Command="{Binding EditUnitCommand}"/>
|
||||
<Button Content="Als Vorlage kopieren" Command="{Binding CopyUnitCommand}"/>
|
||||
<Button Content="Löschen" Command="{Binding DeleteUnitCommand}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Einheiten-Tabelle -->
|
||||
<DataGrid Grid.Row="1" ItemsSource="{Binding Units}"
|
||||
SelectedItem="{Binding SelectedUnit}"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="True"
|
||||
GridLinesVisibility="Horizontal"
|
||||
CanUserReorderColumns="False"
|
||||
Margin="0,0,0,8">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Titel" Binding="{Binding Title}" Width="*"/>
|
||||
<DataGridTextColumn Header="Zeitraum" Binding="{Binding DateRangeDisplay}" Width="200"/>
|
||||
<DataGridTemplateColumn Header="Status" Width="130">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="vm:UnitSummary">
|
||||
<Border Background="{Binding StatusColorHex}" CornerRadius="4"
|
||||
Padding="8,2" HorizontalAlignment="Left">
|
||||
<TextBlock Text="{Binding StatusLabel}" FontSize="12" Foreground="White"/>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Header="Fortschritt" Width="180">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="vm:UnitSummary">
|
||||
<StackPanel Spacing="2" VerticalAlignment="Center" Margin="0,4">
|
||||
<ProgressBar Value="{Binding ProgressFraction}" Maximum="1" Height="6"/>
|
||||
<TextBlock Text="{Binding ProgressText}" FontSize="11" Opacity="0.7"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn Header="Kompetenzen" Binding="{Binding CompetencyCountLabel}" Width="120"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<Separator Grid.Row="2" Margin="0,0,0,8"/>
|
||||
|
||||
<!-- Stunden-Toolbar -->
|
||||
<Grid Grid.Row="3" ColumnDefinitions="*,Auto" Margin="0,0,0,8">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="Stunden" FontSize="14" FontWeight="SemiBold"/>
|
||||
<TextBlock Text="{Binding SelectedUnitTitleSuffix}" FontSize="14" FontWeight="SemiBold"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="8">
|
||||
<Button Content="+ Stunde" Command="{Binding AddLessonCommand}"/>
|
||||
<Button Content="Bearbeiten" Command="{Binding EditLessonCommand}"/>
|
||||
<Button Content="Verschieben" Command="{Binding MoveLessonCommand}"/>
|
||||
<Button Content="Status → Durchgeführt" Command="{Binding AdvanceLessonStatusCommand}"/>
|
||||
<Button Content="Löschen" Command="{Binding DeleteLessonCommand}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Stunden-Tabelle -->
|
||||
<DataGrid Grid.Row="4" ItemsSource="{Binding Lessons}"
|
||||
SelectedItem="{Binding SelectedLesson}"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="True"
|
||||
GridLinesVisibility="Horizontal"
|
||||
CanUserReorderColumns="False">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Datum" Binding="{Binding DateDisplay}" Width="100"/>
|
||||
<DataGridTextColumn Header="Nr." Binding="{Binding LessonNumber}" Width="50"/>
|
||||
<DataGridTextColumn Header="Thema" Binding="{Binding Topic}" Width="*"/>
|
||||
<DataGridTextColumn Header="Beginn" Binding="{Binding StartTimeDisplay}" Width="70"/>
|
||||
<DataGridTemplateColumn Header="Status" Width="130">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="vm:LessonSummary">
|
||||
<Border Background="{Binding StatusColorHex}" CornerRadius="4"
|
||||
Padding="8,2" HorizontalAlignment="Left">
|
||||
<TextBlock Text="{Binding StatusLabel}" FontSize="12" Foreground="White"/>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn Header="Phasen" Binding="{Binding PhaseCountLabel}" Width="80"/>
|
||||
<DataGridTextColumn Header="Dauer" Binding="{Binding TotalDurationLabel}" Width="80"/>
|
||||
<DataGridTextColumn Header="Materialien" Binding="{Binding MaterialsDisplay}" Width="150"/>
|
||||
<DataGridTemplateColumn Header="HA" Width="40">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate x:DataType="vm:LessonSummary">
|
||||
<TextBlock Text="✓" IsVisible="{Binding HasHomework}" HorizontalAlignment="Center"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,114 @@
|
||||
using Avalonia.Controls;
|
||||
using LehrerApp.Core.Interfaces;
|
||||
using LehrerApp.Core.Models;
|
||||
using LehrerApp.Desktop.ViewModels.Groups;
|
||||
using LehrerApp.Desktop.Views.Shared;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.Groups;
|
||||
|
||||
public partial class PlanningTabView : UserControl
|
||||
{
|
||||
public PlanningTabView() => InitializeComponent();
|
||||
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
base.OnDataContextChanged(e);
|
||||
if (DataContext is PlanningTabViewModel vm)
|
||||
{
|
||||
vm.OnAddUnit = groupId => ShowUnitDialog(groupId, editingUnit: null);
|
||||
vm.OnEditUnit = unit => ShowUnitDialog(unit.GroupId, editingUnit: unit);
|
||||
vm.OnConfirmDeleteUnit = ShowDeleteUnitDialog;
|
||||
vm.OnPickCopyTarget = ShowCopyUnitDialog;
|
||||
vm.OnAddLesson = (unitId, groupId, materials, shorthands) =>
|
||||
ShowLessonDialog(unitId, groupId, materials, shorthands, editingLesson: null);
|
||||
vm.OnEditLesson = (lesson, materials, shorthands) =>
|
||||
ShowLessonDialog(lesson.UnitId, lesson.GroupId, materials, shorthands, editingLesson: lesson);
|
||||
vm.OnConfirmDeleteLesson = ShowDeleteLessonDialog;
|
||||
vm.OnPickMoveTarget = ShowMoveLessonDialog;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> ShowUnitDialog(Guid groupId, Unit? editingUnit)
|
||||
{
|
||||
if (DataContext is not PlanningTabViewModel vm) return false;
|
||||
|
||||
var dialogVm = new UnitDialogViewModel(
|
||||
App.Services.GetRequiredService<IUnitRepository>(),
|
||||
App.Services.GetRequiredService<ICompetencyDomainRepository>(),
|
||||
groupId, vm.SubjectId, vm.GradeLevel, vm.SubjectName, editingUnit);
|
||||
|
||||
var dialog = new UnitDialog { DataContext = dialogVm };
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
if (owner is null) return false;
|
||||
|
||||
var ok = await dialog.ShowDialog<bool>(owner);
|
||||
return ok && dialogVm.Result is not null;
|
||||
}
|
||||
|
||||
private async Task<bool> ShowDeleteUnitDialog(UnitSummary unit)
|
||||
{
|
||||
var info = new ConfirmDialogInfo
|
||||
{
|
||||
Title = "Einheit löschen?",
|
||||
Message = $"\"{unit.Title}\" wird inkl. aller zugehörigen Stunden endgültig gelöscht.",
|
||||
ConfirmText = "Löschen",
|
||||
};
|
||||
var dialog = new ConfirmDialog { DataContext = info };
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
return owner is not null && await dialog.ShowDialog<bool>(owner);
|
||||
}
|
||||
|
||||
private async Task<CopyUnitTarget?> ShowCopyUnitDialog(Unit unit)
|
||||
{
|
||||
var dialogVm = new CopyUnitDialogViewModel(
|
||||
App.Services.GetRequiredService<IGroupRepository>(), unit.GroupId);
|
||||
|
||||
var dialog = new CopyUnitDialog { DataContext = dialogVm };
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
if (owner is null) return null;
|
||||
|
||||
var ok = await dialog.ShowDialog<bool>(owner);
|
||||
return ok ? dialogVm.Result : null;
|
||||
}
|
||||
|
||||
private async Task<bool> ShowLessonDialog(Guid unitId, Guid groupId,
|
||||
List<string> materialSuggestions, List<string> shorthandHistorySuggestions, Lesson? editingLesson)
|
||||
{
|
||||
var dialogVm = new LessonDialogViewModel(
|
||||
App.Services.GetRequiredService<ILessonRepository>(),
|
||||
App.Services.GetRequiredService<IShorthandCodeRepository>(),
|
||||
unitId, groupId, materialSuggestions, shorthandHistorySuggestions, editingLesson);
|
||||
|
||||
var dialog = new LessonDialog { DataContext = dialogVm };
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
if (owner is null) return false;
|
||||
|
||||
var ok = await dialog.ShowDialog<bool>(owner);
|
||||
return ok && dialogVm.Result is not null;
|
||||
}
|
||||
|
||||
private async Task<bool> ShowDeleteLessonDialog(LessonSummary lesson)
|
||||
{
|
||||
var info = new ConfirmDialogInfo
|
||||
{
|
||||
Title = "Stunde löschen?",
|
||||
Message = $"Die Stunde vom {lesson.DateDisplay} wird endgültig gelöscht.",
|
||||
ConfirmText = "Löschen",
|
||||
};
|
||||
var dialog = new ConfirmDialog { DataContext = info };
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
return owner is not null && await dialog.ShowDialog<bool>(owner);
|
||||
}
|
||||
|
||||
private async Task<MoveLessonTarget?> ShowMoveLessonDialog(Lesson lesson)
|
||||
{
|
||||
var dialogVm = new MoveLessonDialogViewModel(lesson.Date);
|
||||
var dialog = new MoveLessonDialog { DataContext = dialogVm };
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
if (owner is null) return null;
|
||||
|
||||
var ok = await dialog.ShowDialog<bool>(owner);
|
||||
return ok ? dialogVm.Result : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<Window 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.UnitDialog"
|
||||
x:DataType="vm:UnitDialogViewModel"
|
||||
Title="{Binding DialogTitle}"
|
||||
Width="520" Height="600" MinWidth="440" MinHeight="380"
|
||||
CanResize="True" WindowStartupLocation="CenterOwner">
|
||||
|
||||
<Grid RowDefinitions="*,Auto" Margin="24">
|
||||
<ScrollViewer Grid.Row="0">
|
||||
<StackPanel Spacing="14" Margin="0,0,12,0">
|
||||
<StackPanel Spacing="2">
|
||||
<TextBlock Text="{Binding DialogTitle}" Classes="dialogtitle"/>
|
||||
<TextBlock Text="{Binding SubjectDisplay}" FontSize="12" Opacity="0.6"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Titel *" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding Title}" PlaceholderText="z.B. Optik: Reflexion und Brechung"/>
|
||||
<TextBlock Text="{Binding TitleError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding TitleError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid ColumnDefinitions="*,12,*">
|
||||
<StackPanel Grid.Column="0" Spacing="4">
|
||||
<TextBlock Text="Start" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding StartDateText}" PlaceholderText="TT.MM.JJJJ"/>
|
||||
<TextBlock Text="{Binding StartDateTextError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding StartDateTextError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Spacing="4">
|
||||
<TextBlock Text="Ende" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding EndDateText}" PlaceholderText="TT.MM.JJJJ"/>
|
||||
<TextBlock Text="{Binding EndDateTextError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding EndDateTextError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Status" FontSize="12" Opacity="0.7"/>
|
||||
<ComboBox ItemsSource="{Binding StatusOptions}" SelectedItem="{Binding StatusName}"
|
||||
HorizontalAlignment="Stretch"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Notizen" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding Notes}" AcceptsReturn="True" Height="56" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
|
||||
<Separator Margin="0,4"/>
|
||||
|
||||
<Button Content="{Binding CompetencySummary}" Command="{Binding ToggleCompetencyPanelCommand}"
|
||||
HorizontalAlignment="Left" FontSize="12" Padding="8,4"/>
|
||||
|
||||
<ItemsControl ItemsSource="{Binding CompetencyTagGroups}" IsVisible="{Binding IsCompetencyPanelOpen}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:CompetencyTagGroup">
|
||||
<StackPanel Margin="4,2">
|
||||
<TextBlock Text="{Binding DisplayName}" FontSize="11" Opacity="0.6"/>
|
||||
<ItemsControl ItemsSource="{Binding Items}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:CompetencyTag">
|
||||
<ToggleButton Content="{Binding Display}" IsChecked="{Binding IsSelected}"
|
||||
Margin="0,2,6,2" FontSize="11" Padding="6,2"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid Grid.Row="1" ColumnDefinitions="*,8,*" Margin="0,20,0,0">
|
||||
<Button Grid.Column="0" Content="Abbrechen" HorizontalAlignment="Stretch" Click="OnCancel"/>
|
||||
<Button Grid.Column="2" Content="{Binding SaveButtonText}"
|
||||
HorizontalAlignment="Stretch" Click="OnSave"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,21 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using LehrerApp.Desktop.ViewModels.Groups;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.Groups;
|
||||
|
||||
public partial class UnitDialog : Window
|
||||
{
|
||||
public UnitDialog() => InitializeComponent();
|
||||
|
||||
private void OnSave(object? s, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is UnitDialogViewModel vm && vm.SaveCommand.CanExecute(null))
|
||||
{
|
||||
vm.SaveCommand.Execute(null);
|
||||
if (vm.Result is not null) Close(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCancel(object? s, RoutedEventArgs e) => Close(false);
|
||||
}
|
||||
@@ -56,6 +56,54 @@
|
||||
</ScrollViewer>
|
||||
</ContentPage>
|
||||
|
||||
<!-- Tab: Kürzel-Katalog -->
|
||||
<ContentPage Header="Kürzel-Katalog">
|
||||
<ScrollViewer>
|
||||
<StackPanel Margin="32,20,32,28" Spacing="14" MaxWidth="640">
|
||||
|
||||
<TextBlock Text="Kürzel für den Stundenverlaufsplan (Kapitel 4.2), z.B. Tb = Tafelbild. Im Stundeneditor werden Von/Nach aus diesen Kürzeln zu einem Kurzsymbol wie "Tb->SH" kombiniert."
|
||||
FontSize="12" Opacity="0.6" TextWrapping="Wrap"/>
|
||||
|
||||
<ItemsControl ItemsSource="{Binding ShorthandCodes}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="vm:ShorthandCodeListItem">
|
||||
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}"
|
||||
BorderThickness="0,0,0,1" Padding="0,7">
|
||||
<Grid ColumnDefinitions="80,*,Auto">
|
||||
<TextBlock Grid.Column="0" Text="{Binding Code}"
|
||||
VerticalAlignment="Center" FontSize="14" FontWeight="SemiBold"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Label}"
|
||||
VerticalAlignment="Center" Opacity="0.7" FontSize="13"/>
|
||||
<Button Grid.Column="2" Content="Löschen" FontSize="12" Padding="10,4"
|
||||
Command="{Binding $parent[ItemsControl].((vm:SettingsViewModel)DataContext).DeleteShorthandCodeCommand}"
|
||||
CommandParameter="{Binding}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}"
|
||||
BorderThickness="1" CornerRadius="6" Padding="14,12">
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Text="Neues Kürzel" FontSize="12" FontWeight="SemiBold" Opacity="0.7"/>
|
||||
<Grid ColumnDefinitions="100,12,*,12,Auto">
|
||||
<TextBox Grid.Column="0" Text="{Binding NewShorthandCode}"
|
||||
PlaceholderText="Kürzel (z.B. Tb)"/>
|
||||
<TextBox Grid.Column="2" Text="{Binding NewShorthandLabel}"
|
||||
PlaceholderText="Bedeutung (z.B. Tafelbild)"/>
|
||||
<Button Grid.Column="4" Content="Hinzufügen"
|
||||
Command="{Binding AddShorthandCodeCommand}"/>
|
||||
</Grid>
|
||||
<TextBlock Text="{Binding NewShorthandCodeError}" Foreground="Red" FontSize="12"
|
||||
IsVisible="{Binding NewShorthandCodeError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</ContentPage>
|
||||
|
||||
<!-- Tab: Kompetenzen -->
|
||||
<ContentPage Header="Kompetenzen">
|
||||
<ScrollViewer>
|
||||
|
||||
Reference in New Issue
Block a user