Skip to content

Commit

Permalink
Make due date selection chips take "Aktive Wochentage" (custom school…
Browse files Browse the repository at this point in the history
…days) into account. (#1279)

Users can select "aktive Wochentage" ("active weekdays" -> custom
schooldays) to customize on which days they'll have school.
With this PR selecting the "Nächster Schultag" due date chip when
creating a homework will take the "aktive Wochentage" into account. If
e.g. the user has selected monday, wednesday and thursday as "aktive
Wochentage" then selecting "Nächster Schultag" on mondays will set the
due date to the next wednesday since tuesday is not an "aktiver
Wochentag".

Fixes #1180 
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Introduced customization for enabled weekdays in the homework
scheduling feature, allowing users to specify which days are considered
school days.
- **Enhancements**
- Improved the logic for calculating the next school day based on
user-defined enabled weekdays.
- **Tests**
- Added tests to ensure the correct handling of custom and empty school
day settings.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
Jonas-Sander authored Jan 31, 2024
1 parent 72ee75e commit ae40192
Show file tree
Hide file tree
Showing 6 changed files with 570 additions and 197 deletions.
5 changes: 5 additions & 0 deletions app/lib/homework/homework_dialog/homework_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ class _HomeworkDialogState extends State<HomeworkDialog> {
final markdownAnalytics = BlocProvider.of<MarkdownAnalytics>(context);
final szContext = BlocProvider.of<SharezoneContext>(context);
final analytics = szContext.analytics;
final enabledWeekDays = szContext
.api.user.data!.userSettings.enabledWeekDays
.getEnabledWeekDaysList();

late NextLessonCalculator nextLessonCalculator;
if (widget.nextLessonCalculator != null) {
Expand All @@ -94,6 +97,7 @@ class _HomeworkDialogState extends State<HomeworkDialog> {
homeworkId: widget.id,
api: widget.homeworkDialogApi ?? HomeworkDialogApi(szContext.api),
nextLessonCalculator: nextLessonCalculator,
enabledWeekdays: enabledWeekDays,
markdownAnalytics: markdownAnalytics,
analytics: analytics,
);
Expand All @@ -104,6 +108,7 @@ class _HomeworkDialogState extends State<HomeworkDialog> {
bloc = HomeworkDialogBloc(
api: widget.homeworkDialogApi ?? HomeworkDialogApi(szContext.api),
nextLessonCalculator: nextLessonCalculator,
enabledWeekdays: enabledWeekDays,
markdownAnalytics: markdownAnalytics,
analytics: analytics,
);
Expand Down
20 changes: 13 additions & 7 deletions app/lib/homework/homework_dialog/homework_dialog_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
HomeworkDto? _initialHomework;
late final IList<CloudFile> _initialAttachments;
late final bool isEditing;
final List<WeekDay> enabledWeekdays;

_DateSelection _initialDateSelection = _DateSelection.noSelection;
_DateSelection _dateSelection = _DateSelection.noSelection;
Expand Down Expand Up @@ -496,6 +497,7 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
required this.nextLessonCalculator,
required this.analytics,
required this.markdownAnalytics,
required this.enabledWeekdays,
Clock? clockOverride,
HomeworkId? homeworkId,
}) : _clock = clockOverride ?? clock,
Expand Down Expand Up @@ -792,13 +794,17 @@ class HomeworkDialogBloc extends Bloc<HomeworkDialogEvent, HomeworkDialogState>
}

Date _getNextSchoolday() {
final today = _clock.now().toDate();
final daysUntilNextSchoolday = switch (today.weekDayEnum) {
WeekDay.friday => 3, // Monday
WeekDay.saturday => 2, // Monday
_ => 1 // Tomorrow
};
return today.addDays(daysUntilNextSchoolday);
var candidate = _clock.now().toDate();
// hope this code is refactored by then 🤡
while (candidate.year < 2050) {
candidate = candidate.addDays(1);
if (enabledWeekdays.contains(candidate.weekDayEnum)) {
return candidate;
}
}

// Should never happen, but who knows ¯\_(ツ)_/¯
return _clock.now().toDate().addDays(1);
}

Ready _getNewState() {
Expand Down
3 changes: 3 additions & 0 deletions app/test/homework/homework_dialog_bloc_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import 'package:rxdart/rxdart.dart';
import 'package:sharezone/homework/homework_dialog/homework_dialog_bloc.dart';
import 'package:sharezone/markdown/markdown_analytics.dart';
import 'package:time/time.dart';
import 'package:user/user.dart';

import '../analytics/analytics_test.dart';
import 'homework_dialog_test.dart';
Expand Down Expand Up @@ -51,6 +52,7 @@ void main() {
nextLessonCalculator: nextLessonCalculator,
analytics: analytics,
markdownAnalytics: MarkdownAnalytics(analytics),
enabledWeekdays: EnabledWeekDays.standard.getEnabledWeekDaysList(),
);
}

Expand All @@ -61,6 +63,7 @@ void main() {
analytics: analytics,
homeworkId: id,
markdownAnalytics: MarkdownAnalytics(analytics),
enabledWeekdays: EnabledWeekDays.standard.getEnabledWeekDaysList(),
);
}

