diff --git a/app/lib/homework/homework_dialog/homework_dialog.dart b/app/lib/homework/homework_dialog/homework_dialog.dart index a55410f5b..d5db335d2 100644 --- a/app/lib/homework/homework_dialog/homework_dialog.dart +++ b/app/lib/homework/homework_dialog/homework_dialog.dart @@ -139,6 +139,7 @@ class HwDialogKeys { Key("custom-lesson-chip-dialog-text-field"); static const Key customLessonChipDialogOkButton = Key("custom-lesson-chip-dialog-ok-button"); + static const Key lessonChipDeleteIcon = Key("lesson-chip-delete-icon"); static const Key submissionTile = Key("submission-tile"); static const Key submissionTimeTile = Key("submission-time-tile"); static const Key descriptionField = Key("description-field"); @@ -433,7 +434,7 @@ class _DueDateChip { } class _DueDateChipsController extends ChangeNotifier { - final void Function(DueDateSelection) onChanged; + final void Function(DueDateSelection?) onChanged; IList<_DueDateChip> chips = IList(); _DueDateChipsController({ @@ -506,7 +507,11 @@ class _DueDateChipsController extends ChangeNotifier { } void deleteInXLessonsChip(InXLessonsDueDateSelection inXLessons) { + final old = chips; chips = chips.removeWhere((chip) => chip.dueDate == inXLessons); + if (old != chips) { + onChanged(null); + } notifyListeners(); } } @@ -539,12 +544,22 @@ class _DueDateChipsState extends State<_DueDateChips> { @override void initState() { super.initState(); + final bloc = + bloc_lib.BlocProvider.of(context, listen: false); controller = _DueDateChipsController( initialChips: widget.initialChips, onChanged: (selection) { - final bloc = bloc_lib.BlocProvider.of(context, - listen: false); - bloc.add(DueDateChanged(selection)); + if (selection != null) { + bloc.add(DueDateChanged(selection)); + return; + } + // If a selected chip was deleted then selection will be null and we + // change to manual date selection with the previous selected date. + final state = bloc.state; + if (state is Ready && state.dueDate.$1 != null) { + final oldDate = state.dueDate.$1!; + bloc.add(DueDateChanged(DueDateSelection.date(oldDate))); + } }, ); } @@ -586,6 +601,10 @@ class _DueDateChipsState extends State<_DueDateChips> { child: InputChip( label: Text(chip.label), selected: chip.isSelected, + deleteIcon: const Icon( + Icons.clear, + key: HwDialogKeys.lessonChipDeleteIcon, + ), onSelected: chip.dueDate is! InXLessonsDueDateSelection || lessonChipsSelectable diff --git a/app/test/homework/homework_dialog_test.dart b/app/test/homework/homework_dialog_test.dart index ff4e2c332..02af00a57 100644 --- a/app/test/homework/homework_dialog_test.dart +++ b/app/test/homework/homework_dialog_test.dart @@ -851,6 +851,29 @@ void main() { expect(controller.getSelectedLessonChips(), ['Übernächste Stunde']); expect(controller.getSelectedDueDate(), Date('2023-10-12')); }); + testWidgets( + 'when choosing and then deleting a custom lesson chip then the date will stay the same when selecting another course', + (tester) async { + final controller = createController(tester); + controller.addCourse(courseWith(id: 'foo_course', name: 'Foo course')); + controller.addNextLessonDates('foo_course', + [Date('2023-10-06'), Date('2023-10-08'), Date('2023-10-12')]); + controller.addCourse(courseWith(id: 'bar_course', name: 'Bar course')); + controller.addNextLessonDates('bar_course', + [Date('2023-10-08'), Date('2023-10-12'), Date('2023-10-14')]); + await pumpAndSettleHomeworkDialog(tester, + showDueDateSelectionChips: true); + + await controller.selectCourse('foo_course'); + await controller.createCustomChip(inXLessons: 3); + await controller.deleteCustomChip(inXLessons: 3); + await controller.selectCourse('bar_course'); + + expect(controller.getSelectedLessonChips(), []); + // If we in 3 lessons selection would still exist then the date would be + // 2023-10-14 + expect(controller.getSelectedDueDate(), Date('2023-10-12')); + }); }); } @@ -974,6 +997,12 @@ class _TestController { .selectDate!(date.toDateTime); await tester.pumpAndSettle(); } + + Future deleteCustomChip({required int inXLessons}) async { + // For now only works if only one custom chip exists. + await tester.tap(find.byKey(HwDialogKeys.lessonChipDeleteIcon)); + await tester.pumpAndSettle(); + } } // Used temporarily when testing so one can see what happens "on the screen" in