Arbeitszeit: Zeiterfassung (Kapitel 6.2)

Neuer Tab "Zeiterfassung" neben "Aufgaben" (WorkloadViewModel als Tab-Container,
gleiches Muster wie GroupDetailViewModel): Timer mit Zuordnung zu Aufgabe/Kategorie,
manuelle Nacherfassung (Von-Bis oder Dauer), Wochenübersicht nach Kategorie, sowie
"X / Y min erfasst" direkt in der Aufgabenliste als Ist-vs-Soll-Vergleich.
This commit is contained in:
2026-08-15 23:17:44 +02:00
parent 5c0b6854f5
commit d8b05702bc
14 changed files with 707 additions and 38 deletions
@@ -0,0 +1,101 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:LehrerApp.Desktop.ViewModels.Workload"
xmlns:models="clr-namespace:LehrerApp.Core.Models;assembly=LehrerApp.Core"
x:Class="LehrerApp.Desktop.Views.Workload.TimeTrackingView"
x:DataType="vm:TimeTrackingViewModel">
<ScrollViewer>
<StackPanel Margin="20,16" Spacing="16">
<!-- Timer (6.2.1) -->
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}" CornerRadius="8" Padding="16">
<StackPanel Spacing="10">
<TextBlock Text="Timer" FontWeight="SemiBold" FontSize="14"/>
<Grid ColumnDefinitions="*,8,*" IsEnabled="{Binding !IsTimerRunning}">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Aufgabe (optional)" FontSize="12" Opacity="0.7"/>
<ComboBox ItemsSource="{Binding OpenTasks}" SelectedItem="{Binding SelectedTimerTask}"
HorizontalAlignment="Stretch" PlaceholderText="Keine Aufgabe">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="models:WorkTask">
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Kategorie" FontSize="12" Opacity="0.7"/>
<ComboBox ItemsSource="{Binding CategoryOptions}" SelectedItem="{Binding SelectedTimerCategory}"
HorizontalAlignment="Stretch"/>
</StackPanel>
</Grid>
<Grid ColumnDefinitions="Auto,*">
<Button Grid.Column="0" Content="▶ Start" Command="{Binding StartTimerCommand}"
IsVisible="{Binding !IsTimerRunning}"/>
<Button Grid.Column="0" Content="■ Stop" Command="{Binding StopTimerCommand}"
IsVisible="{Binding IsTimerRunning}"/>
<TextBlock Grid.Column="1" Text="{Binding RunningSinceDisplay}" VerticalAlignment="Center"
Margin="12,0,0,0" FontWeight="SemiBold"/>
</Grid>
</StackPanel>
</Border>
<!-- Wochenübersicht (6.2.3) -->
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}" CornerRadius="8" Padding="16">
<StackPanel Spacing="10">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Text="Diese Woche" FontWeight="SemiBold" FontSize="14"/>
<TextBlock Grid.Column="1" Text="{Binding TotalWeekMinutesDisplay}" Opacity="0.7" FontSize="12"/>
</Grid>
<ItemsControl ItemsSource="{Binding CategorySummaries}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:CategoryWeekSummary">
<Grid ColumnDefinitions="120,*,60" Margin="0,3">
<TextBlock Grid.Column="0" Text="{Binding Category}" FontSize="12" VerticalAlignment="Center"/>
<ProgressBar Grid.Column="1" Value="{Binding BarFraction}" Maximum="1" Height="8"
VerticalAlignment="Center" Margin="8,0"/>
<TextBlock Grid.Column="2" Text="{Binding MinutesDisplay}" FontSize="12"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Noch keine Zeiten diese Woche erfasst." Opacity="0.6" FontSize="12"
IsVisible="{Binding !CategorySummaries.Count}"/>
</StackPanel>
</Border>
<!-- Einträge / Nacherfassung (6.2.2) -->
<Grid ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Text="Einträge" FontWeight="SemiBold" FontSize="14" VerticalAlignment="Center"/>
<Button Grid.Column="1" Content=" Nacherfassen" Command="{Binding AddEntryCommand}"/>
</Grid>
<ItemsControl ItemsSource="{Binding WeekEntries}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:TimeEntryListItem">
<Border Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
CornerRadius="6" Padding="12,8" Margin="0,0,0,6">
<Grid ColumnDefinitions="80,*,Auto,Auto">
<TextBlock Grid.Column="0" Text="{Binding DateDisplay}" FontSize="12" Opacity="0.6"
VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" Margin="8,0" VerticalAlignment="Center">
<TextBlock Text="{Binding CategoryAndTaskDisplay}" FontSize="13"/>
<TextBlock Text="{Binding Description}" FontSize="11" Opacity="0.6"
IsVisible="{Binding Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
<TextBlock Grid.Column="2" Text="{Binding DurationDisplay}" VerticalAlignment="Center"
Margin="0,0,10,0" FontSize="12"/>
<Button Grid.Column="3" Content="Löschen" FontSize="11" Padding="8,3"
Command="{Binding $parent[ItemsControl].((vm:TimeTrackingViewModel)DataContext).DeleteEntryCommand}"
CommandParameter="{Binding}"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Noch keine Einträge diese Woche." Opacity="0.6" Margin="4,4"
IsVisible="{Binding !WeekEntries.Count}"/>
</StackPanel>
</ScrollViewer>
</UserControl>