feat: expand teaching mode with live timeline and seating quick checks
CI / build-and-test (push) Canceled after 0s

This commit is contained in:
2026-09-13 23:16:36 +02:00
parent b8193be6ec
commit eb1b2340b7
14 changed files with 837 additions and 65 deletions
@@ -1,5 +1,9 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Input;
using Avalonia.Threading;
using LehrerApp.Core.Models;
using LehrerApp.Core.Interfaces;
using LehrerApp.Desktop.ViewModels;
using LehrerApp.Desktop.ViewModels.Groups;
using Microsoft.Extensions.DependencyInjection;
@@ -8,7 +12,53 @@ namespace LehrerApp.Desktop.Views.Groups;
public partial class TeachingModeWindow : Window
{
public TeachingModeWindow() => InitializeComponent();
private static readonly Dictionary<Guid, TeachingModeWindow> OpenWindows = [];
private readonly DispatcherTimer _clock = new() { Interval = TimeSpan.FromSeconds(1) };
private WindowState _previousState = WindowState.Maximized;
public static void Open(Lesson lesson)
{
if (OpenWindows.TryGetValue(lesson.Id, out var existing))
{
if (existing.WindowState == WindowState.Minimized) existing.WindowState = WindowState.Normal;
existing.Activate();
return;
}
var group = App.Services.GetRequiredService<IGroupRepository>().GetById(lesson.GroupId);
if (group is null) return;
var window = new TeachingModeWindow
{
DataContext = new TeachingModeViewModel(lesson, group,
App.Services.GetRequiredService<IAlternativeLessonPathRepository>(),
App.Services.GetRequiredService<ILessonRepository>(),
App.Services.GetRequiredService<SeatingPlanTabViewModel>(),
App.Services.GetRequiredService<ParticipationTabViewModel>())
};
OpenWindows.Add(lesson.Id, window);
window.Closed += (_, _) => OpenWindows.Remove(lesson.Id);
window.Show();
}
public TeachingModeWindow()
{
InitializeComponent();
_clock.Tick += (_, _) => (DataContext as TeachingModeViewModel)?.Timeline.Refresh();
Opened += (_, _) => _clock.Start();
Closed += (_, _) => _clock.Stop();
KeyDown += (_, e) =>
{
if (e.Key == Key.F11) { ToggleFullScreen(); e.Handled = true; }
else if (e.Key == Key.Escape && WindowState == WindowState.FullScreen)
{ WindowState = _previousState; e.Handled = true; }
};
}
private void ToggleFullScreen()
{
if (WindowState == WindowState.FullScreen) WindowState = _previousState;
else { _previousState = WindowState; WindowState = WindowState.FullScreen; }
}
private void OnFullScreen(object? sender, RoutedEventArgs e) => ToggleFullScreen();
protected override void OnDataContextChanged(EventArgs e)
{
@@ -35,6 +85,7 @@ public partial class TeachingModeWindow : Window
private async Task ShowQuickInputDialog(ParticipationTabViewModel tabVm)
{
if (tabVm.StudentRows.Count == 0) return;
tabVm.RefreshCurrentGrid();
var quickVm = new QuickInputViewModel(tabVm.StudentRows.ToList(), tabVm.Aspects.ToList());
var dialog = new ParticipationQuickInputDialog { DataContext = quickVm };
await dialog.ShowDialog(this);
@@ -44,6 +95,7 @@ public partial class TeachingModeWindow : Window
private async Task ShowStatusQuickInputDialog(ParticipationTabViewModel tabVm)
{
if (tabVm.StudentRows.Count == 0 || tabVm.SelectedSession is null) return;
tabVm.RefreshCurrentGrid();
var quickVm = new AttendanceHomeworkQuickInputViewModel(tabVm.StudentRows, tabVm.SelectedSessionDisplay);
var dialog = new AttendanceHomeworkQuickInputDialog { DataContext = quickVm };
await dialog.ShowDialog(this);