Neue Abwensenheitsmodi plus Upgrade Sitzplan
This commit is contained in:
@@ -24,6 +24,10 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
[ObservableProperty] private string _planTitle = "";
|
||||
[ObservableProperty] private string _planSubtitle = "";
|
||||
[ObservableProperty] private string _assignmentSummary = "";
|
||||
[ObservableProperty] private bool _isBoardAtTop = true;
|
||||
[ObservableProperty] private bool _isBoardAtBottom;
|
||||
[ObservableProperty] private IReadOnlyList<double> _columnGapWidths = [];
|
||||
[ObservableProperty] private bool _isEditMode;
|
||||
|
||||
public ObservableCollection<SeatingPlanSummary> Plans { get; } = [];
|
||||
public ObservableCollection<SeatCellViewModel> Seats { get; } = [];
|
||||
@@ -33,6 +37,7 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
public bool HasPlans => Plans.Count > 0;
|
||||
public bool HasSelectedPlan => _currentPlan is not null;
|
||||
public bool IsEditable => !_isReadOnly;
|
||||
public bool CanEditLayout => IsEditable && IsEditMode;
|
||||
public Func<SeatingPlan?, Task<SeatingPlan?>>? OnEditPlan { get; set; }
|
||||
public Func<SeatingPlanSummary, Task<bool>>? OnConfirmDelete { get; set; }
|
||||
public Func<SeatAssessmentViewModel, Task>? OnAssessStudent { get; set; }
|
||||
@@ -57,6 +62,7 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
{
|
||||
_groupId = groupId;
|
||||
_isReadOnly = isReadOnly;
|
||||
IsEditMode = false;
|
||||
LoadStudentOptions();
|
||||
ReloadPlans();
|
||||
OnPropertyChanged(nameof(IsEditable));
|
||||
@@ -102,6 +108,9 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
PlanTitle = "";
|
||||
PlanSubtitle = "";
|
||||
AssignmentSummary = "";
|
||||
IsBoardAtTop = true;
|
||||
IsBoardAtBottom = false;
|
||||
ColumnGapWidths = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -110,6 +119,12 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
PlanSubtitle = string.IsNullOrWhiteSpace(plan.Room)
|
||||
? $"{plan.Rows} × {plan.Columns} Plätze"
|
||||
: $"Raum {plan.Room} · {plan.Rows} × {plan.Columns} Plätze";
|
||||
IsBoardAtBottom = plan.IsBoardAtBottom;
|
||||
IsBoardAtTop = !plan.IsBoardAtBottom;
|
||||
var savedGapWidths = plan.ColumnGapWidths ?? [];
|
||||
ColumnGapWidths = Enumerable.Range(0, Math.Max(0, plan.Columns - 1))
|
||||
.Select(i => i < savedGapWidths.Count ? savedGapWidths[i] : 0)
|
||||
.ToArray();
|
||||
for (var row = 0; row < plan.Rows; row++)
|
||||
for (var column = 0; column < plan.Columns; column++)
|
||||
{
|
||||
@@ -118,7 +133,7 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
? StudentSeatOption.Empty
|
||||
: StudentOptions.FirstOrDefault(o => o.StudentId == assignment.StudentId)
|
||||
?? StudentSeatOption.Empty;
|
||||
Seats.Add(new SeatCellViewModel(row, column, StudentOptions, option, OnSeatChanged, IsEditable));
|
||||
Seats.Add(new SeatCellViewModel(row, column, StudentOptions, option, OnSeatChanged, CanEditLayout));
|
||||
}
|
||||
UpdateAssignmentSummary();
|
||||
}
|
||||
@@ -128,7 +143,7 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
|
||||
private void OnSeatChanged(SeatCellViewModel changed)
|
||||
{
|
||||
if (_currentPlan is null || !IsEditable) return;
|
||||
if (_currentPlan is null || !CanEditLayout) return;
|
||||
if (changed.SelectedOption.StudentId is Guid studentId)
|
||||
{
|
||||
foreach (var other in Seats.Where(s => s != changed && s.SelectedOption.StudentId == studentId))
|
||||
@@ -152,7 +167,7 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
|
||||
public void MoveSeat(SeatCellViewModel source, SeatCellViewModel target)
|
||||
{
|
||||
if (!IsEditable || source == target || !source.SelectedOption.StudentId.HasValue) return;
|
||||
if (!CanEditLayout || source == target || !source.SelectedOption.StudentId.HasValue) return;
|
||||
var targetOption = target.SelectedOption;
|
||||
target.SetSelectionSilently(source.SelectedOption);
|
||||
source.SetSelectionSilently(targetOption);
|
||||
@@ -161,7 +176,7 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
|
||||
public void AssignStudent(StudentSeatOption student, SeatCellViewModel target)
|
||||
{
|
||||
if (!IsEditable || !student.StudentId.HasValue) return;
|
||||
if (!CanEditLayout || !student.StudentId.HasValue) return;
|
||||
foreach (var other in Seats.Where(s => s != target && s.SelectedOption.StudentId == student.StudentId))
|
||||
other.SetSelectionSilently(StudentSeatOption.Empty);
|
||||
target.SetSelectionSilently(student);
|
||||
@@ -170,7 +185,7 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
|
||||
public void ClearSeat(SeatCellViewModel seat)
|
||||
{
|
||||
if (!IsEditable || !seat.SelectedOption.StudentId.HasValue) return;
|
||||
if (!CanEditLayout || !seat.SelectedOption.StudentId.HasValue) return;
|
||||
seat.SetSelectionSilently(StudentSeatOption.Empty);
|
||||
SaveSeatAssignments();
|
||||
}
|
||||
@@ -223,8 +238,15 @@ public partial class SeatingPlanTabViewModel : ObservableObject
|
||||
ReloadPlans();
|
||||
}
|
||||
|
||||
private bool CanEdit() => IsEditable;
|
||||
private bool CanEditSelected() => IsEditable && _currentPlan is not null;
|
||||
partial void OnIsEditModeChanged(bool value)
|
||||
{
|
||||
OnPropertyChanged(nameof(CanEditLayout));
|
||||
foreach (var seat in Seats) seat.CanEdit = CanEditLayout;
|
||||
NotifyCommands();
|
||||
}
|
||||
|
||||
private bool CanEdit() => IsEditable && (IsEditMode || !HasPlans);
|
||||
private bool CanEditSelected() => CanEditLayout && _currentPlan is not null;
|
||||
|
||||
private void NotifyCommands()
|
||||
{
|
||||
@@ -264,7 +286,7 @@ public partial class SeatCellViewModel : ObservableObject
|
||||
public int Column { get; }
|
||||
public string PositionLabel => $"Reihe {Row + 1} · Platz {Column + 1}";
|
||||
public ObservableCollection<StudentSeatOption> Options { get; }
|
||||
public bool CanEdit { get; }
|
||||
[ObservableProperty] private bool _canEdit;
|
||||
public bool IsOccupied => SelectedOption.StudentId.HasValue;
|
||||
public string StudentName => IsOccupied ? SelectedOption.DisplayName : "Freier Platz";
|
||||
|
||||
@@ -276,7 +298,7 @@ public partial class SeatCellViewModel : ObservableObject
|
||||
Options = options;
|
||||
_selectedOption = selectedOption;
|
||||
_onChanged = onChanged;
|
||||
CanEdit = canEdit;
|
||||
_canEdit = canEdit;
|
||||
}
|
||||
|
||||
partial void OnSelectedOptionChanged(StudentSeatOption value)
|
||||
@@ -363,6 +385,11 @@ public partial class SeatAssessmentViewModel : ObservableObject
|
||||
AttendanceChoices.Add(new("◇", "Schulveranstaltung", "Strg+7", AttendanceStatus.OtherSchoolEvent, SetAttendance));
|
||||
AttendanceChoices.Add(new("✕", "Geschwänzt", "Strg+9", AttendanceStatus.Truant, SetAttendance));
|
||||
AttendanceChoices.Add(new("!", "Unentschuldigt", "Strg+0", AttendanceStatus.Unexcused, SetAttendance));
|
||||
AttendanceChoices.Add(new("V", "Verspätet", "", AttendanceStatus.Late, SetAttendance));
|
||||
AttendanceChoices.Add(new("V!", "Erheblich verspätet", "", AttendanceStatus.SignificantlyLate, SetAttendance));
|
||||
AttendanceChoices.Add(new("A", "Im Unterricht abgängig", "", AttendanceStatus.LeftDuringClass, SetAttendance));
|
||||
AttendanceChoices.Add(new("L", "Lerninsel", "", AttendanceStatus.LearningIsland, SetAttendance));
|
||||
AttendanceChoices.Add(new("S", "Suspendiert", "", AttendanceStatus.Suspended, SetAttendance));
|
||||
AttendanceChoices.Add(new("·", "Nicht kontrolliert", "Strg+X", null, SetAttendance));
|
||||
}
|
||||
|
||||
@@ -579,10 +606,12 @@ public partial class SeatingPlanDialogViewModel : ObservableObject
|
||||
[ObservableProperty] private string _room = "";
|
||||
[ObservableProperty] private decimal _rows = 4;
|
||||
[ObservableProperty] private decimal _columns = 4;
|
||||
[ObservableProperty] private bool _isBoardAtBottom;
|
||||
[ObservableProperty] private string _nameError = "";
|
||||
[ObservableProperty] private string _layoutError = "";
|
||||
|
||||
public SeatingPlan? Result { get; private set; }
|
||||
public ObservableCollection<ColumnGapEditor> ColumnGaps { get; } = [];
|
||||
public string DialogTitle => _editingPlan is null ? "Neuen Sitzplan anlegen" : "Sitzplan bearbeiten";
|
||||
public string SaveButtonText => _editingPlan is null ? "Anlegen" : "Speichern";
|
||||
|
||||
@@ -591,11 +620,26 @@ public partial class SeatingPlanDialogViewModel : ObservableObject
|
||||
_plans = plans;
|
||||
_groupId = groupId;
|
||||
_editingPlan = editingPlan;
|
||||
RebuildColumnGaps(decimal.ToInt32(Columns));
|
||||
if (editingPlan is null) return;
|
||||
Name = editingPlan.Name ?? "";
|
||||
Room = editingPlan.Room ?? "";
|
||||
Rows = editingPlan.Rows;
|
||||
Columns = editingPlan.Columns;
|
||||
IsBoardAtBottom = editingPlan.IsBoardAtBottom;
|
||||
var savedGapWidths = editingPlan.ColumnGapWidths ?? [];
|
||||
for (var i = 0; i < ColumnGaps.Count && i < savedGapWidths.Count; i++)
|
||||
ColumnGaps[i].Width = (decimal)savedGapWidths[i];
|
||||
}
|
||||
|
||||
partial void OnColumnsChanged(decimal value) => RebuildColumnGaps(decimal.ToInt32(value));
|
||||
|
||||
private void RebuildColumnGaps(int columns)
|
||||
{
|
||||
var previous = ColumnGaps.ToDictionary(g => g.AfterColumn, g => g.Width);
|
||||
ColumnGaps.Clear();
|
||||
for (var afterColumn = 1; afterColumn < columns; afterColumn++)
|
||||
ColumnGaps.Add(new ColumnGapEditor(afterColumn, previous.GetValueOrDefault(afterColumn)));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -621,6 +665,8 @@ public partial class SeatingPlanDialogViewModel : ObservableObject
|
||||
plan.Room = Room?.Trim() ?? "";
|
||||
plan.Rows = decimal.ToInt32(Rows);
|
||||
plan.Columns = decimal.ToInt32(Columns);
|
||||
plan.IsBoardAtBottom = IsBoardAtBottom;
|
||||
plan.ColumnGapWidths = ColumnGaps.Select(g => decimal.ToDouble(g.Width)).ToList();
|
||||
try
|
||||
{
|
||||
_plans.Save(plan);
|
||||
@@ -632,3 +678,10 @@ public partial class SeatingPlanDialogViewModel : ObservableObject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ColumnGapEditor(int afterColumn, decimal width) : ObservableObject
|
||||
{
|
||||
public int AfterColumn { get; } = afterColumn;
|
||||
public string Label => $"Nach Platz {AfterColumn}";
|
||||
[ObservableProperty] private decimal _width = width;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user