From 02403595a6ea3f76b5c56a7af20a6a3bbbf7cce8 Mon Sep 17 00:00:00 2001 From: Jonas Sander <29028262+Jonas-Sander@users.noreply.github.com> Date: Thu, 26 Oct 2023 14:39:36 +0200 Subject: [PATCH] Automatically select next weekday in homework dialog. --- .../homework_dialog/homework_dialog_bloc.dart | 15 ++++- .../homework/homework_dialog_bloc_test.dart | 66 +++++++++++-------- lib/date/lib/src/date.dart | 6 ++ 3 files changed, 60 insertions(+), 27 deletions(-) diff --git a/app/lib/homework/homework_dialog/homework_dialog_bloc.dart b/app/lib/homework/homework_dialog/homework_dialog_bloc.dart index 4771a3750..84e68b88a 100644 --- a/app/lib/homework/homework_dialog/homework_dialog_bloc.dart +++ b/app/lib/homework/homework_dialog/homework_dialog_bloc.dart @@ -9,9 +9,11 @@ import 'package:analytics/analytics.dart'; import 'package:bloc/bloc.dart'; import 'package:bloc_presentation/bloc_presentation.dart'; +import 'package:clock/clock.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:common_domain_models/common_domain_models.dart'; import 'package:date/date.dart'; +import 'package:date/weekday.dart'; import 'package:equatable/equatable.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:files_basics/files_models.dart'; @@ -372,6 +374,7 @@ class HomeworkDialogBloc extends Bloc final Analytics analytics; final MarkdownAnalytics markdownAnalytics; final NextLessonCalculator nextLessonCalculator; + final Clock _clock; HomeworkDto? _initialHomework; late final IList _initialAttachments; late final bool isEditing; @@ -402,8 +405,10 @@ class HomeworkDialogBloc extends Bloc required this.nextLessonCalculator, required this.analytics, required this.markdownAnalytics, + Clock? clock, HomeworkId? homeworkId, - }) : super(homeworkId != null + }) : _clock = clock ?? const Clock(), + super(homeworkId != null ? LoadingHomework(homeworkId, isEditing: true) : emptyCreateHomeworkDialogState) { isEditing = homeworkId != null; @@ -574,6 +579,14 @@ class HomeworkDialogBloc extends Bloc await nextLessonCalculator.tryCalculateNextLesson(course.id); if (nextLesson != null) { add(DueDateChanged(nextLesson)); + } else { + final today = _clock.now().toDate(); + final daysUntilNextSchoolday = switch (today.weekDayEnum) { + WeekDay.friday => 3, // Monday + WeekDay.saturday => 2, // Monday + _ => 1 // Tomorrow + }; + add(DueDateChanged(today.addDays(daysUntilNextSchoolday))); } }, ); diff --git a/app/test/homework/homework_dialog_bloc_test.dart b/app/test/homework/homework_dialog_bloc_test.dart index 60119c222..b727e6a83 100644 --- a/app/test/homework/homework_dialog_bloc_test.dart +++ b/app/test/homework/homework_dialog_bloc_test.dart @@ -10,6 +10,7 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:analytics/analytics.dart'; +import 'package:clock/clock.dart'; import 'package:common_domain_models/common_domain_models.dart'; import 'package:date/date.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; @@ -21,7 +22,6 @@ import 'package:mockito/mockito.dart'; import 'package:rxdart/rxdart.dart'; import 'package:sharezone/homework/homework_dialog/homework_dialog_bloc.dart'; import 'package:sharezone/markdown/markdown_analytics.dart'; -import 'package:sharezone/util/next_lesson_calculator/next_lesson_calculator.dart'; import 'package:time/time.dart'; import '../analytics/analytics_test.dart'; @@ -44,9 +44,10 @@ void main() { analytics = Analytics(analyticsBackend); }); - HomeworkDialogBloc createBlocForNewHomeworkDialog() { + HomeworkDialogBloc createBlocForNewHomeworkDialog({Clock? clock}) { return HomeworkDialogBloc( api: homeworkDialogApi, + clock: clock, nextLessonCalculator: nextLessonCalculator, analytics: analytics, markdownAnalytics: MarkdownAnalytics(analytics), @@ -69,6 +70,43 @@ void main() { homeworkDialogApi.addCourseForTesting(course); } + test('If no next lesson date is found the next weekday will be taken', + () async { + Future testNextLessonDate( + String currentDate, String expectedLessonDate) async { + // The course does not have any lessons in the timetable, so we fallback + // to automatically using the next schoolday. We currently assume that + // all users have schooldays from Monday to Friday. We also don't take + // holidays into account. + nextLessonCalculator.dateToReturn = null; + final testClock = Clock.fixed(Date.parse(currentDate).toDateTime); + addCourse(courseWith(id: 'foo')); + final bloc = createBlocForNewHomeworkDialog(clock: testClock); + + bloc.add(CourseChanged(CourseId('foo'))); + await pumpEventQueue(); + + final state = bloc.state as Ready; + expect(state.dueDate.$1, Date.parse(expectedLessonDate)); + } + + // | Current date | Next lesson date | + // Friday Monday + await testNextLessonDate('2023-10-06', '2023-10-09'); + // Saturday Monday + await testNextLessonDate('2023-10-07', '2023-10-09'); + // Sunday Monday + await testNextLessonDate('2023-10-08', '2023-10-09'); + // Monday Tuesday + await testNextLessonDate('2023-10-09', '2023-10-10'); + // Tuesday Wednesday + await testNextLessonDate('2023-10-10', '2023-10-11'); + // Wednesday Thursday + await testNextLessonDate('2023-10-11', '2023-10-12'); + // Thursday Friday + await testNextLessonDate('2023-10-12', '2023-10-13'); + }); + test( 'Shows error if title is not filled out when creating a new homework and Save is called', () async { @@ -212,30 +250,6 @@ void main() { .firstWhere((element) => element.dueDate.$1 != null); expect(state.dueDate.$1, nextLessonDate); }); - test( - 'leaves due date as not selected if null is returned by $NextLessonCalculator', - () async { - final bloc = createBlocForNewHomeworkDialog(); - addCourse(courseWith( - id: 'foo_course', - )); - - bloc.add(CourseChanged(CourseId('foo_course'))); - - nextLessonCalculator.dateToReturn = null; - await bloc.stream - .whereType() - .firstWhere((element) => element.course is CourseChosen); - - // Make sure that we wait for the due date to be set (might be delayed, - // after the course is set and returned by the view) - await pumpEventQueue(times: 100); - await Future.delayed(Duration.zero); - await pumpEventQueue(times: 100); - - final state = bloc.state as Ready; - expect(state.dueDate.$1, null); - }); test('Returns empty dialog when called for creating a new homework', () { final bloc = createBlocForNewHomeworkDialog(); expect(bloc.state, emptyCreateHomeworkDialogState); diff --git a/lib/date/lib/src/date.dart b/lib/date/lib/src/date.dart index 6dee6caf7..f782ed740 100644 --- a/lib/date/lib/src/date.dart +++ b/lib/date/lib/src/date.dart @@ -105,6 +105,12 @@ class Date { } } +extension DateTimeToDate on DateTime { + Date toDate() { + return Date.fromDateTime(this); + } +} + class DateParser { final Date _date;