From d82db13c5881e27b50cfe4078357d594ae30b61b Mon Sep 17 00:00:00 2001 From: Jonas Sander <29028262+Jonas-Sander@users.noreply.github.com> Date: Tue, 28 May 2024 19:50:57 +0200 Subject: [PATCH] Refactor student homework logic (#1650) I made the code less complex and changed `List` to `IList` everywhere. This is a step to using (parts of) the logic for parents and teachers. --- .../student/src/open_homework_list.dart | 5 +- .../src/teacher_open_homework_list.dart | 5 +- .../teacher_homework_page_widget_test.dart | 74 +++++++----- .../src/firestore_homework_data_source.dart | 7 +- ...re_realtime_completed_homework_loader.dart | 3 +- .../lib/src/homework_transformation.dart | 11 +- .../realtime_completed_homework_loader.dart | 3 +- .../pubspec.lock | 8 ++ .../pubspec.yaml | 1 + .../test/in_memory_homework_loader.dart | 5 +- .../test/lazy_loading_controller_test.dart | 19 +-- .../lib/hausaufgabenheft_logik.dart | 23 ++-- .../completed_homeworks_view_bloc.dart | 74 ------------ .../completed_homeworks_view_bloc/events.dart | 23 ---- .../completed_homeworks_view_bloc/states.dart | 27 ----- .../events.dart | 39 ------ ...lazy_loading_completed_homeworks_bloc.dart | 67 ---------- .../states.dart | 28 ----- .../completed_homework_list_view_factory.dart | 12 +- .../views/completed_homwork_list_view.dart | 4 +- .../src/data_source/homework_data_source.dart | 10 +- .../homework_completion_dispatcher.dart | 2 +- .../homework_page_completion_dispatcher.dart | 51 ++------ .../lib/src/homework_list_extensions.dart | 42 +++++++ .../teacher_archived_homework_list_view.dart | 4 +- .../lehrer/teacher_homework_page_bloc.dart | 77 +++++++----- .../lehrer/teacher_homework_read_model.dart | 4 +- .../lehrer/teacher_homework_section_view.dart | 13 +- .../lehrer/teacher_homework_view_factory.dart | 2 +- .../teacher_open_homework_list_view.dart | 3 +- .../lib/src/models/date.dart | 68 +++-------- .../src/models/{homework => }/homework.dart | 49 ++------ .../homework_completion_status.dart | 0 .../lib/src/models/homework_list.dart | 74 ------------ ...dels_used_by_homework.dart => models.dart} | 8 +- .../lib/src/models/subject.dart | 22 +--- .../lib/src/models/title.dart | 18 +-- .../open_homework_list_bloc/events.dart | 16 --- .../open_homework_list_bloc.dart | 38 ------ .../open_homework_list_bloc/states.dart | 19 --- .../open_homework_view_bloc/events.dart | 41 ------- .../open_homework_view_bloc.dart | 82 ------------- .../open_homework_view_bloc/states.dart | 33 ----- .../sort/homework_sorts.dart | 2 - .../smallest_date_subject_and_title_sort.dart | 41 ------- .../sort/src/homework_attribute_sorts.dart | 2 +- .../sort/src/sort.dart | 54 ++++++++- .../sort/src/sort_with_operations.dart | 8 +- .../subject_smallest_date_and_title_sort.dart | 30 ----- .../sort_and_subcategorizer.dart | 114 ++++++++++++++++-- .../subcategorizer.dart | 14 --- .../subcategorizer_factory.dart | 30 ----- .../subject_subcategorizer.dart | 36 ------ .../todo_date_subcategorizer.dart | 65 ---------- .../views/homework_section_view.dart | 15 ++- .../views/open_homework_list_view.dart | 3 +- .../open_homework_list_view_factory.dart | 16 +-- .../src/setup/create_homework_page_bloc.dart | 35 +++--- .../lib/src/setup/dependencies.dart | 3 +- .../homework_sorting_cache.dart | 4 +- .../student_homework_page_bloc.dart | 102 ++++++++-------- .../views/student_homework_view_factory.dart | 4 +- lib/hausaufgabenheft_logik/pubspec.lock | 8 ++ lib/hausaufgabenheft_logik/pubspec.yaml | 1 + .../test/create_homework_util.dart | 4 +- .../create_student_homework_view_test.dart | 4 +- .../test/date/date_test.dart | 13 -- .../test/homework_list_test.dart | 38 +++--- .../test/homework_page_bloc_test.dart | 33 ++--- .../in_memory_homework_repository.dart | 31 ++--- .../realtime_completed_homework_loader.dart | 5 +- .../test/open_homework_view_bloc_test.dart | 73 ----------- .../test/test_data/homeworks.dart | 2 +- 73 files changed, 582 insertions(+), 1322 deletions(-) delete mode 100644 lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/completed_homeworks_view_bloc.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/events.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/states.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/events.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/lazy_loading_completed_homeworks_bloc.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/states.dart create mode 100644 lib/hausaufgabenheft_logik/lib/src/homework_list_extensions.dart rename lib/hausaufgabenheft_logik/lib/src/models/{homework => }/homework.dart (53%) rename lib/hausaufgabenheft_logik/lib/src/models/{homework => }/homework_completion_status.dart (100%) delete mode 100644 lib/hausaufgabenheft_logik/lib/src/models/homework_list.dart rename lib/hausaufgabenheft_logik/lib/src/models/{homework/models_used_by_homework.dart => models.dart} (75%) delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/events.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/open_homework_list_bloc.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/states.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/events.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/open_homework_view_bloc.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/states.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/smallest_date_subject_and_title_sort.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/subject_smallest_date_and_title_sort.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subcategorizer.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subcategorizer_factory.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subject_subcategorizer.dart delete mode 100644 lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/todo_date_subcategorizer.dart delete mode 100644 lib/hausaufgabenheft_logik/test/open_homework_view_bloc_test.dart diff --git a/app/lib/homework/student/src/open_homework_list.dart b/app/lib/homework/student/src/open_homework_list.dart index e7d94e6e9..51c2c9184 100644 --- a/app/lib/homework/student/src/open_homework_list.dart +++ b/app/lib/homework/student/src/open_homework_list.dart @@ -44,7 +44,7 @@ class OpenHomeworkList extends StatelessWidget { Widget build(BuildContext context) { final bloc = BlocProvider.of(context); - if (_nullOrEmpty(homeworkListView.sections)) return Container(); + if (homeworkListView.sections.isEmpty) return Container(); return GlowingOverscrollColorChanger( color: overscrollColor, child: AnimatedStaggeredScrollView( @@ -72,7 +72,4 @@ class OpenHomeworkList extends StatelessWidget { ), ); } - - bool _nullOrEmpty(List homeworkSections) => - homeworkSections.isEmpty; } diff --git a/app/lib/homework/teacher/src/teacher_open_homework_list.dart b/app/lib/homework/teacher/src/teacher_open_homework_list.dart index 3e6233c9a..34b4e47e1 100644 --- a/app/lib/homework/teacher/src/teacher_open_homework_list.dart +++ b/app/lib/homework/teacher/src/teacher_open_homework_list.dart @@ -29,7 +29,7 @@ class TeacherOpenHomeworkList extends StatelessWidget { @override Widget build(BuildContext context) { - if (_nullOrEmpty(homeworkListView.sections)) return Container(); + if (homeworkListView.sections.isEmpty) return Container(); return GlowingOverscrollColorChanger( color: overscrollColor, child: AnimatedStaggeredScrollView( @@ -48,7 +48,4 @@ class TeacherOpenHomeworkList extends StatelessWidget { ], )); } - - bool _nullOrEmpty(List homeworkSections) => - homeworkSections.isEmpty; } diff --git a/app/test/homework/teacher/teacher_homework_page_widget_test.dart b/app/test/homework/teacher/teacher_homework_page_widget_test.dart index c1059dbc8..12999f99a 100644 --- a/app/test/homework/teacher/teacher_homework_page_widget_test.dart +++ b/app/test/homework/teacher/teacher_homework_page_widget_test.dart @@ -13,6 +13,7 @@ import 'package:analytics/null_analytics_backend.dart'; import 'package:bloc_provider/bloc_provider.dart'; import 'package:bloc_provider/multi_bloc_provider.dart'; import 'package:common_domain_models/common_domain_models.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/material.dart' as flutter show Color; import 'package:flutter/material.dart' hide Color; import 'package:flutter_test/flutter_test.dart'; @@ -161,16 +162,22 @@ void main() { bloc: homeworkPageBloc, initialTab: HomeworkTab.open); homeworkPageBloc.emitNewState(Success( - TeacherOpenHomeworkListView([ - TeacherHomeworkSectionView('Section 1', [ - randomHomeworkViewWith(title: 'HW in first Section'), - ]), - TeacherHomeworkSectionView('Section 2', [ - randomHomeworkViewWith(title: 'HW in second Section'), - ]), - ], sorting: HomeworkSort.subjectSmallestDateAndTitleSort), + TeacherOpenHomeworkListView( + IList([ + TeacherHomeworkSectionView( + 'Section 1', + IListConst([ + randomHomeworkViewWith(title: 'HW in first Section'), + ])), + TeacherHomeworkSectionView( + 'Section 2', + IList([ + randomHomeworkViewWith(title: 'HW in second Section'), + ])), + ]), + sorting: HomeworkSort.subjectSmallestDateAndTitleSort), TeacherArchivedHomeworkListView( - [], + const IListConst([]), loadedAllArchivedHomeworks: true, ), )); @@ -242,7 +249,7 @@ void main() { await pumpHomeworkPage(tester, bloc: homeworkPageBloc, initialTab: HomeworkTab.archived); - final firstHomeworkBatch = generateRandomHomeworks(count: 30); + final firstHomeworkBatch = generateRandomHomeworks(count: 30).toIList(); homeworkPageBloc.emitNewState( Success( @@ -274,10 +281,8 @@ void main() { reason: "After scrolling down to near the last loaded homework the bloc should've received the event to load the next archived homeworks (as there are more to load in this test)."); - final allLoadedHomeworks = [ - ...firstHomeworkBatch, - ...generateRandomHomeworks(count: 10) - ]; + final allLoadedHomeworks = + IList([...firstHomeworkBatch, ...generateRandomHomeworks(count: 10)]); homeworkPageBloc.emitNewState( Success( @@ -362,11 +367,13 @@ void main() { bloc: homeworkPageBloc, initialTab: HomeworkTab.open); homeworkPageBloc.emitNewState(Success( - TeacherOpenHomeworkListView([ - TeacherHomeworkSectionView('Section 1', views), - ], sorting: HomeworkSort.subjectSmallestDateAndTitleSort), + TeacherOpenHomeworkListView( + IList([ + TeacherHomeworkSectionView('Section 1', views.toIList()), + ]), + sorting: HomeworkSort.subjectSmallestDateAndTitleSort), TeacherArchivedHomeworkListView( - [], + const IListConst([]), loadedAllArchivedHomeworks: true, ), )); @@ -416,7 +423,7 @@ void main() { _noOpenHomeworks, TeacherArchivedHomeworkListView( // No homeworks loaded already - [], + const IListConst([]), // but there are homeworks to load loadedAllArchivedHomeworks: false, ), @@ -489,32 +496,37 @@ TeacherHomeworkView randomHomeworkViewWith({ Success _openHomeworksWith(HomeworkSort sort) { return Success( - TeacherOpenHomeworkListView([ - TeacherHomeworkSectionView('Heute', [ - randomHomeworkViewWith(title: 'S. 32'), - randomHomeworkViewWith(title: 'S. 34'), - randomHomeworkViewWith(title: 'S. 31'), - ]) - ], sorting: sort), + TeacherOpenHomeworkListView( + IList([ + TeacherHomeworkSectionView( + 'Heute', + IList([ + randomHomeworkViewWith(title: 'S. 32'), + randomHomeworkViewWith(title: 'S. 34'), + randomHomeworkViewWith(title: 'S. 31'), + ])), + ]), + sorting: sort), _noArchivedHomeworks, ); } final _noHomeworks = Success( TeacherOpenHomeworkListView( - [], + const IListConst([]), sorting: HomeworkSort.smallestDateSubjectAndTitle, ), TeacherArchivedHomeworkListView( - [], + const IListConst([]), loadedAllArchivedHomeworks: true, ), ); -final _noOpenHomeworks = TeacherOpenHomeworkListView([], +final _noOpenHomeworks = TeacherOpenHomeworkListView(const IListConst([]), sorting: HomeworkSort.smallestDateSubjectAndTitle); -final _noArchivedHomeworks = - TeacherArchivedHomeworkListView([], loadedAllArchivedHomeworks: true); +final _noArchivedHomeworks = TeacherArchivedHomeworkListView( + const IListConst([]), + loadedAllArchivedHomeworks: true); Future _pumpHomeworkPageWithNoHomeworks( WidgetTester tester, { diff --git a/lib/firebase_hausaufgabenheft_logik/lib/src/firestore_homework_data_source.dart b/lib/firebase_hausaufgabenheft_logik/lib/src/firestore_homework_data_source.dart index 510e1f05f..bf6f23288 100644 --- a/lib/firebase_hausaufgabenheft_logik/lib/src/firestore_homework_data_source.dart +++ b/lib/firebase_hausaufgabenheft_logik/lib/src/firestore_homework_data_source.dart @@ -10,6 +10,7 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:common_domain_models/common_domain_models.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; import 'homework_transformation.dart'; @@ -24,7 +25,7 @@ class FirestoreHomeworkDataSource extends HomeworkDataSource { this.createLazyLoadingController, this._homeworkTransformer); @override - Stream> get openHomeworks { + Stream> get openHomeworks { return _homeworkCollection .where("assignedUserArrays.openStudentUids", arrayContains: uid) .snapshots() @@ -37,12 +38,12 @@ class FirestoreHomeworkDataSource extends HomeworkDataSource { return homework; } - Future> getCurrentOpenOverdueHomeworkIds() async { + Future> getCurrentOpenOverdueHomeworkIds() async { final open = await openHomeworks.first; final overdue = open .where((homeworks) => homeworks.isOverdueRelativeTo(Date.now())) .toList(); - final overdueIds = overdue.map((hws) => hws.id).toList(); + final overdueIds = overdue.map((hws) => hws.id).toIList(); return overdueIds; } diff --git a/lib/firebase_hausaufgabenheft_logik/lib/src/firestore_realtime_completed_homework_loader.dart b/lib/firebase_hausaufgabenheft_logik/lib/src/firestore_realtime_completed_homework_loader.dart index 9284987a3..572d0c792 100644 --- a/lib/firebase_hausaufgabenheft_logik/lib/src/firestore_realtime_completed_homework_loader.dart +++ b/lib/firebase_hausaufgabenheft_logik/lib/src/firestore_realtime_completed_homework_loader.dart @@ -7,6 +7,7 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; import 'homework_transformation.dart'; @@ -22,7 +23,7 @@ class FirestoreRealtimeCompletedHomeworkLoader this._homeworkCollection, this._userId, this._homeworkTransformer); @override - Stream> loadMostRecentHomeworks( + Stream> loadMostRecentHomeworks( int numberOfHomeworks) { return _homeworkCollection .where('assignedUserArrays.completedStudentUids', diff --git a/lib/firebase_hausaufgabenheft_logik/lib/src/homework_transformation.dart b/lib/firebase_hausaufgabenheft_logik/lib/src/homework_transformation.dart index cfefa36f8..b622337af 100644 --- a/lib/firebase_hausaufgabenheft_logik/lib/src/homework_transformation.dart +++ b/lib/firebase_hausaufgabenheft_logik/lib/src/homework_transformation.dart @@ -11,6 +11,7 @@ import 'dart:developer'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:common_domain_models/common_domain_models.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:hausaufgabenheft_logik/color.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; @@ -19,25 +20,25 @@ import 'homework_dto.dart'; typedef CourseColorRetriever = FutureOr Function(String courseId); class HomeworkTransformer extends StreamTransformerBase< - QuerySnapshot>, List> { + QuerySnapshot>, IList> { final String userId; final CourseColorRetriever getCourseColorHexValue; HomeworkTransformer(this.userId, {required this.getCourseColorHexValue}); @override - Stream> bind(Stream stream) { + Stream> bind(Stream stream) { return stream.asyncMap(querySnapshotToHomeworks); } - Future> querySnapshotToHomeworks( + Future> querySnapshotToHomeworks( QuerySnapshot querySnapshot) async { - final homeworks = []; + IList homeworks = const IListConst([]); for (final document in querySnapshot.docs) { final homework = await tryToConvertToHomework(document, userId, getCourseColorHexValue: getCourseColorHexValue); if (homework != null) { - homeworks.add(homework); + homeworks = homeworks.add(homework); } } return homeworks; diff --git a/lib/firebase_hausaufgabenheft_logik/lib/src/realtime_completed_homework_loader.dart b/lib/firebase_hausaufgabenheft_logik/lib/src/realtime_completed_homework_loader.dart index 297e8894a..fe53f0755 100644 --- a/lib/firebase_hausaufgabenheft_logik/lib/src/realtime_completed_homework_loader.dart +++ b/lib/firebase_hausaufgabenheft_logik/lib/src/realtime_completed_homework_loader.dart @@ -6,9 +6,10 @@ // // SPDX-License-Identifier: EUPL-1.2 +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; abstract class RealtimeCompletedHomeworkLoader { - Stream> loadMostRecentHomeworks( + Stream> loadMostRecentHomeworks( int numberOfHomeworks); } diff --git a/lib/firebase_hausaufgabenheft_logik/pubspec.lock b/lib/firebase_hausaufgabenheft_logik/pubspec.lock index b4a75c930..7f904b577 100644 --- a/lib/firebase_hausaufgabenheft_logik/pubspec.lock +++ b/lib/firebase_hausaufgabenheft_logik/pubspec.lock @@ -158,6 +158,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + fast_immutable_collections: + dependency: "direct main" + description: + name: fast_immutable_collections + sha256: b910ccdc99bb38a2abbce07c5afb8f81d4e222a892e4d095a548b99814837b0c + url: "https://pub.dev" + source: hosted + version: "9.2.1" firebase_core: dependency: transitive description: diff --git a/lib/firebase_hausaufgabenheft_logik/pubspec.yaml b/lib/firebase_hausaufgabenheft_logik/pubspec.yaml index 6d3f124e0..7aed50061 100644 --- a/lib/firebase_hausaufgabenheft_logik/pubspec.yaml +++ b/lib/firebase_hausaufgabenheft_logik/pubspec.yaml @@ -25,6 +25,7 @@ dependencies: time: path: ../time cloud_firestore: ^4.17.2 + fast_immutable_collections: ^9.1.5 flutter: sdk: flutter clock: ^1.1.1 diff --git a/lib/firebase_hausaufgabenheft_logik/test/in_memory_homework_loader.dart b/lib/firebase_hausaufgabenheft_logik/test/in_memory_homework_loader.dart index dc83d43d1..e57539347 100644 --- a/lib/firebase_hausaufgabenheft_logik/test/in_memory_homework_loader.dart +++ b/lib/firebase_hausaufgabenheft_logik/test/in_memory_homework_loader.dart @@ -6,17 +6,18 @@ // // SPDX-License-Identifier: EUPL-1.2 +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:firebase_hausaufgabenheft_logik/src/realtime_completed_homework_loader.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; import 'package:rxdart/subjects.dart'; class InMemoryHomeworkLoader extends RealtimeCompletedHomeworkLoader { - final BehaviorSubject> _completedHomeworksSubject; + final BehaviorSubject> _completedHomeworksSubject; InMemoryHomeworkLoader(this._completedHomeworksSubject); @override - Stream> loadMostRecentHomeworks( + Stream> loadMostRecentHomeworks( int numberOfHomeworks) { return _completedHomeworksSubject.map((homeworks) { if (homeworks.length < numberOfHomeworks) return homeworks; diff --git a/lib/firebase_hausaufgabenheft_logik/test/lazy_loading_controller_test.dart b/lib/firebase_hausaufgabenheft_logik/test/lazy_loading_controller_test.dart index 11c176af8..64ae882d5 100644 --- a/lib/firebase_hausaufgabenheft_logik/test/lazy_loading_controller_test.dart +++ b/lib/firebase_hausaufgabenheft_logik/test/lazy_loading_controller_test.dart @@ -10,6 +10,7 @@ import 'dart:async'; import 'package:clock/clock.dart'; import 'package:common_domain_models/common_domain_models.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:firebase_hausaufgabenheft_logik/src/realtime_updating_lazy_loading_controller.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; @@ -22,14 +23,14 @@ class ReportingInMemoryHomeworkLoader extends InMemoryHomeworkLoader { bool wasInvoked = false; @override - Stream> loadMostRecentHomeworks( + Stream> loadMostRecentHomeworks( int numberOfHomeworks) { wasInvoked = true; return super.loadMostRecentHomeworks(numberOfHomeworks); } } -List listOfHomeworksWithLength(int length) => List.generate( +IList listOfHomeworksWithLength(int length) => List.generate( length, (index) => HomeworkReadModel( id: HomeworkId("$index"), @@ -38,21 +39,21 @@ List listOfHomeworksWithLength(int length) => List.generate( subject: Subject("Mathe", abbreviation: 'Ma'), title: const Title("ABC"), withSubmissions: false), - ); + ).toIList(); -Stream> getHomeworkResultsAsStream( +Stream> getHomeworkResultsAsStream( Stream resultStream) => resultStream.map((res) => res.homeworks); void main() { group('LazyLoadingController', () { late ReportingInMemoryHomeworkLoader homeworkLoader; - late rx.BehaviorSubject> homeworkSubject; + late rx.BehaviorSubject> homeworkSubject; - void addToDataSource(List homeworks) { - final hws = homeworkSubject.valueOrNull; + void addToDataSource(IList homeworks) { + var hws = homeworkSubject.valueOrNull; if (hws != null) { - hws.addAll(homeworks); + hws = hws.addAll(homeworks); homeworkSubject.add(hws); } else { homeworkSubject.add(homeworks); @@ -60,7 +61,7 @@ void main() { } setUp(() { - homeworkSubject = rx.BehaviorSubject>(); + homeworkSubject = rx.BehaviorSubject>(); homeworkLoader = ReportingInMemoryHomeworkLoader(homeworkSubject); }); diff --git a/lib/hausaufgabenheft_logik/lib/hausaufgabenheft_logik.dart b/lib/hausaufgabenheft_logik/lib/hausaufgabenheft_logik.dart index 117e4fb0d..0d6924715 100644 --- a/lib/hausaufgabenheft_logik/lib/hausaufgabenheft_logik.dart +++ b/lib/hausaufgabenheft_logik/lib/hausaufgabenheft_logik.dart @@ -39,18 +39,17 @@ /// library hausaufgabenheft_logik; -export 'src/student_homework_page_bloc/events.dart'; -export 'src/student_homework_page_bloc/student_homework_page_bloc.dart'; -export 'src/student_homework_page_bloc/states.dart'; -export 'src/models/homework/homework.dart'; -export 'src/models/homework/models_used_by_homework.dart'; -export 'src/open_homeworks/sort_and_subcategorization/sort/smallest_date_subject_and_title_sort.dart'; -export 'src/open_homeworks/sort_and_subcategorization/sort/src/sort.dart'; -export 'src/open_homeworks/sort_and_subcategorization/sort/subject_smallest_date_and_title_sort.dart'; export 'src/completed_homeworks/views/completed_homwork_list_view.dart'; -export 'src/open_homeworks/views/open_homework_list_view.dart'; -export 'src/open_homeworks/sort_and_subcategorization/sort_and_subcategorizer.dart'; -export 'src/views/homework_view.dart'; -export 'src/open_homeworks/views/homework_section_view.dart'; export 'src/data_source/homework_data_source.dart'; export 'src/homework_completion/homework_completion_dispatcher.dart'; +export 'src/homework_list_extensions.dart'; +export 'src/models/homework.dart'; +export 'src/models/models.dart'; +export 'src/open_homeworks/sort_and_subcategorization/sort/src/sort.dart'; +export 'src/open_homeworks/sort_and_subcategorization/sort_and_subcategorizer.dart'; +export 'src/open_homeworks/views/homework_section_view.dart'; +export 'src/open_homeworks/views/open_homework_list_view.dart'; +export 'src/student_homework_page_bloc/events.dart'; +export 'src/student_homework_page_bloc/states.dart'; +export 'src/student_homework_page_bloc/student_homework_page_bloc.dart'; +export 'src/views/homework_view.dart'; diff --git a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/completed_homeworks_view_bloc.dart b/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/completed_homeworks_view_bloc.dart deleted file mode 100644 index 1193a0cfb..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/completed_homeworks_view_bloc.dart +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'dart:async'; - -import 'package:bloc/bloc.dart'; -import 'package:bloc_base/bloc_base.dart' as bloc_base; -import 'package:hausaufgabenheft_logik/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/lazy_loading_completed_homeworks_bloc.dart' - as lazy_loading; -import 'package:hausaufgabenheft_logik/src/completed_homeworks/views/completed_homework_list_view_factory.dart'; -import 'package:rxdart/rxdart.dart'; - -import 'events.dart'; -import 'states.dart'; - -export 'events.dart'; -export 'states.dart'; - -class CompletedHomeworksViewBloc extends Bloc implements bloc_base.BlocBase { - final lazy_loading.LazyLoadingCompletedHomeworksBloc - _lazyLoadingCompletedHomeworksBloc; - final CompletedHomeworkListViewFactory _completedHomeworkListViewFactory; - final int nrOfInitialCompletedHomeworksToLoad; - late StreamSubscription _streamSubscription; - late Stream _lazyLoadingSuccessStates; - - CompletedHomeworksViewBloc(this._lazyLoadingCompletedHomeworksBloc, - this._completedHomeworkListViewFactory, - {this.nrOfInitialCompletedHomeworksToLoad = 8}) - : super(Loading()) { - _lazyLoadingSuccessStates = _lazyLoadingCompletedHomeworksBloc.stream - .whereType(); - - on((event, emit) { - _lazyLoadingCompletedHomeworksBloc.add( - lazy_loading.LoadCompletedHomeworks( - nrOfInitialCompletedHomeworksToLoad)); - - _streamSubscription = _lazyLoadingSuccessStates.listen((state) { - add(_Transform(state)); - }); - }); - on((event, emit) { - _lazyLoadingCompletedHomeworksBloc - .add(lazy_loading.AdvanceCompletedHomeworks(event.advanceBy)); - }); - on<_Transform>((event, emit) { - final success = event.successState; - final listView = _completedHomeworkListViewFactory.create( - success.homeworks, success.loadedAllHomeworks); - emit(Success(listView)); - }); - } - - @override - void dispose() { - _streamSubscription.cancel(); - } -} - -class _Transform extends CompletedHomeworksViewBlocEvent { - final lazy_loading.Success successState; - - _Transform(this.successState); - - @override - List get props => [successState]; -} diff --git a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/events.dart b/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/events.dart deleted file mode 100644 index 808c9f672..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/events.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:equatable/equatable.dart'; - -abstract class CompletedHomeworksViewBlocEvent extends Equatable {} - -class StartTransformingHomeworks extends CompletedHomeworksViewBlocEvent { - @override - List get props => []; -} - -class AdvanceCompletedHomeworks extends CompletedHomeworksViewBlocEvent { - final int advanceBy; - @override - List get props => [advanceBy]; - AdvanceCompletedHomeworks(this.advanceBy); -} diff --git a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/states.dart b/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/states.dart deleted file mode 100644 index 099c61839..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/completed_homeworks_view_bloc/states.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:equatable/equatable.dart'; - -import 'package:hausaufgabenheft_logik/src/completed_homeworks/views/completed_homwork_list_view.dart'; - -abstract class CompletedHomeworksViewBlocState extends Equatable {} - -class Loading extends CompletedHomeworksViewBlocState { - @override - List get props => []; -} - -class Success extends CompletedHomeworksViewBlocState { - final CompletedHomeworkListView completedHomeworksView; - - Success(this.completedHomeworksView); - - @override - List get props => [completedHomeworksView]; -} diff --git a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/events.dart b/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/events.dart deleted file mode 100644 index 3fc59ad3f..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/events.dart +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:equatable/equatable.dart'; - -abstract class LazyLoadingCompletedHomeworksEvent extends Equatable {} - -class LoadCompletedHomeworks extends LazyLoadingCompletedHomeworksEvent { - final int numberOfHomeworksToLoad; - - LoadCompletedHomeworks(this.numberOfHomeworksToLoad); - - @override - List get props => [numberOfHomeworksToLoad]; - - @override - String toString() { - return 'LoadCompletedHomeworks(numberOfHomeworksToLoad: $numberOfHomeworksToLoad)'; - } -} - -class AdvanceCompletedHomeworks extends LazyLoadingCompletedHomeworksEvent { - final int advanceBy; - - AdvanceCompletedHomeworks(this.advanceBy); - - @override - List get props => [advanceBy]; - - @override - String toString() { - return 'AdvanceCompletedHomeworks(advanceBy: $advanceBy)'; - } -} diff --git a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/lazy_loading_completed_homeworks_bloc.dart b/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/lazy_loading_completed_homeworks_bloc.dart deleted file mode 100644 index 0e5462718..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/lazy_loading_completed_homeworks_bloc.dart +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:bloc/bloc.dart'; -import 'package:bloc_base/bloc_base.dart' as bloc_base; - -import '../../data_source/homework_data_source.dart'; -import '../../models/homework_list.dart'; -import 'events.dart'; -import 'states.dart'; - -export 'events.dart'; -export 'states.dart'; - -class LazyLoadingCompletedHomeworksBloc extends Bloc< - LazyLoadingCompletedHomeworksEvent, - LazyLoadingCompletedHomeworksBlocState> implements bloc_base.BlocBase { - final HomeworkDataSource _homeworkRepository; - LazyLoadingController? _lazyLoadingController; - - LazyLoadingCompletedHomeworksBloc(this._homeworkRepository) - : super(Loading()) { - on( - (event, emit) { - _lazyLoadingController = - _homeworkRepository.getLazyLoadingCompletedHomeworksController( - event.numberOfHomeworksToLoad); - _lazyLoadingController!.results.listen((res) => add( - _Yield(Success( - HomeworkList(res.homeworks), - loadedAllHomeworks: !res.moreHomeworkAvailable, - )), - )); - }, - ); - on( - (event, emit) { - assert(_lazyLoadingController != null); - _lazyLoadingController!.advanceBy(event.advanceBy); - }, - ); - on<_Yield>( - (event, emit) => emit(event.payload), - ); - } - - @override - void dispose() {} -} - -class _Yield extends LazyLoadingCompletedHomeworksEvent { - final dynamic payload; - _Yield(this.payload) : assert(payload != null); - - @override - List get props => [payload]; - - @override - String toString() { - return '_Yield(payload: $payload)'; - } -} diff --git a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/states.dart b/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/states.dart deleted file mode 100644 index 4630642be..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/states.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:equatable/equatable.dart'; - -import '../../models/homework_list.dart'; - -abstract class LazyLoadingCompletedHomeworksBlocState extends Equatable {} - -class Success extends LazyLoadingCompletedHomeworksBlocState { - final HomeworkList homeworks; - final bool loadedAllHomeworks; - - Success(this.homeworks, {required this.loadedAllHomeworks}); - - @override - List get props => [homeworks, loadedAllHomeworks]; -} - -class Loading extends LazyLoadingCompletedHomeworksBlocState { - @override - List get props => []; -} diff --git a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/views/completed_homework_list_view_factory.dart b/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/views/completed_homework_list_view_factory.dart index 251fdd717..b0a73f0fa 100644 --- a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/views/completed_homework_list_view_factory.dart +++ b/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/views/completed_homework_list_view_factory.dart @@ -6,8 +6,8 @@ // // SPDX-License-Identifier: EUPL-1.2 -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; -import 'completed_homwork_list_view.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; import '../../views/student_homework_view_factory.dart'; class CompletedHomeworkListViewFactory { @@ -15,12 +15,12 @@ class CompletedHomeworkListViewFactory { CompletedHomeworkListViewFactory(this._studentHomeworkViewFactory); - CompletedHomeworkListView create( - HomeworkList completedHomeworks, bool loadedAllCompletedHomeworks) { - final orderedHomeworks = [ + CompletedHomeworkListView create(IList completedHomeworks, + bool loadedAllCompletedHomeworks) { + final orderedHomeworks = IList([ for (final completedHomework in completedHomeworks) _studentHomeworkViewFactory.createFrom(completedHomework) - ]; + ]); return CompletedHomeworkListView(orderedHomeworks, loadedAllCompletedHomeworks: loadedAllCompletedHomeworks); } diff --git a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/views/completed_homwork_list_view.dart b/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/views/completed_homwork_list_view.dart index 3640edd27..8f091879c 100644 --- a/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/views/completed_homwork_list_view.dart +++ b/lib/hausaufgabenheft_logik/lib/src/completed_homeworks/views/completed_homwork_list_view.dart @@ -6,11 +6,13 @@ // // SPDX-License-Identifier: EUPL-1.2 +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; + import '../../views/homework_view.dart'; class CompletedHomeworkListView { final bool loadedAllCompletedHomeworks; - final List orderedHomeworks; + final IList orderedHomeworks; CompletedHomeworkListView(this.orderedHomeworks, {required this.loadedAllCompletedHomeworks}); diff --git a/lib/hausaufgabenheft_logik/lib/src/data_source/homework_data_source.dart b/lib/hausaufgabenheft_logik/lib/src/data_source/homework_data_source.dart index 38d93339d..bfbf52e3a 100644 --- a/lib/hausaufgabenheft_logik/lib/src/data_source/homework_data_source.dart +++ b/lib/hausaufgabenheft_logik/lib/src/data_source/homework_data_source.dart @@ -6,11 +6,12 @@ // // SPDX-License-Identifier: EUPL-1.2 -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework.dart'; import 'package:collection/collection.dart' show DeepCollectionEquality; abstract class HomeworkDataSource { - Stream> get openHomeworks; + Stream> get openHomeworks; LazyLoadingController getLazyLoadingCompletedHomeworksController( int nrOfInitialHomeworkToLoad); } @@ -21,12 +22,13 @@ abstract class LazyLoadingController { } class LazyLoadingResult { - final List homeworks; + final IList homeworks; final bool moreHomeworkAvailable; LazyLoadingResult(this.homeworks, {required this.moreHomeworkAvailable}); - LazyLoadingResult.empty({this.moreHomeworkAvailable = true}) : homeworks = []; + LazyLoadingResult.empty({this.moreHomeworkAvailable = true}) + : homeworks = const IListConst([]); @override String toString() { diff --git a/lib/hausaufgabenheft_logik/lib/src/homework_completion/homework_completion_dispatcher.dart b/lib/hausaufgabenheft_logik/lib/src/homework_completion/homework_completion_dispatcher.dart index 82adc8444..a2b8d2437 100644 --- a/lib/hausaufgabenheft_logik/lib/src/homework_completion/homework_completion_dispatcher.dart +++ b/lib/hausaufgabenheft_logik/lib/src/homework_completion/homework_completion_dispatcher.dart @@ -7,7 +7,7 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:common_domain_models/common_domain_models.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/homework_completion_status.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework_completion_status.dart'; /// The boundary to the outer world. /// The only purpose for this class is to change the completion status of a diff --git a/lib/hausaufgabenheft_logik/lib/src/homework_completion/homework_page_completion_dispatcher.dart b/lib/hausaufgabenheft_logik/lib/src/homework_completion/homework_page_completion_dispatcher.dart index 4bd4db52a..587bef3a3 100644 --- a/lib/hausaufgabenheft_logik/lib/src/homework_completion/homework_page_completion_dispatcher.dart +++ b/lib/hausaufgabenheft_logik/lib/src/homework_completion/homework_page_completion_dispatcher.dart @@ -7,7 +7,7 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:common_domain_models/common_domain_models.dart'; -import 'package:equatable/equatable.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; /// The [HomeworkPageCompletionDispatcher] is a homework page sepecific input for @@ -20,48 +20,23 @@ import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; /// [AllOverdueHomeworkCompletionEvent] while the [HomeworkCompletionDispatcher] /// is not bound to the homework page. class HomeworkPageCompletionDispatcher { - final Future> Function() getCurrentOverdueHomeworkIds; + final Future> Function() getCurrentOverdueHomeworkIds; final HomeworkCompletionDispatcher _homeworkCompletionDispatcher; HomeworkPageCompletionDispatcher(this._homeworkCompletionDispatcher, {required this.getCurrentOverdueHomeworkIds}); - Future add(HomeworkCompletionEvent event) async { - if (event is SingleHomeworkCompletionEvent) { - _homeworkCompletionDispatcher.dispatch( - HomeworkCompletion( - HomeworkId(event.homeworkId), - event.newValue ? CompletionStatus.completed : CompletionStatus.open, - ), - ); - } else if (event is AllOverdueHomeworkCompletionEvent) { - final overdueHwIds = await getCurrentOverdueHomeworkIds(); - for (final overdueHwId in overdueHwIds) { - _homeworkCompletionDispatcher.dispatch( - HomeworkCompletion(overdueHwId, CompletionStatus.completed), - ); - } - } else { - throw UnimplementedError('$event is not implemented'); - } + Future changeCompletionStatus( + HomeworkId homeworkId, CompletionStatus newCompletionValue) async { + _homeworkCompletionDispatcher + .dispatch(HomeworkCompletion(homeworkId, newCompletionValue)); } -} - -abstract class HomeworkCompletionEvent extends Equatable {} - -class SingleHomeworkCompletionEvent extends HomeworkCompletionEvent { - final String homeworkId; - final bool newValue; - - SingleHomeworkCompletionEvent(this.homeworkId, this.newValue); - @override - List get props => [homeworkId]; -} - -/// Will change the completion status of all open homeworks, where the todo date -/// is before today, to completed. -class AllOverdueHomeworkCompletionEvent extends HomeworkCompletionEvent { - @override - List get props => []; + Future completeAllOverdueHomeworks() async { + final hws = await getCurrentOverdueHomeworkIds(); + for (final hw in hws) { + _homeworkCompletionDispatcher + .dispatch(HomeworkCompletion(hw, CompletionStatus.completed)); + } + } } diff --git a/lib/hausaufgabenheft_logik/lib/src/homework_list_extensions.dart b/lib/hausaufgabenheft_logik/lib/src/homework_list_extensions.dart new file mode 100644 index 000000000..9e0c6fa61 --- /dev/null +++ b/lib/hausaufgabenheft_logik/lib/src/homework_list_extensions.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) +// Licensed under the EUPL-1.2-or-later. +// +// You may obtain a copy of the Licence at: +// https://joinup.ec.europa.eu/software/page/eupl +// +// SPDX-License-Identifier: EUPL-1.2 + +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework_completion_status.dart'; + +import 'open_homeworks/sort_and_subcategorization/sort/src/sort.dart'; +import 'models/date.dart'; +import 'models/homework.dart'; +import 'models/subject.dart'; + +extension SortWith on IList { + IList sortWith(Sort sort) { + return sort.sort(this); + } +} + +extension HomeworkListExtension on IList { + IList get completed => + where((homework) => homework.status == CompletionStatus.completed) + .toIList(); + IList get open => + where((homework) => homework.status == CompletionStatus.open).toIList(); + + IList getDistinctOrderedSubjects() { + final subjects = {}; + for (final homework in this) { + subjects.add(homework.subject); + } + return subjects.toIList(); + } + + IList getOverdue([Date? now]) { + now = now ?? Date.now(); + return where((homeworks) => homeworks.isOverdueRelativeTo(now!)).toIList(); + } +} diff --git a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_archived_homework_list_view.dart b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_archived_homework_list_view.dart index e90427b7f..eabbc26a4 100644 --- a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_archived_homework_list_view.dart +++ b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_archived_homework_list_view.dart @@ -6,11 +6,13 @@ // // SPDX-License-Identifier: EUPL-1.2 +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; + import 'teacher_homework_view.dart'; class TeacherArchivedHomeworkListView { final bool loadedAllArchivedHomeworks; - final List orderedHomeworks; + final IList orderedHomeworks; TeacherArchivedHomeworkListView(this.orderedHomeworks, {required this.loadedAllArchivedHomeworks}); diff --git a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_page_bloc.dart b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_page_bloc.dart index ce0ec760d..afc535b0e 100644 --- a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_page_bloc.dart +++ b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_page_bloc.dart @@ -11,6 +11,7 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:bloc_base/bloc_base.dart' as bloc_base; import 'package:common_domain_models/common_domain_models.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:hausaufgabenheft_logik/color.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik_lehrer.dart'; import 'package:meta/meta.dart'; @@ -66,31 +67,37 @@ class _States { // ignore: unused_field static final _placeholder = Success( - TeacherOpenHomeworkListView([], + TeacherOpenHomeworkListView(const IListConst([]), sorting: HomeworkSort.smallestDateSubjectAndTitle), - TeacherArchivedHomeworkListView([], loadedAllArchivedHomeworks: true), + TeacherArchivedHomeworkListView(const IListConst([]), + loadedAllArchivedHomeworks: true), ); /// Answer for [_ArchivedHwLazyLoadingState.askedForFirstBatch] - static final __archivedHomeworksFirstState = TeacherArchivedHomeworkListView([ - _Homeworks._noSubmissionNoPermissions, - _Homeworks._withSubmissionWithPermissions, - ..._generateRandomHomeworks(count: 18) - ], loadedAllArchivedHomeworks: false); + static final __archivedHomeworksFirstState = TeacherArchivedHomeworkListView( + IList([ + _Homeworks._noSubmissionNoPermissions, + _Homeworks._withSubmissionWithPermissions, + ..._generateRandomHomeworks(count: 18) + ]), + loadedAllArchivedHomeworks: false); /// Answer for [_ArchivedHwLazyLoadingState.askedForSecondBatch] - static final __archivedHomeworksSecondState = - TeacherArchivedHomeworkListView([ - ...__archivedHomeworksFirstState.orderedHomeworks, - ..._generateRandomHomeworks(count: 10) - ], loadedAllArchivedHomeworks: false); + static final __archivedHomeworksSecondState = TeacherArchivedHomeworkListView( + IList([ + ...__archivedHomeworksFirstState.orderedHomeworks, + ..._generateRandomHomeworks(count: 10) + ]), + loadedAllArchivedHomeworks: false); /// Answer for [_ArchivedHwLazyLoadingState.askedForAll] static final __archivedHomeworksLoadedAllState = - TeacherArchivedHomeworkListView([ - ...__archivedHomeworksSecondState.orderedHomeworks, - ..._generateRandomHomeworks(count: 10) - ], loadedAllArchivedHomeworks: true); + TeacherArchivedHomeworkListView( + IList([ + ...__archivedHomeworksSecondState.orderedHomeworks, + ..._generateRandomHomeworks(count: 10) + ]), + loadedAllArchivedHomeworks: true); static TeacherArchivedHomeworkListView __getArchivedListView( _ArchivedHwLazyLoadingState loadingState) { @@ -107,26 +114,36 @@ class _States { static Success _homeworksAllLoadedSortedBySubject( _ArchivedHwLazyLoadingState loadingState) { return Success( - TeacherOpenHomeworkListView([ - TeacherHomeworkSectionView('Mathe', [ - _Homeworks._noSubmissionWithPermissions, - _Homeworks._withSubmissionNoPermissions - ]) - ], sorting: HomeworkSort.subjectSmallestDateAndTitleSort), + TeacherOpenHomeworkListView( + IList([ + TeacherHomeworkSectionView( + 'Mathe', + IList([ + _Homeworks._noSubmissionWithPermissions, + _Homeworks._withSubmissionNoPermissions + ])) + ]), + sorting: HomeworkSort.subjectSmallestDateAndTitleSort), __getArchivedListView(loadingState)); } static Success _homeworksAllLoadedSortedByTodoDate( _ArchivedHwLazyLoadingState loadingState) { return Success( - TeacherOpenHomeworkListView([ - TeacherHomeworkSectionView('Heute', [ - _Homeworks._noSubmissionWithPermissions, - ]), - TeacherHomeworkSectionView('In 3 Tagen', [ - _Homeworks._withSubmissionNoPermissions, - ]) - ], sorting: HomeworkSort.smallestDateSubjectAndTitle), + TeacherOpenHomeworkListView( + IList([ + TeacherHomeworkSectionView( + 'Heute', + IList([ + _Homeworks._noSubmissionWithPermissions, + ])), + TeacherHomeworkSectionView( + 'In 3 Tagen', + IList([ + _Homeworks._withSubmissionNoPermissions, + ])) + ]), + sorting: HomeworkSort.smallestDateSubjectAndTitle), __getArchivedListView(loadingState), ); } diff --git a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_read_model.dart b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_read_model.dart index 2047a396a..a9dc1d8c6 100644 --- a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_read_model.dart +++ b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_read_model.dart @@ -7,8 +7,8 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:common_domain_models/common_domain_models.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/models_used_by_homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/models.dart'; /// Ein ReadModel für die Lehrer-Hausaufgaben-Seite. /// Siehe [HomeworkReadModel]. diff --git a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_section_view.dart b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_section_view.dart index c8f2ae2e9..94cf6af39 100644 --- a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_section_view.dart +++ b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_section_view.dart @@ -7,13 +7,14 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:equatable/equatable.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik_lehrer.dart'; import 'teacher_homework_view_factory.dart'; class TeacherHomeworkSectionView extends Equatable { final String title; - final List homeworks; + final IList homeworks; bool get isEmpty => homeworks.isEmpty; bool get isNotEmpty => homeworks.isNotEmpty; @@ -25,12 +26,14 @@ class TeacherHomeworkSectionView extends Equatable { factory TeacherHomeworkSectionView.fromModels( String title, - List homeworks, + IList homeworks, TeacherHomeworkViewFactory viewFactory, ) { - return TeacherHomeworkSectionView(title, [ - for (final h in homeworks) viewFactory.createFrom(h), - ]); + return TeacherHomeworkSectionView( + title, + IList([ + for (final h in homeworks) viewFactory.createFrom(h), + ])); } @override diff --git a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_view_factory.dart b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_view_factory.dart index e5525edf9..d2c0cf138 100644 --- a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_view_factory.dart +++ b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_homework_view_factory.dart @@ -6,7 +6,7 @@ // // SPDX-License-Identifier: EUPL-1.2 -import 'package:hausaufgabenheft_logik/src/models/homework/models_used_by_homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/models.dart'; import 'package:hausaufgabenheft_logik/src/views/color.dart'; import '../../hausaufgabenheft_logik_lehrer.dart'; diff --git a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_open_homework_list_view.dart b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_open_homework_list_view.dart index 50f64d26b..c97f10112 100644 --- a/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_open_homework_list_view.dart +++ b/lib/hausaufgabenheft_logik/lib/src/lehrer/teacher_open_homework_list_view.dart @@ -8,11 +8,12 @@ import 'package:collection/collection.dart' show DeepCollectionEquality; import 'package:collection/collection.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'teacher_homework_section_view.dart'; class TeacherOpenHomeworkListView { - final List sections; + final IList sections; final HomeworkSort sorting; TeacherOpenHomeworkListView( diff --git a/lib/hausaufgabenheft_logik/lib/src/models/date.dart b/lib/hausaufgabenheft_logik/lib/src/models/date.dart index c4dcc7b45..68da72aa3 100644 --- a/lib/hausaufgabenheft_logik/lib/src/models/date.dart +++ b/lib/hausaufgabenheft_logik/lib/src/models/date.dart @@ -7,12 +7,16 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:clock/clock.dart'; +import 'package:equatable/equatable.dart'; -class Date implements Comparable { +class Date extends Equatable implements Comparable { final int day; final int month; final int year; + @override + List get props => [day, month, year]; + const Date({ required this.day, required this.month, @@ -30,63 +34,29 @@ class Date implements Comparable { DateTime asDateTime() => DateTime(year, month, day, 0, 0, 0, 0, 0); - bool operator >(Date other) { - return compareTo(other) > 0; - } - - bool operator <(Date other) { - return compareTo(other) < 0; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Date && - other.day == day && - other.month == month && - other.year == year; + Date addDays(int daysToAdd) { + final dateTime = asDateTime(); + DateTime newDateTime; + newDateTime = dateTime.add(Duration(days: daysToAdd)); + return Date.fromDateTime(newDateTime); } @override int compareTo(Date other) { - if (year > other.year) { - return 1; - } else if (year < other.year) { - return -1; + if (year.compareTo(other.year) != 0) { + return year.compareTo(other.year); + } else if (month.compareTo(other.month) != 0) { + return month.compareTo(other.month); } else { - if (month > other.month) { - return 1; - } else if (month < other.month) { - return -1; - } else { - if (day > other.day) { - return 1; - } else if (day < other.day) { - return -1; - } - return 0; - } + return day.compareTo(other.day); } } - @override - int get hashCode => day.hashCode ^ month.hashCode ^ year.hashCode; - - @override - String toString() { - return 'Date(day: $day, month: $month, year: $year)'; - } - - /// Does NOT roll over to the next month, just plain stupid addition - Date addDaysWithNoChecking(int days) { - return Date(year: year, month: month, day: day + days); + bool operator >(Date other) { + return compareTo(other) > 0; } - Date addDays(int daysToAdd) { - final dateTime = asDateTime(); - DateTime newDateTime; - newDateTime = dateTime.add(Duration(days: daysToAdd)); - return Date.fromDateTime(newDateTime); + bool operator <(Date other) { + return compareTo(other) < 0; } } diff --git a/lib/hausaufgabenheft_logik/lib/src/models/homework/homework.dart b/lib/hausaufgabenheft_logik/lib/src/models/homework.dart similarity index 53% rename from lib/hausaufgabenheft_logik/lib/src/models/homework/homework.dart rename to lib/hausaufgabenheft_logik/lib/src/models/homework.dart index 4e7bafc50..bac3a415c 100644 --- a/lib/hausaufgabenheft_logik/lib/src/models/homework/homework.dart +++ b/lib/hausaufgabenheft_logik/lib/src/models/homework.dart @@ -7,11 +7,12 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:common_domain_models/common_domain_models.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/homework_completion_status.dart'; +import 'package:equatable/equatable.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework_completion_status.dart'; -import '../date.dart'; -import '../subject.dart'; -import '../title.dart'; +import 'date.dart'; +import 'subject.dart'; +import 'title.dart'; /// The read model of a Homework that is specific to one user. /// The Homework should only be used to display a homework, created specifically @@ -20,7 +21,7 @@ import '../title.dart'; /// In Sharezone it used in the context of the HomeworkPage, as it is basically /// a merge from the information of the homework-details (title, subject, ...) /// and the specific done status of the user viewing the homework. -class HomeworkReadModel { +class HomeworkReadModel extends Equatable { final HomeworkId id; final DateTime todoDate; final Subject subject; @@ -28,46 +29,20 @@ class HomeworkReadModel { final bool withSubmissions; final CompletionStatus status; - HomeworkReadModel({ + @override + List get props => + [id, todoDate, subject, title, withSubmissions, status]; + + const HomeworkReadModel({ required this.id, required this.title, required this.subject, required this.status, required this.withSubmissions, required this.todoDate, - }) { - ArgumentError.checkNotNull(id); - ArgumentError.checkNotNull(todoDate); - ArgumentError.checkNotNull(status); - ArgumentError.checkNotNull(subject); - ArgumentError.checkNotNull(withSubmissions); - ArgumentError.checkNotNull(title); - } - - @override - int get hashCode => - id.hashCode ^ - todoDate.hashCode ^ - status.hashCode ^ - subject.hashCode ^ - title.hashCode; - - @override - bool operator ==(other) => - identical(this, other) || - other is HomeworkReadModel && - id == other.id && - title == other.title && - subject == other.subject && - status == other.status && - todoDate == other.todoDate; + }); bool isOverdueRelativeTo(Date today) { return Date.fromDateTime(todoDate) < today; } - - @override - String toString() { - return 'Homework(Id: $id, title: $title, subject: $subject, todoDate: $todoDate, done: $status)'; - } } diff --git a/lib/hausaufgabenheft_logik/lib/src/models/homework/homework_completion_status.dart b/lib/hausaufgabenheft_logik/lib/src/models/homework_completion_status.dart similarity index 100% rename from lib/hausaufgabenheft_logik/lib/src/models/homework/homework_completion_status.dart rename to lib/hausaufgabenheft_logik/lib/src/models/homework_completion_status.dart diff --git a/lib/hausaufgabenheft_logik/lib/src/models/homework_list.dart b/lib/hausaufgabenheft_logik/lib/src/models/homework_list.dart deleted file mode 100644 index cd04c54a4..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/models/homework_list.dart +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'dart:collection'; -import 'package:hausaufgabenheft_logik/src/models/homework/homework_completion_status.dart'; - -import 'homework/homework.dart'; -import 'date.dart'; -import 'subject.dart'; -import '../open_homeworks/sort_and_subcategorization/sort/src/sort.dart'; - -class HomeworkList extends ListBase { - final List _homeworks; - - HomeworkList(List homeworks) - : _homeworks = List.from(homeworks); - @override - int get length => _homeworks.length; - - @override - set length(int newLength) => _homeworks.length = newLength; - - @override - HomeworkReadModel operator [](int index) => _homeworks[index]; - - @override - void operator []=(int index, value) => _homeworks[index] = value; - - @override // Overwritten for performance reasons as stated in ListBase - void add(HomeworkReadModel element) => _homeworks.add(element); - - @override // Overwritten for performance reasons as stated in ListBase - void addAll(Iterable iterable) => - _homeworks.addAll(iterable); - - void sortWith(Sort sort) => sort.sort(this); - - @override - String toString() { - var s = 'HomeworkList([\n'; - for (final homework in _homeworks) { - s += '$homework\n'; - } - s += '])'; - return s; - } - - List getDistinctOrderedSubjects() { - final subjects = {}; - for (final homework in _homeworks) { - subjects.add(homework.subject); - } - return subjects.toList(); - } - - HomeworkList getOverdue([Date? now]) { - now = now ?? Date.now(); - return HomeworkList(_homeworks - .where((homeworks) => homeworks.isOverdueRelativeTo(now!)) - .toList()); - } - - HomeworkList get completed => HomeworkList(_homeworks - .where((homework) => homework.status == CompletionStatus.completed) - .toList()); - HomeworkList get open => HomeworkList(_homeworks - .where((homework) => homework.status == CompletionStatus.open) - .toList()); -} diff --git a/lib/hausaufgabenheft_logik/lib/src/models/homework/models_used_by_homework.dart b/lib/hausaufgabenheft_logik/lib/src/models/models.dart similarity index 75% rename from lib/hausaufgabenheft_logik/lib/src/models/homework/models_used_by_homework.dart rename to lib/hausaufgabenheft_logik/lib/src/models/models.dart index 5cceec335..64c09e722 100644 --- a/lib/hausaufgabenheft_logik/lib/src/models/homework/models_used_by_homework.dart +++ b/lib/hausaufgabenheft_logik/lib/src/models/models.dart @@ -6,9 +6,7 @@ // // SPDX-License-Identifier: EUPL-1.2 -library models; - -export '../date.dart'; -export '../subject.dart'; -export '../title.dart'; +export 'date.dart'; +export 'subject.dart'; +export 'title.dart'; export 'homework_completion_status.dart'; diff --git a/lib/hausaufgabenheft_logik/lib/src/models/subject.dart b/lib/hausaufgabenheft_logik/lib/src/models/subject.dart index c4e367a79..cd884845b 100644 --- a/lib/hausaufgabenheft_logik/lib/src/models/subject.dart +++ b/lib/hausaufgabenheft_logik/lib/src/models/subject.dart @@ -6,33 +6,21 @@ // // SPDX-License-Identifier: EUPL-1.2 +import 'package:equatable/equatable.dart'; import 'package:hausaufgabenheft_logik/src/views/color.dart'; -class Subject { +class Subject extends Equatable { final String name; final Color? color; final String abbreviation; + @override + List get props => [name, color, abbreviation]; + Subject(this.name, {this.color, required this.abbreviation}) { if (name.isEmpty) { throw ArgumentError.value( name, 'name', "The subject name can't be empty"); } } - - @override - int get hashCode => name.hashCode; - - bool get isValid => name.isNotEmpty; - - @override - bool operator ==(other) { - return identical(this, other) || - other is Subject && name == other.name && color == other.color; - } - - @override - String toString() { - return 'Subject(name: $name, color: $color)'; - } } diff --git a/lib/hausaufgabenheft_logik/lib/src/models/title.dart b/lib/hausaufgabenheft_logik/lib/src/models/title.dart index ab23fda41..7e4d8c330 100644 --- a/lib/hausaufgabenheft_logik/lib/src/models/title.dart +++ b/lib/hausaufgabenheft_logik/lib/src/models/title.dart @@ -6,26 +6,18 @@ // // SPDX-License-Identifier: EUPL-1.2 -class Title implements Comparable { - final String value; +import 'package:equatable/equatable.dart'; - const Title(this.value); +class Title extends Equatable implements Comparable<Title> { + final String value; @override - bool operator ==(other) { - return identical(this, other) || other is Title && value == other.value; - } + List<Object> get props => [value]; - @override - int get hashCode => value.hashCode; + const Title(this.value); @override int compareTo(Title other) { return value.compareTo(other.value); } - - @override - String toString() { - return 'Title(value: $value)'; - } } diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/events.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/events.dart deleted file mode 100644 index f6d4a3ce1..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/events.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:equatable/equatable.dart'; - -abstract class OpenHomeworkListBlocEvent extends Equatable {} - -class LoadHomeworks extends OpenHomeworkListBlocEvent { - @override - List<Object> get props => []; -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/open_homework_list_bloc.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/open_homework_list_bloc.dart deleted file mode 100644 index c1541a906..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/open_homework_list_bloc.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:bloc/bloc.dart'; -import 'package:hausaufgabenheft_logik/src/data_source/homework_data_source.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; - -import 'events.dart'; -import 'states.dart'; - -export 'events.dart'; -export 'states.dart'; - -class OpenHomeworkListBloc - extends Bloc<OpenHomeworkListBlocEvent, OpenHomeworkListBlocState> { - final HomeworkDataSource _repository; - - OpenHomeworkListBloc(this._repository) : super(Uninitialized()) { - on<LoadHomeworks>((event, emit) { - _repository.openHomeworks - .listen((hws) => add(_Yield(Success(HomeworkList(hws))))); - }); - on<_Yield>((event, emit) => emit(event.payload)); - } -} - -class _Yield extends OpenHomeworkListBlocEvent { - final dynamic payload; - _Yield(this.payload) : assert(payload != null); - - @override - List<Object> get props => [payload]; -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/states.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/states.dart deleted file mode 100644 index 633de2296..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_list_bloc/states.dart +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; - -abstract class OpenHomeworkListBlocState {} - -class Uninitialized extends OpenHomeworkListBlocState {} - -class Success extends OpenHomeworkListBlocState { - final HomeworkList homeworks; - - Success(this.homeworks); -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/events.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/events.dart deleted file mode 100644 index 4edcaf79e..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/events.dart +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:equatable/equatable.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/src/sort.dart'; - -abstract class OpenHomeworkViewEvent extends Equatable {} - -class LoadHomeworks extends OpenHomeworkViewEvent { - final Sort<HomeworkReadModel> sort; - - LoadHomeworks(this.sort); - - @override - List<Object> get props => [sort]; - - @override - String toString() { - return 'LoadHomeworks(sort: $sort)'; - } -} - -class SortingChanged extends OpenHomeworkViewEvent { - final Sort<HomeworkReadModel> sort; - - SortingChanged(this.sort); - - @override - List<Object> get props => [sort]; - - @override - String toString() { - return 'SortingChanged(sort: $sort)'; - } -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/open_homework_view_bloc.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/open_homework_view_bloc.dart deleted file mode 100644 index 9bfd28727..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/open_homework_view_bloc.dart +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'dart:async'; - -import 'package:bloc/bloc.dart'; -import 'package:bloc_base/bloc_base.dart' as bloc_base; -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/src/sort.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/open_homework_list_bloc/open_homework_list_bloc.dart' - as hws_bloc; -import 'package:hausaufgabenheft_logik/src/open_homeworks/views/open_homework_list_view_factory.dart'; - -import 'events.dart'; -import 'states.dart'; - -export 'events.dart'; -export 'states.dart'; - -class OpenHomeworksViewBloc - extends Bloc<OpenHomeworkViewEvent, OpenHomeworksViewBlocState> - implements bloc_base.BlocBase { - final OpenHomeworkListViewFactory _listViewFactory; - final hws_bloc.OpenHomeworkListBloc _openHomeworksBloc; - - late Stream<HomeworkList> _openHomeworks; - late StreamSubscription _streamSubscription; - HomeworkList? _latestHomeworks; - Sort<HomeworkReadModel>? _currentSort; - - OpenHomeworksViewBloc(this._openHomeworksBloc, this._listViewFactory) - : super(Uninitialized()) { - _latestHomeworks = HomeworkList([]); - _openHomeworks = _openHomeworksBloc.stream.transform(_toHomeworkList); - - on<LoadHomeworks>((event, emit) { - _currentSort = event.sort; - _openHomeworksBloc.add(hws_bloc.LoadHomeworks()); - _streamSubscription = _openHomeworks.listen((hws) { - _latestHomeworks = hws; - add(_CreateListView(hws, _currentSort)); - }); - }); - on<SortingChanged>((event, emit) { - _currentSort = event.sort; - add(_CreateListView(_latestHomeworks, _currentSort)); - }); - on<_CreateListView>((event, emit) { - final view = _listViewFactory.create(event.homeworks!, event.sort!); - var success = Success(view); - emit(success); - }); - } - - @override - void dispose() { - _streamSubscription.cancel(); - } -} - -class _CreateListView extends OpenHomeworkViewEvent { - final HomeworkList? homeworks; - final Sort<HomeworkReadModel>? sort; - - _CreateListView(this.homeworks, this.sort); - - @override - List<Object?> get props => [homeworks, sort]; -} - -final _toHomeworkList = StreamTransformer<hws_bloc.OpenHomeworkListBlocState, - HomeworkList>.fromHandlers(handleData: (state, sink) { - if (state is hws_bloc.Success) { - sink.add(state.homeworks); - } -}); diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/states.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/states.dart deleted file mode 100644 index ce62f0a44..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/open_homework_view_bloc/states.dart +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:hausaufgabenheft_logik/src/open_homeworks/views/open_homework_list_view.dart'; - -abstract class OpenHomeworksViewBlocState {} - -class Uninitialized extends OpenHomeworksViewBlocState {} - -class Success extends OpenHomeworksViewBlocState { - final OpenHomeworkListView openHomeworkListView; - - Success(this.openHomeworkListView); - - @override - bool operator ==(Object other) { - return identical(this, other) || - other is Success && other.openHomeworkListView == openHomeworkListView; - } - - @override - int get hashCode => openHomeworkListView.hashCode; - - @override - String toString() { - return 'Success(openHomeworkListView: $openHomeworkListView)'; - } -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/homework_sorts.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/homework_sorts.dart index 29c29d14a..b7eb8950c 100644 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/homework_sorts.dart +++ b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/homework_sorts.dart @@ -6,6 +6,4 @@ // // SPDX-License-Identifier: EUPL-1.2 -export 'smallest_date_subject_and_title_sort.dart'; export 'src/sort.dart'; -export 'subject_smallest_date_and_title_sort.dart'; diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/smallest_date_subject_and_title_sort.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/smallest_date_subject_and_title_sort.dart deleted file mode 100644 index 96f5b3f43..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/smallest_date_subject_and_title_sort.dart +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import '../../../models/homework/homework.dart'; -import '../../../models/date.dart'; -import 'src/sort.dart'; -import 'src/sort_with_operations.dart'; -import 'src/homework_attribute_sorts.dart'; - -/// Sorts the homeworks firstly by date (earliest date first). -/// If they have the same date, they will be sorted alphabetically by subject. -/// If they have the same date and subject, they will be sorted alphabetically by title. -class SmallestDateSubjectAndTitleSort extends Sort<HomeworkReadModel> { - late Date Function() getCurrentDate; - - SmallestDateSubjectAndTitleSort({Date Function()? getCurrentDate}) { - this.getCurrentDate = getCurrentDate ?? () => Date.now(); - } - - @override - List<HomeworkReadModel> sort(List<HomeworkReadModel> list) { - sortWithOperations<HomeworkReadModel>( - list, List.from([dateSort, subjectSort, titleSort])); - return list; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - other is SmallestDateSubjectAndTitleSort && - other.getCurrentDate == getCurrentDate; - } - - @override - int get hashCode => getCurrentDate.hashCode; -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/homework_attribute_sorts.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/homework_attribute_sorts.dart index c3f88e697..90d692fa8 100644 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/homework_attribute_sorts.dart +++ b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/homework_attribute_sorts.dart @@ -6,7 +6,7 @@ // // SPDX-License-Identifier: EUPL-1.2 -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework.dart'; import 'sort_with_operations.dart'; diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/sort.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/sort.dart index fc3e796c7..d2ed3d779 100644 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/sort.dart +++ b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/sort.dart @@ -6,6 +6,56 @@ // // SPDX-License-Identifier: EUPL-1.2 -abstract class Sort<T> { - void sort(List<T> list); +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; + +import 'homework_attribute_sorts.dart'; +import 'sort_with_operations.dart'; + +sealed class Sort<T> { + IList<T> sort(IList<T> list); +} + +/// Sorts the homeworks firstly by date (earliest date first). +/// If they have the same date, they will be sorted alphabetically by subject. +/// If they have the same date and subject, they will be sorted alphabetically by title. +class SmallestDateSubjectAndTitleSort extends Sort<HomeworkReadModel> { + late Date Function() getCurrentDate; + + SmallestDateSubjectAndTitleSort({Date Function()? getCurrentDate}) { + this.getCurrentDate = getCurrentDate ?? () => Date.now(); + } + + @override + IList<HomeworkReadModel> sort(IList<HomeworkReadModel> list) { + return sortWithOperations<HomeworkReadModel>( + list, const IListConst([dateSort, subjectSort, titleSort])); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + other is SmallestDateSubjectAndTitleSort && + other.getCurrentDate == getCurrentDate; + } + + @override + int get hashCode => getCurrentDate.hashCode; +} + +/// Sorts the homeworks firstly by Subject. +/// If they have the same subject, they will be sorted by date (earliest date first). +/// If they have the same date and subject, they will be sorted alphabetically by title. +class SubjectSmallestDateAndTitleSort extends Sort<HomeworkReadModel> { + @override + IList<HomeworkReadModel> sort(IList<HomeworkReadModel> list) { + return sortWithOperations<HomeworkReadModel>( + list, const IListConst([subjectSort, dateSort, titleSort])); + } + + @override + bool operator ==(Object other) => true; + + @override + int get hashCode => 1337; } diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/sort_with_operations.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/sort_with_operations.dart index 836ae1873..e8b5a4956 100644 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/sort_with_operations.dart +++ b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/src/sort_with_operations.dart @@ -6,6 +6,8 @@ // // SPDX-License-Identifier: EUPL-1.2 +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; + /// Sorts the [listToSort] sequentially with the [comparisions]. /// If a comparision does treat the objects as equal, the next comparision will be executed on those. /// The result of the last comparision will be used either way. @@ -29,10 +31,10 @@ /// h6 - Informatik: “Buch S. 33” (06.10.19) /// h5 - Mathematik: “Buch S. 33” (01.01.19) /// h7 - Mathematik: “Buch S. 37” (06.10.20) -void sortWithOperations<T>( - List<T> listToSort, List<Comparision<T>> comparisions) { +IList<T> sortWithOperations<T>( + IList<T> listToSort, IList<Comparision<T>> comparisions) { final last = comparisions.last; - listToSort.sort((ha1, ha2) { + return listToSort.sort((ha1, ha2) { for (final comparision in comparisions) { final result = comparision(ha1, ha2); if (result.objectsAreNotEqual || comparision == last) { diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/subject_smallest_date_and_title_sort.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/subject_smallest_date_and_title_sort.dart deleted file mode 100644 index 79b5a2cbd..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort/subject_smallest_date_and_title_sort.dart +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import '../../../models/homework/homework.dart'; -import 'src/sort.dart'; -import 'src/sort_with_operations.dart'; -import 'src/homework_attribute_sorts.dart'; - -/// Sorts the homeworks firstly by Subject. -/// If they have the same subject, they will be sorted by date (earliest date first). -/// If they have the same date and subject, they will be sorted alphabetically by title. -class SubjectSmallestDateAndTitleSort extends Sort<HomeworkReadModel> { - @override - List<HomeworkReadModel> sort(List<HomeworkReadModel> list) { - sortWithOperations<HomeworkReadModel>( - list, List.from([subjectSort, dateSort, titleSort])); - return list; - } - - @override - bool operator ==(Object other) => true; - - @override - int get hashCode => 1337; -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort_and_subcategorizer.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort_and_subcategorizer.dart index c9f04f10d..7ab318433 100644 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort_and_subcategorizer.dart +++ b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/sort_and_subcategorizer.dart @@ -6,22 +6,110 @@ // // SPDX-License-Identifier: EUPL-1.2 -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/src/sort.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/views/homework_section_view.dart'; - -import 'subcategorizer.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:hausaufgabenheft_logik/color.dart'; +import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; +import 'package:hausaufgabenheft_logik/src/views/student_homework_view_factory.dart'; class HomeworkSortAndSubcategorizer { - Subcategorizer Function(Sort<HomeworkReadModel> sortToMatch) - getMatchingSubcategorizer; + final StudentHomeworkViewFactory _viewFactory; + final Date Function() getCurrentDate; + + HomeworkSortAndSubcategorizer({ + required Color defaultColor, + required this.getCurrentDate, + }) : _viewFactory = StudentHomeworkViewFactory( + defaultColorValue: defaultColor.value, + getCurrentDate: getCurrentDate, + ); + + IList<HomeworkSectionView> sortAndSubcategorize( + IList<HomeworkReadModel> homeworks, Sort<HomeworkReadModel> sort) { + final sorted = homeworks.sortWith(sort); + + final matchingSubcategorizer = switch (sort) { + SubjectSmallestDateAndTitleSort() => + _SubjectSubcategeorizer(_viewFactory), + SmallestDateSubjectAndTitleSort() => + _TodoDateSubcategorizer(getCurrentDate(), _viewFactory), + }; + + return matchingSubcategorizer.subcategorize(sorted); + } +} + +abstract class _Subcategorizer { + IList<HomeworkSectionView> subcategorize(IList<HomeworkReadModel> homeworks); +} + +class _SubjectSubcategeorizer extends _Subcategorizer { + final StudentHomeworkViewFactory _viewFactory; + + _SubjectSubcategeorizer(this._viewFactory); + + @override + IList<HomeworkSectionView> subcategorize(IList<HomeworkReadModel> homeworks) { + final subjects = homeworks.getDistinctOrderedSubjects(); + var homeworkSections = IList<HomeworkSectionView>(); + for (final subject in subjects) { + final IList<HomeworkReadModel> homeworksWithSubject = + homeworks.where((h) => h.subject == subject).toIList(); + + final homeworkViewsWithSubject = + homeworksWithSubject.map((h) => _viewFactory.createFrom(h)).toIList(); + + homeworkSections = homeworkSections + .add(HomeworkSectionView(subject.name, homeworkViewsWithSubject)); + } + return homeworkSections; + } +} + +class _TodoDateSubcategorizer extends _Subcategorizer { + final Date currentDate; + final StudentHomeworkViewFactory _viewFactory; + + _TodoDateSubcategorizer(this.currentDate, this._viewFactory); + + @override + IList<HomeworkSectionView> subcategorize(IList<HomeworkReadModel> homeworks) { + final now = currentDate; + final tomorrow = now.addDays(1); + final in2Days = tomorrow.addDays(1); + + final IList<HomeworkReadModel> overdueHomework = + homeworks.where((h) => Date.fromDateTime(h.todoDate) < now).toIList(); + final IList<HomeworkReadModel> todayHomework = + homeworks.where((h) => Date.fromDateTime(h.todoDate) == now).toIList(); + final IList<HomeworkReadModel> tomorrowHomework = homeworks + .where((h) => Date.fromDateTime(h.todoDate) == tomorrow) + .toIList(); + final IList<HomeworkReadModel> in2DaysHomework = homeworks + .where((h) => Date.fromDateTime(h.todoDate) == in2Days) + .toIList(); + final IList<HomeworkReadModel> futureHomework = homeworks + .where((h) => Date.fromDateTime(h.todoDate) > in2Days) + .toIList(); + + final overdueSec = HomeworkSectionView.fromModels( + 'Überfällig', overdueHomework, _viewFactory); + final todaySec = + HomeworkSectionView.fromModels('Heute', todayHomework, _viewFactory); + final tomorrowSec = HomeworkSectionView.fromModels( + 'Morgen', tomorrowHomework, _viewFactory); + final inTwoDaysSec = HomeworkSectionView.fromModels( + 'Übermorgen', in2DaysHomework, _viewFactory); + final afterTwoDaysSec = + HomeworkSectionView.fromModels('Später', futureHomework, _viewFactory); - HomeworkSortAndSubcategorizer(this.getMatchingSubcategorizer); + final sections = [ + overdueSec, + todaySec, + tomorrowSec, + inTwoDaysSec, + afterTwoDaysSec + ]; - List<HomeworkSectionView> sortAndSubcategorize( - HomeworkList homeworks, Sort<HomeworkReadModel> sort) { - homeworks.sortWith(sort); - return getMatchingSubcategorizer(sort).subcategorize(homeworks); + return sections.where((section) => section.isNotEmpty).toIList(); } } diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subcategorizer.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subcategorizer.dart deleted file mode 100644 index 8b9de8397..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subcategorizer.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/views/homework_section_view.dart'; - -abstract class Subcategorizer { - List<HomeworkSectionView> subcategorize(HomeworkList homeworks); -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subcategorizer_factory.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subcategorizer_factory.dart deleted file mode 100644 index 392747ad3..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subcategorizer_factory.dart +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/homework_sorts.dart'; -import 'package:hausaufgabenheft_logik/src/views/student_homework_view_factory.dart'; - -import 'subcategorizer.dart'; -import 'subject_subcategorizer.dart'; -import 'todo_date_subcategorizer.dart'; - -class SubcategorizerFactory { - final StudentHomeworkViewFactory _viewFactory; - - SubcategorizerFactory(this._viewFactory); - - Subcategorizer getMatchingSubcategorizer(Sort sort) { - if (sort is SubjectSmallestDateAndTitleSort) { - return SubjectSubcategeorizer(_viewFactory); - } else if (sort is SmallestDateSubjectAndTitleSort) { - return TodoDateSubcategorizer(sort.getCurrentDate(), _viewFactory); - } else { - throw UnimplementedError('No matching Subcategorizer for $sort'); - } - } -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subject_subcategorizer.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subject_subcategorizer.dart deleted file mode 100644 index f38bc09ad..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/subject_subcategorizer.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; -import 'package:hausaufgabenheft_logik/src/views/student_homework_view_factory.dart'; - -import 'subcategorizer.dart'; - -class SubjectSubcategeorizer extends Subcategorizer { - final StudentHomeworkViewFactory _viewFactory; - - SubjectSubcategeorizer(this._viewFactory); - - @override - List<HomeworkSectionView> subcategorize(HomeworkList homeworks) { - final subjects = homeworks.getDistinctOrderedSubjects(); - final homeworkSections = <HomeworkSectionView>[]; - for (final subject in subjects) { - final List<HomeworkReadModel> homeworksWithSubject = - homeworks.where((h) => h.subject == subject).toList(); - - final homeworkViewsWithSubject = - homeworksWithSubject.map((h) => _viewFactory.createFrom(h)).toList(); - - homeworkSections - .add(HomeworkSectionView(subject.name, homeworkViewsWithSubject)); - } - return homeworkSections; - } -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/todo_date_subcategorizer.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/todo_date_subcategorizer.dart deleted file mode 100644 index 29e6caf88..000000000 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/sort_and_subcategorization/todo_date_subcategorizer.dart +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; -import 'package:hausaufgabenheft_logik/src/views/student_homework_view_factory.dart'; - -import 'subcategorizer.dart'; - -class TodoDateSubcategorizer extends Subcategorizer { - final Date currentDate; - final StudentHomeworkViewFactory _viewFactory; - - TodoDateSubcategorizer(this.currentDate, this._viewFactory); - - @override - List<HomeworkSectionView> subcategorize(HomeworkList homeworks) { - final latestHomeworkList = homeworks; - final now = currentDate; - final tomorrow = now.addDays(1); - final in2Days = tomorrow.addDays(1); - - final List<HomeworkReadModel> overdueHomework = latestHomeworkList - .where((h) => Date.fromDateTime(h.todoDate) < now) - .toList(); - final List<HomeworkReadModel> todayHomework = latestHomeworkList - .where((h) => Date.fromDateTime(h.todoDate) == now) - .toList(); - final List<HomeworkReadModel> tomorrowHomework = latestHomeworkList - .where((h) => Date.fromDateTime(h.todoDate) == tomorrow) - .toList(); - final List<HomeworkReadModel> in2DaysHomework = latestHomeworkList - .where((h) => Date.fromDateTime(h.todoDate) == in2Days) - .toList(); - final List<HomeworkReadModel> futureHomework = latestHomeworkList - .where((h) => Date.fromDateTime(h.todoDate) > in2Days) - .toList(); - - final overdueSec = HomeworkSectionView.fromModels( - 'Überfällig', overdueHomework, _viewFactory); - final todaySec = - HomeworkSectionView.fromModels('Heute', todayHomework, _viewFactory); - final tomorrowSec = HomeworkSectionView.fromModels( - 'Morgen', tomorrowHomework, _viewFactory); - final inTwoDaysSec = HomeworkSectionView.fromModels( - 'Übermorgen', in2DaysHomework, _viewFactory); - final afterTwoDaysSec = - HomeworkSectionView.fromModels('Später', futureHomework, _viewFactory); - - final sections = [ - overdueSec, - todaySec, - tomorrowSec, - inTwoDaysSec, - afterTwoDaysSec - ]; - - return sections.where((section) => section.isNotEmpty).toList(); - } -} diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/homework_section_view.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/homework_section_view.dart index 6b9c0b11d..aa7d19c7e 100644 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/homework_section_view.dart +++ b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/homework_section_view.dart @@ -7,14 +7,15 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:equatable/equatable.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework.dart'; import '../../views/homework_view.dart'; import '../../views/student_homework_view_factory.dart'; class HomeworkSectionView extends Equatable { final String title; - final List<StudentHomeworkView> homeworks; + final IList<StudentHomeworkView> homeworks; bool get isEmpty => homeworks.isEmpty; bool get isNotEmpty => homeworks.isNotEmpty; @@ -26,11 +27,13 @@ class HomeworkSectionView extends Equatable { factory HomeworkSectionView.fromModels( String title, - List<HomeworkReadModel> homeworks, + IList<HomeworkReadModel> homeworks, StudentHomeworkViewFactory viewFactory) { - return HomeworkSectionView(title, [ - for (final h in homeworks) viewFactory.createFrom(h), - ]); + return HomeworkSectionView( + title, + IList([ + for (final h in homeworks) viewFactory.createFrom(h), + ])); } @override diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/open_homework_list_view.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/open_homework_list_view.dart index d6257a657..73fb74dd8 100644 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/open_homework_list_view.dart +++ b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/open_homework_list_view.dart @@ -7,13 +7,14 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:collection/collection.dart' show DeepCollectionEquality; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; import 'homework_section_view.dart'; class OpenHomeworkListView { final bool showCompleteOverdueHomeworkPrompt; - final List<HomeworkSectionView> sections; + final IList<HomeworkSectionView> sections; final HomeworkSort sorting; OpenHomeworkListView( diff --git a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/open_homework_list_view_factory.dart b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/open_homework_list_view_factory.dart index 60fdbb739..985e6b33d 100644 --- a/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/open_homework_list_view_factory.dart +++ b/lib/hausaufgabenheft_logik/lib/src/open_homeworks/views/open_homework_list_view_factory.dart @@ -6,9 +6,10 @@ // // SPDX-License-Identifier: EUPL-1.2 -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/models_used_by_homework.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/models.dart'; +import 'package:hausaufgabenheft_logik/src/homework_list_extensions.dart'; import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/src/sort.dart'; import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort_and_subcategorizer.dart'; import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/src/homework_sort_enum_sort_object_conversion_extensions.dart'; @@ -23,9 +24,9 @@ class OpenHomeworkListViewFactory { this._sortAndSubcategorizer, this._getCurrentDate); OpenHomeworkListView create( - List<HomeworkReadModel> openHomeworks, Sort<HomeworkReadModel> sort) { - final homeworkSectionViews = _sortAndSubcategorizer.sortAndSubcategorize( - openHomeworks as HomeworkList, sort); + IList<HomeworkReadModel> openHomeworks, Sort<HomeworkReadModel> sort) { + final homeworkSectionViews = + _sortAndSubcategorizer.sortAndSubcategorize(openHomeworks, sort); final showCompleteOverdueHomeworkPrompt = _shouldShowCompleteOverdueHomeworkPrompt(openHomeworks); @@ -37,7 +38,8 @@ class OpenHomeworkListViewFactory { ); } - bool _shouldShowCompleteOverdueHomeworkPrompt(HomeworkList openHomeworks) { + bool _shouldShowCompleteOverdueHomeworkPrompt( + IList<HomeworkReadModel> openHomeworks) { var now = _getCurrentDate(); var overdueOpenHomeworks = openHomeworks.getOverdue(now); return overdueOpenHomeworks.length > 2; diff --git a/lib/hausaufgabenheft_logik/lib/src/setup/create_homework_page_bloc.dart b/lib/hausaufgabenheft_logik/lib/src/setup/create_homework_page_bloc.dart index cfac84e32..17b660143 100644 --- a/lib/hausaufgabenheft_logik/lib/src/setup/create_homework_page_bloc.dart +++ b/lib/hausaufgabenheft_logik/lib/src/setup/create_homework_page_bloc.dart @@ -7,17 +7,13 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:clock/clock.dart'; +import 'package:hausaufgabenheft_logik/color.dart'; import 'package:hausaufgabenheft_logik/src/homework_completion/homework_page_completion_dispatcher.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/open_homework_list_bloc/open_homework_list_bloc.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/open_homework_view_bloc/open_homework_view_bloc.dart'; import 'package:hausaufgabenheft_logik/src/student_homework_page_bloc/homework_sorting_cache.dart'; -import '../completed_homeworks/completed_homeworks_view_bloc/completed_homeworks_view_bloc.dart'; -import '../completed_homeworks/lazy_loading_completed_homeworks_bloc/lazy_loading_completed_homeworks_bloc.dart'; import '../completed_homeworks/views/completed_homework_list_view_factory.dart'; -import '../models/homework/models_used_by_homework.dart'; +import '../models/models.dart'; import '../open_homeworks/sort_and_subcategorization/sort_and_subcategorizer.dart'; -import '../open_homeworks/sort_and_subcategorization/subcategorizer_factory.dart'; import '../open_homeworks/views/open_homework_list_view_factory.dart'; import '../student_homework_page_bloc/student_homework_page_bloc.dart'; import '../views/student_homework_view_factory.dart'; @@ -26,33 +22,32 @@ import 'dependencies.dart'; HomeworkPageBloc createHomeworkPageBloc( HausaufgabenheftDependencies dependencies, HausaufgabenheftConfig config) { + final getCurrentDateTime = + dependencies.getCurrentDateTime ?? () => clock.now(); + getCurrentDate() => Date.fromDateTime(getCurrentDateTime()); + final viewFactory = StudentHomeworkViewFactory( defaultColorValue: config.defaultCourseColorValue); - final subcategorizerFactory = SubcategorizerFactory(viewFactory); final sortAndSubcategorizer = HomeworkSortAndSubcategorizer( - subcategorizerFactory.getMatchingSubcategorizer); + defaultColor: Color(config.defaultCourseColorValue), + getCurrentDate: getCurrentDate, + ); final openHomeworkListViewFactory = - OpenHomeworkListViewFactory(sortAndSubcategorizer, () => Date.now()); - final openHomeworkListBloc = OpenHomeworkListBloc(dependencies.dataSource); - final openHomeworksViewBloc = - OpenHomeworksViewBloc(openHomeworkListBloc, openHomeworkListViewFactory); + OpenHomeworkListViewFactory(sortAndSubcategorizer, getCurrentDate); final completedHomeworkListViewFactory = CompletedHomeworkListViewFactory(viewFactory); - final lazyLoadingCompletedHomeworksBloc = - LazyLoadingCompletedHomeworksBloc(dependencies.dataSource); - final completedHomeworksViewBloc = CompletedHomeworksViewBloc( - lazyLoadingCompletedHomeworksBloc, completedHomeworkListViewFactory, - nrOfInitialCompletedHomeworksToLoad: - config.nrOfInitialCompletedHomeworksToLoad); final homeworkPageCompletionReceiver = HomeworkPageCompletionDispatcher( dependencies.completionDispatcher, getCurrentOverdueHomeworkIds: dependencies.getOpenOverdueHomeworkIds); return HomeworkPageBloc( - openHomeworksViewBloc: openHomeworksViewBloc, - completedHomeworksViewBloc: completedHomeworksViewBloc, + openHomeworkListViewFactory: openHomeworkListViewFactory, + completedHomeworkListViewFactory: completedHomeworkListViewFactory, + homeworkDataSource: dependencies.dataSource, + numberOfInitialCompletedHomeworksToLoad: + config.nrOfInitialCompletedHomeworksToLoad, homeworkCompletionReceiver: homeworkPageCompletionReceiver, homeworkSortingCache: HomeworkSortingCache(dependencies.keyValueStore), getCurrentDateTime: dependencies.getCurrentDateTime ?? () => clock.now(), diff --git a/lib/hausaufgabenheft_logik/lib/src/setup/dependencies.dart b/lib/hausaufgabenheft_logik/lib/src/setup/dependencies.dart index 5bba6d9e9..f0fc2cfa8 100644 --- a/lib/hausaufgabenheft_logik/lib/src/setup/dependencies.dart +++ b/lib/hausaufgabenheft_logik/lib/src/setup/dependencies.dart @@ -7,6 +7,7 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:common_domain_models/common_domain_models.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:key_value_store/key_value_store.dart'; import '../data_source/homework_data_source.dart'; import '../homework_completion/homework_completion_dispatcher.dart'; @@ -20,7 +21,7 @@ class HausaufgabenheftDependencies { /// Used to complete all overdue homeworks at once by using the completion /// dispatcher. - final Future<List<HomeworkId>> Function() getOpenOverdueHomeworkIds; + final Future<IList<HomeworkId>> Function() getOpenOverdueHomeworkIds; final KeyValueStore keyValueStore; diff --git a/lib/hausaufgabenheft_logik/lib/src/student_homework_page_bloc/homework_sorting_cache.dart b/lib/hausaufgabenheft_logik/lib/src/student_homework_page_bloc/homework_sorting_cache.dart index 14b9aa0b9..9dac83f26 100644 --- a/lib/hausaufgabenheft_logik/lib/src/student_homework_page_bloc/homework_sorting_cache.dart +++ b/lib/hausaufgabenheft_logik/lib/src/student_homework_page_bloc/homework_sorting_cache.dart @@ -20,8 +20,8 @@ class HomeworkSortingCache { await _keyValueStore.setString(_key, homeworkSortToString(homeworkSort)); } - Future<HomeworkSort?> getLastSorting({HomeworkSort? orElse}) async { + Future<HomeworkSort?> getLastSorting() async { final string = _keyValueStore.getString(_key); - return string != null ? homeworkSortFromString(string) : orElse; + return string != null ? homeworkSortFromString(string) : null; } } diff --git a/lib/hausaufgabenheft_logik/lib/src/student_homework_page_bloc/student_homework_page_bloc.dart b/lib/hausaufgabenheft_logik/lib/src/student_homework_page_bloc/student_homework_page_bloc.dart index 46bf032f3..351713a03 100644 --- a/lib/hausaufgabenheft_logik/lib/src/student_homework_page_bloc/student_homework_page_bloc.dart +++ b/lib/hausaufgabenheft_logik/lib/src/student_homework_page_bloc/student_homework_page_bloc.dart @@ -10,44 +10,44 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:bloc_base/bloc_base.dart' as bloc_base; +import 'package:common_domain_models/common_domain_models.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; +import 'package:hausaufgabenheft_logik/src/completed_homeworks/views/completed_homework_list_view_factory.dart'; +import 'package:hausaufgabenheft_logik/src/homework_completion/homework_page_completion_dispatcher.dart'; +import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/src/homework_sort_enum_sort_object_conversion_extensions.dart'; +import 'package:hausaufgabenheft_logik/src/open_homeworks/views/open_homework_list_view_factory.dart'; import 'package:hausaufgabenheft_logik/src/student_homework_page_bloc/homework_sorting_cache.dart'; import 'package:rxdart/rxdart.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/src/homework_sort_enum_sort_object_conversion_extensions.dart'; -import 'package:hausaufgabenheft_logik/src/completed_homeworks/completed_homeworks_view_bloc/completed_homeworks_view_bloc.dart' - as completed; -import 'package:hausaufgabenheft_logik/src/homework_completion/homework_page_completion_dispatcher.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/open_homework_view_bloc/open_homework_view_bloc.dart' - as open; - -/// This Bloc serves basically only as an interface to the outer world with 2 -/// tasks: -/// * It delegates all incoming [HomeworkPageEvent]s to the other blocs. -/// * It merges the Success states from the [OpenHomeworksViewBloc] and -/// [CompletedHomeworksViewBloc] together into one [Success] state. -/// * It caches the last sorting of Homeworks so that it stays consistent -/// between visits of the homework page. + class HomeworkPageBloc extends Bloc<HomeworkPageEvent, HomeworkPageState> implements bloc_base.BlocBase { - final open.OpenHomeworksViewBloc _openHomeworksViewBloc; - final completed.CompletedHomeworksViewBloc _completedHomeworksViewBloc; final HomeworkPageCompletionDispatcher _homeworkCompletionReceiver; + final HomeworkDataSource _homeworkDataSource; final HomeworkSortingCache _homeworkSortingCache; final DateTime Function() _getCurrentDateTime; + final int numberOfInitialCompletedHomeworksToLoad; + final CompletedHomeworkListViewFactory _completedHomeworkListViewFactory; + final OpenHomeworkListViewFactory _openHomeworkListViewFactory; + final _currentSortStream = BehaviorSubject<Sort<HomeworkReadModel>>(); + LazyLoadingController? _lazyLoadingController; /// Whether [close] or [dispose] has been called; bool _isClosed = false; HomeworkPageBloc({ - required open.OpenHomeworksViewBloc openHomeworksViewBloc, - required completed.CompletedHomeworksViewBloc completedHomeworksViewBloc, required HomeworkPageCompletionDispatcher homeworkCompletionReceiver, required HomeworkSortingCache homeworkSortingCache, + required HomeworkDataSource homeworkDataSource, + required CompletedHomeworkListViewFactory completedHomeworkListViewFactory, + required OpenHomeworkListViewFactory openHomeworkListViewFactory, + required this.numberOfInitialCompletedHomeworksToLoad, required DateTime Function() getCurrentDateTime, - }) : _openHomeworksViewBloc = openHomeworksViewBloc, - _completedHomeworksViewBloc = completedHomeworksViewBloc, + }) : _homeworkDataSource = homeworkDataSource, + _openHomeworkListViewFactory = openHomeworkListViewFactory, _homeworkSortingCache = homeworkSortingCache, _homeworkCompletionReceiver = homeworkCompletionReceiver, + _completedHomeworkListViewFactory = completedHomeworkListViewFactory, _getCurrentDateTime = getCurrentDateTime, super(Uninitialized()) { on<LoadHomeworks>((event, emit) { @@ -76,58 +76,61 @@ class HomeworkPageBloc extends Bloc<HomeworkPageEvent, HomeworkPageState> StreamSubscription? _combineLatestSubscription; Future<void> _mapLoadHomeworksToState() async { - _completedHomeworksViewBloc.add(completed.StartTransformingHomeworks()); - - final sortEnum = (await _homeworkSortingCache.getLastSorting( - orElse: HomeworkSort.smallestDateSubjectAndTitle))!; - final sort = sortEnum.toSortObject(getCurrentDate: _getCurrentDate); - _openHomeworksViewBloc.add(open.LoadHomeworks(sort)); - - final completedHomeworksSuccessStates = - _completedHomeworksViewBloc.stream.whereType<completed.Success>(); - - final openHomeworksSuccessStates = - _openHomeworksViewBloc.stream.whereType<open.Success>(); - - _combineLatestSubscription = - Rx.combineLatest2<completed.Success, open.Success, Success>( - completedHomeworksSuccessStates, - openHomeworksSuccessStates, - _toSuccessState, - ).listen((s) { + final sortEnum = await _homeworkSortingCache.getLastSorting() ?? + HomeworkSort.smallestDateSubjectAndTitle; + _currentSortStream + .add(sortEnum.toSortObject(getCurrentDate: _getCurrentDate)); + + _lazyLoadingController = + _homeworkDataSource.getLazyLoadingCompletedHomeworksController( + numberOfInitialCompletedHomeworksToLoad); + + _combineLatestSubscription = Rx.combineLatest3<IList<HomeworkReadModel>, + Sort<HomeworkReadModel>, LazyLoadingResult, Success>( + _homeworkDataSource.openHomeworks, + _currentSortStream, + _lazyLoadingController!.results, (openHws, sort, lazyCompletedHwsRes) { + final open = _openHomeworkListViewFactory.create(openHws, sort); + + final completed = _completedHomeworkListViewFactory.create( + lazyCompletedHwsRes.homeworks, + !lazyCompletedHwsRes.moreHomeworkAvailable); + + return Success(completed, open); + }).listen((s) { if (!_isClosed) { add(_Yield(s)); } }); } - Success _toSuccessState(completed.Success completed, open.Success open) => - Success(completed.completedHomeworksView, open.openHomeworkListView); - void _mapAdvanceCompletedHomeworks(AdvanceCompletedHomeworks event) async { - _completedHomeworksViewBloc - .add(completed.AdvanceCompletedHomeworks(event.advanceBy)); + _lazyLoadingController!.advanceBy(event.advanceBy); } Future<void> _mapFilterChangedToState(OpenHwSortingChanged event) async { await _homeworkSortingCache.setLastSorting(event.sort); - final newSorting = event.sort.toSortObject(getCurrentDate: _getCurrentDate); - _openHomeworksViewBloc.add(open.SortingChanged(newSorting)); + _currentSortStream + .add(event.sort.toSortObject(getCurrentDate: _getCurrentDate)); } Future<void> _mapHomeworkChangedCompletionStatus( CompletionStatusChanged event) async { - await _homeworkCompletionReceiver - .add(SingleHomeworkCompletionEvent(event.homeworkId, event.newValue)); + await _homeworkCompletionReceiver.changeCompletionStatus( + HomeworkId(event.homeworkId), + event.newValue == true + ? CompletionStatus.completed + : CompletionStatus.open); } Future<void> _mapHomeworkMarkOverdueToState(CompletedAllOverdue event) async { - await _homeworkCompletionReceiver.add(AllOverdueHomeworkCompletionEvent()); + await _homeworkCompletionReceiver.completeAllOverdueHomeworks(); } @override Future<void> close() { _isClosed = true; + _currentSortStream.close(); _combineLatestSubscription?.cancel(); return super.close(); } @@ -135,6 +138,7 @@ class HomeworkPageBloc extends Bloc<HomeworkPageEvent, HomeworkPageState> @override void dispose() { _isClosed = true; + _currentSortStream.close(); _combineLatestSubscription?.cancel(); } } diff --git a/lib/hausaufgabenheft_logik/lib/src/views/student_homework_view_factory.dart b/lib/hausaufgabenheft_logik/lib/src/views/student_homework_view_factory.dart index d507d6371..d8deff607 100644 --- a/lib/hausaufgabenheft_logik/lib/src/views/student_homework_view_factory.dart +++ b/lib/hausaufgabenheft_logik/lib/src/views/student_homework_view_factory.dart @@ -6,8 +6,8 @@ // // SPDX-License-Identifier: EUPL-1.2 -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/models_used_by_homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/models.dart'; import 'package:hausaufgabenheft_logik/src/views/color.dart'; import 'package:hausaufgabenheft_logik/src/views/homework_view.dart'; diff --git a/lib/hausaufgabenheft_logik/pubspec.lock b/lib/hausaufgabenheft_logik/pubspec.lock index af545a917..6b1977698 100644 --- a/lib/hausaufgabenheft_logik/pubspec.lock +++ b/lib/hausaufgabenheft_logik/pubspec.lock @@ -127,6 +127,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.5" + fast_immutable_collections: + dependency: "direct main" + description: + name: fast_immutable_collections + sha256: b910ccdc99bb38a2abbce07c5afb8f81d4e222a892e4d095a548b99814837b0c + url: "https://pub.dev" + source: hosted + version: "9.2.1" file: dependency: "direct dev" description: diff --git a/lib/hausaufgabenheft_logik/pubspec.yaml b/lib/hausaufgabenheft_logik/pubspec.yaml index a39969ea1..abe6de277 100644 --- a/lib/hausaufgabenheft_logik/pubspec.yaml +++ b/lib/hausaufgabenheft_logik/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: bloc: ^8.1.2 rxdart: ^0.27.1 equatable: ^2.0.5 + fast_immutable_collections: ^9.1.5 collection: ^1.17.2 meta: any key_value_store: diff --git a/lib/hausaufgabenheft_logik/test/create_homework_util.dart b/lib/hausaufgabenheft_logik/test/create_homework_util.dart index 6aa2d2631..88a6028c4 100644 --- a/lib/hausaufgabenheft_logik/test/create_homework_util.dart +++ b/lib/hausaufgabenheft_logik/test/create_homework_util.dart @@ -7,8 +7,8 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:common_domain_models/common_domain_models.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/models_used_by_homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/models.dart'; import 'package:hausaufgabenheft_logik/src/views/color.dart'; import 'package:test_randomness/test_randomness.dart'; diff --git a/lib/hausaufgabenheft_logik/test/create_student_homework_view_test.dart b/lib/hausaufgabenheft_logik/test/create_student_homework_view_test.dart index cdbc3642e..5753e1885 100644 --- a/lib/hausaufgabenheft_logik/test/create_student_homework_view_test.dart +++ b/lib/hausaufgabenheft_logik/test/create_student_homework_view_test.dart @@ -7,8 +7,8 @@ // SPDX-License-Identifier: EUPL-1.2 import 'package:common_domain_models/common_domain_models.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/models_used_by_homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/models.dart'; import 'package:hausaufgabenheft_logik/src/views/color.dart'; import 'package:hausaufgabenheft_logik/src/views/student_homework_view_factory.dart'; import 'package:hausaufgabenheft_logik/src/views/homework_view.dart'; diff --git a/lib/hausaufgabenheft_logik/test/date/date_test.dart b/lib/hausaufgabenheft_logik/test/date/date_test.dart index f1b3db911..6778063fe 100644 --- a/lib/hausaufgabenheft_logik/test/date/date_test.dart +++ b/lib/hausaufgabenheft_logik/test/date/date_test.dart @@ -23,19 +23,6 @@ void main() { final dateAsDateTime = date.asDateTime(); expect(dateAsDateTime, DateTime(2019, 1, 1, 0, 0, 0, 0, 0)); }); - - test( - '.addDaysWithNoChecking adds appropiate amount of days, while not checking if the month has been exceeded', - () { - expect(const Date(year: 2019, month: 1, day: 1).addDaysWithNoChecking(1), - const Date(year: 2019, month: 1, day: 2)); - expect( - const Date(year: 2019, month: 1, day: 10).addDaysWithNoChecking(-5), - const Date(year: 2019, month: 1, day: 5)); - // Explicit: DANGER, STUPID ALGORITHM - expect(const Date(year: 2019, month: 1, day: 30).addDaysWithNoChecking(5), - const Date(year: 2019, month: 1, day: 35)); - }); test('.addDays adds day regarding the month length', () { expect(const Date(year: 2019, month: 11, day: 30).addDays(1), const Date(year: 2019, month: 12, day: 1)); // has 30 days diff --git a/lib/hausaufgabenheft_logik/test/homework_list_test.dart b/lib/hausaufgabenheft_logik/test/homework_list_test.dart index aaa5c09d7..9f2ebda21 100644 --- a/lib/hausaufgabenheft_logik/test/homework_list_test.dart +++ b/lib/hausaufgabenheft_logik/test/homework_list_test.dart @@ -6,18 +6,15 @@ // // SPDX-License-Identifier: EUPL-1.2 -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/models_used_by_homework.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/smallest_date_subject_and_title_sort.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/subject_smallest_date_and_title_sort.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; import 'package:test/test.dart'; import 'create_homework_util.dart'; import 'test_data/homeworks.dart'; void main() { - group('HomeworkList', () { + group('List<HomeworkReadModel>', () { group('sort with SubjectSmallestDateAndTitleSort', () { testSubjectSort('firstly sorts by Subject', (homeworks) => homeworks.sortWith(SubjectSmallestDateAndTitleSort())); @@ -32,7 +29,7 @@ void main() { testSort( 'integration test', - unsorted: HomeworkList(unsortedHomework), + unsorted: unsortedHomework, sorted: sortedHomeworksForSortBySubjectDateTitle, sort: (homeworks) => homeworks.sortWith(SubjectSmallestDateAndTitleSort()), @@ -52,7 +49,7 @@ void main() { testSort( 'integration test', - unsorted: HomeworkList(unsortedHomework), + unsorted: unsortedHomework, sorted: sortedHomeworksForSortByDateSubjectTitle, sort: (homeworks) => homeworks.sortWith(SmallestDateSubjectAndTitleSort()), @@ -67,7 +64,7 @@ void main() { ); final unsorted = List<HomeworkReadModel>.from(sorted)..shuffle(); testSort('does sort titles starting with numbers by their value', - unsorted: HomeworkList(unsorted), + unsorted: unsorted, sorted: sorted, sort: (hw) => hw.sortWith(SmallestDateSubjectAndTitleSort()), skip: true); @@ -79,9 +76,11 @@ void main() { var deutsch = Subject('Deutsch', abbreviation: 'De'); final subjects = [mathe, englisch, mathe, mathe, deutsch]; final homeworks = [ - for (final subject in subjects) createHomework(subject: subject.name) + for (final subject in subjects) + createHomework( + subject: subject.name, abbreviation: subject.abbreviation) ]; - final homeworkList = HomeworkList(homeworks); + final homeworkList = homeworks.toIList(); final result = homeworkList.getDistinctOrderedSubjects(); @@ -91,36 +90,35 @@ void main() { void testDateSort(String title, ListCallback sort) => testSort( title, - unsorted: - HomeworkList([haDate_23_02_19, haDate_02_01_19, haDate_30_2_2020]), + unsorted: [haDate_23_02_19, haDate_02_01_19, haDate_30_2_2020], sorted: [haDate_02_01_19, haDate_23_02_19, haDate_30_2_2020], sort: sort, ); void testSort(String title, - {required HomeworkList unsorted, + {required List<HomeworkReadModel> unsorted, required List<HomeworkReadModel> sorted, required ListCallback sort, bool skip = false}) { test(title, () { - sort(unsorted); - expect(unsorted, sorted); + final actualSorted = sort(unsorted.toIList()); + expect(actualSorted.toList(), sorted); }, skip: skip); } void testSubjectSort(String title, ListCallback sort) => testSort( title, - unsorted: HomeworkList( - [haSubjectInformatics, haSubjectEnglish, haSubjectMaths]), + unsorted: [haSubjectInformatics, haSubjectEnglish, haSubjectMaths], sorted: [haSubjectEnglish, haSubjectInformatics, haSubjectMaths], sort: sort, ); void testTitleSort(String title, ListCallback sort) => testSort( title, - unsorted: HomeworkList([haTitleBlatt, haTitleAufgaben, haTitleClown]), + unsorted: [haTitleBlatt, haTitleAufgaben, haTitleClown], sorted: [haTitleAufgaben, haTitleBlatt, haTitleClown], sort: sort, ); -typedef ListCallback = void Function(HomeworkList); +typedef ListCallback = IList<HomeworkReadModel> Function( + IList<HomeworkReadModel>); diff --git a/lib/hausaufgabenheft_logik/test/homework_page_bloc_test.dart b/lib/hausaufgabenheft_logik/test/homework_page_bloc_test.dart index a1652b449..c03882545 100644 --- a/lib/hausaufgabenheft_logik/test/homework_page_bloc_test.dart +++ b/lib/hausaufgabenheft_logik/test/homework_page_bloc_test.dart @@ -11,17 +11,11 @@ import 'dart:developer'; import 'package:bloc/bloc.dart'; import 'package:clock/clock.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik_setup.dart'; -import 'package:hausaufgabenheft_logik/src/completed_homeworks/completed_homeworks_view_bloc/completed_homeworks_view_bloc.dart' - as completed; -import 'package:hausaufgabenheft_logik/src/completed_homeworks/lazy_loading_completed_homeworks_bloc/lazy_loading_completed_homeworks_bloc.dart' - as lazy_loading; -import 'package:hausaufgabenheft_logik/src/completed_homeworks/views/completed_homework_list_view_factory.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; import 'package:hausaufgabenheft_logik/src/student_homework_page_bloc/homework_sorting_cache.dart'; import 'package:hausaufgabenheft_logik/src/views/color.dart'; -import 'package:hausaufgabenheft_logik/src/views/student_homework_view_factory.dart'; import 'package:key_value_store/in_memory_key_value_store.dart'; import 'package:key_value_store/key_value_store.dart'; import 'package:rxdart/rxdart.dart'; @@ -193,7 +187,7 @@ void main() { bloc.add(LoadHomeworks()); bloc.add(OpenHwSortingChanged(HomeworkSort.smallestDateSubjectAndTitle)); - Success result = await bloc.stream.whereType<Success>().skip(1).first; + Success result = await bloc.stream.whereType<Success>().first; final notDone = result.open; expect(notDone.sections.length, 5); @@ -487,9 +481,12 @@ void main() { extension on OpenHomeworkListView { List<StudentHomeworkView> get orderedHomeworks { - final listOfListOfHomeworks = sections.map((s) => s.homeworks).toList(); + final listOfListOfHomeworks = + sections.map((s) => s.homeworks.toList()).toList(); if (listOfListOfHomeworks.isEmpty) return []; - if (listOfListOfHomeworks.length == 1) return listOfListOfHomeworks.single; + if (listOfListOfHomeworks.length == 1) { + return listOfListOfHomeworks.single.toList(); + } return listOfListOfHomeworks.reduce((l1, l2) => [...l1, ...l2]).toList(); } } @@ -507,7 +504,7 @@ HomeworkPageBloc createBloc( completionDispatcher: RepositoryHomeworkCompletionDispatcher(repository), getOpenOverdueHomeworkIds: () async { final open = await repository.openHomeworks.first; - return HomeworkList(open).getOverdue().map((hw) => hw.id).toList(); + return open.getOverdue().map((hw) => hw.id).toIList(); }, keyValueStore: keyValueStore ?? InMemoryKeyValueStore(), getCurrentDateTime: getCurrentDateTime, @@ -519,20 +516,6 @@ HomeworkPageBloc createBloc( ); } -completed.CompletedHomeworksViewBloc createCompletedHomeworksViewBloc( - StudentHomeworkViewFactory viewFactory, - InMemoryHomeworkRepository repository, - {required int nrOfInitialCompletedHomeworksToLoad}) { - final completedHomeworkListViewFactory = - CompletedHomeworkListViewFactory(viewFactory); - final lazyLoadingCompletedHomeworksBloc = - lazy_loading.LazyLoadingCompletedHomeworksBloc(repository); - final completedHomeworksViewBloc = completed.CompletedHomeworksViewBloc( - lazyLoadingCompletedHomeworksBloc, completedHomeworkListViewFactory, - nrOfInitialCompletedHomeworksToLoad: nrOfInitialCompletedHomeworksToLoad); - return completedHomeworksViewBloc; -} - InMemoryHomeworkRepository createRepositoy() => InMemoryHomeworkRepository(); Date dateFromDay(int day) => Date(year: 2019, month: 1, day: day); diff --git a/lib/hausaufgabenheft_logik/test/in_memory_repo/in_memory_homework_repository.dart b/lib/hausaufgabenheft_logik/test/in_memory_repo/in_memory_homework_repository.dart index 08db69a9a..7c90e949f 100644 --- a/lib/hausaufgabenheft_logik/test/in_memory_repo/in_memory_homework_repository.dart +++ b/lib/hausaufgabenheft_logik/test/in_memory_repo/in_memory_homework_repository.dart @@ -9,20 +9,21 @@ import 'dart:async'; import 'package:common_domain_models/common_domain_models.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:rxdart/rxdart.dart'; import 'package:hausaufgabenheft_logik/hausaufgabenheft_logik.dart'; import 'firebase_realtime_updating_lazy_loading_controller.dart'; import 'realtime_completed_homework_loader.dart'; class InMemoryHomeworkRepository extends HomeworkDataSource { - final List<HomeworkReadModel> _homeworks = []; - List<HomeworkReadModel> get _openHomeworks => - _homeworks.where((h) => h.status == CompletionStatus.open).toList(); - List<HomeworkReadModel> get _completedHomeworks => - _homeworks.where((h) => h.status == CompletionStatus.completed).toList(); - - final _openHomeworkStream = BehaviorSubject<List<HomeworkReadModel>>(); - final _completedHomeworkStream = BehaviorSubject<List<HomeworkReadModel>>(); + IList<HomeworkReadModel> _homeworks = const IListConst([]); + IList<HomeworkReadModel> get _openHomeworks => + _homeworks.where((h) => h.status == CompletionStatus.open).toIList(); + IList<HomeworkReadModel> get _completedHomeworks => + _homeworks.where((h) => h.status == CompletionStatus.completed).toIList(); + + final _openHomeworkStream = BehaviorSubject<IList<HomeworkReadModel>>(); + final _completedHomeworkStream = BehaviorSubject<IList<HomeworkReadModel>>(); final Duration fakeDelay; InMemoryHomeworkRepository({this.fakeDelay = Duration.zero}) { @@ -30,30 +31,30 @@ class InMemoryHomeworkRepository extends HomeworkDataSource { } @override - Stream<List<HomeworkReadModel>> get openHomeworks => + Stream<IList<HomeworkReadModel>> get openHomeworks => _openHomeworkStream.stream.delay(fakeDelay); final bool _loadedAllCompleted = false; bool get loadedAllCompleted => _loadedAllCompleted; Future<void> add(HomeworkReadModel homework) async { - _homeworks.add(homework); + _homeworks = _homeworks.add(homework); addHomeworksToStreams(); } Future<void> delete(HomeworkReadModel homework) async { - _homeworks.removeWhere((h) => h.id == homework.id); + _homeworks = _homeworks.removeWhere((h) => h.id == homework.id); addHomeworksToStreams(); } - Future<List<HomeworkReadModel>> getAll() async { + Future<IList<HomeworkReadModel>> getAll() async { await Future.delayed(fakeDelay); return _homeworks; } Future<void> update(HomeworkReadModel homework) async { final index = _homeworks.indexWhere((h) => h.id == homework.id); - _homeworks[index] = homework; + _homeworks = _homeworks.replace(index, homework); addHomeworksToStreams(); } @@ -76,12 +77,12 @@ class InMemoryHomeworkRepository extends HomeworkDataSource { } class InMemoryHomeworkLoader extends RealtimeCompletedHomeworkLoader { - final BehaviorSubject<List<HomeworkReadModel>> _completedHomeworksSubject; + final BehaviorSubject<IList<HomeworkReadModel>> _completedHomeworksSubject; InMemoryHomeworkLoader(this._completedHomeworksSubject); @override - Stream<List<HomeworkReadModel>> loadMostRecentHomeworks( + Stream<IList<HomeworkReadModel>> loadMostRecentHomeworks( int numberOfHomeworks) { return _completedHomeworksSubject.map((homeworks) { if (homeworks.length < numberOfHomeworks) return homeworks; diff --git a/lib/hausaufgabenheft_logik/test/in_memory_repo/realtime_completed_homework_loader.dart b/lib/hausaufgabenheft_logik/test/in_memory_repo/realtime_completed_homework_loader.dart index 0bfa89cbe..a0beb5f59 100644 --- a/lib/hausaufgabenheft_logik/test/in_memory_repo/realtime_completed_homework_loader.dart +++ b/lib/hausaufgabenheft_logik/test/in_memory_repo/realtime_completed_homework_loader.dart @@ -6,9 +6,10 @@ // // SPDX-License-Identifier: EUPL-1.2 -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:hausaufgabenheft_logik/src/models/homework.dart'; abstract class RealtimeCompletedHomeworkLoader { - Stream<List<HomeworkReadModel>> loadMostRecentHomeworks( + Stream<IList<HomeworkReadModel>> loadMostRecentHomeworks( int numberOfHomeworks); } diff --git a/lib/hausaufgabenheft_logik/test/open_homework_view_bloc_test.dart b/lib/hausaufgabenheft_logik/test/open_homework_view_bloc_test.dart deleted file mode 100644 index 29a683f45..000000000 --- a/lib/hausaufgabenheft_logik/test/open_homework_view_bloc_test.dart +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2022 Sharezone UG (haftungsbeschränkt) -// Licensed under the EUPL-1.2-or-later. -// -// You may obtain a copy of the Licence at: -// https://joinup.ec.europa.eu/software/page/eupl -// -// SPDX-License-Identifier: EUPL-1.2 - -import 'package:bloc/bloc.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework/homework.dart'; -import 'package:hausaufgabenheft_logik/src/models/homework_list.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/open_homework_list_bloc/open_homework_list_bloc.dart' - as list_bloc; -import 'package:hausaufgabenheft_logik/src/open_homeworks/open_homework_view_bloc/open_homework_view_bloc.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/sort_and_subcategorization/sort/homework_sorts.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/views/homework_section_view.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/views/open_homework_list_view.dart'; -import 'package:hausaufgabenheft_logik/src/open_homeworks/views/open_homework_list_view_factory.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:test/test.dart'; - -void main() { - group('OpenHomeworksViewBloc', () { - late OpenHomeworksViewBloc openHomeworksViewBloc; - MockOpenHomeworkListBloc mockOpenHomeworkListBloc; - late MockOpenHomeworkListViewFactory mockOpenHomeworkListViewFactory; - setUp(() { - mockOpenHomeworkListBloc = MockOpenHomeworkListBloc(); - mockOpenHomeworkListViewFactory = MockOpenHomeworkListViewFactory(); - openHomeworksViewBloc = OpenHomeworksViewBloc( - mockOpenHomeworkListBloc, mockOpenHomeworkListViewFactory); - }); - - test('returns correct homework', () async { - var sections = [const HomeworkSectionView('Some Section', [])]; - mockOpenHomeworkListViewFactory.sectionsToReturn = sections; - - openHomeworksViewBloc - .add(LoadHomeworks(SmallestDateSubjectAndTitleSort())); - - final success = - await openHomeworksViewBloc.stream.whereType<Success>().first; - expect(success.openHomeworkListView.sections, sections); - }); - }); -} - -class MockOpenHomeworkListViewFactory implements OpenHomeworkListViewFactory { - List<HomeworkSectionView> sectionsToReturn = []; - List<HomeworkReadModel> gotHomeworks = []; - @override - OpenHomeworkListView create( - List<HomeworkReadModel> openHomeworks, Sort<HomeworkReadModel> sort) { - gotHomeworks = openHomeworks; - return OpenHomeworkListView( - sectionsToReturn, - showCompleteOverdueHomeworkPrompt: true, - sorting: HomeworkSort.smallestDateSubjectAndTitle, - ); - } -} - -class MockOpenHomeworkListBloc extends Bloc<list_bloc.OpenHomeworkListBlocEvent, - list_bloc.OpenHomeworkListBlocState> - implements list_bloc.OpenHomeworkListBloc { - var homeworkListToReturn = HomeworkList([]); - - MockOpenHomeworkListBloc() : super(list_bloc.Uninitialized()) { - on<list_bloc.OpenHomeworkListBlocEvent>((event, emit) { - emit(list_bloc.Success(homeworkListToReturn)); - }); - } -} diff --git a/lib/hausaufgabenheft_logik/test/test_data/homeworks.dart b/lib/hausaufgabenheft_logik/test/test_data/homeworks.dart index a8fe1b040..b6e211d7c 100644 --- a/lib/hausaufgabenheft_logik/test/test_data/homeworks.dart +++ b/lib/hausaufgabenheft_logik/test/test_data/homeworks.dart @@ -6,7 +6,7 @@ // // SPDX-License-Identifier: EUPL-1.2 -import 'package:hausaufgabenheft_logik/src/models/homework/models_used_by_homework.dart'; +import 'package:hausaufgabenheft_logik/src/models/models.dart'; import '../create_homework_util.dart';