feat: add seating plans for learning groups
This commit is contained in:
@@ -101,6 +101,11 @@
|
||||
</DataGrid>
|
||||
</ContentPage>
|
||||
|
||||
<!-- Tab: Sitzpläne -->
|
||||
<ContentPage Header="Sitzpläne">
|
||||
<views:SeatingPlanTabView DataContext="{Binding SeatingPlanTab}"/>
|
||||
</ContentPage>
|
||||
|
||||
<!-- Tab: Mitarbeit -->
|
||||
<ContentPage Header="Mitarbeit">
|
||||
<views:ParticipationTabView DataContext="{Binding ParticipationTab}"/>
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<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.SeatingPlanDialog"
|
||||
x:DataType="vm:SeatingPlanDialogViewModel"
|
||||
Title="{Binding DialogTitle}" Width="480" Height="470"
|
||||
CanResize="False" WindowStartupLocation="CenterOwner">
|
||||
<Grid RowDefinitions="*,Auto" Margin="24">
|
||||
<StackPanel Spacing="16">
|
||||
<StackPanel Spacing="3">
|
||||
<TextBlock Text="{Binding DialogTitle}" Classes="dialogtitle"/>
|
||||
<TextBlock Text="Name und Raum unterscheiden mehrere Pläne derselben Lerngruppe."
|
||||
FontSize="12" Opacity="0.6" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Name *" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding Name}" PlaceholderText="z. B. Standard, Gruppenarbeit"/>
|
||||
<TextBlock Text="{Binding NameError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding NameError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Raum" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding Room}" PlaceholderText="z. B. B204, Physikraum"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid ColumnDefinitions="*,16,*">
|
||||
<StackPanel Grid.Column="0" Spacing="4">
|
||||
<TextBlock Text="Reihen" FontSize="12" Opacity="0.7"/>
|
||||
<NumericUpDown Value="{Binding Rows}" Minimum="1" Maximum="10" Increment="1"
|
||||
FormatString="0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Spacing="4">
|
||||
<TextBlock Text="Plätze pro Reihe" FontSize="12" Opacity="0.7"/>
|
||||
<NumericUpDown Value="{Binding Columns}" Minimum="1" Maximum="10" Increment="1"
|
||||
FormatString="0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<TextBlock Text="{Binding LayoutError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding LayoutError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
|
||||
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumLowBrush}"
|
||||
CornerRadius="6" Padding="12">
|
||||
<TextBlock Text="Beim Verkleinern des Rasters entfallen Zuordnungen außerhalb der neuen Größe."
|
||||
FontSize="12" Opacity="0.7" TextWrapping="Wrap"/>
|
||||
</Border>
|
||||
</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="{Binding SaveButtonText}" HorizontalAlignment="Stretch" Click="OnSave"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,19 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using LehrerApp.Desktop.ViewModels.Groups;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.Groups;
|
||||
|
||||
public partial class SeatingPlanDialog : Window
|
||||
{
|
||||
public SeatingPlanDialog() => InitializeComponent();
|
||||
|
||||
private void OnSave(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is not SeatingPlanDialogViewModel vm) return;
|
||||
vm.SaveCommand.Execute(null);
|
||||
if (vm.Result is not null) Close(true);
|
||||
}
|
||||
|
||||
private void OnCancel(object? sender, RoutedEventArgs e) => Close(false);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<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.SeatingPlanTabView"
|
||||
x:DataType="vm:SeatingPlanTabViewModel">
|
||||
<Grid ColumnDefinitions="260,*">
|
||||
<Border Grid.Column="0" BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}"
|
||||
BorderThickness="0,0,1,0" Padding="16">
|
||||
<Grid RowDefinitions="Auto,*,Auto">
|
||||
<StackPanel Grid.Row="0" Spacing="4" Margin="0,0,0,12">
|
||||
<TextBlock Text="Sitzpläne" FontSize="18" FontWeight="SemiBold"/>
|
||||
<TextBlock Text="Mehrere Pläne, z. B. für verschiedene Räume" FontSize="12"
|
||||
Opacity="0.6" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
<ListBox Grid.Row="1" ItemsSource="{Binding Plans}" SelectedItem="{Binding SelectedPlan}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:SeatingPlanSummary">
|
||||
<StackPanel Margin="4,6" Spacing="2">
|
||||
<TextBlock Text="{Binding Name}" FontWeight="SemiBold"/>
|
||||
<TextBlock Text="{Binding RoomDisplay}" FontSize="12" Opacity="0.6"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<StackPanel Grid.Row="2" Spacing="8" Margin="0,12,0,0">
|
||||
<Button Content="+ Sitzplan" Command="{Binding AddPlanCommand}" HorizontalAlignment="Stretch"/>
|
||||
<Grid ColumnDefinitions="*,8,*" IsVisible="{Binding HasSelectedPlan}">
|
||||
<Button Grid.Column="0" Content="Bearbeiten" Command="{Binding EditPlanCommand}"
|
||||
HorizontalAlignment="Stretch"/>
|
||||
<Button Grid.Column="2" Content="Löschen" Command="{Binding DeletePlanCommand}"
|
||||
HorizontalAlignment="Stretch"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Column="1">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="10"
|
||||
IsVisible="{Binding HasPlans, Converter={x:Static BoolConverters.Not}}">
|
||||
<TextBlock Text="Noch kein Sitzplan" FontSize="20" FontWeight="SemiBold"
|
||||
HorizontalAlignment="Center"/>
|
||||
<TextBlock Text="Lege einen Plan an und ordne die Schüler den Plätzen zu."
|
||||
Opacity="0.6" TextAlignment="Center"/>
|
||||
<Button Content="Ersten Sitzplan anlegen" Command="{Binding AddPlanCommand}"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid RowDefinitions="Auto,*" IsVisible="{Binding HasSelectedPlan}" Margin="24">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="*,Auto" Margin="0,0,0,18">
|
||||
<StackPanel Spacing="3">
|
||||
<TextBlock Text="{Binding PlanTitle}" FontSize="22" FontWeight="SemiBold"/>
|
||||
<TextBlock Text="{Binding PlanSubtitle}" Opacity="0.65"/>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="1" Text="{Binding AssignmentSummary}" VerticalAlignment="Bottom"
|
||||
FontSize="12" Opacity="0.6"/>
|
||||
</Grid>
|
||||
|
||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Spacing="14" HorizontalAlignment="Center">
|
||||
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumLowBrush}"
|
||||
CornerRadius="6" Padding="36,8" HorizontalAlignment="Center">
|
||||
<TextBlock Text="Tafel / Vorderseite" FontWeight="SemiBold" Opacity="0.75"/>
|
||||
</Border>
|
||||
<ItemsControl ItemsSource="{Binding Seats}" HorizontalAlignment="Center">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<UniformGrid Columns="{Binding PlanColumns}"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:SeatCellViewModel">
|
||||
<Border Width="190" MinHeight="76" Margin="5" Padding="10"
|
||||
BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}"
|
||||
BorderThickness="1" CornerRadius="7">
|
||||
<StackPanel Spacing="5">
|
||||
<TextBlock Text="{Binding PositionLabel}" FontSize="10" Opacity="0.5"/>
|
||||
<ComboBox ItemsSource="{Binding Options}" SelectedItem="{Binding SelectedOption}"
|
||||
IsEnabled="{Binding CanEdit}" HorizontalAlignment="Stretch">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:StudentSeatOption">
|
||||
<TextBlock Text="{Binding DisplayName}"/>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,46 @@
|
||||
using Avalonia.Controls;
|
||||
using LehrerApp.Core.Models;
|
||||
using LehrerApp.Desktop.ViewModels.Groups;
|
||||
using LehrerApp.Desktop.Views.Shared;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.Groups;
|
||||
|
||||
public partial class SeatingPlanTabView : UserControl
|
||||
{
|
||||
public SeatingPlanTabView() => InitializeComponent();
|
||||
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
base.OnDataContextChanged(e);
|
||||
if (DataContext is SeatingPlanTabViewModel vm)
|
||||
{
|
||||
vm.OnEditPlan = ShowPlanDialog;
|
||||
vm.OnConfirmDelete = ShowDeleteConfirmDialog;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<SeatingPlan?> ShowPlanDialog(SeatingPlan? plan)
|
||||
{
|
||||
if (DataContext is not SeatingPlanTabViewModel vm) return null;
|
||||
var dialogVm = vm.CreateDialogViewModel(plan);
|
||||
var dialog = new SeatingPlanDialog { DataContext = dialogVm };
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
if (owner is null || !await dialog.ShowDialog<bool>(owner)) return null;
|
||||
return dialogVm.Result;
|
||||
}
|
||||
|
||||
private async Task<bool> ShowDeleteConfirmDialog(SeatingPlanSummary plan)
|
||||
{
|
||||
var dialog = new ConfirmDialog
|
||||
{
|
||||
DataContext = new ConfirmDialogInfo
|
||||
{
|
||||
Title = "Sitzplan löschen?",
|
||||
Message = $"Der Sitzplan „{plan.Name}“ und seine Zuordnungen werden gelöscht.",
|
||||
ConfirmText = "Löschen",
|
||||
},
|
||||
};
|
||||
var owner = TopLevel.GetTopLevel(this) as Window;
|
||||
return owner is not null && await dialog.ShowDialog<bool>(owner);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user