feat: Stundenplan-Badge für unkontrollierte Hausaufgaben (4.5.4)
Lesson bekommt HomeworkChecked/HomeworkCheckDismissed. Der Stundenplan (Tagesliste und Wochenraster im "Heute"-Tab) zeigt ein 📓-Badge, wenn die letzte Stunde einer Gruppe eine Hausaufgabe hatte, die noch nicht kontrolliert oder bewusst übersprungen wurde. Umschaltbar über zwei sich gegenseitig ausschließende Checkboxen ("Kontrolliert"/"Nicht kontrollieren") im Verlaufsplan-Editor, direkt neben dem Hausaufgabenfeld. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,12 @@ public class Lesson
|
||||
public TimeOnly? StartTime { get; set; }
|
||||
public List<LessonPhaseStep> Phases { get; set; } = [];
|
||||
public string? Homework { get; set; }
|
||||
/// Markiert, dass die hier eingetragene Hausaufgabe in einer Folgestunde besprochen/kontrolliert
|
||||
/// wurde — treibt das Stundenplan-Badge "Hausaufgabe kontrollieren" (4.5.4).
|
||||
public bool HomeworkChecked { get; set; }
|
||||
/// Bewusstes Abschalten der Erinnerung, ohne eine tatsächliche Kontrolle vorzutäuschen (z.B.
|
||||
/// wenn die Hausaufgabe absichtlich nicht mehr kontrolliert wird).
|
||||
public bool HomeworkCheckDismissed { get; set; }
|
||||
public string? Reflection { get; set; }
|
||||
public LessonStatus Status { get; set; } = LessonStatus.Planned;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
@@ -179,6 +179,59 @@ public sealed class LessonDialogViewModelTests
|
||||
Assert.Single(lessons.GetByUnit(unitId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasHomeworkText_OhneHausaufgabe_IstFalse()
|
||||
{
|
||||
var vm = BuildVm(Guid.NewGuid(), Guid.NewGuid());
|
||||
Assert.False(vm.HasHomeworkText);
|
||||
|
||||
vm.Homework = " ";
|
||||
Assert.False(vm.HasHomeworkText);
|
||||
|
||||
vm.Homework = "S. 42";
|
||||
Assert.True(vm.HasHomeworkText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_UebernimmtHomeworkCheckedUndDismissed()
|
||||
{
|
||||
var vm = BuildVm(Guid.NewGuid(), Guid.NewGuid());
|
||||
vm.Topic = "Brechung"; vm.DateText = "01.09.2025";
|
||||
vm.Homework = "S. 42"; vm.HomeworkChecked = true;
|
||||
|
||||
vm.SaveCommand.Execute(null);
|
||||
|
||||
Assert.True(vm.Result!.HomeworkChecked);
|
||||
Assert.False(vm.Result.HomeworkCheckDismissed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HomeworkChecked_UndHomeworkCheckDismissed_SchliessenSichGegenseitigAus()
|
||||
{
|
||||
var vm = BuildVm(Guid.NewGuid(), Guid.NewGuid());
|
||||
|
||||
vm.HomeworkChecked = true;
|
||||
Assert.False(vm.HomeworkCheckDismissed);
|
||||
|
||||
vm.HomeworkCheckDismissed = true;
|
||||
Assert.False(vm.HomeworkChecked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Bearbeiten_UebernimmtGespeicherteHomeworkFlags()
|
||||
{
|
||||
var editing = new Lesson
|
||||
{
|
||||
Topic = "Alt", Date = new DateOnly(2025, 9, 1), Homework = "S. 42",
|
||||
HomeworkCheckDismissed = true,
|
||||
};
|
||||
|
||||
var vm = BuildVm(Guid.NewGuid(), Guid.NewGuid(), editing);
|
||||
|
||||
Assert.True(vm.HomeworkCheckDismissed);
|
||||
Assert.False(vm.HomeworkChecked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasAlternativePath_AngehaktOeffnetZuweisungUndUebernimmtErgebnis()
|
||||
{
|
||||
|
||||
@@ -132,6 +132,88 @@ public sealed class TimetableViewModelTests
|
||||
Assert.True(item.HasExam);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_HeutigeStunde_VorherigeUnkontrollierteHausaufgabe_ZeigtBadge()
|
||||
{
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
var group = new LearningGroup { Name = "Q1 Chemie" };
|
||||
var slots = new FakeTimetableSlots();
|
||||
slots.Add(new TimetableSlot { GroupId = group.Id, Weekday = today.DayOfWeek, PeriodNumber = 1 });
|
||||
var lessons = new FakeLessons();
|
||||
lessons.Add(new Lesson { GroupId = group.Id, Date = today.AddDays(-3), Homework = "S. 42, Aufgabe 3" });
|
||||
var vm = BuildViewModel(slots, new FakeGroups([group]), lessons: lessons);
|
||||
|
||||
var item = Assert.Single(vm.TodayItems);
|
||||
Assert.True(item.HasUnhandledHomework);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_HeutigeStunde_HausaufgabeKontrolliert_KeinBadge()
|
||||
{
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
var group = new LearningGroup { Name = "Q1 Chemie" };
|
||||
var slots = new FakeTimetableSlots();
|
||||
slots.Add(new TimetableSlot { GroupId = group.Id, Weekday = today.DayOfWeek, PeriodNumber = 1 });
|
||||
var lessons = new FakeLessons();
|
||||
lessons.Add(new Lesson
|
||||
{
|
||||
GroupId = group.Id, Date = today.AddDays(-3), Homework = "S. 42, Aufgabe 3", HomeworkChecked = true,
|
||||
});
|
||||
var vm = BuildViewModel(slots, new FakeGroups([group]), lessons: lessons);
|
||||
|
||||
var item = Assert.Single(vm.TodayItems);
|
||||
Assert.False(item.HasUnhandledHomework);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_HeutigeStunde_HausaufgabenKontrolleBewusstAbgeschaltet_KeinBadge()
|
||||
{
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
var group = new LearningGroup { Name = "Q1 Chemie" };
|
||||
var slots = new FakeTimetableSlots();
|
||||
slots.Add(new TimetableSlot { GroupId = group.Id, Weekday = today.DayOfWeek, PeriodNumber = 1 });
|
||||
var lessons = new FakeLessons();
|
||||
lessons.Add(new Lesson
|
||||
{
|
||||
GroupId = group.Id, Date = today.AddDays(-3), Homework = "S. 42, Aufgabe 3",
|
||||
HomeworkCheckDismissed = true,
|
||||
});
|
||||
var vm = BuildViewModel(slots, new FakeGroups([group]), lessons: lessons);
|
||||
|
||||
var item = Assert.Single(vm.TodayItems);
|
||||
Assert.False(item.HasUnhandledHomework);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_HeutigeStunde_VorherigeStundeOhneHausaufgabe_KeinBadge()
|
||||
{
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
var group = new LearningGroup { Name = "Q1 Chemie" };
|
||||
var slots = new FakeTimetableSlots();
|
||||
slots.Add(new TimetableSlot { GroupId = group.Id, Weekday = today.DayOfWeek, PeriodNumber = 1 });
|
||||
var lessons = new FakeLessons();
|
||||
lessons.Add(new Lesson { GroupId = group.Id, Date = today.AddDays(-3) });
|
||||
var vm = BuildViewModel(slots, new FakeGroups([group]), lessons: lessons);
|
||||
|
||||
var item = Assert.Single(vm.TodayItems);
|
||||
Assert.False(item.HasUnhandledHomework);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_Wochenkachel_VorherigeUnkontrollierteHausaufgabe_ZeigtBadge()
|
||||
{
|
||||
var group = new LearningGroup { Name = "Q1 Chemie" };
|
||||
var date = DateInCurrentWeek(DayOfWeek.Wednesday);
|
||||
var slots = new FakeTimetableSlots();
|
||||
slots.Add(new TimetableSlot { GroupId = group.Id, Weekday = DayOfWeek.Wednesday, PeriodNumber = 1 });
|
||||
var lessons = new FakeLessons();
|
||||
lessons.Add(new Lesson { GroupId = group.Id, Date = date.AddDays(-2), Homework = "Vokabeln lernen" });
|
||||
var vm = BuildViewModel(slots, new FakeGroups([group]), lessons: lessons);
|
||||
|
||||
var cell = vm.WeekItems.Single(c => c.IsSlotCell && c.Weekday == DayOfWeek.Wednesday && c.PeriodNumber == 1);
|
||||
Assert.True(cell.HasUnhandledHomework);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenGroup_RuftOnNavigateToGroupMitDerGroupIdAuf()
|
||||
{
|
||||
|
||||
@@ -635,6 +635,8 @@ public partial class LessonDialogViewModel : ObservableObject
|
||||
[ObservableProperty] private string _topic = "";
|
||||
[ObservableProperty] private string _startTimeText = "";
|
||||
[ObservableProperty] private string _homework = "";
|
||||
[ObservableProperty] private bool _homeworkChecked;
|
||||
[ObservableProperty] private bool _homeworkCheckDismissed;
|
||||
[ObservableProperty] private string _reflection = "";
|
||||
[ObservableProperty] private string _statusName = LessonStatusDisplay.Options[0];
|
||||
[ObservableProperty] private string _dateTextError = "";
|
||||
@@ -646,6 +648,9 @@ public partial class LessonDialogViewModel : ObservableObject
|
||||
[ObservableProperty] private bool _hasTimeBudgetInfo;
|
||||
|
||||
public string[] StatusOptions => LessonStatusDisplay.Options;
|
||||
/// Nur bei vorhandenem Hausaufgabentext sinnvoll — steuert die Sichtbarkeit von
|
||||
/// HomeworkChecked/HomeworkCheckDismissed im Dialog (4.5.4).
|
||||
public bool HasHomeworkText => !string.IsNullOrWhiteSpace(Homework);
|
||||
public string[] MaterialSuggestions { get; }
|
||||
public string[] ShorthandSuggestions { get; }
|
||||
public ObservableCollection<PhaseStepEditItem> Phases { get; } = [];
|
||||
@@ -707,6 +712,8 @@ public partial class LessonDialogViewModel : ObservableObject
|
||||
Topic = editingLesson.Topic;
|
||||
StartTimeText = editingLesson.StartTime?.ToString("HH:mm") ?? "";
|
||||
Homework = editingLesson.Homework ?? "";
|
||||
HomeworkChecked = editingLesson.HomeworkChecked;
|
||||
HomeworkCheckDismissed = editingLesson.HomeworkCheckDismissed;
|
||||
Reflection = editingLesson.Reflection ?? "";
|
||||
StatusName = LessonStatusDisplay.ToName(editingLesson.Status);
|
||||
foreach (var p in editingLesson.Phases) AddPhaseInternal(p);
|
||||
@@ -803,6 +810,11 @@ public partial class LessonDialogViewModel : ObservableObject
|
||||
RecomputeTimes();
|
||||
}
|
||||
partial void OnDateTextChanged(string value) => RecomputeTimes();
|
||||
partial void OnHomeworkChanged(string value) => OnPropertyChanged(nameof(HasHomeworkText));
|
||||
// "Kontrolliert" und "bewusst nicht kontrollieren" schließen sich gegenseitig aus — beides sind
|
||||
// "erledigt"-Zustände mit unterschiedlicher Bedeutung, nie gleichzeitig sinnvoll.
|
||||
partial void OnHomeworkCheckedChanged(bool value) { if (value) HomeworkCheckDismissed = false; }
|
||||
partial void OnHomeworkCheckDismissedChanged(bool value) { if (value) HomeworkChecked = false; }
|
||||
|
||||
/// Dauer ist die primäre Eingabe je Phase; die Uhrzeit wird daraus nur zur Anzeige
|
||||
/// abgeleitet — kumulativ ab "Beginn", sofern gesetzt (sonst bleibt sie leer).
|
||||
@@ -907,6 +919,8 @@ public partial class LessonDialogViewModel : ObservableObject
|
||||
Result.StartTime = startTime;
|
||||
Result.Phases = Phases.Select(p => p.ToModel()).ToList();
|
||||
Result.Homework = string.IsNullOrWhiteSpace(Homework) ? null : Homework.Trim();
|
||||
Result.HomeworkChecked = HomeworkChecked;
|
||||
Result.HomeworkCheckDismissed = HomeworkCheckDismissed;
|
||||
Result.Reflection = string.IsNullOrWhiteSpace(Reflection) ? null : Reflection.Trim();
|
||||
Result.Status = LessonStatusDisplay.FromName(StatusName);
|
||||
_lessons.Save(Result);
|
||||
|
||||
@@ -197,7 +197,8 @@ public partial class TimetableViewModel : ObservableObject
|
||||
var lesson = _lessons.GetByGroupAndDate(slot.GroupId, today).FirstOrDefault();
|
||||
var exam = _exams.GetByGroup(slot.GroupId).FirstOrDefault(e => e.Date == today);
|
||||
items.Add(new TodayLessonItem(slot.GroupId, slot.PeriodNumber, group.Name,
|
||||
slot.Room ?? "", ColorFor(group.Name), lesson?.Topic, exam?.Title));
|
||||
slot.Room ?? "", ColorFor(group.Name), lesson?.Topic, exam?.Title,
|
||||
HasUnhandledHomework(slot.GroupId, today)));
|
||||
}
|
||||
|
||||
foreach (var sub in substitutionsToday.Where(s => s.Kind == SubstitutionKind.Lesson &&
|
||||
@@ -331,7 +332,8 @@ public partial class TimetableViewModel : ObservableObject
|
||||
subject?.ShortName is { Length: > 0 } sn ? sn : subject?.Name ?? "",
|
||||
group?.Name ?? "?", slot.Room ?? "", lesson?.Topic ?? "",
|
||||
colorHex, holidayBadge, hasExam, isLastBeforeExam,
|
||||
MentionsExperiment(lesson), slot.GroupId, isHoliday));
|
||||
MentionsExperiment(lesson), slot.GroupId, isHoliday,
|
||||
HasUnhandledHomework(slot.GroupId, date)));
|
||||
}
|
||||
AddWeekSupervisionRowIfAny(period, dutiesByPeriod, substitutionsThisWeek, dateByWeekday);
|
||||
}
|
||||
@@ -392,6 +394,21 @@ public partial class TimetableViewModel : ObservableObject
|
||||
p.Activity?.Contains("Experiment", StringComparison.OrdinalIgnoreCase) == true ||
|
||||
p.Material?.Contains("Experiment", StringComparison.OrdinalIgnoreCase) == true)) == true;
|
||||
|
||||
/// <summary>4.5.4: Hat die letzte vor <paramref name="date"/> liegende Lesson dieser Gruppe eine
|
||||
/// Hausaufgabe, die weder als kontrolliert noch als bewusst übersprungen markiert ist? Schaut
|
||||
/// bewusst nur auf die unmittelbar vorherige Lesson (nicht auf die gesamte Historie) — sobald
|
||||
/// eine neuere Lesson stattfindet, ist eine noch ältere offene Hausaufgabe nicht mehr das, worauf
|
||||
/// sich "letzte Stunde" bezieht. Lookback-Fenster von 120 Tagen deckt auch längere Ferienpausen
|
||||
/// ab, ohne unbegrenzt weit zurückzuscannen.</summary>
|
||||
private bool HasUnhandledHomework(Guid groupId, DateOnly date)
|
||||
{
|
||||
var previousLesson = _lessons.GetByGroupAndRange(groupId, date.AddDays(-120), date.AddDays(-1))
|
||||
.OrderByDescending(l => l.Date).ThenByDescending(l => l.LessonNumber ?? 0)
|
||||
.FirstOrDefault();
|
||||
if (previousLesson is null || string.IsNullOrWhiteSpace(previousLesson.Homework)) return false;
|
||||
return !previousLesson.HomeworkChecked && !previousLesson.HomeworkCheckDismissed;
|
||||
}
|
||||
|
||||
/// <summary>Fällt <paramref name="date"/> auf einen gesetzlichen Feiertag oder in Schulferien?</summary>
|
||||
private static bool IsFreeDay(DateOnly date, List<SchoolHoliday> schoolHolidays, HashSet<DateOnly> publicHolidayDates) =>
|
||||
publicHolidayDates.Contains(date) || schoolHolidays.Any(h => date >= h.StartDate && date <= h.EndDate);
|
||||
@@ -629,6 +646,7 @@ public class WeekCellItem
|
||||
public bool HasExam { get; private init; }
|
||||
public bool IsLastBeforeExam { get; private init; }
|
||||
public bool HasExperiment { get; private init; }
|
||||
public bool HasUnhandledHomework { get; private init; }
|
||||
public bool IsHoliday { get; private init; }
|
||||
public string SupervisionLocation { get; private init; } = "";
|
||||
public bool HasSupervision => SupervisionLocation.Length > 0;
|
||||
@@ -667,13 +685,14 @@ public class WeekCellItem
|
||||
|
||||
public static WeekCellItem ForSlot(DayOfWeek day, int period, bool isToday, string subjectLabel,
|
||||
string groupName, string room, string topic, string colorHex, string holidayBadge,
|
||||
bool hasExam, bool isLastBeforeExam, bool hasExperiment, Guid groupId, bool isHoliday) => new()
|
||||
bool hasExam, bool isLastBeforeExam, bool hasExperiment, Guid groupId, bool isHoliday,
|
||||
bool hasUnhandledHomework = false) => new()
|
||||
{
|
||||
Weekday = day, PeriodNumber = period, IsAssigned = true, IsToday = isToday,
|
||||
SubjectLabel = subjectLabel, GroupName = groupName, Room = room, Topic = topic,
|
||||
ColorHex = colorHex, HolidayBadge = holidayBadge, HasExam = hasExam,
|
||||
IsLastBeforeExam = isLastBeforeExam, HasExperiment = hasExperiment, GroupId = groupId,
|
||||
IsHoliday = isHoliday,
|
||||
IsHoliday = isHoliday, HasUnhandledHomework = hasUnhandledHomework,
|
||||
};
|
||||
|
||||
public static WeekCellItem ForSubstitutionLesson(DayOfWeek day, int period, bool isToday, SubstitutionEntry entry) => new()
|
||||
@@ -737,12 +756,14 @@ public class TodayLessonItem
|
||||
public bool HasLessonTopic => !string.IsNullOrWhiteSpace(LessonTopic);
|
||||
public bool HasExam => ExamTitle is not null;
|
||||
public bool HasGroupId => GroupId != Guid.Empty;
|
||||
public bool HasUnhandledHomework { get; private init; }
|
||||
|
||||
public TodayLessonItem(Guid groupId, int periodNumber, string groupName, string room,
|
||||
string colorHex, string? lessonTopic, string? examTitle)
|
||||
string colorHex, string? lessonTopic, string? examTitle, bool hasUnhandledHomework = false)
|
||||
{
|
||||
GroupId = groupId; PeriodNumber = periodNumber; GroupName = groupName; Room = room;
|
||||
ColorHex = colorHex; LessonTopic = lessonTopic; ExamTitle = examTitle;
|
||||
HasUnhandledHomework = hasUnhandledHomework;
|
||||
}
|
||||
|
||||
public static TodayLessonItem ForSubstitution(int periodNumber, SubstitutionEntry entry) => new(
|
||||
|
||||
@@ -126,6 +126,12 @@
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="Hausaufgabe" FontSize="12" Opacity="0.7"/>
|
||||
<TextBox Text="{Binding Homework}" AcceptsReturn="True" Height="48" TextWrapping="Wrap"/>
|
||||
<StackPanel Orientation="Horizontal" Spacing="16" IsVisible="{Binding HasHomeworkText}">
|
||||
<CheckBox Content="Kontrolliert" IsChecked="{Binding HomeworkChecked}"
|
||||
ToolTip.Tip="Hausaufgabe wurde in einer Folgestunde besprochen — blendet das Stundenplan-Badge aus."/>
|
||||
<CheckBox Content="Nicht kontrollieren" IsChecked="{Binding HomeworkCheckDismissed}"
|
||||
ToolTip.Tip="Erinnerung bewusst abschalten, ohne eine Kontrolle vorzutäuschen."/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Spacing="4">
|
||||
|
||||
@@ -96,6 +96,9 @@
|
||||
TextWrapping="Wrap" IsVisible="{Binding HasLessonTopic}"/>
|
||||
<TextBlock Text="{Binding ExamTitle}" FontSize="11" Foreground="#D85A30" FontWeight="SemiBold"
|
||||
IsVisible="{Binding HasExam}"/>
|
||||
<TextBlock Text="📓 Hausaufgabe aus letzter Stunde noch nicht kontrolliert" FontSize="11"
|
||||
Foreground="#8E6C00" FontWeight="SemiBold"
|
||||
IsVisible="{Binding HasUnhandledHomework}"/>
|
||||
</StackPanel>
|
||||
<Button Grid.Column="3" Content="Zur Lerngruppe" FontSize="11" Padding="9,4"
|
||||
VerticalAlignment="Center" IsVisible="{Binding HasGroupId}"
|
||||
@@ -196,6 +199,8 @@
|
||||
<TextBlock Text="📝" FontSize="11" IsVisible="{Binding HasExam}" ToolTip.Tip="Klausur"/>
|
||||
<TextBlock Text="⏰" FontSize="11" IsVisible="{Binding IsLastBeforeExam}" ToolTip.Tip="Letzte Stunde vor der Klausur"/>
|
||||
<TextBlock Text="🧪" FontSize="11" IsVisible="{Binding HasExperiment}" ToolTip.Tip="Experiment geplant"/>
|
||||
<TextBlock Text="📓" FontSize="11" IsVisible="{Binding HasUnhandledHomework}"
|
||||
ToolTip.Tip="Hausaufgabe aus letzter Stunde noch nicht kontrolliert"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -723,11 +723,29 @@ Ausdrücklich als Idee für später festgehalten, **nicht** jetzt umsetzen:
|
||||
Rückfrage an die Lehrkraft?). Muss überdacht werden, bevor das gebaut wird.
|
||||
- [ ] **4.5.3** Aus diesem Lesson-Viewer heraus weiter verzweigen können: in die Zeugnisnote/
|
||||
Bewertung der Gruppe, und in die Schnelldialoge für Mitarbeit sowie Anwesenheit/Hausaufgaben.
|
||||
- [ ] **4.5.4** Badges am Stundenplan/Lesson-Viewer, die anzeigen, ob eine Stunde bereits
|
||||
"kontrolliert" ist — u.a. ob in der vorherigen Stunde Hausaufgaben erteilt wurden und ob
|
||||
diese noch nicht kontrolliert sind. Muss sich pro Fall abschalten lassen: manchmal wird eine
|
||||
Hausaufgabe bewusst nicht kontrolliert, ohne dass bis Schuljahresende ständig daran erinnert
|
||||
werden soll.
|
||||
- [x] **4.5.4** Badges am Stundenplan, die anzeigen, ob eine Hausaufgabe aus der letzten Stunde
|
||||
noch nicht kontrolliert ist.
|
||||
|
||||
**Umsetzung:** `Lesson` bekam zwei neue Felder, `HomeworkChecked`/`HomeworkCheckDismissed`
|
||||
(LiteDB füllt sie für bestehende Datensätze automatisch mit `false`, keine Migration nötig).
|
||||
`TimetableViewModel.HasUnhandledHomework(groupId, date)` sucht die letzte vor `date`
|
||||
liegende Lesson dieser Gruppe (`ILessonRepository.GetByGroupAndRange`, 120-Tage-Fenster
|
||||
wegen möglicher Ferienlücken) und meldet `true`, wenn diese eine nicht-leere `Homework`
|
||||
hat und weder `HomeworkChecked` noch `HomeworkCheckDismissed` gesetzt ist. Bewusst nur die
|
||||
unmittelbar vorherige Lesson, nicht die gesamte Historie — sobald eine neuere Stunde
|
||||
stattfindet, ist eine noch ältere offene Hausaufgabe nicht mehr das, worauf sich "letzte
|
||||
Stunde" bezieht. 📓-Badge dafür sowohl in der Tagesliste als auch im Wochenraster des
|
||||
"Heute"-Tabs (`TodayLessonItem.HasUnhandledHomework`/`WeekCellItem.HasUnhandledHomework`).
|
||||
|
||||
**Abweichung vom ursprünglichen Vorschlag** ("Klick-Toggle direkt am Badge"): jede
|
||||
Wochenraster-Zelle ist bereits ein klickbarer `Button` (Navigation zur Lerngruppe) —
|
||||
ein zweites klickbares Element im selben Badge hätte in Avalonia einen verschachtelten
|
||||
Button-in-Button ergeben, mit unsicherem Klick-Routing. Stattdessen leben die beiden
|
||||
Checkboxen "Kontrolliert"/"Nicht kontrollieren" (gegenseitig exklusiv,
|
||||
`LessonDialogViewModel.HomeworkChecked`/`HomeworkCheckDismissed`) direkt im Verlaufsplan-
|
||||
Editor neben dem Hausaufgabenfeld — genau dort, wo `Homework` ohnehin schon gepflegt wird.
|
||||
Klick auf die Stunde im Stundenplan navigiert wie gehabt zur Lerngruppe/Planung, von dort
|
||||
ist die betroffene (vorherige) Stunde ein Klick entfernt.
|
||||
- [ ] **4.5.5** Stunden aus dieser Ansicht heraus verschieben können, wenn kurzfristig etwas
|
||||
dazwischenkommt.
|
||||
- [ ] **4.5.6** Bei Doppelstunden (90-Minuten-Planung laut Verlaufsplan, 4.2.2) den Inhalt
|
||||
|
||||
Reference in New Issue
Block a user