CRUD: move firestore implementation in his own package #231
| @ -33,11 +33,11 @@ class AdvancedCubitView extends StatelessWidget { | |||||||
|       ), |       ), | ||||||
|       body: BlocProvider( |       body: BlocProvider( | ||||||
|         create: (context) => |         create: (context) => | ||||||
|             UserAdvancedCubit(context.read<CrudRepository<User>>())..getAll(), |             UserAdvancedCubit(context.read<CrudRepository<User>>()) | ||||||
|  |               ..streaming(), | ||||||
|         child: Builder(builder: (context) { |         child: Builder(builder: (context) { | ||||||
|           return Column( |           return Column( | ||||||
|             children: [ |             children: [ | ||||||
|               const Text("Data:"), |  | ||||||
|               BlocBuilder<UserAdvancedCubit, CrudState>( |               BlocBuilder<UserAdvancedCubit, CrudState>( | ||||||
|                 buildWhen: (previous, current) { |                 buildWhen: (previous, current) { | ||||||
|                   if (current is CrudLoading && current is! CrudReading) { |                   if (current is CrudLoading && current is! CrudReading) { | ||||||
| @ -117,31 +117,6 @@ class AdvancedCubitView extends StatelessWidget { | |||||||
|                   }, |                   }, | ||||||
|                 ), |                 ), | ||||||
|               ), |               ), | ||||||
|               ElevatedButton( |  | ||||||
|                 onPressed: () { |  | ||||||
|                   context.read<UserAdvancedCubit>().getAll(); |  | ||||||
|                 }, |  | ||||||
|                 child: BlocBuilder<UserAdvancedCubit, CrudState>( |  | ||||||
|                   buildWhen: (previous, current) { |  | ||||||
|                     if (current is CrudLoading && current is! CrudReading) { |  | ||||||
|                       return false; |  | ||||||
|                     } |  | ||||||
|                     return true; |  | ||||||
|                   }, |  | ||||||
|                   builder: (context, state) { |  | ||||||
|                     return state is CrudReading |  | ||||||
|                         ? const SizedBox( |  | ||||||
|                             width: 20, |  | ||||||
|                             height: 20, |  | ||||||
|                             child: CircularProgressIndicator( |  | ||||||
|                               color: Colors.white, |  | ||||||
|                             ), |  | ||||||
|                           ) |  | ||||||
|                         : const Text("GetAll"); |  | ||||||
|                   }, |  | ||||||
|                 ), |  | ||||||
|               ), |  | ||||||
|               const SizedBox(height: 20), |  | ||||||
|             ], |             ], | ||||||
|           ); |           ); | ||||||
|         }), |         }), | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ | |||||||
| 
 | 
 | ||||||
| import 'package:crud_bloc_example/advanced_cubit_view.dart'; | import 'package:crud_bloc_example/advanced_cubit_view.dart'; | ||||||
| import 'package:crud_bloc_example/basic_cubit_view.dart'; | import 'package:crud_bloc_example/basic_cubit_view.dart'; | ||||||
|  | import 'package:crud_bloc_example/streaming_cubit_view.dart'; | ||||||
| import 'package:crud_bloc_example/user_entity.dart'; | import 'package:crud_bloc_example/user_entity.dart'; | ||||||
| import 'package:crud_bloc_example/user_model.dart'; | import 'package:crud_bloc_example/user_model.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| @ -65,32 +66,47 @@ class MyHomePage extends StatelessWidget { | |||||||
|       appBar: AppBar( |       appBar: AppBar( | ||||||
|         title: const Text('Flutter Demo Home Page'), |         title: const Text('Flutter Demo Home Page'), | ||||||
|       ), |       ), | ||||||
|       body: Column( |       body: Center( | ||||||
|         children: [ |         child: Column( | ||||||
|           ElevatedButton( |           mainAxisAlignment: MainAxisAlignment.center, | ||||||
|             onPressed: () { |           children: [ | ||||||
|               Navigator.push( |             ElevatedButton( | ||||||
|                 context, |               onPressed: () { | ||||||
|                 MaterialPageRoute( |                 Navigator.push( | ||||||
|                   builder: (context) => const BasicCubitView(), |                   context, | ||||||
|                 ), |                   MaterialPageRoute( | ||||||
|               ); |                     builder: (context) => const BasicCubitView(), | ||||||
|             }, |                   ), | ||||||
|             child: const Text('Basic example'), |                 ); | ||||||
|           ), |               }, | ||||||
|           const SizedBox(height: 20), |               child: const Text('Basic example'), | ||||||
|           ElevatedButton( |             ), | ||||||
|             onPressed: () { |             const SizedBox(height: 20), | ||||||
|               Navigator.push( |             ElevatedButton( | ||||||
|                 context, |               onPressed: () { | ||||||
|                 MaterialPageRoute( |                 Navigator.push( | ||||||
|                   builder: (context) => const AdvancedCubitView(), |                   context, | ||||||
|                 ), |                   MaterialPageRoute( | ||||||
|               ); |                     builder: (context) => const StreamingCubitView(), | ||||||
|             }, |                   ), | ||||||
|             child: const Text('Advanced example'), |                 ); | ||||||
|           ), |               }, | ||||||
|         ], |               child: const Text('Streaming example'), | ||||||
|  |             ), | ||||||
|  |             const SizedBox(height: 20), | ||||||
|  |             ElevatedButton( | ||||||
|  |               onPressed: () { | ||||||
|  |                 Navigator.push( | ||||||
|  |                   context, | ||||||
|  |                   MaterialPageRoute( | ||||||
|  |                     builder: (context) => const AdvancedCubitView(), | ||||||
|  |                   ), | ||||||
|  |                 ); | ||||||
|  |               }, | ||||||
|  |               child: const Text('Advanced example'), | ||||||
|  |             ), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | |||||||
							
								
								
									
										125
									
								
								packages/wyatt_crud_bloc/example/lib/streaming_cubit_view.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								packages/wyatt_crud_bloc/example/lib/streaming_cubit_view.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,125 @@ | |||||||
|  | // Copyright (C) 2023 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 'dart:math'; | ||||||
|  | 
 | ||||||
|  | import 'package:crud_bloc_example/user_entity.dart'; | ||||||
|  | import 'package:crud_bloc_example/user_streaming_cubit.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
|  | import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; | ||||||
|  | 
 | ||||||
|  | class StreamingCubitView extends StatelessWidget { | ||||||
|  |   const StreamingCubitView({super.key}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Scaffold( | ||||||
|  |       appBar: AppBar( | ||||||
|  |         title: const Text("Streaming Cubit"), | ||||||
|  |       ), | ||||||
|  |       body: BlocProvider( | ||||||
|  |         create: (context) => | ||||||
|  |             UserStreamingCubit(context.read<CrudRepository<User>>())..read(), | ||||||
|  |         child: Builder(builder: (context) { | ||||||
|  |           return Column( | ||||||
|  |             children: [ | ||||||
|  |               BlocBuilder<UserStreamingCubit, CrudState>( | ||||||
|  |                 buildWhen: (previous, current) { | ||||||
|  |                   if (current is CrudLoading && current is! CrudReading) { | ||||||
|  |                     return false; | ||||||
|  |                   } | ||||||
|  |                   return true; | ||||||
|  |                 }, | ||||||
|  |                 builder: (context, state) { | ||||||
|  |                   return Expanded( | ||||||
|  |                     child: CrudBuilder.typed<CrudListLoaded<User?>>( | ||||||
|  |                       state: state, | ||||||
|  |                       builder: ((context, state) { | ||||||
|  |                         return ListView.builder( | ||||||
|  |                           itemCount: state.data.length, | ||||||
|  |                           itemBuilder: (context, index) { | ||||||
|  |                             final user = state.data.elementAt(index); | ||||||
|  |                             return ListTile( | ||||||
|  |                               title: Text(user?.name ?? 'Error'), | ||||||
|  |                               subtitle: Text(user?.email ?? 'Error'), | ||||||
|  |                               onTap: () { | ||||||
|  |                                 context | ||||||
|  |                                     .read<UserStreamingCubit>() | ||||||
|  |                                     .delete(id: (user?.id)!); | ||||||
|  |                               }, | ||||||
|  |                               onLongPress: () { | ||||||
|  |                                 context.read<UserStreamingCubit>().update( | ||||||
|  |                                       single: UpdateParameters( | ||||||
|  |                                           id: user?.id ?? '', | ||||||
|  |                                           raw: { | ||||||
|  |                                             'email': '${user?.id}@updated.io', | ||||||
|  |                                           }), | ||||||
|  |                                     ); | ||||||
|  |                               }, | ||||||
|  |                             ); | ||||||
|  |                           }, | ||||||
|  |                         ); | ||||||
|  |                       }), | ||||||
|  |                       initialBuilder: (context, state) => | ||||||
|  |                           const Center(child: CircularProgressIndicator()), | ||||||
|  |                       loadingBuilder: (context, state) => | ||||||
|  |                           const Center(child: CircularProgressIndicator()), | ||||||
|  |                       errorBuilder: (context, state) => Text("Error: $state"), | ||||||
|  |                     ), | ||||||
|  |                   ); | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |               const SizedBox(height: 20), | ||||||
|  |               ElevatedButton( | ||||||
|  |                 onPressed: () { | ||||||
|  |                   final r = Random().nextInt(1000); | ||||||
|  |                   context.read<UserStreamingCubit>().create( | ||||||
|  |                         User( | ||||||
|  |                           id: '$r', | ||||||
|  |                           name: 'Wyatt $r', | ||||||
|  |                           email: '$r@wyattapp.io', | ||||||
|  |                           phone: '06$r', | ||||||
|  |                         ), | ||||||
|  |                       ); | ||||||
|  |                 }, | ||||||
|  |                 child: BlocBuilder<UserStreamingCubit, CrudState>( | ||||||
|  |                   buildWhen: (previous, current) { | ||||||
|  |                     if (current is CrudLoading && current is! CrudCreating) { | ||||||
|  |                       return false; | ||||||
|  |                     } | ||||||
|  |                     return true; | ||||||
|  |                   }, | ||||||
|  |                   builder: (context, state) { | ||||||
|  |                     return state is CrudCreating | ||||||
|  |                         ? const SizedBox( | ||||||
|  |                             width: 20, | ||||||
|  |                             height: 20, | ||||||
|  |                             child: CircularProgressIndicator( | ||||||
|  |                               color: Colors.white, | ||||||
|  |                             ), | ||||||
|  |                           ) | ||||||
|  |                         : const Text("Create"); | ||||||
|  |                   }, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ); | ||||||
|  |         }), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -46,6 +46,9 @@ class UserAdvancedCubit extends CrudAdvancedCubit<User> { | |||||||
|   @override |   @override | ||||||
|   Search<User>? get crudSearch => Search(crudRepository); |   Search<User>? get crudSearch => Search(crudRepository); | ||||||
| 
 | 
 | ||||||
|  |   @override | ||||||
|  |   Streaming<User>? get crudStreaming => Streaming(crudRepository); | ||||||
|  | 
 | ||||||
|   @override |   @override | ||||||
|   Update<User>? get crudUpdate => Update(crudRepository); |   Update<User>? get crudUpdate => Update(crudRepository); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -0,0 +1,42 @@ | |||||||
|  | // 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:crud_bloc_example/user_entity.dart'; | ||||||
|  | import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; | ||||||
|  | 
 | ||||||
|  | /// A [CrudCubit] for [User]. | ||||||
|  | class UserStreamingCubit extends CrudCubit<User> { | ||||||
|  |   final CrudRepository<User> crudRepository; | ||||||
|  | 
 | ||||||
|  |   UserStreamingCubit(this.crudRepository); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   DefaultCreate<User>? get createOperation => Create(crudRepository); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   DefaultDelete? get deleteOperation => Delete(crudRepository); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   DefaultRead? get readOperation => Streaming(crudRepository); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   DefaultUpdate? get updateOperation => Update(crudRepository); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   ModelIdentifier<User> get modelIdentifier => ModelIdentifier( | ||||||
|  |         getIdentifier: (user) => user.id ?? '', | ||||||
|  |       ); | ||||||
|  | } | ||||||
| @ -16,6 +16,7 @@ | |||||||
| 
 | 
 | ||||||
| import 'dart:async'; | import 'dart:async'; | ||||||
| 
 | 
 | ||||||
|  | import 'package:rxdart/subjects.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/core/enums/operation_type.dart'; | import 'package:wyatt_crud_bloc/src/core/enums/operation_type.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; | import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/data/data_sources/crud_data_source.dart'; | import 'package:wyatt_crud_bloc/src/data/data_sources/crud_data_source.dart'; | ||||||
| @ -58,8 +59,8 @@ class CrudDataSourceInMemoryImpl extends CrudDataSource { | |||||||
|   }) : _data = data ?? {}; |   }) : _data = data ?? {}; | ||||||
| 
 | 
 | ||||||
|   final Map<String, Map<String, dynamic>> _data; |   final Map<String, Map<String, dynamic>> _data; | ||||||
|   final StreamController<List<Map<String, dynamic>?>> _streamData = |   final BehaviorSubject<List<Map<String, dynamic>?>> _streamData = | ||||||
|       StreamController(); |       BehaviorSubject<List<Map<String, dynamic>?>>.seeded([]); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Future<void> create(Map<String, dynamic> object, {String? id}) async { |   Future<void> create(Map<String, dynamic> object, {String? id}) async { | ||||||
| @ -142,7 +143,7 @@ class CrudDataSourceInMemoryImpl extends CrudDataSource { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return res; |         return res; | ||||||
|       }).asBroadcastStream(); |       }); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Future<void> update( |   Future<void> update( | ||||||
|  | |||||||
| @ -20,14 +20,14 @@ import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart'; | |||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/usecases.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/usecases.dart'; | ||||||
| import 'package:wyatt_type_utils/wyatt_type_utils.dart'; | import 'package:wyatt_type_utils/wyatt_type_utils.dart'; | ||||||
| 
 | 
 | ||||||
| /// {@template stream} | /// {@template streaming} | ||||||
| /// A use case that streams the object models. | /// A use case that streams the object models. | ||||||
| /// {@endtemplate} | /// {@endtemplate} | ||||||
| class Stream<Model> | class Streaming<Model> | ||||||
|     extends Usecase<StreamParameters, StreamResult<List<Model?>>> |     extends Usecase<StreamParameters, StreamResult<List<Model?>>> | ||||||
|     with ReadOperation<StreamParameters, StreamResult<List<Model?>>> { |     with ReadOperation<StreamParameters, StreamResult<List<Model?>>> { | ||||||
|   /// {@macro stream} |   /// {@macro streaming} | ||||||
|   const Stream(this.crudRepository); |   const Streaming(this.crudRepository); | ||||||
| 
 | 
 | ||||||
|   final CrudRepository<Model> crudRepository; |   final CrudRepository<Model> crudRepository; | ||||||
| 
 | 
 | ||||||
| @ -26,6 +26,7 @@ export 'get.dart'; | |||||||
| export 'get_all.dart'; | export 'get_all.dart'; | ||||||
| export 'params/params.dart'; | export 'params/params.dart'; | ||||||
| export 'search.dart'; | export 'search.dart'; | ||||||
|  | export 'streaming.dart'; | ||||||
| export 'update.dart'; | export 'update.dart'; | ||||||
| export 'update_all.dart'; | export 'update_all.dart'; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ | |||||||
| 
 | 
 | ||||||
| import 'dart:async'; | import 'dart:async'; | ||||||
| 
 | 
 | ||||||
|  | import 'package:wyatt_architecture/wyatt_architecture.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; | import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/core/model_identifier.dart'; | import 'package:wyatt_crud_bloc/src/core/model_identifier.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; | import 'package:wyatt_crud_bloc/src/domain/entities/query.dart'; | ||||||
| @ -24,11 +25,14 @@ import 'package:wyatt_crud_bloc/src/domain/usecases/delete.dart'; | |||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/delete_all.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/delete_all.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/get.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/get.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/get_all.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/get_all.dart'; | ||||||
|  | import 'package:wyatt_crud_bloc/src/domain/usecases/params/stream_parameters.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/search.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/search.dart'; | ||||||
|  | import 'package:wyatt_crud_bloc/src/domain/usecases/streaming.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/update.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/update.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/update_all.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/update_all.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart'; | import 'package:wyatt_crud_bloc/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart'; | ||||||
|  | import 'package:wyatt_type_utils/wyatt_type_utils.dart'; | ||||||
| 
 | 
 | ||||||
| /// {@template crud_cubit_advanced} | /// {@template crud_cubit_advanced} | ||||||
| /// Cubit that handles CRUD operations with more granularity. | /// Cubit that handles CRUD operations with more granularity. | ||||||
| @ -43,6 +47,7 @@ abstract class CrudAdvancedCubit<Model> extends CrudBaseCubit { | |||||||
|   GetAll<Model>? get crudGetAll; |   GetAll<Model>? get crudGetAll; | ||||||
|   Get<Model>? get crudGet; |   Get<Model>? get crudGet; | ||||||
|   Search<Model>? get crudSearch; |   Search<Model>? get crudSearch; | ||||||
|  |   Streaming<Model>? get crudStreaming; | ||||||
|   UpdateAll<Model>? get crudUpdateAll; |   UpdateAll<Model>? get crudUpdateAll; | ||||||
|   Update<Model>? get crudUpdate; |   Update<Model>? get crudUpdate; | ||||||
| 
 | 
 | ||||||
| @ -50,6 +55,8 @@ abstract class CrudAdvancedCubit<Model> extends CrudBaseCubit { | |||||||
|   /// Used to identify a model. |   /// Used to identify a model. | ||||||
|   ModelIdentifier<Model> get modelIdentifier; |   ModelIdentifier<Model> get modelIdentifier; | ||||||
| 
 | 
 | ||||||
|  |   StreamSubscription<Result<List<Model?>, AppException>>? _streamSubscription; | ||||||
|  | 
 | ||||||
|   FutureOr<void> create(Model model) async { |   FutureOr<void> create(Model model) async { | ||||||
|     final crud = crudCreate; |     final crud = crudCreate; | ||||||
|     if (crud == null) { |     if (crud == null) { | ||||||
| @ -59,6 +66,10 @@ abstract class CrudAdvancedCubit<Model> extends CrudBaseCubit { | |||||||
|     final stateCopy = state; |     final stateCopy = state; | ||||||
|     emit(const CrudCreating()); |     emit(const CrudCreating()); | ||||||
|     final result = await crud.call(model); |     final result = await crud.call(model); | ||||||
|  |     if (crudStreaming != null && _streamSubscription != null && result.isOk) { | ||||||
|  |       // If streaming is available, we don't need to update stateCopy. | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     emit( |     emit( | ||||||
|       result.fold( |       result.fold( | ||||||
|         (_) { |         (_) { | ||||||
| @ -97,6 +108,10 @@ abstract class CrudAdvancedCubit<Model> extends CrudBaseCubit { | |||||||
|     final stateCopy = state; |     final stateCopy = state; | ||||||
|     emit(const CrudDeleting()); |     emit(const CrudDeleting()); | ||||||
|     final result = await crud.call(id); |     final result = await crud.call(id); | ||||||
|  |     if (crudStreaming != null && _streamSubscription != null && result.isOk) { | ||||||
|  |       // If streaming is available, we don't need to update stateCopy. | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     emit( |     emit( | ||||||
|       result.fold( |       result.fold( | ||||||
|         (_) { |         (_) { | ||||||
| @ -139,6 +154,10 @@ abstract class CrudAdvancedCubit<Model> extends CrudBaseCubit { | |||||||
|     final stateCopy = state; |     final stateCopy = state; | ||||||
|     emit(const CrudDeleting()); |     emit(const CrudDeleting()); | ||||||
|     final result = await crud.call(null); |     final result = await crud.call(null); | ||||||
|  |     if (crudStreaming != null && _streamSubscription != null && result.isOk) { | ||||||
|  |       // If streaming is available, we don't need to update stateCopy. | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     emit( |     emit( | ||||||
|       result.fold( |       result.fold( | ||||||
|         (_) { |         (_) { | ||||||
| @ -202,6 +221,31 @@ abstract class CrudAdvancedCubit<Model> extends CrudBaseCubit { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   FutureOr<void> streaming({ | ||||||
|  |     String? id, | ||||||
|  |     List<Query>? conditions, | ||||||
|  |   }) async { | ||||||
|  |     final crud = crudStreaming; | ||||||
|  |     if (crud == null) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     final result = await crud.call( | ||||||
|  |       StreamParameters( | ||||||
|  |         id: id, | ||||||
|  |         conditions: conditions, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     _streamSubscription = result.ok?.listen((event) { | ||||||
|  |       emit( | ||||||
|  |         event.fold( | ||||||
|  |           CrudListLoaded<Model?>.new, | ||||||
|  |           (error) => CrudError(error.toString()), | ||||||
|  |         ), | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   FutureOr<void> update(UpdateParameters<Model> param) async { |   FutureOr<void> update(UpdateParameters<Model> param) async { | ||||||
|     final crud = crudUpdate; |     final crud = crudUpdate; | ||||||
|     if (crud == null) { |     if (crud == null) { | ||||||
| @ -211,6 +255,10 @@ abstract class CrudAdvancedCubit<Model> extends CrudBaseCubit { | |||||||
|     final stateCopy = state; |     final stateCopy = state; | ||||||
|     emit(const CrudUpdating()); |     emit(const CrudUpdating()); | ||||||
|     final result = await crud.call(param); |     final result = await crud.call(param); | ||||||
|  |     if (crudStreaming != null && _streamSubscription != null && result.isOk) { | ||||||
|  |       // If streaming is available, we don't need to update stateCopy. | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     emit( |     emit( | ||||||
|       await result.foldAsync( |       await result.foldAsync( | ||||||
|         (_) async { |         (_) async { | ||||||
| @ -284,6 +332,10 @@ abstract class CrudAdvancedCubit<Model> extends CrudBaseCubit { | |||||||
|     final stateCopy = state; |     final stateCopy = state; | ||||||
|     emit(const CrudUpdating()); |     emit(const CrudUpdating()); | ||||||
|     final result = await crud.call(param); |     final result = await crud.call(param); | ||||||
|  |     if (crudStreaming != null && _streamSubscription != null && result.isOk) { | ||||||
|  |       // If streaming is available, we don't need to update stateCopy. | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     emit( |     emit( | ||||||
|       await result.foldAsync( |       await result.foldAsync( | ||||||
|         (_) async { |         (_) async { | ||||||
| @ -334,4 +386,10 @@ abstract class CrudAdvancedCubit<Model> extends CrudBaseCubit { | |||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<void> close() async { | ||||||
|  |     await _streamSubscription?.cancel(); | ||||||
|  |     return super.close(); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ | |||||||
| 
 | 
 | ||||||
| import 'dart:async'; | import 'dart:async'; | ||||||
| 
 | 
 | ||||||
|  | import 'package:wyatt_architecture/wyatt_architecture.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; | import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; | import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/core/model_identifier.dart'; | import 'package:wyatt_crud_bloc/src/core/model_identifier.dart'; | ||||||
| @ -25,11 +26,14 @@ import 'package:wyatt_crud_bloc/src/domain/usecases/delete.dart'; | |||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/delete_all.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/delete_all.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/get.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/get.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/get_all.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/get_all.dart'; | ||||||
|  | import 'package:wyatt_crud_bloc/src/domain/usecases/params/stream_parameters.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/search.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/search.dart'; | ||||||
|  | import 'package:wyatt_crud_bloc/src/domain/usecases/streaming.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/update.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/update.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/domain/usecases/update_all.dart'; | import 'package:wyatt_crud_bloc/src/domain/usecases/update_all.dart'; | ||||||
| import 'package:wyatt_crud_bloc/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart'; | import 'package:wyatt_crud_bloc/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart'; | ||||||
|  | import 'package:wyatt_type_utils/wyatt_type_utils.dart'; | ||||||
| 
 | 
 | ||||||
| typedef DefaultCreate<Model> = CreateOperation<Model, void>; | typedef DefaultCreate<Model> = CreateOperation<Model, void>; | ||||||
| typedef DefaultRead = ReadOperation<dynamic, dynamic>; | typedef DefaultRead = ReadOperation<dynamic, dynamic>; | ||||||
| @ -63,6 +67,8 @@ abstract class CrudCubit<Model> extends CrudBaseCubit { | |||||||
|   /// Used to identify a model. |   /// Used to identify a model. | ||||||
|   ModelIdentifier<Model> get modelIdentifier; |   ModelIdentifier<Model> get modelIdentifier; | ||||||
| 
 | 
 | ||||||
|  |   StreamSubscription<Result<List<Model?>, AppException>>? _streamSubscription; | ||||||
|  | 
 | ||||||
|   Expected? _checkOperation<Expected>(dynamic operation) { |   Expected? _checkOperation<Expected>(dynamic operation) { | ||||||
|     if (operation == null) { |     if (operation == null) { | ||||||
|       return null; |       return null; | ||||||
| @ -90,9 +96,11 @@ abstract class CrudCubit<Model> extends CrudBaseCubit { | |||||||
|         conditions != null) { |         conditions != null) { | ||||||
|       return _search(conditions); |       return _search(conditions); | ||||||
|     } |     } | ||||||
|     if (_checkOperation<Stream<Model>>(readOperation) != null && |     if (_checkOperation<Streaming<Model>>(readOperation) != null) { | ||||||
|         conditions == null) { |       return _streaming( | ||||||
|       return _getAll(); |         id: id, | ||||||
|  |         conditions: conditions, | ||||||
|  |       ); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -129,6 +137,11 @@ abstract class CrudCubit<Model> extends CrudBaseCubit { | |||||||
|     final stateCopy = state; |     final stateCopy = state; | ||||||
|     emit(const CrudCreating()); |     emit(const CrudCreating()); | ||||||
|     final result = await crud.call(model); |     final result = await crud.call(model); | ||||||
|  |     final crudStreaming = _checkOperation<Streaming<Model>>(readOperation); | ||||||
|  |     if (crudStreaming != null && _streamSubscription != null && result.isOk) { | ||||||
|  |       // If streaming is available, we don't need to update stateCopy. | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     emit( |     emit( | ||||||
|       result.fold( |       result.fold( | ||||||
|         (_) { |         (_) { | ||||||
| @ -167,6 +180,11 @@ abstract class CrudCubit<Model> extends CrudBaseCubit { | |||||||
|     final stateCopy = state; |     final stateCopy = state; | ||||||
|     emit(const CrudDeleting()); |     emit(const CrudDeleting()); | ||||||
|     final result = await crud.call(id); |     final result = await crud.call(id); | ||||||
|  |     final crudStreaming = _checkOperation<Streaming<Model>>(readOperation); | ||||||
|  |     if (crudStreaming != null && _streamSubscription != null && result.isOk) { | ||||||
|  |       // If streaming is available, we don't need to update stateCopy. | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     emit( |     emit( | ||||||
|       result.fold( |       result.fold( | ||||||
|         (_) { |         (_) { | ||||||
| @ -209,6 +227,11 @@ abstract class CrudCubit<Model> extends CrudBaseCubit { | |||||||
|     final stateCopy = state; |     final stateCopy = state; | ||||||
|     emit(const CrudDeleting()); |     emit(const CrudDeleting()); | ||||||
|     final result = await crud.call(null); |     final result = await crud.call(null); | ||||||
|  |     final crudStreaming = _checkOperation<Streaming<Model>>(readOperation); | ||||||
|  |     if (crudStreaming != null && _streamSubscription != null && result.isOk) { | ||||||
|  |       // If streaming is available, we don't need to update stateCopy. | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     emit( |     emit( | ||||||
|       result.fold( |       result.fold( | ||||||
|         (_) { |         (_) { | ||||||
| @ -256,6 +279,31 @@ abstract class CrudCubit<Model> extends CrudBaseCubit { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   FutureOr<void> _streaming({ | ||||||
|  |     String? id, | ||||||
|  |     List<Query>? conditions, | ||||||
|  |   }) async { | ||||||
|  |     final crud = _checkOperation<Streaming<Model>>(readOperation); | ||||||
|  |     if (crud == null) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     final result = await crud.call( | ||||||
|  |       StreamParameters( | ||||||
|  |         id: id, | ||||||
|  |         conditions: conditions, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     _streamSubscription = result.ok?.listen((event) { | ||||||
|  |       emit( | ||||||
|  |         event.fold( | ||||||
|  |           CrudListLoaded<Model?>.new, | ||||||
|  |           (error) => CrudError(error.toString()), | ||||||
|  |         ), | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   FutureOr<void> _search(List<Query> conditions) async { |   FutureOr<void> _search(List<Query> conditions) async { | ||||||
|     final crud = _checkOperation<Search<Model>>(readOperation); |     final crud = _checkOperation<Search<Model>>(readOperation); | ||||||
|     if (crud == null) { |     if (crud == null) { | ||||||
| @ -281,6 +329,11 @@ abstract class CrudCubit<Model> extends CrudBaseCubit { | |||||||
|     final stateCopy = state; |     final stateCopy = state; | ||||||
|     emit(const CrudUpdating()); |     emit(const CrudUpdating()); | ||||||
|     final result = await crud.call(param); |     final result = await crud.call(param); | ||||||
|  |     final crudStreaming = _checkOperation<Streaming<Model>>(readOperation); | ||||||
|  |     if (crudStreaming != null && _streamSubscription != null && result.isOk) { | ||||||
|  |       // If streaming is available, we don't need to update stateCopy. | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     emit( |     emit( | ||||||
|       await result.foldAsync( |       await result.foldAsync( | ||||||
|         (_) async { |         (_) async { | ||||||
| @ -360,6 +413,11 @@ abstract class CrudCubit<Model> extends CrudBaseCubit { | |||||||
|     final stateCopy = state; |     final stateCopy = state; | ||||||
|     emit(const CrudUpdating()); |     emit(const CrudUpdating()); | ||||||
|     final result = await crud.call(param); |     final result = await crud.call(param); | ||||||
|  |     final crudStreaming = _checkOperation<Streaming<Model>>(readOperation); | ||||||
|  |     if (crudStreaming != null && _streamSubscription != null && result.isOk) { | ||||||
|  |       // If streaming is available, we don't need to update stateCopy. | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     emit( |     emit( | ||||||
|       await result.foldAsync( |       await result.foldAsync( | ||||||
|         (_) async { |         (_) async { | ||||||
| @ -410,4 +468,10 @@ abstract class CrudCubit<Model> extends CrudBaseCubit { | |||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<void> close() async { | ||||||
|  |     await _streamSubscription?.cancel(); | ||||||
|  |     return super.close(); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ dependencies: | |||||||
|   wyatt_type_utils: |   wyatt_type_utils: | ||||||
|     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
|     version: ^0.0.5 |     version: ^0.0.5 | ||||||
|  |   rxdart: ^0.27.7 | ||||||
| 
 | 
 | ||||||
| dev_dependencies: | dev_dependencies: | ||||||
|   flutter_test: { sdk: flutter } |   flutter_test: { sdk: flutter } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user