Neue Abwensenheitsmodi plus Upgrade Sitzplan
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
<Grid Grid.Row="2" RowDefinitions="Auto,Auto" ColumnDefinitions="*,Auto" Margin="0,12,0,0">
|
||||
<StackPanel Grid.Row="0" Grid.Column="0" Spacing="3">
|
||||
<TextBlock FontSize="10" Opacity="0.55" TextWrapping="Wrap"
|
||||
Text="Anwesenheit: 1 anwesend · 2 Entschuldigung offen · 5 krank/entschuldigt · 7 andere Schulveranstaltung · 9 geschwänzt · 0 unentschuldigt · X nicht kontrolliert"/>
|
||||
Text="Anwesenheit: 1 anwesend · 2 Entschuldigung offen · 5 krank/entschuldigt · 7 andere Schulveranstaltung · 9 geschwänzt · 0 unentschuldigt · X nicht kontrolliert · seltene Status per Klick im Menü"/>
|
||||
<TextBlock FontSize="10" Opacity="0.55" TextWrapping="Wrap"
|
||||
Text="Hausaufgaben mit Alt/⌥: 1 gemacht · 3 teilweise/Rest offen · 4 Rest nachgereicht · 5 Rest nicht nachgereicht · 7 nicht gemacht/offen · 8 vollständig nachgereicht · 0 endgültig nicht nachgereicht · X keine aufgegeben"/>
|
||||
<TextBlock FontSize="10" Opacity="0.55"
|
||||
|
||||
@@ -67,6 +67,13 @@ public partial class AttendanceHomeworkQuickInputDialog : Window
|
||||
AddAttendanceItem(flyout, row, "[7] ◇ Andere Schulveranstaltung", AttendanceStatus.OtherSchoolEvent);
|
||||
AddAttendanceItem(flyout, row, "[9] ✕ Geschwänzt", AttendanceStatus.Truant);
|
||||
AddAttendanceItem(flyout, row, "[0] ! Unentschuldigt", AttendanceStatus.Unexcused);
|
||||
flyout.Items.Add(new Separator());
|
||||
AddAttendanceItem(flyout, row, "V Verspätet", AttendanceStatus.Late);
|
||||
AddAttendanceItem(flyout, row, "V! Erheblich verspätet", AttendanceStatus.SignificantlyLate);
|
||||
AddAttendanceItem(flyout, row, "A Während des Unterrichts abgängig", AttendanceStatus.LeftDuringClass);
|
||||
AddAttendanceItem(flyout, row, "L Lerninsel", AttendanceStatus.LearningIsland);
|
||||
AddAttendanceItem(flyout, row, "S Suspendiert", AttendanceStatus.Suspended);
|
||||
flyout.Items.Add(new Separator());
|
||||
AddAttendanceItem(flyout, row, "[X] · Nicht kontrolliert", null);
|
||||
button.Flyout = flyout;
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
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">
|
||||
Title="{Binding DialogTitle}" Width="620" Height="680" MinHeight="560"
|
||||
CanResize="True" WindowStartupLocation="CenterOwner">
|
||||
<Grid RowDefinitions="*,Auto" Margin="24">
|
||||
<ScrollViewer>
|
||||
<StackPanel Spacing="16">
|
||||
<StackPanel Spacing="3">
|
||||
<TextBlock Text="{Binding DialogTitle}" Classes="dialogtitle"/>
|
||||
@@ -40,12 +41,39 @@
|
||||
<TextBlock Text="{Binding LayoutError}" Foreground="Red" FontSize="11"
|
||||
IsVisible="{Binding LayoutError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Tafelposition" FontSize="12" Opacity="0.7"/>
|
||||
<CheckBox Content="Tafel unterhalb der Sitzplätze anzeigen"
|
||||
IsChecked="{Binding IsBoardAtBottom}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="7">
|
||||
<TextBlock Text="Abstände zwischen den Tischen" FontSize="12" Opacity="0.7"/>
|
||||
<TextBlock Text="Breite 0 bedeutet: kein zusätzlicher Abstand. So lassen sich z. B. Tischgruppen und Mittelgänge abbilden."
|
||||
FontSize="11" Opacity="0.55" TextWrapping="Wrap"/>
|
||||
<ItemsControl ItemsSource="{Binding ColumnGaps}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate><WrapPanel/></ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:ColumnGapEditor">
|
||||
<StackPanel Width="125" Margin="0,0,10,8" Spacing="3">
|
||||
<TextBlock Text="{Binding Label}" FontSize="11" Opacity="0.65"/>
|
||||
<NumericUpDown Value="{Binding Width}" Minimum="0" Maximum="300"
|
||||
Increment="10" FormatString="0 px"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
|
||||
<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>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid Grid.Row="1" ColumnDefinitions="*,8,*" Margin="0,20,0,0">
|
||||
<Button Grid.Column="0" Content="Abbrechen" HorizontalAlignment="Stretch" Click="OnCancel"/>
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace LehrerApp.Desktop.Views.Groups;
|
||||
|
||||
/// <summary>
|
||||
/// Ordnet Sitzplätze in einem Raster an und fügt zwischen ausgewählten Spalten zusätzliche
|
||||
/// transparente Breite ein. Anders als ein UniformGrid kann der Abstand je Spaltengrenze variieren.
|
||||
/// </summary>
|
||||
public sealed class SeatingPlanPanel : Panel
|
||||
{
|
||||
public static readonly StyledProperty<int> ColumnsProperty =
|
||||
AvaloniaProperty.Register<SeatingPlanPanel, int>(nameof(Columns), 1);
|
||||
|
||||
public static readonly StyledProperty<IReadOnlyList<double>> ColumnGapWidthsProperty =
|
||||
AvaloniaProperty.Register<SeatingPlanPanel, IReadOnlyList<double>>(
|
||||
nameof(ColumnGapWidths), Array.Empty<double>());
|
||||
|
||||
public int Columns
|
||||
{
|
||||
get => GetValue(ColumnsProperty);
|
||||
set => SetValue(ColumnsProperty, value);
|
||||
}
|
||||
|
||||
public IReadOnlyList<double> ColumnGapWidths
|
||||
{
|
||||
get => GetValue(ColumnGapWidthsProperty);
|
||||
set => SetValue(ColumnGapWidthsProperty, value);
|
||||
}
|
||||
|
||||
static SeatingPlanPanel() =>
|
||||
AffectsMeasure<SeatingPlanPanel>(ColumnsProperty, ColumnGapWidthsProperty);
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
child.Measure(Size.Infinity);
|
||||
|
||||
if (Children.Count == 0) return default;
|
||||
var columns = Math.Max(1, Columns);
|
||||
var rows = (int)Math.Ceiling((double)Children.Count / columns);
|
||||
var cellWidth = Children.Max(child => child.DesiredSize.Width);
|
||||
var cellHeight = Children.Max(child => child.DesiredSize.Height);
|
||||
return new Size(cellWidth * columns + GapWidth(columns), cellHeight * rows);
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
if (Children.Count == 0) return finalSize;
|
||||
var columns = Math.Max(1, Columns);
|
||||
var cellWidth = Children.Max(child => child.DesiredSize.Width);
|
||||
var cellHeight = Children.Max(child => child.DesiredSize.Height);
|
||||
|
||||
for (var index = 0; index < Children.Count; index++)
|
||||
{
|
||||
var column = index % columns;
|
||||
var row = index / columns;
|
||||
var child = Children[index];
|
||||
var x = column * cellWidth + GapWidthBefore(column);
|
||||
var childX = x + Math.Max(0, (cellWidth - child.DesiredSize.Width) / 2);
|
||||
var childY = row * cellHeight + Math.Max(0, (cellHeight - child.DesiredSize.Height) / 2);
|
||||
child.Arrange(new Rect(childX, childY, child.DesiredSize.Width, child.DesiredSize.Height));
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
private double GapWidth(int columns) =>
|
||||
Enumerable.Range(0, Math.Max(0, columns - 1)).Sum(GapAt);
|
||||
|
||||
private double GapWidthBefore(int column) =>
|
||||
Enumerable.Range(0, Math.Max(0, column)).Sum(GapAt);
|
||||
|
||||
private double GapAt(int index) => index < ColumnGapWidths.Count
|
||||
? Math.Clamp(ColumnGapWidths[index], 0, 300)
|
||||
: 0;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="clr-namespace:LehrerApp.Desktop.ViewModels.Groups"
|
||||
xmlns:groups="clr-namespace:LehrerApp.Desktop.Views.Groups"
|
||||
x:Class="LehrerApp.Desktop.Views.Groups.SeatingPlanTabView"
|
||||
x:DataType="vm:SeatingPlanTabViewModel">
|
||||
<UserControl.Styles>
|
||||
@@ -37,7 +38,7 @@
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<StackPanel Grid.Row="2" Spacing="8" Margin="0,12,0,0">
|
||||
<StackPanel Grid.Row="2" Spacing="8" Margin="0,12,0,0" IsVisible="{Binding IsEditMode}">
|
||||
<Button Content="+ Sitzplan" Command="{Binding AddPlanCommand}" HorizontalAlignment="Stretch"/>
|
||||
<Grid ColumnDefinitions="*,8,*" IsVisible="{Binding HasSelectedPlan}">
|
||||
<Button Grid.Column="0" Content="Bearbeiten" Command="{Binding EditPlanCommand}"
|
||||
@@ -60,16 +61,20 @@
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid RowDefinitions="Auto,*" ColumnDefinitions="*,220" IsVisible="{Binding HasSelectedPlan}" Margin="24">
|
||||
<Grid RowDefinitions="Auto,*" ColumnDefinitions="*,Auto" IsVisible="{Binding HasSelectedPlan}" Margin="24">
|
||||
<Grid Grid.Row="0" Grid.ColumnSpan="2" 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>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Bottom">
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Bottom" Spacing="4">
|
||||
<ToggleSwitch Content="Bearbeitungsmodus" IsChecked="{Binding IsEditMode}"
|
||||
IsVisible="{Binding IsEditable}" HorizontalAlignment="Right"/>
|
||||
<TextBlock Text="{Binding AssignmentSummary}" HorizontalAlignment="Right" FontSize="12" Opacity="0.6"/>
|
||||
<TextBlock Text="Ziehen: Platz ändern · Klicken: bewerten" HorizontalAlignment="Right"
|
||||
FontSize="11" Opacity="0.5"/>
|
||||
FontSize="11" Opacity="0.5" IsVisible="{Binding IsEditMode}"/>
|
||||
<TextBlock Text="Klicken: bewerten" HorizontalAlignment="Right"
|
||||
FontSize="11" Opacity="0.5" IsVisible="{Binding IsEditMode, Converter={x:Static BoolConverters.Not}}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -82,13 +87,15 @@
|
||||
DragDrop.DragLeave="OnRoomDragLeave">
|
||||
<StackPanel Spacing="14" HorizontalAlignment="Center">
|
||||
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumLowBrush}"
|
||||
CornerRadius="6" Padding="36,8" HorizontalAlignment="Center">
|
||||
CornerRadius="6" Padding="36,8" HorizontalAlignment="Center"
|
||||
IsVisible="{Binding IsBoardAtTop}">
|
||||
<TextBlock Text="Tafel / Vorderseite" FontWeight="SemiBold" Opacity="0.75"/>
|
||||
</Border>
|
||||
<ItemsControl ItemsSource="{Binding Seats}" HorizontalAlignment="Center">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<UniformGrid Columns="{Binding PlanColumns}"/>
|
||||
<groups:SeatingPlanPanel Columns="{Binding PlanColumns}"
|
||||
ColumnGapWidths="{Binding ColumnGapWidths}"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
@@ -109,7 +116,7 @@
|
||||
<StackPanel Spacing="5">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock Text="{Binding PositionLabel}" FontSize="10" Opacity="0.5"/>
|
||||
<TextBlock Grid.Column="1" Text="⠿" Opacity="0.45" IsVisible="{Binding IsOccupied}"/>
|
||||
<TextBlock Grid.Column="1" Text="⠿" Opacity="0.45" IsVisible="{Binding CanEdit}"/>
|
||||
</Grid>
|
||||
<TextBlock Text="{Binding StudentName}" FontWeight="SemiBold" FontSize="13"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
@@ -118,12 +125,18 @@
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumLowBrush}"
|
||||
CornerRadius="6" Padding="36,8" HorizontalAlignment="Center"
|
||||
IsVisible="{Binding IsBoardAtBottom}">
|
||||
<TextBlock Text="Tafel / Vorderseite" FontWeight="SemiBold" Opacity="0.75"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Die Schülerliste hat einen eigenen Scrollbereich und bleibt dadurch auch bei
|
||||
großen Räumen neben den aktuell sichtbaren Sitzplätzen erreichbar. -->
|
||||
<Border Grid.Row="1" Grid.Column="1"
|
||||
Width="220" IsVisible="{Binding IsEditMode}"
|
||||
DragDrop.AllowDrop="True" DragDrop.DragOver="OnUnassignedDragOver"
|
||||
DragDrop.Drop="OnUnassignedDrop"
|
||||
BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}"
|
||||
|
||||
@@ -48,7 +48,7 @@ public partial class SeatingPlanTabView : UserControl
|
||||
!e.GetCurrentPoint(control).Properties.IsLeftButtonPressed) return;
|
||||
var candidate = control.DataContext;
|
||||
if (candidate is SeatCellViewModel { IsOccupied: false } or null) return;
|
||||
if (DataContext is not SeatingPlanTabViewModel { IsEditable: true }) return;
|
||||
if (DataContext is not SeatingPlanTabViewModel { CanEditLayout: true }) return;
|
||||
_dragCandidate = candidate;
|
||||
_dragTrigger = e;
|
||||
_pressPosition = e.GetPosition(this);
|
||||
@@ -132,7 +132,7 @@ public partial class SeatingPlanTabView : UserControl
|
||||
}
|
||||
|
||||
private bool CanDropOn(SeatCellViewModel target) =>
|
||||
DataContext is SeatingPlanTabViewModel { IsEditable: true }
|
||||
DataContext is SeatingPlanTabViewModel { CanEditLayout: true }
|
||||
&& ((_draggedSeat is not null && _draggedSeat != target) || _draggedStudent?.StudentId is not null);
|
||||
|
||||
private void OnUnassignedDragOver(object? sender, DragEventArgs e) =>
|
||||
|
||||
Reference in New Issue
Block a user