From f58a2ec8cd4d560ac427302ef8e6d226a56eeab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sun, 5 May 2024 15:48:26 +0200 Subject: [PATCH] revamp on bloc approach --- build.yaml | 3 +- lib/app.dart | 2 +- lib/main.dart | 29 ++-- .../grade_averages_controller.dart | 10 -- .../marianum_message_controller.dart | 24 --- .../marianum_message_state.dart | 10 -- .../marianum_message_state.freezed.dart | 143 ------------------ lib/state/app/modules/app_modules.dart | 29 ++++ .../bloc/grade_averages_bloc.dart | 49 ++++++ .../bloc/grade_averages_event.dart | 20 +++ .../bloc}/grade_averages_state.dart | 8 +- .../bloc}/grade_averages_state.freezed.dart | 43 +++--- .../bloc}/grade_averages_state.g.dart | 13 +- .../screens/grade_averages_list_view.dart | 70 +++++++++ .../screens/grade_averages_view.dart | 98 ++++++++++++ lib/state/infrastructure/controller.dart | 5 - lib/state/infrastructure/loadable_state.dart | 37 ----- .../infrastructure/state_extensions.dart | 7 - lib/state/widgets/components/error_bar.dart | 116 +++++++------- lib/state/widgets/controller_consumer.dart | 24 +-- lib/state/widgets/controller_provider.dart | 42 ++--- lib/state/widgets/controllers_provider.dart | 34 ++--- .../widgets/loadable_controller_consumer.dart | 82 +++++----- lib/view/pages/files/fileElement.dart | 2 +- lib/view/pages/files/files.dart | 2 +- lib/view/pages/more/test.dart | 96 ++++++------ lib/view/pages/overhang.dart | 4 +- pubspec.yaml | 1 + 28 files changed, 523 insertions(+), 480 deletions(-) delete mode 100644 lib/state/app/application/gradeAverages/grade_averages_controller.dart delete mode 100644 lib/state/app/application/marianumMessage/marianum_message_controller.dart delete mode 100644 lib/state/app/application/marianumMessage/marianum_message_state.dart delete mode 100644 lib/state/app/application/marianumMessage/marianum_message_state.freezed.dart create mode 100644 lib/state/app/modules/app_modules.dart create mode 100644 lib/state/app/modules/gradeAverages/bloc/grade_averages_bloc.dart create mode 100644 lib/state/app/modules/gradeAverages/bloc/grade_averages_event.dart rename lib/state/app/{application/gradeAverages => modules/gradeAverages/bloc}/grade_averages_state.dart (77%) rename lib/state/app/{application/gradeAverages => modules/gradeAverages/bloc}/grade_averages_state.freezed.dart (81%) rename lib/state/app/{application/gradeAverages => modules/gradeAverages/bloc}/grade_averages_state.g.dart (64%) create mode 100644 lib/state/app/modules/gradeAverages/screens/grade_averages_list_view.dart create mode 100644 lib/state/app/modules/gradeAverages/screens/grade_averages_view.dart delete mode 100644 lib/state/infrastructure/controller.dart delete mode 100644 lib/state/infrastructure/loadable_state.dart delete mode 100644 lib/state/infrastructure/state_extensions.dart diff --git a/build.yaml b/build.yaml index 24cf608..dcc8576 100644 --- a/build.yaml +++ b/build.yaml @@ -3,4 +3,5 @@ targets: builders: json_serializable: options: - explicit_to_json: false \ No newline at end of file + explicit_to_json: false + generic_argument_factories: true \ No newline at end of file diff --git a/lib/app.dart b/lib/app.dart index 11ea0ac..7802cfd 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -137,7 +137,7 @@ class _AppState extends State with WidgetsBindingObserver { ), ), PersistentTabConfig( - screen: const Breaker(breaker: BreakerArea.files, child: Files([])), + screen: Breaker(breaker: BreakerArea.files, child: Files()), item: ItemConfig( activeForegroundColor: Theme.of(context).primaryColor, inactiveForegroundColor: Theme.of(context).colorScheme.secondary, diff --git a/lib/main.dart b/lib/main.dart index 10b741b..53189a2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,8 +7,10 @@ import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:jiffy/jiffy.dart'; import 'package:loader_overlay/loader_overlay.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; @@ -33,22 +35,27 @@ import 'widget/placeholderView.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); + + var initialisationTasks = [ + Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform) + .then((value) async => log("Firebase token: ${await FirebaseMessaging.instance.getToken() ?? "Error: no Firebase token!"}")) + .onError((error, stackTrace) => log('Error initializing Firebase: $error')), - try { - await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); - log("Firebase token: ${await FirebaseMessaging.instance.getToken() ?? "Error: no Firebase token!"}"); - } catch (e) { - log('Error initializing Firebase app!'); - } + PlatformAssetBundle().load('assets/ca/lets-encrypt-r3.pem') + .then((certificate) => SecurityContext.defaultContext.setTrustedCertificatesBytes(certificate.buffer.asUint8List())), - var data = await PlatformAssetBundle().load('assets/ca/lets-encrypt-r3.pem'); - SecurityContext.defaultContext.setTrustedCertificatesBytes(data.buffer.asUint8List()); + Future(() async { + await HydratedStorage.build(storageDirectory: await getTemporaryDirectory()).then((storage) => HydratedBloc.storage = storage); + }) + ]; + + await Future.wait(initialisationTasks); if(kReleaseMode) { ErrorWidget.builder = (error) => PlaceholderView( - icon: Icons.phonelink_erase_rounded, - text: error.toStringShort(), - ); + icon: Icons.phonelink_erase_rounded, + text: error.toStringShort(), + ); } runApp( diff --git a/lib/state/app/application/gradeAverages/grade_averages_controller.dart b/lib/state/app/application/gradeAverages/grade_averages_controller.dart deleted file mode 100644 index 6e0f829..0000000 --- a/lib/state/app/application/gradeAverages/grade_averages_controller.dart +++ /dev/null @@ -1,10 +0,0 @@ - -import '../../../infrastructure/controller.dart'; -import 'grade_averages_state.dart'; - -class GradeAveragesController extends Controller { - GradeAveragesController(super.initialState); - - void setGradeType(GradingSchemes scheme) => emit(state.copyWith(gradingScheme: scheme)); - double average() => state.grades.reduce((a, b) => a + b) / state.grades.length; -} diff --git a/lib/state/app/application/marianumMessage/marianum_message_controller.dart b/lib/state/app/application/marianumMessage/marianum_message_controller.dart deleted file mode 100644 index 22ebc2b..0000000 --- a/lib/state/app/application/marianumMessage/marianum_message_controller.dart +++ /dev/null @@ -1,24 +0,0 @@ -import '../../../infrastructure/controller.dart'; -import '../../../infrastructure/loadable_state.dart'; -import 'marianum_message_state.dart'; - -class MarianumMessageController extends Controller> { - MarianumMessageController() : super(const LoadableState(loadingState: LoadingState.none, data: MarianumMessageState(test: []))); - - void loading() { - emit(state.loading()); - Future.delayed(const Duration(seconds: 3)).then((value) => emit(state.done(const MarianumMessageState(test: [])))); - } - - void backgroundLoading() { - emit(state.cached(const MarianumMessageState(test: []))); - } - - void done() { - emit(state.done(const MarianumMessageState(test: []))); - } - - void error() { - emit(state.error(state: const MarianumMessageState(test: []))); - } -} diff --git a/lib/state/app/application/marianumMessage/marianum_message_state.dart b/lib/state/app/application/marianumMessage/marianum_message_state.dart deleted file mode 100644 index 9d893f0..0000000 --- a/lib/state/app/application/marianumMessage/marianum_message_state.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'marianum_message_state.freezed.dart'; - -@freezed -class MarianumMessageState with _$MarianumMessageState { - const factory MarianumMessageState({ - required List test - }) = _MarianumMessageState; -} diff --git a/lib/state/app/application/marianumMessage/marianum_message_state.freezed.dart b/lib/state/app/application/marianumMessage/marianum_message_state.freezed.dart deleted file mode 100644 index 49a75a1..0000000 --- a/lib/state/app/application/marianumMessage/marianum_message_state.freezed.dart +++ /dev/null @@ -1,143 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'marianum_message_state.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -/// @nodoc -mixin _$MarianumMessageState { - List get test => throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $MarianumMessageStateCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $MarianumMessageStateCopyWith<$Res> { - factory $MarianumMessageStateCopyWith(MarianumMessageState value, - $Res Function(MarianumMessageState) then) = - _$MarianumMessageStateCopyWithImpl<$Res, MarianumMessageState>; - @useResult - $Res call({List test}); -} - -/// @nodoc -class _$MarianumMessageStateCopyWithImpl<$Res, - $Val extends MarianumMessageState> - implements $MarianumMessageStateCopyWith<$Res> { - _$MarianumMessageStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? test = null, - }) { - return _then(_value.copyWith( - test: null == test - ? _value.test - : test // ignore: cast_nullable_to_non_nullable - as List, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$MarianumMessageStateImplCopyWith<$Res> - implements $MarianumMessageStateCopyWith<$Res> { - factory _$$MarianumMessageStateImplCopyWith(_$MarianumMessageStateImpl value, - $Res Function(_$MarianumMessageStateImpl) then) = - __$$MarianumMessageStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({List test}); -} - -/// @nodoc -class __$$MarianumMessageStateImplCopyWithImpl<$Res> - extends _$MarianumMessageStateCopyWithImpl<$Res, _$MarianumMessageStateImpl> - implements _$$MarianumMessageStateImplCopyWith<$Res> { - __$$MarianumMessageStateImplCopyWithImpl(_$MarianumMessageStateImpl _value, - $Res Function(_$MarianumMessageStateImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? test = null, - }) { - return _then(_$MarianumMessageStateImpl( - test: null == test - ? _value._test - : test // ignore: cast_nullable_to_non_nullable - as List, - )); - } -} - -/// @nodoc - -class _$MarianumMessageStateImpl implements _MarianumMessageState { - const _$MarianumMessageStateImpl({required final List test}) - : _test = test; - - final List _test; - @override - List get test { - if (_test is EqualUnmodifiableListView) return _test; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_test); - } - - @override - String toString() { - return 'MarianumMessageState(test: $test)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$MarianumMessageStateImpl && - const DeepCollectionEquality().equals(other._test, _test)); - } - - @override - int get hashCode => - Object.hash(runtimeType, const DeepCollectionEquality().hash(_test)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$MarianumMessageStateImplCopyWith<_$MarianumMessageStateImpl> - get copyWith => - __$$MarianumMessageStateImplCopyWithImpl<_$MarianumMessageStateImpl>( - this, _$identity); -} - -abstract class _MarianumMessageState implements MarianumMessageState { - const factory _MarianumMessageState({required final List test}) = - _$MarianumMessageStateImpl; - - @override - List get test; - @override - @JsonKey(ignore: true) - _$$MarianumMessageStateImplCopyWith<_$MarianumMessageStateImpl> - get copyWith => throw _privateConstructorUsedError; -} diff --git a/lib/state/app/modules/app_modules.dart b/lib/state/app/modules/app_modules.dart new file mode 100644 index 0000000..28849dc --- /dev/null +++ b/lib/state/app/modules/app_modules.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +import '../../../view/pages/files/files.dart'; +import '../../../view/pages/talk/chatList.dart'; +import '../../../view/pages/timetable/timetable.dart'; + +class AppModule { + String name; + IconData icon; + Widget Function() create; + + AppModule(this.name, this.icon, this.create); + + static Map modules() => { + Module.timetable: AppModule('Vertretung', Icons.calendar_month, Timetable.new), + Module.talk: AppModule('Talk', Icons.chat, ChatList.new), + Module.files: AppModule('Files', Icons.folder, Files.new), + }; +} + +enum Module { + timetable, + talk, + files, + marianumMessage, + roomPlan, + gradeAveragesCalculator, + holidays, +} diff --git a/lib/state/app/modules/gradeAverages/bloc/grade_averages_bloc.dart b/lib/state/app/modules/gradeAverages/bloc/grade_averages_bloc.dart new file mode 100644 index 0000000..6a084ca --- /dev/null +++ b/lib/state/app/modules/gradeAverages/bloc/grade_averages_bloc.dart @@ -0,0 +1,49 @@ +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'grade_averages_event.dart'; +import 'grade_averages_state.dart'; + +class GradeAveragesBloc extends HydratedBloc { + GradeAveragesBloc() : super(const GradeAveragesState(gradingSystem: GradeAveragesGradingSystem.middleSchool, grades: [])) { + + on((event, emit) { + add(ResetAll()); + emit( + state.copyWith( + gradingSystem: event.isMiddleSchool + ? GradeAveragesGradingSystem.middleSchool + : GradeAveragesGradingSystem.highSchool + ) + ); + }); + + on((event, emit) { + emit(state.copyWith(grades: [])); + }); + + on((event, emit) { + emit(state.copyWith(grades: [...state.grades]..removeWhere((grade) => grade == event.grade))); + }); + + on((event, emit) { + emit(state.copyWith(grades: [...state.grades, event.grade])); + }); + + on((event, emit) { + emit(state.copyWith(grades: List.from(state.grades)..remove(event.grade))); + }); + + } + + double average() => state.grades.isEmpty ? 0 : state.grades.reduce((a, b) => a + b) / state.grades.length; + bool isMiddleSchool() => state.gradingSystem == GradeAveragesGradingSystem.middleSchool; + bool canDecrementOrDelete(int grade) => state.grades.contains(grade); + int countOfGrade(int grade) => state.grades.where((g) => g == grade).length; + int gradesInGradingSystem() => state.gradingSystem == GradeAveragesGradingSystem.middleSchool ? 6 : 16; + int getGradeFromIndex(int index) => isMiddleSchool() ? index + 1 : 15 - index; + + @override + GradeAveragesState? fromJson(Map json) => GradeAveragesState.fromJson(json); + @override + Map? toJson(GradeAveragesState state) => state.toJson(); +} diff --git a/lib/state/app/modules/gradeAverages/bloc/grade_averages_event.dart b/lib/state/app/modules/gradeAverages/bloc/grade_averages_event.dart new file mode 100644 index 0000000..0be46eb --- /dev/null +++ b/lib/state/app/modules/gradeAverages/bloc/grade_averages_event.dart @@ -0,0 +1,20 @@ + +sealed class GradeAveragesEvent {} + +final class GradingSystemChanged extends GradeAveragesEvent { + final bool isMiddleSchool; + GradingSystemChanged(this.isMiddleSchool); +} +final class ResetAll extends GradeAveragesEvent {} +final class ResetGrade extends GradeAveragesEvent { + final int grade; + ResetGrade(this.grade); +} +final class IncrementGrade extends GradeAveragesEvent { + final int grade; + IncrementGrade(this.grade); +} +final class DecrementGrade extends GradeAveragesEvent { + final int grade; + DecrementGrade(this.grade); +} diff --git a/lib/state/app/application/gradeAverages/grade_averages_state.dart b/lib/state/app/modules/gradeAverages/bloc/grade_averages_state.dart similarity index 77% rename from lib/state/app/application/gradeAverages/grade_averages_state.dart rename to lib/state/app/modules/gradeAverages/bloc/grade_averages_state.dart index c9df18e..0462541 100644 --- a/lib/state/app/application/gradeAverages/grade_averages_state.dart +++ b/lib/state/app/modules/gradeAverages/bloc/grade_averages_state.dart @@ -6,14 +6,14 @@ part 'grade_averages_state.g.dart'; @freezed class GradeAveragesState with _$GradeAveragesState { const factory GradeAveragesState({ - required GradingSchemes gradingScheme, - required List grades, + required GradeAveragesGradingSystem gradingSystem, + required List grades, }) = _GradeAveragesState; factory GradeAveragesState.fromJson(Map json) => _$GradeAveragesStateFromJson(json); } -enum GradingSchemes { - middleSchool, +enum GradeAveragesGradingSystem { highSchool, + middleSchool, } diff --git a/lib/state/app/application/gradeAverages/grade_averages_state.freezed.dart b/lib/state/app/modules/gradeAverages/bloc/grade_averages_state.freezed.dart similarity index 81% rename from lib/state/app/application/gradeAverages/grade_averages_state.freezed.dart rename to lib/state/app/modules/gradeAverages/bloc/grade_averages_state.freezed.dart index 9985e09..c636f4d 100644 --- a/lib/state/app/application/gradeAverages/grade_averages_state.freezed.dart +++ b/lib/state/app/modules/gradeAverages/bloc/grade_averages_state.freezed.dart @@ -20,7 +20,8 @@ GradeAveragesState _$GradeAveragesStateFromJson(Map json) { /// @nodoc mixin _$GradeAveragesState { - GradingSchemes get gradingScheme => throw _privateConstructorUsedError; + GradeAveragesGradingSystem get gradingSystem => + throw _privateConstructorUsedError; List get grades => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @@ -35,7 +36,7 @@ abstract class $GradeAveragesStateCopyWith<$Res> { GradeAveragesState value, $Res Function(GradeAveragesState) then) = _$GradeAveragesStateCopyWithImpl<$Res, GradeAveragesState>; @useResult - $Res call({GradingSchemes gradingScheme, List grades}); + $Res call({GradeAveragesGradingSystem gradingSystem, List grades}); } /// @nodoc @@ -51,14 +52,14 @@ class _$GradeAveragesStateCopyWithImpl<$Res, $Val extends GradeAveragesState> @pragma('vm:prefer-inline') @override $Res call({ - Object? gradingScheme = null, + Object? gradingSystem = null, Object? grades = null, }) { return _then(_value.copyWith( - gradingScheme: null == gradingScheme - ? _value.gradingScheme - : gradingScheme // ignore: cast_nullable_to_non_nullable - as GradingSchemes, + gradingSystem: null == gradingSystem + ? _value.gradingSystem + : gradingSystem // ignore: cast_nullable_to_non_nullable + as GradeAveragesGradingSystem, grades: null == grades ? _value.grades : grades // ignore: cast_nullable_to_non_nullable @@ -75,7 +76,7 @@ abstract class _$$GradeAveragesStateImplCopyWith<$Res> __$$GradeAveragesStateImplCopyWithImpl<$Res>; @override @useResult - $Res call({GradingSchemes gradingScheme, List grades}); + $Res call({GradeAveragesGradingSystem gradingSystem, List grades}); } /// @nodoc @@ -89,14 +90,14 @@ class __$$GradeAveragesStateImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? gradingScheme = null, + Object? gradingSystem = null, Object? grades = null, }) { return _then(_$GradeAveragesStateImpl( - gradingScheme: null == gradingScheme - ? _value.gradingScheme - : gradingScheme // ignore: cast_nullable_to_non_nullable - as GradingSchemes, + gradingSystem: null == gradingSystem + ? _value.gradingSystem + : gradingSystem // ignore: cast_nullable_to_non_nullable + as GradeAveragesGradingSystem, grades: null == grades ? _value._grades : grades // ignore: cast_nullable_to_non_nullable @@ -109,14 +110,14 @@ class __$$GradeAveragesStateImplCopyWithImpl<$Res> @JsonSerializable() class _$GradeAveragesStateImpl implements _GradeAveragesState { const _$GradeAveragesStateImpl( - {required this.gradingScheme, required final List grades}) + {required this.gradingSystem, required final List grades}) : _grades = grades; factory _$GradeAveragesStateImpl.fromJson(Map json) => _$$GradeAveragesStateImplFromJson(json); @override - final GradingSchemes gradingScheme; + final GradeAveragesGradingSystem gradingSystem; final List _grades; @override List get grades { @@ -127,7 +128,7 @@ class _$GradeAveragesStateImpl implements _GradeAveragesState { @override String toString() { - return 'GradeAveragesState(gradingScheme: $gradingScheme, grades: $grades)'; + return 'GradeAveragesState(gradingSystem: $gradingSystem, grades: $grades)'; } @override @@ -135,15 +136,15 @@ class _$GradeAveragesStateImpl implements _GradeAveragesState { return identical(this, other) || (other.runtimeType == runtimeType && other is _$GradeAveragesStateImpl && - (identical(other.gradingScheme, gradingScheme) || - other.gradingScheme == gradingScheme) && + (identical(other.gradingSystem, gradingSystem) || + other.gradingSystem == gradingSystem) && const DeepCollectionEquality().equals(other._grades, _grades)); } @JsonKey(ignore: true) @override int get hashCode => Object.hash( - runtimeType, gradingScheme, const DeepCollectionEquality().hash(_grades)); + runtimeType, gradingSystem, const DeepCollectionEquality().hash(_grades)); @JsonKey(ignore: true) @override @@ -162,14 +163,14 @@ class _$GradeAveragesStateImpl implements _GradeAveragesState { abstract class _GradeAveragesState implements GradeAveragesState { const factory _GradeAveragesState( - {required final GradingSchemes gradingScheme, + {required final GradeAveragesGradingSystem gradingSystem, required final List grades}) = _$GradeAveragesStateImpl; factory _GradeAveragesState.fromJson(Map json) = _$GradeAveragesStateImpl.fromJson; @override - GradingSchemes get gradingScheme; + GradeAveragesGradingSystem get gradingSystem; @override List get grades; @override diff --git a/lib/state/app/application/gradeAverages/grade_averages_state.g.dart b/lib/state/app/modules/gradeAverages/bloc/grade_averages_state.g.dart similarity index 64% rename from lib/state/app/application/gradeAverages/grade_averages_state.g.dart rename to lib/state/app/modules/gradeAverages/bloc/grade_averages_state.g.dart index 056d665..af7af59 100644 --- a/lib/state/app/application/gradeAverages/grade_averages_state.g.dart +++ b/lib/state/app/modules/gradeAverages/bloc/grade_averages_state.g.dart @@ -9,19 +9,20 @@ part of 'grade_averages_state.dart'; _$GradeAveragesStateImpl _$$GradeAveragesStateImplFromJson( Map json) => _$GradeAveragesStateImpl( - gradingScheme: - $enumDecode(_$GradingSchemesEnumMap, json['gradingScheme']), + gradingSystem: $enumDecode( + _$GradeAveragesGradingSystemEnumMap, json['gradingSystem']), grades: (json['grades'] as List).map((e) => e as int).toList(), ); Map _$$GradeAveragesStateImplToJson( _$GradeAveragesStateImpl instance) => { - 'gradingScheme': _$GradingSchemesEnumMap[instance.gradingScheme]!, + 'gradingSystem': + _$GradeAveragesGradingSystemEnumMap[instance.gradingSystem]!, 'grades': instance.grades, }; -const _$GradingSchemesEnumMap = { - GradingSchemes.middleSchool: 'middleSchool', - GradingSchemes.highSchool: 'highSchool', +const _$GradeAveragesGradingSystemEnumMap = { + GradeAveragesGradingSystem.highSchool: 'highSchool', + GradeAveragesGradingSystem.middleSchool: 'middleSchool', }; diff --git a/lib/state/app/modules/gradeAverages/screens/grade_averages_list_view.dart b/lib/state/app/modules/gradeAverages/screens/grade_averages_list_view.dart new file mode 100644 index 0000000..3366a9c --- /dev/null +++ b/lib/state/app/modules/gradeAverages/screens/grade_averages_list_view.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../bloc/grade_averages_bloc.dart'; +import '../bloc/grade_averages_event.dart'; + +class GradeAveragesListView extends StatelessWidget { + const GradeAveragesListView({super.key}); + + @override + Widget build(BuildContext context) { + var bloc = context.watch(); + + String getGradeDisplay(int grade) { + if(bloc.isMiddleSchool()) { + return 'Note $grade'; + } else { + return "$grade Punkt${grade > 1 ? "e" : ""}"; + } + } + + return ListView.builder( + itemCount: bloc.gradesInGradingSystem(), + itemBuilder: (context, index) { + var grade = bloc.getGradeFromIndex(index); + return Material( + child: ListTile( + tileColor: grade.isEven ? Colors.transparent : Colors.transparent.withAlpha(50), + title: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(getGradeDisplay(grade)), + const SizedBox(width: 30), + IconButton( + onPressed: () { + bloc.add(DecrementGrade(grade)); + }, + icon: const Icon(Icons.remove), + color: Theme.of(context).colorScheme.onSurface, + ), + Text('${bloc.countOfGrade(grade)}', style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold)), + IconButton( + onPressed: () { + bloc.add(IncrementGrade(grade)); + }, + icon: const Icon(Icons.add), + color: Theme.of(context).colorScheme.onSurface, + ), + ], + ), + ), + trailing: Visibility( + maintainState: true, + maintainAnimation: true, + maintainSize: true, + visible: bloc.canDecrementOrDelete(grade), + child: IconButton( + icon: const Icon(Icons.delete), + onPressed: () { + bloc.add(ResetGrade(grade)); + }, + ), + ), + ), + ); + }, + ); + } +} diff --git a/lib/state/app/modules/gradeAverages/screens/grade_averages_view.dart b/lib/state/app/modules/gradeAverages/screens/grade_averages_view.dart new file mode 100644 index 0000000..ccda360 --- /dev/null +++ b/lib/state/app/modules/gradeAverages/screens/grade_averages_view.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../../../../../widget/confirmDialog.dart'; +import '../bloc/grade_averages_bloc.dart'; +import '../bloc/grade_averages_event.dart'; +import '../bloc/grade_averages_state.dart'; +import 'grade_averages_list_view.dart'; + +class GradeAveragesScreen extends StatelessWidget { + const GradeAveragesScreen({super.key}); + + @override + Widget build(BuildContext context) => BlocProvider( + create: (context) => GradeAveragesBloc(), + child: BlocBuilder( + builder: (context, state) { + var bloc = context.watch(); + + return Scaffold( + appBar: AppBar( + title: const Text('Notendurschnittsrechner'), + actions: [ + Visibility( + visible: bloc.state.grades.isNotEmpty, + child: IconButton( + onPressed: () { + showDialog( + context: context, + builder: (context) => ConfirmDialog( + title: 'Zurücksetzen?', + content: 'Alle Einträge werden entfernt.', + confirmButton: 'Zurücksetzen', + onConfirm: () { + bloc.add(ResetAll()); + }, + ), + ); + }, + icon: const Icon(Icons.delete_forever)), + ), + PopupMenuButton( + initialValue: bloc.isMiddleSchool(), + icon: const Icon(Icons.more_horiz), + itemBuilder: (context) => [true, false].map((isMiddleSchool) => PopupMenuItem( + value: isMiddleSchool, + child: Row( + children: [ + Icon( + isMiddleSchool ? Icons.calculate_outlined : Icons.school_outlined, + color: Theme.of(context).colorScheme.onSurface + ), + const SizedBox(width: 15), + Text(isMiddleSchool ? 'Notensystem' : 'Punktesystem'), + ], + ), + )).toList(), + onSelected: (isMiddleSchool) { + if (bloc.state.grades.isNotEmpty) { + showDialog( + context: context, + builder: (context) => ConfirmDialog( + title: 'Notensystem wechseln', + content: + 'Beim wechsel des Notensystems werden alle Einträge zurückgesetzt.', + confirmButton: 'Fortfahren', + onConfirm: () => bloc.add(GradingSystemChanged(isMiddleSchool)), + ), + ); + } else { + bloc.add(GradingSystemChanged(isMiddleSchool)); + } + }, + ), + ], + ), + + body: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 30), + Text(bloc.average().toStringAsFixed(2), style: const TextStyle(fontSize: 30, fontWeight: FontWeight.bold)), + const SizedBox(height: 10), + const Divider(), + const SizedBox(height: 10), + Text(bloc.isMiddleSchool() ? 'Wähle unten die Anzahl deiner jewiligen Noten aus' : 'Wähle unten die Anzahl deiner jeweiligen Punkte aus'), + const SizedBox(height: 10), + const Expanded( + child: GradeAveragesListView() + ), + ], + ), + ); + }, + ), + ); +} diff --git a/lib/state/infrastructure/controller.dart b/lib/state/infrastructure/controller.dart deleted file mode 100644 index 2ceca86..0000000 --- a/lib/state/infrastructure/controller.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter_bloc/flutter_bloc.dart'; - -abstract class Controller extends Cubit { - Controller(super.initialState); -} diff --git a/lib/state/infrastructure/loadable_state.dart b/lib/state/infrastructure/loadable_state.dart deleted file mode 100644 index 65299c6..0000000 --- a/lib/state/infrastructure/loadable_state.dart +++ /dev/null @@ -1,37 +0,0 @@ - -class LoadableState { - final LoadingState loadingState; - final TState? data; - - const LoadableState({required this.loadingState, required this.data}); - - LoadableState loading() => - LoadableState(loadingState: LoadingState.loading, data: null); - - LoadableState cached(TState state) => - LoadableState(loadingState: LoadingState.loading, data: state); - - LoadableState done(TState state) => - LoadableState(loadingState: LoadingState.none, data: state); - - LoadableState error({TState? state}) => - LoadableState(loadingState: LoadingState.failed, data: state); - - bool isBackgroundLoading() => - loadingState == LoadingState.loading && data != null; - - bool hasError() => - loadingState == LoadingState.failed; - - bool hasStateData() => - data != null; - - bool errorBarVisible() => - hasError() && hasStateData(); -} - -enum LoadingState { - loading, - failed, - none, -} diff --git a/lib/state/infrastructure/state_extensions.dart b/lib/state/infrastructure/state_extensions.dart deleted file mode 100644 index 1a828e1..0000000 --- a/lib/state/infrastructure/state_extensions.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -extension StateExtensions on BuildContext { - TState readController() => read(); - TState watchController() => watch(); -} diff --git a/lib/state/widgets/components/error_bar.dart b/lib/state/widgets/components/error_bar.dart index af63231..0d1c8bf 100644 --- a/lib/state/widgets/components/error_bar.dart +++ b/lib/state/widgets/components/error_bar.dart @@ -1,58 +1,58 @@ -import 'package:flutter/material.dart'; - -import '../../app/base/infrastructure/errorBar/error_bar_controller.dart'; -import '../../infrastructure/state_extensions.dart'; -import '../controller_provider.dart'; - -class ErrorBar extends StatelessWidget { - final bool visible; - const ErrorBar({required this.visible, super.key}); - - final Duration animationDuration = const Duration(milliseconds: 200); - - @override - Widget build(BuildContext context) => ControllerProvider( - create: (context) => ErrorBarController(), - child: (context) => AnimatedSize( - duration: animationDuration, - child: AnimatedSwitcher( - duration: animationDuration, - transitionBuilder: (Widget child, Animation animation) => SlideTransition( - position: Tween( - begin: const Offset(0.0, -1.0), - end: Offset.zero, - ).animate(animation), - child: child, - ), - child: Visibility( - key: Key(visible.hashCode.toString()), - visible: visible, - replacement: const SizedBox(width: double.infinity), - child: Builder( - builder: (context) { - var controller = context.watchController(); - var status = controller.connectivityStatusKnown() && !controller.isConnected() - ? (icon: Icons.wifi_off_outlined, text: 'Offline', color: Colors.grey.shade600) - : (icon: Icons.wifi_find_outlined, text: 'Verbindung fehlgeschlagen', color: Theme.of(context).primaryColor); - - return Container( - height: 20, - decoration: BoxDecoration( - color: status.color, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(status.icon, size: 14), - const SizedBox(width: 10), - Text(status.text, style: const TextStyle(fontSize: 12)) - ], - ), - ); - }, - ) - ) - ), - ), - ); -} +// import 'package:flutter/material.dart'; +// +// import '../../app/base/infrastructure/errorBar/error_bar_controller.dart'; +// import '../../infrastructure/state_extensions.dart'; +// import '../controller_provider.dart'; +// +// class ErrorBar extends StatelessWidget { +// final bool visible; +// const ErrorBar({required this.visible, super.key}); +// +// final Duration animationDuration = const Duration(milliseconds: 200); +// +// @override +// Widget build(BuildContext context) => ControllerProvider( +// create: (context) => ErrorBarController(), +// child: (context) => AnimatedSize( +// duration: animationDuration, +// child: AnimatedSwitcher( +// duration: animationDuration, +// transitionBuilder: (Widget child, Animation animation) => SlideTransition( +// position: Tween( +// begin: const Offset(0.0, -1.0), +// end: Offset.zero, +// ).animate(animation), +// child: child, +// ), +// child: Visibility( +// key: Key(visible.hashCode.toString()), +// visible: visible, +// replacement: const SizedBox(width: double.infinity), +// child: Builder( +// builder: (context) { +// var controller = context.watchController(); +// var status = controller.connectivityStatusKnown() && !controller.isConnected() +// ? (icon: Icons.wifi_off_outlined, text: 'Offline', color: Colors.grey.shade600) +// : (icon: Icons.wifi_find_outlined, text: 'Verbindung fehlgeschlagen', color: Theme.of(context).primaryColor); +// +// return Container( +// height: 20, +// decoration: BoxDecoration( +// color: status.color, +// ), +// child: Row( +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Icon(status.icon, size: 14), +// const SizedBox(width: 10), +// Text(status.text, style: const TextStyle(fontSize: 12)) +// ], +// ), +// ); +// }, +// ) +// ) +// ), +// ), +// ); +// } diff --git a/lib/state/widgets/controller_consumer.dart b/lib/state/widgets/controller_consumer.dart index 70b5302..c814d94 100644 --- a/lib/state/widgets/controller_consumer.dart +++ b/lib/state/widgets/controller_consumer.dart @@ -1,12 +1,12 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -import '../infrastructure/controller.dart'; - -class ControllerConsumer, TState> extends StatelessWidget { - final Widget Function(BuildContext context, TState state) child; - const ControllerConsumer({required this.child, super.key}); - - @override - Widget build(BuildContext context) => BlocBuilder(builder: child); -} +// import 'package:flutter/material.dart'; +// import 'package:flutter_bloc/flutter_bloc.dart'; +// +// import '../infrastructure/controller.dart'; +// +// class ControllerConsumer, TState> extends StatelessWidget { +// final Widget Function(BuildContext context, TState state) child; +// const ControllerConsumer({required this.child, super.key}); +// +// @override +// Widget build(BuildContext context) => BlocBuilder(builder: child); +// } diff --git a/lib/state/widgets/controller_provider.dart b/lib/state/widgets/controller_provider.dart index af9d9d7..e232ac3 100644 --- a/lib/state/widgets/controller_provider.dart +++ b/lib/state/widgets/controller_provider.dart @@ -1,21 +1,21 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:provider/single_child_widget.dart'; - -import '../infrastructure/controller.dart'; - - -class ControllerProvider extends SingleChildStatelessWidget { - final TState Function(BuildContext context) create; - final bool lazy; - final Widget Function(BuildContext context) child; - ControllerProvider({required this.create, this.lazy = true, required this.child, super.key}) - : super(child: Builder(builder: child)); - - @override - Widget buildWithChild(BuildContext context, Widget? child) => BlocProvider( - create: create, - lazy: lazy, - child: child, - ); -} +// import 'package:flutter/material.dart'; +// import 'package:flutter_bloc/flutter_bloc.dart'; +// import 'package:provider/single_child_widget.dart'; +// +// import '../infrastructure/controller.dart'; +// +// +// class ControllerProvider extends SingleChildStatelessWidget { +// final TState Function(BuildContext context) create; +// final bool lazy; +// final Widget Function(BuildContext context) child; +// ControllerProvider({required this.create, this.lazy = true, required this.child, super.key}) +// : super(child: Builder(builder: child)); +// +// @override +// Widget buildWithChild(BuildContext context, Widget? child) => BlocProvider( +// create: create, +// lazy: lazy, +// child: child, +// ); +// } diff --git a/lib/state/widgets/controllers_provider.dart b/lib/state/widgets/controllers_provider.dart index 0474581..1b5417b 100644 --- a/lib/state/widgets/controllers_provider.dart +++ b/lib/state/widgets/controllers_provider.dart @@ -1,17 +1,17 @@ - -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -import 'controller_provider.dart'; - -class ControllersProvider extends StatelessWidget { - final List controllers; - final Widget Function(BuildContext context) child; - const ControllersProvider({required this.controllers, required this.child, super.key}); - - @override - Widget build(BuildContext context) => MultiBlocProvider( - providers: controllers, - child: Builder(builder: child) - ); -} +// +// import 'package:flutter/material.dart'; +// import 'package:flutter_bloc/flutter_bloc.dart'; +// +// import 'controller_provider.dart'; +// +// class ControllersProvider extends StatelessWidget { +// final List controllers; +// final Widget Function(BuildContext context) child; +// const ControllersProvider({required this.controllers, required this.child, super.key}); +// +// @override +// Widget build(BuildContext context) => MultiBlocProvider( +// providers: controllers, +// child: Builder(builder: child) +// ); +// } diff --git a/lib/state/widgets/loadable_controller_consumer.dart b/lib/state/widgets/loadable_controller_consumer.dart index 8fa0d33..5fa8b48 100644 --- a/lib/state/widgets/loadable_controller_consumer.dart +++ b/lib/state/widgets/loadable_controller_consumer.dart @@ -1,40 +1,42 @@ -import 'package:flutter/material.dart'; - -import '../infrastructure/controller.dart'; -import '../infrastructure/loadable_state.dart'; -import '../infrastructure/state_extensions.dart'; -import 'components/background_loading_indicator.dart'; -import 'components/error_bar.dart'; -import 'components/primary_loading_indicator.dart'; - -class LoadableControllerConsumer, TState extends LoadableState> extends StatelessWidget { - final Widget child; - const LoadableControllerConsumer({required this.child, super.key}); - - final Duration animationDuration = const Duration(milliseconds: 200); - - @override - Widget build(BuildContext context) { - var state = context.readController().state; - return Column( - children: [ - ErrorBar(visible: state.errorBarVisible()), - Expanded( - child: Stack( - children: [ - PrimaryLoadingIndicator(visible: !state.hasStateData()), - BackgroundLoadingIndicator(visible: state.isBackgroundLoading() && !state.errorBarVisible()), - - AnimatedOpacity( - opacity: state.hasStateData() ? 1.0 : 0.0, - duration: animationDuration, - curve: Curves.easeInOut, - child: state.hasStateData() ? child : const SizedBox.shrink() - ), - ], - ), - ) - ], - ); - } -} +// import 'package:flutter/material.dart'; +// import 'package:flutter_bloc/flutter_bloc.dart'; +// +// import '../infrastructure/controller.dart'; +// import '../infrastructure/loadable_state.dart'; +// import '../infrastructure/state_extensions.dart'; +// import 'components/background_loading_indicator.dart'; +// import 'components/error_bar.dart'; +// import 'components/primary_loading_indicator.dart'; +// +// class LoadableControllerConsumer, TState extends LoadableState> extends StatelessWidget { +// final Widget child; +// const LoadableControllerConsumer({required this.child, super.key}); +// +// final Duration animationDuration = const Duration(milliseconds: 200); +// +// @override +// Widget build(BuildContext context) { +// var state = context.readController().state; +// +// return Column( +// children: [ +// // ErrorBar(visible: state.errorBarVisible()), +// // Expanded( +// // child: Stack( +// // children: [ +// // PrimaryLoadingIndicator(visible: !state.hasStateData()), +// // BackgroundLoadingIndicator(visible: state.isBackgroundLoading() && !state.errorBarVisible()), +// // +// // AnimatedOpacity( +// // opacity: state.hasStateData() ? 1.0 : 0.0, +// // duration: animationDuration, +// // curve: Curves.easeInOut, +// // child: state.hasStateData() ? child : const SizedBox.shrink() +// // ), +// // ], +// // ), +// // ) +// ], +// ); +// } +// } diff --git a/lib/view/pages/files/fileElement.dart b/lib/view/pages/files/fileElement.dart index 478da24..96aa306 100644 --- a/lib/view/pages/files/fileElement.dart +++ b/lib/view/pages/files/fileElement.dart @@ -99,7 +99,7 @@ class _FileElementState extends State { onTap: () { if(widget.file.isDirectory) { Navigator.of(context).push(MaterialPageRoute( - builder: (context) => Files(widget.path.toList()..add(widget.file.name)), + builder: (context) => Files(path: widget.path.toList()..add(widget.file.name)), )); } else { if(EndpointData().getEndpointMode() == EndpointMode.stage) { diff --git a/lib/view/pages/files/files.dart b/lib/view/pages/files/files.dart index 8068408..86ab4f4 100644 --- a/lib/view/pages/files/files.dart +++ b/lib/view/pages/files/files.dart @@ -21,7 +21,7 @@ import 'filesUploadDialog.dart'; class Files extends StatefulWidget { final List path; - const Files(this.path, {super.key}); + Files({List? path, super.key}) : path = path ?? []; @override State createState() => _FilesState(); diff --git a/lib/view/pages/more/test.dart b/lib/view/pages/more/test.dart index e6c69ad..36ec438 100644 --- a/lib/view/pages/more/test.dart +++ b/lib/view/pages/more/test.dart @@ -1,48 +1,48 @@ -import 'package:flutter/material.dart'; -import '../../../state/app/application/marianumMessage/marianum_message_controller.dart'; -import '../../../state/app/application/marianumMessage/marianum_message_state.dart'; -import '../../../state/infrastructure/loadable_state.dart'; -import '../../../state/infrastructure/state_extensions.dart'; -import '../../../state/widgets/controller_consumer.dart'; -import '../../../state/widgets/loadable_controller_consumer.dart'; -import '../../../state/widgets/sub_selected_controller_consumer.dart'; -import '../../../state/widgets/controller_provider.dart'; - -class Test extends StatelessWidget { - const Test({super.key}); - - @override - Widget build(BuildContext context) => ControllerProvider( - create: (context) => MarianumMessageController(), - child: (context) => Scaffold( - appBar: AppBar(title: const Text('TEST')), - body: LoadableControllerConsumer>( - child: Column( - children: [ - TextButton( - onPressed: () => context.readController().loading(), - child: Text(context.watchController().state.loadingState.toString()) - ), - TextButton( - onPressed: () => context.readController().backgroundLoading(), - child: Text(context.watchController().state.loadingState.toString()) - ), - TextButton( - onPressed: () => context.readController().done(), - child: Text(context.watchController().state.loadingState.toString()) - ), - TextButton( - onPressed: () => context.readController().error(), - child: Text(context.watchController().state.loadingState.toString()) - ), - ControllerConsumer>(child: (context, state) => Text(state.data!.test.toString())), - SubSelectedControllerConsumer, LoadingState>( - subSelect: (state) => state.loadingState, - child: (context, state) => Text(state.toString()), - ) - ], - ), - ), - ), - ); -} +// import 'package:flutter/material.dart'; +// import '../../../state/app/application/marianumMessage/marianum_message_controller.dart'; +// import '../../../state/app/application/marianumMessage/marianum_message_state.dart'; +// import '../../../state/infrastructure/loadable_state.dart'; +// import '../../../state/infrastructure/state_extensions.dart'; +// import '../../../state/widgets/controller_consumer.dart'; +// import '../../../state/widgets/loadable_controller_consumer.dart'; +// import '../../../state/widgets/sub_selected_controller_consumer.dart'; +// import '../../../state/widgets/controller_provider.dart'; +// +// class Test extends StatelessWidget { +// const Test({super.key}); +// +// @override +// Widget build(BuildContext context) => ControllerProvider( +// create: (context) => MarianumMessageController(), +// child: (context) => Scaffold( +// appBar: AppBar(title: const Text('TEST')), +// body: ControllerConsumer( +// child: (context, state) => Column( +// children: [ +// TextButton( +// onPressed: () => context.readController().someaction(), +// child: Text(context.watchController().state.toString()) +// ), +// TextButton( +// onPressed: () => context.readController().backgroundLoading(), +// child: Text(context.watchController().state.toString()) +// ), +// TextButton( +// onPressed: () => context.readController().done(), +// child: Text(context.watchController().state.toString()) +// ), +// TextButton( +// onPressed: () => context.readController().error(), +// child: Text(context.watchController().state.toString()) +// ), +// ControllerConsumer(child: (context, state) => Text(state.base.toString())), +// SubSelectedControllerConsumer( +// subSelect: (state) => state.messages, +// child: (context, state) => Text(state.toString()), +// ) +// ], +// ), +// ), +// ), +// ); +// } diff --git a/lib/view/pages/overhang.dart b/lib/view/pages/overhang.dart index 79f59bf..184953b 100644 --- a/lib/view/pages/overhang.dart +++ b/lib/view/pages/overhang.dart @@ -6,6 +6,7 @@ import 'package:in_app_review/in_app_review.dart'; import '../../extensions/renderNotNull.dart'; import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart'; +import '../../state/app/modules/gradeAverages/screens/grade_averages_view.dart'; import '../../widget/ListItem.dart'; import '../../widget/centeredLeading.dart'; import '../../widget/infoDialog.dart'; @@ -16,7 +17,6 @@ import 'more/holidays/holidays.dart'; import 'more/message/message.dart'; import 'more/roomplan/roomplan.dart'; import 'more/share/selectShareTypeDialog.dart'; -import 'more/test.dart'; class Overhang extends StatelessWidget { const Overhang({super.key}); @@ -77,7 +77,7 @@ class Overhang extends StatelessWidget { ), ListTile( leading: const Icon(Icons.science_outlined), - onTap: () => pushScreen(context, withNavBar: false, screen: const Test()), + onTap: () => pushScreen(context, withNavBar: false, screen: const GradeAveragesScreen()), ) ], ), diff --git a/pubspec.yaml b/pubspec.yaml index e9de63c..61599a4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -102,6 +102,7 @@ dependencies: flutter_bloc: ^8.1.5 freezed_annotation: ^2.4.1 connectivity_plus: ^6.0.3 + hydrated_bloc: ^9.1.5 dev_dependencies: flutter_test: