bloc/feature/fix_and_repo #24
| @ -1 +1,4 @@ | |||||||
| include: package:wyatt_analysis/analysis_options.flutter.yaml | include: package:wyatt_analysis/analysis_options.flutter.yaml | ||||||
|  | 
 | ||||||
|  | analyzer: | ||||||
|  |   exclude: "!example/**" | ||||||
| @ -4,7 +4,7 @@ | |||||||
| # This file should be version controlled. | # This file should be version controlled. | ||||||
| 
 | 
 | ||||||
| version: | version: | ||||||
|   revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 |   revision: f1875d570e39de09040c8f79aa13cc56baab8db1 | ||||||
|   channel: stable |   channel: stable | ||||||
| 
 | 
 | ||||||
| project_type: app | project_type: app | ||||||
| @ -13,11 +13,11 @@ project_type: app | |||||||
| migration: | migration: | ||||||
|   platforms: |   platforms: | ||||||
|     - platform: root |     - platform: root | ||||||
|       create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 |       create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 | ||||||
|       base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 |       base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 | ||||||
|     - platform: android |     - platform: web | ||||||
|       create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 |       create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 | ||||||
|       base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 |       base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 | ||||||
| 
 | 
 | ||||||
|   # User provided section |   # User provided section | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
|  | import 'package:bloc_helper_example/counter/repository/counter_repository.dart'; | ||||||
| import 'package:equatable/equatable.dart'; | import 'package:equatable/equatable.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
| 
 | 
 | ||||||
| @ -21,14 +22,16 @@ part 'counter_event.dart'; | |||||||
| part 'counter_state.dart'; | part 'counter_state.dart'; | ||||||
| 
 | 
 | ||||||
| class CounterBloc extends Bloc<CounterEvent, CounterState> { | class CounterBloc extends Bloc<CounterEvent, CounterState> { | ||||||
|   CounterBloc() : super(const CounterInitial()) { |   final CounterRepository counterRepository; | ||||||
|  | 
 | ||||||
|  |   CounterBloc(this.counterRepository) : super(const CounterInitial()) { | ||||||
|      |      | ||||||
|     on<CounterIncrement>((event, emit) { |     on<CounterIncrement>((event, emit) { | ||||||
|       emit(CounterModified(state.count + 1)); |       emit(CounterModified(counterRepository.increment(state.count))); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     on<CounterDecrement>((event, emit) { |     on<CounterDecrement>((event, emit) { | ||||||
|       emit(CounterModified(state.count - 1)); |       emit(CounterModified(counterRepository.decrement(state.count))); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ | |||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| import 'package:bloc_helper_example/counter/bloc/counter_bloc.dart'; | import 'package:bloc_helper_example/counter/bloc/counter_bloc.dart'; | ||||||
|  | import 'package:bloc_helper_example/counter/repository/counter_repository.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | ||||||
| 
 | 
 | ||||||
| @ -23,7 +24,7 @@ class CounterBlocPage | |||||||
|   const CounterBlocPage({super.key}); |   const CounterBlocPage({super.key}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   CounterBloc create(BuildContext context) => CounterBloc(); |   CounterBloc create(BuildContext context) => CounterBloc(repo<CounterRepository>(context)); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget onBuild(BuildContext context, CounterState state) { |   Widget onBuild(BuildContext context, CounterState state) { | ||||||
|  | |||||||
| @ -35,14 +35,16 @@ class CounterConsumerPage | |||||||
|         children: <Widget>[ |         children: <Widget>[ | ||||||
|           FloatingActionButton( |           FloatingActionButton( | ||||||
|             heroTag: null, |             heroTag: null, | ||||||
|             key: const Key('counterConsumerView_increment_floatingActionButton'), |             key: | ||||||
|  |                 const Key('counterConsumerView_increment_floatingActionButton'), | ||||||
|             child: const Icon(Icons.add), |             child: const Icon(Icons.add), | ||||||
|             onPressed: () => bloc(context).increment(), |             onPressed: () => bloc(context).increment(), | ||||||
|           ), |           ), | ||||||
|           const SizedBox(height: 8), |           const SizedBox(height: 8), | ||||||
|           FloatingActionButton( |           FloatingActionButton( | ||||||
|             heroTag: null, |             heroTag: null, | ||||||
|             key: const Key('counterConsumerView_decrement_floatingActionButton'), |             key: | ||||||
|  |                 const Key('counterConsumerView_decrement_floatingActionButton'), | ||||||
|             child: const Icon(Icons.remove), |             child: const Icon(Icons.remove), | ||||||
|             onPressed: () => bloc(context).decrement(), |             onPressed: () => bloc(context).decrement(), | ||||||
|           ), |           ), | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ | |||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| import 'package:bloc_helper_example/counter/cubit/counter_cubit.dart'; | import 'package:bloc_helper_example/counter/cubit/counter_cubit.dart'; | ||||||
|  | import 'package:bloc_helper_example/counter/repository/counter_repository.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | ||||||
| 
 | 
 | ||||||
| @ -23,7 +24,7 @@ class CounterCubitPage | |||||||
|   const CounterCubitPage({super.key}); |   const CounterCubitPage({super.key}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   CounterCubit create(BuildContext context) => CounterCubit(); |   CounterCubit create(BuildContext context) => CounterCubit(repo<CounterRepository>(context)); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget onBuild(BuildContext context, CounterState state) { |   Widget onBuild(BuildContext context, CounterState state) { | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ | |||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| import 'package:bloc_helper_example/counter/bloc/counter_bloc.dart'; | import 'package:bloc_helper_example/counter/bloc/counter_bloc.dart'; | ||||||
|  | import 'package:bloc_helper_example/counter/repository/counter_repository.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
| import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | ||||||
| @ -24,7 +25,11 @@ class CounterProviderPage | |||||||
|   const CounterProviderPage({super.key}); |   const CounterProviderPage({super.key}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget buildChild(BuildContext context) { |   CounterBloc create(BuildContext context) => | ||||||
|  |       CounterBloc(repo<CounterRepository>(context)); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget builder(BuildContext context) { | ||||||
|     final textTheme = Theme.of(context).textTheme; |     final textTheme = Theme.of(context).textTheme; | ||||||
|     return Scaffold( |     return Scaffold( | ||||||
|       appBar: AppBar(title: const Text('Counter with Provider')), |       appBar: AppBar(title: const Text('Counter with Provider')), | ||||||
| @ -39,14 +44,16 @@ class CounterProviderPage | |||||||
|         children: <Widget>[ |         children: <Widget>[ | ||||||
|           FloatingActionButton( |           FloatingActionButton( | ||||||
|             heroTag: null, |             heroTag: null, | ||||||
|             key: const Key('counterProviderView_increment_floatingActionButton'), |             key: | ||||||
|  |                 const Key('counterProviderView_increment_floatingActionButton'), | ||||||
|             child: const Icon(Icons.add), |             child: const Icon(Icons.add), | ||||||
|             onPressed: () => add(context, CounterIncrement()), |             onPressed: () => add(context, CounterIncrement()), | ||||||
|           ), |           ), | ||||||
|           const SizedBox(height: 8), |           const SizedBox(height: 8), | ||||||
|           FloatingActionButton( |           FloatingActionButton( | ||||||
|             heroTag: null, |             heroTag: null, | ||||||
|             key: const Key('counterProviderView_decrement_floatingActionButton'), |             key: | ||||||
|  |                 const Key('counterProviderView_decrement_floatingActionButton'), | ||||||
|             child: const Icon(Icons.remove), |             child: const Icon(Icons.remove), | ||||||
|             onPressed: () => add(context, CounterDecrement()), |             onPressed: () => add(context, CounterDecrement()), | ||||||
|           ), |           ), | ||||||
| @ -54,7 +61,4 @@ class CounterProviderPage | |||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   CounterBloc create(BuildContext context) => CounterBloc(); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,19 +14,22 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
|  | import 'package:bloc_helper_example/counter/repository/counter_repository.dart'; | ||||||
| import 'package:equatable/equatable.dart'; | import 'package:equatable/equatable.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
| 
 | 
 | ||||||
| part 'counter_state.dart'; | part 'counter_state.dart'; | ||||||
| 
 | 
 | ||||||
| class CounterCubit extends Cubit<CounterState> { | class CounterCubit extends Cubit<CounterState> { | ||||||
|   CounterCubit() : super(const CounterInitial()); |   final CounterRepository counterRepository; | ||||||
|  | 
 | ||||||
|  |   CounterCubit(this.counterRepository) : super(const CounterInitial()); | ||||||
| 
 | 
 | ||||||
|   void increment() { |   void increment() { | ||||||
|     emit(CounterModified(state.count + 1)); |     emit(CounterModified(counterRepository.increment(state.count))); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void decrement() { |   void decrement() { | ||||||
|     emit(CounterModified(state.count - 1)); |     emit(CounterModified(counterRepository.decrement(state.count))); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,27 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | class CounterRepository { | ||||||
|  |   int increment(int before) { | ||||||
|  |     final after = before + 1; | ||||||
|  |     return after; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   int decrement(int before) { | ||||||
|  |     final after = before - 1; | ||||||
|  |     return after; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,37 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:bloc_helper_example/counter/repository/counter_repository.dart'; | ||||||
|  | import 'package:bloc_helper_example/main_page.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart'; | ||||||
|  | 
 | ||||||
|  | class CounterRepositoryProviderPage | ||||||
|  |     extends RepositoryProviderScreen<CounterRepository> { | ||||||
|  |   const CounterRepositoryProviderPage({super.key}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   CounterRepository create(BuildContext context) => CounterRepository(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget builder(BuildContext context) => MaterialApp( | ||||||
|  |         title: 'Flutter Demo', | ||||||
|  |         theme: ThemeData( | ||||||
|  |           primarySwatch: Colors.blue, | ||||||
|  |         ), | ||||||
|  |         home: const MainPage(), | ||||||
|  |       ); | ||||||
|  | } | ||||||
| @ -14,77 +14,12 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| import 'package:bloc_helper_example/counter/counter_bloc_page.dart'; |  | ||||||
| import 'package:bloc_helper_example/counter/counter_consumer_page.dart'; |  | ||||||
| import 'package:bloc_helper_example/counter/counter_cubit_page.dart'; |  | ||||||
| import 'package:bloc_helper_example/counter/counter_provider_page.dart'; |  | ||||||
| import 'package:bloc_helper_example/counter/cubit/counter_cubit.dart'; |  | ||||||
| import 'package:bloc_helper_example/counter_observer.dart'; | import 'package:bloc_helper_example/counter_observer.dart'; | ||||||
|  | import 'package:bloc_helper_example/counter_repository_provider_page.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
| 
 | 
 | ||||||
| void main() { | void main() { | ||||||
|   BlocOverrides.runZoned(() => runApp(const MyApp()), |   BlocOverrides.runZoned(() => runApp(const CounterRepositoryProviderPage()), | ||||||
|       blocObserver: CounterObserver()); |       blocObserver: CounterObserver()); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| class MyApp extends StatelessWidget { |  | ||||||
|   const MyApp({Key? key}) : super(key: key); |  | ||||||
| 
 |  | ||||||
|   // This widget is the root of your application. |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     return MaterialApp( |  | ||||||
|       title: 'Flutter Demo', |  | ||||||
|       theme: ThemeData( |  | ||||||
|         primarySwatch: Colors.blue, |  | ||||||
|       ), |  | ||||||
|       home: const MainPage(), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class MainPage extends StatelessWidget { |  | ||||||
|   const MainPage({Key? key}) : super(key: key); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     return Scaffold( |  | ||||||
|       appBar: AppBar( |  | ||||||
|         title: const Text('Main Page'), |  | ||||||
|       ), |  | ||||||
|       body: Center( |  | ||||||
|         child: Column( |  | ||||||
|           mainAxisAlignment: MainAxisAlignment.center, |  | ||||||
|           children: <Widget>[ |  | ||||||
|             ElevatedButton( |  | ||||||
|               child: const Text('Counter with BlocScreen'), |  | ||||||
|               onPressed: () => Navigator.of(context).push( |  | ||||||
|                   MaterialPageRoute(builder: (_) => const CounterBlocPage())), |  | ||||||
|             ), |  | ||||||
|             ElevatedButton( |  | ||||||
|               child: const Text('Counter with CubitScreen'), |  | ||||||
|               onPressed: () => Navigator.of(context).push( |  | ||||||
|                   MaterialPageRoute(builder: (_) => const CounterCubitPage())), |  | ||||||
|             ), |  | ||||||
|             ElevatedButton( |  | ||||||
|               child: const Text('Counter with BlocProviderScreen'), |  | ||||||
|               onPressed: () => Navigator.of(context).push(MaterialPageRoute( |  | ||||||
|                   builder: (_) => const CounterProviderPage())), |  | ||||||
|             ), |  | ||||||
|             ElevatedButton( |  | ||||||
|               child: const Text('Counter with BlocConsumerScreen'), |  | ||||||
|               onPressed: () => Navigator.of(context) |  | ||||||
|                   .push(MaterialPageRoute(builder: (context) { |  | ||||||
|                 return BlocProvider<CounterCubit>( |  | ||||||
|                   create: (context) => CounterCubit(), |  | ||||||
|                   child: const CounterConsumerPage(), |  | ||||||
|                 ); |  | ||||||
|               })), |  | ||||||
|             ), |  | ||||||
|           ], |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  | |||||||
							
								
								
									
										69
									
								
								packages/wyatt_bloc_helper/example/lib/main_page.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								packages/wyatt_bloc_helper/example/lib/main_page.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:bloc_helper_example/counter/counter_bloc_page.dart'; | ||||||
|  | import 'package:bloc_helper_example/counter/counter_consumer_page.dart'; | ||||||
|  | import 'package:bloc_helper_example/counter/counter_cubit_page.dart'; | ||||||
|  | import 'package:bloc_helper_example/counter/counter_provider_page.dart'; | ||||||
|  | import 'package:bloc_helper_example/counter/cubit/counter_cubit.dart'; | ||||||
|  | import 'package:bloc_helper_example/counter/repository/counter_repository.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
|  | 
 | ||||||
|  | class MainPage extends StatelessWidget { | ||||||
|  |   const MainPage({Key? key}) : super(key: key); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Scaffold( | ||||||
|  |       appBar: AppBar( | ||||||
|  |         title: const Text('Main Page'), | ||||||
|  |       ), | ||||||
|  |       body: Center( | ||||||
|  |         child: Column( | ||||||
|  |           mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |           children: <Widget>[ | ||||||
|  |             ElevatedButton( | ||||||
|  |               child: const Text('Counter with BlocScreen'), | ||||||
|  |               onPressed: () => Navigator.of(context).push( | ||||||
|  |                   MaterialPageRoute(builder: (_) => const CounterBlocPage())), | ||||||
|  |             ), | ||||||
|  |             ElevatedButton( | ||||||
|  |               child: const Text('Counter with CubitScreen'), | ||||||
|  |               onPressed: () => Navigator.of(context).push( | ||||||
|  |                   MaterialPageRoute(builder: (_) => const CounterCubitPage())), | ||||||
|  |             ), | ||||||
|  |             ElevatedButton( | ||||||
|  |               child: const Text('Counter with BlocProviderScreen'), | ||||||
|  |               onPressed: () => Navigator.of(context).push(MaterialPageRoute( | ||||||
|  |                   builder: (_) => const CounterProviderPage())), | ||||||
|  |             ), | ||||||
|  |             ElevatedButton( | ||||||
|  |               child: const Text('Counter with BlocConsumerScreen'), | ||||||
|  |               onPressed: () => Navigator.of(context) | ||||||
|  |                   .push(MaterialPageRoute(builder: (context) { | ||||||
|  |                 return BlocProvider<CounterCubit>( | ||||||
|  |                   create: (context) => CounterCubit(context.read<CounterRepository>()), | ||||||
|  |                   child: const CounterConsumerPage(), | ||||||
|  |                 ); | ||||||
|  |               })), | ||||||
|  |             ), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -5,15 +5,14 @@ | |||||||
| // gestures. You can also use WidgetTester to find child widgets in the widget | // gestures. You can also use WidgetTester to find child widgets in the widget | ||||||
| // tree, read text, and verify that the values of widget properties are correct. | // tree, read text, and verify that the values of widget properties are correct. | ||||||
| 
 | 
 | ||||||
|  | import 'package:bloc_helper_example/counter_repository_provider_page.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter_test/flutter_test.dart'; | import 'package:flutter_test/flutter_test.dart'; | ||||||
| 
 | 
 | ||||||
| import 'package:bloc_helper_example/main.dart'; |  | ||||||
| 
 |  | ||||||
| void main() { | void main() { | ||||||
|   testWidgets('Counter increments smoke test', (WidgetTester tester) async { |   testWidgets('Counter increments smoke test', (WidgetTester tester) async { | ||||||
|     // Build our app and trigger a frame. |     // Build our app and trigger a frame. | ||||||
|     await tester.pumpWidget(const MyApp()); |     await tester.pumpWidget(const CounterRepositoryProviderPage()); | ||||||
| 
 | 
 | ||||||
|     // Verify that our counter starts at 0. |     // Verify that our counter starts at 0. | ||||||
|     expect(find.text('0'), findsOneWidget); |     expect(find.text('0'), findsOneWidget); | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								packages/wyatt_bloc_helper/example/web/favicon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								packages/wyatt_bloc_helper/example/web/favicon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 917 B | 
							
								
								
									
										
											BIN
										
									
								
								packages/wyatt_bloc_helper/example/web/icons/Icon-192.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								packages/wyatt_bloc_helper/example/web/icons/Icon-192.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								packages/wyatt_bloc_helper/example/web/icons/Icon-512.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								packages/wyatt_bloc_helper/example/web/icons/Icon-512.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 8.1 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.5 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 20 KiB | 
							
								
								
									
										58
									
								
								packages/wyatt_bloc_helper/example/web/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								packages/wyatt_bloc_helper/example/web/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  | <head> | ||||||
|  |   <!-- | ||||||
|  |     If you are serving your web app in a path other than the root, change the | ||||||
|  |     href value below to reflect the base path you are serving from. | ||||||
|  | 
 | ||||||
|  |     The path provided below has to start and end with a slash "/" in order for | ||||||
|  |     it to work correctly. | ||||||
|  | 
 | ||||||
|  |     For more details: | ||||||
|  |     * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base | ||||||
|  | 
 | ||||||
|  |     This is a placeholder for base href that will be replaced by the value of | ||||||
|  |     the `--base-href` argument provided to `flutter build`. | ||||||
|  |   --> | ||||||
|  |   <base href="$FLUTTER_BASE_HREF"> | ||||||
|  | 
 | ||||||
|  |   <meta charset="UTF-8"> | ||||||
|  |   <meta content="IE=Edge" http-equiv="X-UA-Compatible"> | ||||||
|  |   <meta name="description" content="A new Flutter project."> | ||||||
|  | 
 | ||||||
|  |   <!-- iOS meta tags & icons --> | ||||||
|  |   <meta name="apple-mobile-web-app-capable" content="yes"> | ||||||
|  |   <meta name="apple-mobile-web-app-status-bar-style" content="black"> | ||||||
|  |   <meta name="apple-mobile-web-app-title" content="example"> | ||||||
|  |   <link rel="apple-touch-icon" href="icons/Icon-192.png"> | ||||||
|  | 
 | ||||||
|  |   <!-- Favicon --> | ||||||
|  |   <link rel="icon" type="image/png" href="favicon.png"/> | ||||||
|  | 
 | ||||||
|  |   <title>example</title> | ||||||
|  |   <link rel="manifest" href="manifest.json"> | ||||||
|  | 
 | ||||||
|  |   <script> | ||||||
|  |     // The value below is injected by flutter build, do not touch. | ||||||
|  |     var serviceWorkerVersion = null; | ||||||
|  |   </script> | ||||||
|  |   <!-- This script adds the flutter initialization JS code --> | ||||||
|  |   <script src="flutter.js" defer></script> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  |   <script> | ||||||
|  |     window.addEventListener('load', function(ev) { | ||||||
|  |       // Download main.dart.js | ||||||
|  |       _flutter.loader.loadEntrypoint({ | ||||||
|  |         serviceWorker: { | ||||||
|  |           serviceWorkerVersion: serviceWorkerVersion, | ||||||
|  |         } | ||||||
|  |       }).then(function(engineInitializer) { | ||||||
|  |         return engineInitializer.initializeEngine(); | ||||||
|  |       }).then(function(appRunner) { | ||||||
|  |         return appRunner.runApp(); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   </script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										35
									
								
								packages/wyatt_bloc_helper/example/web/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								packages/wyatt_bloc_helper/example/web/manifest.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | { | ||||||
|  |     "name": "example", | ||||||
|  |     "short_name": "example", | ||||||
|  |     "start_url": ".", | ||||||
|  |     "display": "standalone", | ||||||
|  |     "background_color": "#0175C2", | ||||||
|  |     "theme_color": "#0175C2", | ||||||
|  |     "description": "A new Flutter project.", | ||||||
|  |     "orientation": "portrait-primary", | ||||||
|  |     "prefer_related_applications": false, | ||||||
|  |     "icons": [ | ||||||
|  |         { | ||||||
|  |             "src": "icons/Icon-192.png", | ||||||
|  |             "sizes": "192x192", | ||||||
|  |             "type": "image/png" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "src": "icons/Icon-512.png", | ||||||
|  |             "sizes": "512x512", | ||||||
|  |             "type": "image/png" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "src": "icons/Icon-maskable-192.png", | ||||||
|  |             "sizes": "192x192", | ||||||
|  |             "type": "image/png", | ||||||
|  |             "purpose": "maskable" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "src": "icons/Icon-maskable-512.png", | ||||||
|  |             "sizes": "512x512", | ||||||
|  |             "type": "image/png", | ||||||
|  |             "purpose": "maskable" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
| @ -14,27 +14,79 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart' as blocbase; | ||||||
| import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_consumer_screen.dart'; | import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_consumer_screen.dart'; | ||||||
| import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_provider_screen.dart'; | import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_provider_screen.dart'; | ||||||
| import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_screen.dart'; | import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_screen.dart'; | ||||||
| import 'package:wyatt_bloc_helper/src/mixins/bloc_base_provider_mixin.dart'; | import 'package:wyatt_bloc_helper/src/mixins/bloc_base_provider_mixin.dart'; | ||||||
| import 'package:wyatt_bloc_helper/src/mixins/bloc_provider_mixin.dart'; | import 'package:wyatt_bloc_helper/src/mixins/bloc_provider_mixin.dart'; | ||||||
|  | import 'package:wyatt_bloc_helper/src/mixins/repository_base_provider_mixin.dart'; | ||||||
| 
 | 
 | ||||||
| abstract class BlocProviderScreen<B extends Bloc<E, S>, E, S extends Object> | /// {@template bloc_provider} | ||||||
|     extends BlocBaseProviderScreen<B, S> | /// Need to implement a [create] function that is responsible for | ||||||
|     with BlocBaseProviderMixin<B>, BlocProviderMixin<B, E> { | /// creating the [Bloc] and a [builder] which will return a child | ||||||
|   const BlocProviderScreen({super.key}); | /// that have access to the instance via `context.read<Bloc>()`. | ||||||
|  | /// It is used as a dependency injection (DI) widget so that a single instance | ||||||
|  | /// of a [Bloc] can be provided to multiple widgets within a subtree. | ||||||
|  | /// | ||||||
|  | /// It automatically handles closing the instance when used with [create]. | ||||||
|  | /// By default, [create] is called only when the instance is accessed. | ||||||
|  | /// To override this behavior, set [lazy] to `false`. | ||||||
|  | /// | ||||||
|  | /// By default, it provide already provided instance found in the tree. | ||||||
|  | /// To override this behavior, set [smart] to `false`. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class BlocProviderScreen<Bloc extends blocbase.Bloc<Event, State>, | ||||||
|  |         Event, State extends Object> extends BlocBaseProviderScreen<Bloc, State> | ||||||
|  |     with | ||||||
|  |         BlocBaseProviderMixin<Bloc>, | ||||||
|  |         RepositoryProviderMixin, | ||||||
|  |         BlocProviderMixin<Bloc, Event> { | ||||||
|  |   /// {@macro bloc_provider} | ||||||
|  |   const BlocProviderScreen({super.key, super.lazy = true, super.smart = true}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| abstract class BlocConsumerScreen<B extends Bloc<E, S>, E, S extends Object> | /// {@template bloc_consumer} | ||||||
|     extends BlocBaseConsumerScreen<B, S> | /// [BlocConsumerScreen] exposes [onBuild] and [onListen] in order react | ||||||
|     with BlocBaseProviderMixin<B>, BlocProviderMixin<B, E> { | /// to new states. | ||||||
|  | /// | ||||||
|  | /// An optional [shouldBuildWhen] and [shouldListenWhen] can be implemented | ||||||
|  | /// for more granular control over when [onListen] and [onBuild] are called. | ||||||
|  | /// The [shouldListenWhen] and [shouldBuildWhen] will be invoked on | ||||||
|  | /// each [Bloc] or `state` change. | ||||||
|  | /// They each take the previous `state` and current `state` and must return | ||||||
|  | /// a [bool] which determines whether or not the [onBuild] and/or [onListen] | ||||||
|  | /// function will be invoked. | ||||||
|  | /// The previous `state` will be initialized to the `state` of the [Bloc] when | ||||||
|  | /// the BlocConsumer is initialized. | ||||||
|  | /// [shouldListenWhen] and [shouldBuildWhen] are optional and if they | ||||||
|  | /// aren't implemented, they will default to `true`. | ||||||
|  | /// | ||||||
|  | /// An optional [onWrap] can also be implemented. This build a wrapper arround | ||||||
|  | /// the built BlocConsumer that is **not** rebuild on each state. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class BlocConsumerScreen<Bloc extends blocbase.Bloc<Event, State>, | ||||||
|  |         Event, State extends Object> extends BlocBaseConsumerScreen<Bloc, State> | ||||||
|  |     with | ||||||
|  |         BlocBaseProviderMixin<Bloc>, | ||||||
|  |         RepositoryProviderMixin, | ||||||
|  |         BlocProviderMixin<Bloc, Event> { | ||||||
|  |   /// {@macro bloc_consumer} | ||||||
|   const BlocConsumerScreen({super.key}); |   const BlocConsumerScreen({super.key}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| abstract class BlocScreen<B extends Bloc<E, S>, E, S extends Object> | /// {@template bloc_screen} | ||||||
|     extends BlocBaseScreen<B, S> | /// Provide AND access to a [Bloc]. | ||||||
|     with BlocBaseProviderMixin<B>, BlocProviderMixin<B, E> { | /// | ||||||
|   const BlocScreen({super.key}); | /// This extends [BlocConsumerScreen] with the methods | ||||||
|  | /// of [BlocBaseScreen]. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class BlocScreen<Bloc extends blocbase.Bloc<Event, State>, Event, | ||||||
|  |         State extends Object> extends BlocBaseScreen<Bloc, State> | ||||||
|  |     with | ||||||
|  |         BlocBaseProviderMixin<Bloc>, | ||||||
|  |         RepositoryProviderMixin, | ||||||
|  |         BlocProviderMixin<Bloc, Event> { | ||||||
|  |   /// {@macro bloc_screen} | ||||||
|  |   const BlocScreen({super.key, super.lazy = true, super.smart = true}); | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,39 +17,62 @@ | |||||||
| import 'package:flutter/widgets.dart'; | import 'package:flutter/widgets.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
| 
 | 
 | ||||||
| abstract class BlocBaseConsumerScreen<B extends BlocBase<S>, S extends Object> | /// {@template bloc_base_consumer} | ||||||
|     extends StatelessWidget { | /// [BlocBaseConsumerScreen] exposes [onBuild] and [onListen] in order react | ||||||
|  | /// to new states. | ||||||
|  | /// | ||||||
|  | /// An optional [shouldBuildWhen] and [shouldListenWhen] can be implemented | ||||||
|  | /// for more granular control over when [onListen] and [onBuild] are called. | ||||||
|  | /// The [shouldListenWhen] and [shouldBuildWhen] will be invoked on | ||||||
|  | /// each [Bloc] or `state` change. | ||||||
|  | /// They each take the previous `state` and current `state` and must return | ||||||
|  | /// a [bool] which determines whether or not the [onBuild] and/or [onListen] | ||||||
|  | /// function will be invoked. | ||||||
|  | /// The previous `state` will be initialized to the `state` of the [Bloc] when | ||||||
|  | /// the [BlocConsumer] is initialized. | ||||||
|  | /// [shouldListenWhen] and [shouldBuildWhen] are optional and if they | ||||||
|  | /// aren't implemented, they will default to `true`. | ||||||
|  | /// | ||||||
|  | /// An optional [onWrap] can also be implemented. This build a wrapper arround | ||||||
|  | /// the built [BlocConsumer] that is **not** rebuild on each state. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class BlocBaseConsumerScreen<Bloc extends BlocBase<State>, | ||||||
|  |     State extends Object> extends StatelessWidget { | ||||||
|  |   /// {@macro bloc_base_consumer} | ||||||
|   const BlocBaseConsumerScreen({super.key}); |   const BlocBaseConsumerScreen({super.key}); | ||||||
| 
 | 
 | ||||||
|   /// Takes the previous `state` and the current `state` and is responsible for |   /// Takes the previous `state` and the current `state` and is responsible for | ||||||
|   /// returning a [bool] which determines whether or not to trigger |   /// returning a [bool] which determines whether or not to trigger | ||||||
|   /// [onBuild] with the current `state`. |   /// [onBuild] with the current `state`. | ||||||
|   bool shouldBuildWhen(S previous, S current) => true; |   bool shouldBuildWhen(State previous, State current) => true; | ||||||
| 
 | 
 | ||||||
|   /// Takes the previous `state` and the current `state` and is responsible for |   /// Takes the previous `state` and the current `state` and is responsible for | ||||||
|   /// returning a [bool] which determines whether or not to trigger |   /// returning a [bool] which determines whether or not to trigger | ||||||
|   /// [onListen] with the current `state`. |   /// [onListen] with the current `state`. | ||||||
|   bool shouldListenWhen(S previous, S current) => true; |   bool shouldListenWhen(State previous, State current) => true; | ||||||
|  | 
 | ||||||
|  |   /// The [onWrap] function which will be invoked on build. | ||||||
|  |   /// The [onWrap] takes a `BuildContext` that **doesn't have** access | ||||||
|  |   /// to the [Bloc] or [Cubit]. | ||||||
|  |   Widget onWrap(BuildContext context, Widget child) => child; | ||||||
| 
 | 
 | ||||||
|   /// The [onBuild] function which will be invoked on each widget build. |   /// The [onBuild] function which will be invoked on each widget build. | ||||||
|   /// The [onBuild] takes the `BuildContext` and current `state` and |   /// The [onBuild] takes the `BuildContext` and current `state` and | ||||||
|   /// must return a widget. |   /// must return a widget. | ||||||
|   Widget onBuild(BuildContext context, S state); |   Widget onBuild(BuildContext context, State state); | ||||||
| 
 |  | ||||||
|   /// The [onWrap] function which will be invoked on each widget build. |  | ||||||
|   /// The [onWrap] takes the `BuildContext` |  | ||||||
|   /// Used to wrap which depends on the state. |  | ||||||
|   Widget onWrap(BuildContext context, Widget child) => child; |  | ||||||
| 
 | 
 | ||||||
|   /// Takes the `BuildContext` along with the `state` |   /// Takes the `BuildContext` along with the `state` | ||||||
|   /// and is responsible for executing in response to `state` changes. |   /// and is responsible for executing in response to `state` changes. | ||||||
|   void onListen(BuildContext context, S state) {} |   void onListen(BuildContext context, State state) {} | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) => BlocConsumer<B, S>( |   Widget build(BuildContext context) => onWrap( | ||||||
|         listenWhen: shouldListenWhen, |         context, | ||||||
|         listener: onListen, |         BlocConsumer<Bloc, State>( | ||||||
|         buildWhen: shouldBuildWhen, |           listenWhen: shouldListenWhen, | ||||||
|         builder: (context, state) => onWrap(context, onBuild(context, state)), |           listener: onListen, | ||||||
|  |           buildWhen: shouldBuildWhen, | ||||||
|  |           builder: onBuild, | ||||||
|  |         ), | ||||||
|       ); |       ); | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,20 +16,53 @@ | |||||||
| 
 | 
 | ||||||
| import 'package:flutter/widgets.dart'; | import 'package:flutter/widgets.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
|  | import 'package:wyatt_bloc_helper/src/utils/smart_provider.dart'; | ||||||
| 
 | 
 | ||||||
| abstract class BlocBaseProviderScreen<B extends BlocBase<S>, S extends Object> | /// {@template bloc_base_provider} | ||||||
|     extends StatelessWidget { | /// Need to implement a [create] function that is responsible for | ||||||
|   const BlocBaseProviderScreen({super.key}); | /// creating the [Bloc] or [Cubit] and a [builder] which will return a child | ||||||
|  | /// that have access to the instance via `context.read<Bloc>()`. | ||||||
|  | /// It is used as a dependency injection (DI) widget so that a single instance | ||||||
|  | /// of a [Bloc] or [Cubit] can be provided to multiple widgets within a subtree. | ||||||
|  | /// | ||||||
|  | /// It automatically handles closing the instance when used with [create]. | ||||||
|  | /// By default, [create] is called only when the instance is accessed. | ||||||
|  | /// To override this behavior, set [lazy] to `false`. | ||||||
|  | ///  | ||||||
|  | /// By default, it provide already provided instance found in the tree. | ||||||
|  | /// To override this behavior, set [smart] to `false`. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class BlocBaseProviderScreen<Bloc extends BlocBase<State>, | ||||||
|  |     State extends Object> extends StatelessWidget { | ||||||
|  |   /// {@macro bloc_base_provider} | ||||||
|  |   const BlocBaseProviderScreen({ | ||||||
|  |     super.key, | ||||||
|  |     this.lazy = true, | ||||||
|  |     this.smart = true, | ||||||
|  |   }); | ||||||
| 
 | 
 | ||||||
|   /// Creates the [Cubit] or [Bloc] to be used. |   /// Whether the [Bloc] or [Cubit] should be created lazily. | ||||||
|   B create(BuildContext context); |   /// Defaults to `true` which means the [Bloc] or [Cubit] is created only when | ||||||
|  |   /// accessed the first time, not when provided. | ||||||
|  |   final bool lazy; | ||||||
|  | 
 | ||||||
|  |   /// Whether this uses [SmartProvider]. | ||||||
|  |   /// Defaults to `true`. But if you want to provide new [Bloc] or [Cubit]  | ||||||
|  |   /// of a same type in a sub-tree you may have to disable this. | ||||||
|  |   final bool smart; | ||||||
|  | 
 | ||||||
|  |   /// Creates the [Bloc] or [Cubit] to be used. | ||||||
|  |   Bloc create(BuildContext context); | ||||||
| 
 | 
 | ||||||
|   /// Creates the child [Widget] to be used. |   /// Creates the child [Widget] to be used. | ||||||
|   Widget buildChild(BuildContext context); |   Widget builder(BuildContext context); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) => BlocProvider<B>( |   Widget build(BuildContext context) => SmartProvider.bloc<Bloc, State>( | ||||||
|  |         context, | ||||||
|  |         lazy: lazy, | ||||||
|  |         enable: smart, | ||||||
|         create: (_) => create(context), |         create: (_) => create(context), | ||||||
|         child: Builder(builder: buildChild), |         child: Builder(builder: builder), | ||||||
|       ); |       ); | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,17 +17,44 @@ | |||||||
| import 'package:flutter/widgets.dart'; | import 'package:flutter/widgets.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
| import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_consumer_screen.dart'; | import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_consumer_screen.dart'; | ||||||
|  | import 'package:wyatt_bloc_helper/src/utils/smart_provider.dart'; | ||||||
| 
 | 
 | ||||||
| abstract class BlocBaseScreen<B extends BlocBase<S>, S extends Object> | /// {@template bloc_base_screen} | ||||||
|     extends BlocBaseConsumerScreen<B, S> { | /// Provide AND access to a [Bloc] or [Cubit]. | ||||||
|   const BlocBaseScreen({super.key}); | /// | ||||||
|  | /// This extends [BlocBaseConsumerScreen] with the methods | ||||||
|  | // ignore: comment_references | ||||||
|  | /// of [BlocBaseProviderScreen]. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class BlocBaseScreen<Bloc extends BlocBase<State>, | ||||||
|  |     State extends Object> extends BlocBaseConsumerScreen<Bloc, State> { | ||||||
|  |   /// {@macro bloc_base_screen} | ||||||
|  |   const BlocBaseScreen({ | ||||||
|  |     super.key, | ||||||
|  |     this.lazy = true, | ||||||
|  |     this.smart = true, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   /// Whether the [Bloc] or [Cubit] should be created lazily. | ||||||
|  |   /// Defaults to `true` which means the [Bloc] is created only when | ||||||
|  |   /// accessed the first time, not when provided. | ||||||
|  |   final bool lazy; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   /// Whether this uses [SmartProvider]. | ||||||
|  |   /// Defaults to `true`. But if you want to provide new Bloc of a same type, | ||||||
|  |   /// in a sub-tree you may have to disable this. | ||||||
|  |   final bool smart; | ||||||
| 
 | 
 | ||||||
|   /// Creates the [Cubit] or [Bloc] to be used. |   /// Creates the [Cubit] or [Bloc] to be used. | ||||||
|   B create(BuildContext context); |   Bloc create(BuildContext context); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) => BlocProvider<B>( |   Widget build(BuildContext context) => SmartProvider.bloc<Bloc, State>( | ||||||
|         create: (_) => create(context), |       context, | ||||||
|         child: super.build(context), |       lazy: lazy, | ||||||
|       ); |       enable: smart, | ||||||
|  |       create: (_) => create(context), | ||||||
|  |       child: super.build(context), | ||||||
|  |     ); | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,23 +14,70 @@ | |||||||
| // You should have received a copy of the GNU General Public License | // You should have received a copy of the GNU General Public License | ||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart' as blocbase; | ||||||
| import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_consumer_screen.dart'; | import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_consumer_screen.dart'; | ||||||
| import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_provider_screen.dart'; | import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_provider_screen.dart'; | ||||||
| import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_screen.dart'; | import 'package:wyatt_bloc_helper/src/bloc_base/bloc_base_screen.dart'; | ||||||
| import 'package:wyatt_bloc_helper/src/mixins/bloc_base_provider_mixin.dart'; | import 'package:wyatt_bloc_helper/src/mixins/bloc_base_provider_mixin.dart'; | ||||||
|  | import 'package:wyatt_bloc_helper/src/mixins/repository_base_provider_mixin.dart'; | ||||||
| 
 | 
 | ||||||
| abstract class CubitProviderScreen<B extends Cubit<S>, S extends Object> | /// {@template cubit_provider} | ||||||
|     extends BlocBaseProviderScreen<B, S> with BlocBaseProviderMixin<B> { | /// Need to implement a [create] function that is responsible for | ||||||
|   const CubitProviderScreen({super.key}); | /// creating the [Cubit] and a [builder] which will return a child | ||||||
|  | /// that have access to the instance via `context.read<Cubit>()`. | ||||||
|  | /// It is used as a dependency injection (DI) widget so that a single instance | ||||||
|  | /// of a [Cubit] can be provided to multiple widgets within a subtree. | ||||||
|  | /// | ||||||
|  | /// It automatically handles closing the instance when used with [create]. | ||||||
|  | /// By default, [create] is called only when the instance is accessed. | ||||||
|  | /// To override this behavior, set [lazy] to `false`. | ||||||
|  | /// | ||||||
|  | /// By default, it provide already provided instance in found in the tree. | ||||||
|  | /// To override this behavior, set [smart] to `false`. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class CubitProviderScreen<Cubit extends blocbase.Cubit<State>, | ||||||
|  |         State extends Object> extends BlocBaseProviderScreen<Cubit, State> | ||||||
|  |     with BlocBaseProviderMixin<Cubit>, RepositoryProviderMixin { | ||||||
|  |   /// {@macro cubit_provider} | ||||||
|  |   const CubitProviderScreen({super.key, super.lazy = true, super.smart = true}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| abstract class CubitConsumerScreen<B extends Cubit<S>, S extends Object> | /// {@template cubit_consumer} | ||||||
|     extends BlocBaseConsumerScreen<B, S> with BlocBaseProviderMixin<B> { | /// [CubitConsumerScreen] exposes [onBuild] and [onListen] in order react | ||||||
|  | /// to new states. | ||||||
|  | /// | ||||||
|  | /// An optional [shouldBuildWhen] and [shouldListenWhen] can be implemented | ||||||
|  | /// for more granular control over when [onListen] and [onBuild] are called. | ||||||
|  | /// The [shouldListenWhen] and [shouldBuildWhen] will be invoked on | ||||||
|  | /// each [Cubit] or `state` change. | ||||||
|  | /// They each take the previous `state` and current `state` and must return | ||||||
|  | /// a [bool] which determines whether or not the [onBuild] and/or [onListen] | ||||||
|  | /// function will be invoked. | ||||||
|  | /// The previous `state` will be initialized to the `state` of the [Cubit] when | ||||||
|  | /// the BlocConsumer is initialized. | ||||||
|  | /// [shouldListenWhen] and [shouldBuildWhen] are optional and if they | ||||||
|  | /// aren't implemented, they will default to `true`. | ||||||
|  | /// | ||||||
|  | /// An optional [onWrap] can also be implemented. This build a wrapper arround | ||||||
|  | /// the built BlocConsumer that is **not** rebuild on each state. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class CubitConsumerScreen<Cubit extends blocbase.Cubit<State>, | ||||||
|  |         State extends Object> extends BlocBaseConsumerScreen<Cubit, State> | ||||||
|  |     with BlocBaseProviderMixin<Cubit>, RepositoryProviderMixin { | ||||||
|  |   /// {@macro cubit_consumer} | ||||||
|   const CubitConsumerScreen({super.key}); |   const CubitConsumerScreen({super.key}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| abstract class CubitScreen<B extends Cubit<S>, S extends Object> | /// {@template cubit_screen} | ||||||
|     extends BlocBaseScreen<B, S> with BlocBaseProviderMixin<B> { | /// Provide AND access to a [Cubit]. | ||||||
|   const CubitScreen({super.key}); | /// | ||||||
|  | /// This extends [CubitConsumerScreen] with the methods | ||||||
|  | // ignore: comment_references | ||||||
|  | /// of [CubitProviderScreen]. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class CubitScreen<Cubit extends blocbase.Cubit<State>, | ||||||
|  |         State extends Object> extends BlocBaseScreen<Cubit, State> | ||||||
|  |     with BlocBaseProviderMixin<Cubit>, RepositoryProviderMixin { | ||||||
|  |   /// {@macro cubit_screen} | ||||||
|  |   const CubitScreen({super.key, super.lazy = true, super.smart = true}); | ||||||
| } | } | ||||||
|  | |||||||
| @ -19,10 +19,14 @@ import 'package:flutter_bloc/flutter_bloc.dart'; | |||||||
| 
 | 
 | ||||||
| /// A mixin that provides implementation of helper methods for | /// A mixin that provides implementation of helper methods for | ||||||
| /// [Bloc] and [Cubit] widgets. | /// [Bloc] and [Cubit] widgets. | ||||||
| mixin BlocBaseProviderMixin<B extends BlocBase<Object>> { | mixin BlocBaseProviderMixin<Bloc extends BlocBase<Object>> { | ||||||
|   /// Returns the [BlocBase] used by this [BlocBaseProviderMixin]. |   /// Returns the [BlocBase] used by this [BlocBaseProviderMixin]. | ||||||
|   B bloc(BuildContext context) => context.read<B>(); |   Bloc bloc(BuildContext context) => context.read<Bloc>(); | ||||||
| 
 | 
 | ||||||
|   /// Returns the [BlocBase] used by this [BlocBaseProviderMixin]. |   /// Returns another [BlocBase] **not** used by this [BlocBaseProviderMixin]. | ||||||
|   R repo<R>(BuildContext context) => context.read<R>(); |   /// Short hand for `context.read<AnotherBloc>();` | ||||||
|  |   ///  | ||||||
|  |   /// To get [BlocBase] used by by this [BlocBaseProviderMixin] see `bloc()` | ||||||
|  |   AnotherBloc anotherBloc<AnotherBloc>(BuildContext context) => | ||||||
|  |       context.read<AnotherBloc>(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,10 +15,14 @@ | |||||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| import 'package:flutter/widgets.dart'; | import 'package:flutter/widgets.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart' as blocbase; | ||||||
| 
 | 
 | ||||||
| /// [Bloc] specific mixin that provides implementation | /// [Bloc] specific mixin that provides implementation | ||||||
| /// of helper methods for events. | /// of helper methods for events. | ||||||
| mixin BlocProviderMixin<B extends Bloc<E, Object>, E> { | mixin BlocProviderMixin<Bloc extends blocbase.Bloc<Event, Object>, Event> { | ||||||
|   void add(BuildContext context, E event) => context.read<B>().add(event); |   /// Add an event to the [Bloc]. | ||||||
|  |   ///  | ||||||
|  |   /// Short hand for `context.read<Bloc>().add(event)`. | ||||||
|  |   void add(BuildContext context, Event event) => | ||||||
|  |       context.read<Bloc>().add(event); | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,26 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/widgets.dart'; | ||||||
|  | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
|  | 
 | ||||||
|  | /// A mixin that provides implementation of helper methods for | ||||||
|  | /// Repository widgets. | ||||||
|  | mixin RepositoryProviderMixin { | ||||||
|  |   /// Returns the [Repository] used by this [Widget]. | ||||||
|  |   Repository repo<Repository>(BuildContext context) => | ||||||
|  |       context.read<Repository>(); | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								packages/wyatt_bloc_helper/lib/src/repo.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								packages/wyatt_bloc_helper/lib/src/repo.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:wyatt_bloc_helper/src/mixins/repository_base_provider_mixin.dart'; | ||||||
|  | import 'package:wyatt_bloc_helper/src/repository/repository_provider_screen.dart'; | ||||||
|  | 
 | ||||||
|  | /// {@template repository_provider} | ||||||
|  | /// Need to implement a [create] function that is responsible for | ||||||
|  | /// creating the [Repository] and a [builder] which will return a child | ||||||
|  | /// that have access to the instance via `context.read<Repository>()`. | ||||||
|  | /// It is used as a dependency injection (DI) widget so that a single instance | ||||||
|  | /// of a [Repository] can be provided to multiple widgets within a subtree. | ||||||
|  | /// | ||||||
|  | /// It automatically handles closing the instance when used with [create]. | ||||||
|  | /// By default, [create] is called only when the instance is accessed. | ||||||
|  | /// To override this behavior, set [lazy] to `false`. | ||||||
|  | /// | ||||||
|  | /// By default, it provide already provided instance found in the tree. | ||||||
|  | /// To override this behavior, set [smart] to `false`. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class RepositoryProviderScreen<Repository> | ||||||
|  |     extends RepositoryBaseProviderScreen<Repository> | ||||||
|  |     with RepositoryProviderMixin { | ||||||
|  |   /// {@macro repository_provider} | ||||||
|  |   const RepositoryProviderScreen({super.key}); | ||||||
|  | } | ||||||
| @ -0,0 +1,67 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:wyatt_bloc_helper/src/utils/smart_provider.dart'; | ||||||
|  | 
 | ||||||
|  | /// {@template repository_base_provider} | ||||||
|  | /// Need to implement a [create] function that is responsible for | ||||||
|  | /// creating the [Repository] and a [builder] which will return a child | ||||||
|  | /// that have access to the instance via `context.read<Repository>()`. | ||||||
|  | /// It is used as a dependency injection (DI) widget so that a single instance | ||||||
|  | /// of a [Repository] can be provided to multiple widgets within a subtree. | ||||||
|  | /// | ||||||
|  | /// It automatically handles closing the instance when used with [create]. | ||||||
|  | /// By default, [create] is called only when the instance is accessed. | ||||||
|  | /// To override this behavior, set [lazy] to `false`. | ||||||
|  | ///  | ||||||
|  | /// By default, it provide already provided instance found in the tree. | ||||||
|  | /// To override this behavior, set [smart] to `false`. | ||||||
|  | /// {@endtemplate} | ||||||
|  | abstract class RepositoryBaseProviderScreen<Repository> | ||||||
|  |     extends StatelessWidget { | ||||||
|  |   /// {@macro repository_base_provider} | ||||||
|  |   const RepositoryBaseProviderScreen({ | ||||||
|  |     super.key, | ||||||
|  |     this.lazy = true, | ||||||
|  |     this.smart = true, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   /// Whether the [Repository] should be created lazily. | ||||||
|  |   /// Defaults to `true` which means the [Repository] is created only when | ||||||
|  |   /// accessed the first time, not when provided. | ||||||
|  |   final bool lazy; | ||||||
|  | 
 | ||||||
|  |   /// Whether this uses [SmartProvider]. | ||||||
|  |   /// Defaults to `true`. But if you want to provide new [Repository] of a  | ||||||
|  |   /// same type in a sub-tree you may have to disable this. | ||||||
|  |   final bool smart; | ||||||
|  | 
 | ||||||
|  |   /// Creates the [Repository] to be used. | ||||||
|  |   Repository create(BuildContext context); | ||||||
|  | 
 | ||||||
|  |   /// Creates the child [Widget] to be used. | ||||||
|  |   Widget builder(BuildContext context); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) => SmartProvider.repo<Repository>( | ||||||
|  |         context, | ||||||
|  |         lazy: lazy, | ||||||
|  |         enable: smart, | ||||||
|  |         create: (_) => create(context), | ||||||
|  |         child: Builder(builder: builder), | ||||||
|  |       ); | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								packages/wyatt_bloc_helper/lib/src/utils/smart_provider.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								packages/wyatt_bloc_helper/lib/src/utils/smart_provider.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | // Copyright (C) 2022 WYATT GROUP | ||||||
|  | // Please see the AUTHORS file for details. | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or | ||||||
|  | // any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/widgets.dart'; | ||||||
|  | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
|  | 
 | ||||||
|  | abstract class SmartProvider { | ||||||
|  |   static BlocProvider<Bloc> | ||||||
|  |       bloc<Bloc extends BlocBase<State>, State extends Object>( | ||||||
|  |     BuildContext context, { | ||||||
|  |     required Bloc Function(BuildContext) create, | ||||||
|  |     Widget? child, | ||||||
|  |     bool lazy = true, | ||||||
|  |     bool enable = true, | ||||||
|  |   }) { | ||||||
|  |     if (enable) { | ||||||
|  |       final bloc = context.read<Bloc?>(); | ||||||
|  |       if (bloc != null) { | ||||||
|  |         return BlocProvider<Bloc>.value( | ||||||
|  |           value: bloc, | ||||||
|  |           child: child, | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return BlocProvider<Bloc>( | ||||||
|  |       lazy: lazy, | ||||||
|  |       create: (_) => create(context), | ||||||
|  |       child: child, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static RepositoryProvider<Repository> repo<Repository>( | ||||||
|  |     BuildContext context, { | ||||||
|  |     required Repository Function(BuildContext) create, | ||||||
|  |     Widget? child, | ||||||
|  |     bool lazy = true, | ||||||
|  |     bool enable = true, | ||||||
|  |   }) { | ||||||
|  |     if (enable) { | ||||||
|  |       final repo = context.read<Repository?>(); | ||||||
|  |       if (repo != null) { | ||||||
|  |         return RepositoryProvider<Repository>.value( | ||||||
|  |           value: repo, | ||||||
|  |           child: child, | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return RepositoryProvider<Repository>( | ||||||
|  |       lazy: lazy, | ||||||
|  |       create: (_) => create(context), | ||||||
|  |       child: child, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -18,3 +18,4 @@ library wyatt_bloc_helper; | |||||||
| 
 | 
 | ||||||
| export 'src/bloc.dart'; | export 'src/bloc.dart'; | ||||||
| export 'src/cubit.dart'; | export 'src/cubit.dart'; | ||||||
|  | export 'src/repo.dart'; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user