Expand Down
53 changes: 51 additions & 2 deletions app/test/homework/homework_dialog_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ 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:files_basics/files_models.dart';
import 'package:files_basics/local_file.dart';
import 'package:filesharing_logic/filesharing_logic_models.dart';
Expand All @@ -33,16 +34,19 @@ import 'package:sharezone/settings/src/subpages/timetable/time_picker_settings_c
import 'package:sharezone/util/api.dart';
import 'package:sharezone/util/api/course_gateway.dart';
import 'package:sharezone/util/api/homework_api.dart';
import 'package:sharezone/util/api/user_api.dart';
import 'package:sharezone/util/cache/streaming_key_value_store.dart';
import 'package:sharezone/util/next_lesson_calculator/next_lesson_calculator.dart';
import 'package:sharezone_widgets/sharezone_widgets.dart';
import 'package:user/user.dart';

import '../analytics/analytics_test.dart';
import 'homework_dialog_bloc_test.dart';
@GenerateNiceMocks([
MockSpec<DocumentReference>(),
MockSpec<SharezoneContext>(),
MockSpec<SharezoneGateway>(),
MockSpec<UserGateway>(),
MockSpec<HomeworkGateway>(),
MockSpec<CourseGateway>(),
])
Expand Down Expand Up @@ -228,6 +232,8 @@ void main() {
late MockSharezoneGateway sharezoneGateway;
late MockCourseGateway courseGateway;
late MockHomeworkGateway homeworkGateway;
late MockUserGateway userGateway;
late AppUser appUser;
Clock? clockOverride;

HomeworkDto? homework;
Expand All @@ -236,11 +242,13 @@ void main() {
sharezoneGateway = MockSharezoneGateway();
courseGateway = MockCourseGateway();
homeworkGateway = MockHomeworkGateway();
userGateway = MockUserGateway();
homeworkDialogApi = MockHomeworkDialogApi();
nextLessonCalculator = MockNextLessonCalculator();
sharezoneContext = MockSharezoneContext();
analyticsBackend = LocalAnalyticsBackend();
analytics = Analytics(analyticsBackend);
appUser = AppUser.create(id: '123');
homework = null;
clockOverride = null;
});
Expand All @@ -249,6 +257,8 @@ void main() {
{bool showDueDateSelectionChips = false}) async {
when(sharezoneGateway.course).thenReturn(courseGateway);
when(sharezoneContext.api).thenReturn(sharezoneGateway);
when(sharezoneGateway.user).thenReturn(userGateway);
when(userGateway.data).thenAnswer((_) => appUser);
when(sharezoneContext.analytics).thenReturn(analytics);
if (homework != null) {
when(sharezoneGateway.homework).thenReturn(homeworkGateway);
Expand Down Expand Up @@ -597,6 +607,9 @@ void main() {
homeworkDialogApi,
courseGateway,
setClockOverride: (clock) => clockOverride = clock,
editUser: (callback) {
appUser = callback(appUser);
},
);
}

Expand Down Expand Up @@ -724,6 +737,34 @@ void main() {
expect(controller.getSelectedLessonChips(), ['Nächster Schultag']);
expect(controller.getSelectedDueDate(), Date('2023-11-06'));
});
testWidgets('custom schooldays get accounted for', (tester) async {
final controller = createController(tester);
controller.setSchooldays(
[WeekDay.tuesday, WeekDay.wednesday, WeekDay.friday, WeekDay.sunday]);
// Friday, thus next schoolday is Sunday
controller.setToday(Date('2024-01-12'));

await pumpAndSettleHomeworkDialog(tester,
showDueDateSelectionChips: true);

await controller.selectLessonChip('Nächster Schultag');
expect(controller.getSelectedDueDate(), Date('2024-01-14')); // Sunday
});
testWidgets(
'if user has schooldays set to empty, tomorrow will be returned for the next school day',
(tester) async {
final controller = createController(tester);
// Right now people can actually deselect all schooldays. This doesn't
// really make sense but we should still handle it.
controller.setSchooldays([]);
controller.setToday(Date('2024-02-10'));

await pumpAndSettleHomeworkDialog(tester,
showDueDateSelectionChips: true);

await controller.selectLessonChip('Nächster Schultag');
expect(controller.getSelectedDueDate(), Date('2024-02-11'));
});
testWidgets('when no course is selected then the lesson chips are disabled',
(tester) async {
final controller = createController(tester);
Expand Down Expand Up @@ -947,12 +988,14 @@ class _TestController {
final WidgetTester tester;
final MockNextLessonCalculator nextLessonCalculator;
void Function(Clock clock) setClockOverride;
void Function(AppUser Function(AppUser) f) editUser;

_TestController(
this.tester,
this.nextLessonCalculator,
this.homeworkDialogApi,
this.courseGateway, {
required this.editUser,
required this.setClockOverride,
});

Expand Down Expand Up @@ -1010,8 +1053,6 @@ class _TestController {
return datePicker.selectedDate?.toDate();
}

void setNextSchoolday(Date date) {}

final _addedCourses = <String, Course>{};
void addCourse(Course course) {
_addedCourses[course.id] = course;
Expand Down Expand Up @@ -1060,6 +1101,14 @@ class _TestController {
await tester.tap(find.byKey(HwDialogKeys.lessonChipDeleteIcon));
await tester.pumpAndSettle();
}

void setSchooldays(List<WeekDay> list) {
editUser((appUser) {
return appUser.copyWith(
userSettings: appUser.userSettings.copyWith(
enabledWeekDays: EnabledWeekDays.fromEnabledWeekDaysList(list)));
});
}
}

// Used temporarily when testing so one can see what happens "on the screen" in
Expand Down
Loading

0 comments on commit ae40192

Please sign in to comment.