Add Supabase implementation for CRUD #238
							
								
								
									
										46
									
								
								packages/wyatt_crud_bloc/example/lib/main_supabase.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								packages/wyatt_crud_bloc/example/lib/main_supabase.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | // 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/app.dart'; | ||||||
|  | import 'package:crud_bloc_example/app_bloc_observer.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
|  | import 'package:supabase_flutter/supabase_flutter.dart'; | ||||||
|  | import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart'; | ||||||
|  | import 'package:wyatt_crud_bloc_supabase/wyatt_crud_bloc_supabase.dart'; | ||||||
|  | 
 | ||||||
|  | const supabaseUrl = 'https://yarkjotsulnccxdkztiv.supabase.co'; | ||||||
|  | const supabaseKey = String.fromEnvironment('SUPABASE_KEY'); | ||||||
|  | 
 | ||||||
|  | Future<void> main() async { | ||||||
|  |   WidgetsFlutterBinding.ensureInitialized(); | ||||||
|  |   Bloc.observer = AppBlocObserver(); | ||||||
|  | 
 | ||||||
|  |   await Supabase.initialize( | ||||||
|  |     url: supabaseUrl, | ||||||
|  |     anonKey: supabaseKey, | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   final CrudDataSource crudDataSource = CrudDataSourceSupabaseImpl( | ||||||
|  |     'users', | ||||||
|  |     id: (_, json) => json['id'] as String, | ||||||
|  |     getIdKey: (_) => 'id', | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   runApp(MyApp( | ||||||
|  |     crudDataSource: crudDataSource, | ||||||
|  |   )); | ||||||
|  | } | ||||||
| @ -33,11 +33,14 @@ dependencies: | |||||||
|   equatable: ^2.0.5 |   equatable: ^2.0.5 | ||||||
|   firebase_core: ^2.22.0 |   firebase_core: ^2.22.0 | ||||||
|   cloud_firestore: ^4.13.0 |   cloud_firestore: ^4.13.0 | ||||||
|  |   supabase_flutter: ^2.3.4 | ||||||
|   flutter_bloc: ^8.1.3 |   flutter_bloc: ^8.1.3 | ||||||
|   wyatt_crud_bloc: |   wyatt_crud_bloc: | ||||||
|     path: "../" |     path: "../" | ||||||
|   wyatt_crud_bloc_firestore: |   wyatt_crud_bloc_firestore: | ||||||
|     path: "../wyatt_crud_bloc_firestore" |     path: "../wyatt_crud_bloc_firestore" | ||||||
|  |   wyatt_crud_bloc_supabase: | ||||||
|  |     path: "../wyatt_crud_bloc_supabase" | ||||||
|    |    | ||||||
|   wyatt_architecture: |   wyatt_architecture: | ||||||
|     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ |     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/.gitignore
									
									
									
									
										vendored
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/.gitignore
									
									
									
									
										vendored
									
									
										Symbolic link
									
								
							| @ -0,0 +1 @@ | |||||||
|  | ../../../.gitignore | ||||||
							
								
								
									
										10
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/.metadata
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/.metadata
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | # This file tracks properties of this Flutter project. | ||||||
|  | # Used by Flutter tool to assess capabilities and perform upgrades etc. | ||||||
|  | # | ||||||
|  | # This file should be version controlled and should not be manually edited. | ||||||
|  | 
 | ||||||
|  | version: | ||||||
|  |   revision: "d211f42860350d914a5ad8102f9ec32764dc6d06" | ||||||
|  |   channel: "stable" | ||||||
|  | 
 | ||||||
|  | project_type: package | ||||||
							
								
								
									
										1
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/.pubignore
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/.pubignore
									
									
									
									
									
										Symbolic link
									
								
							| @ -0,0 +1 @@ | |||||||
|  | ../../../.pubignore | ||||||
							
								
								
									
										1
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/AUTHORS
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/AUTHORS
									
									
									
									
									
										Symbolic link
									
								
							| @ -0,0 +1 @@ | |||||||
|  | ../../../AUTHORS | ||||||
| @ -0,0 +1,3 @@ | |||||||
|  | ## 0.0.1 | ||||||
|  | 
 | ||||||
|  | * TODO: Describe initial release. | ||||||
							
								
								
									
										1
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/LICENSE
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/LICENSE
									
									
									
									
									
										Symbolic link
									
								
							| @ -0,0 +1 @@ | |||||||
|  | ../../../LICENSE | ||||||
							
								
								
									
										39
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								packages/wyatt_crud_bloc/wyatt_crud_bloc_supabase/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | <!-- | ||||||
|  | This README describes the package. If you publish this package to pub.dev, | ||||||
|  | this README's contents appear on the landing page for your package. | ||||||
|  | 
 | ||||||
|  | For information about how to write a good package README, see the guide for | ||||||
|  | [writing package pages](https://dart.dev/guides/libraries/writing-package-pages). | ||||||
|  | 
 | ||||||
|  | For general information about developing packages, see the Dart guide for | ||||||
|  | [creating packages](https://dart.dev/guides/libraries/create-library-packages) | ||||||
|  | and the Flutter guide for | ||||||
|  | [developing packages and plugins](https://flutter.dev/developing-packages). | ||||||
|  | --> | ||||||
|  | 
 | ||||||
|  | TODO: Put a short description of the package here that helps potential users | ||||||
|  | know whether this package might be useful for them. | ||||||
|  | 
 | ||||||
|  | ## Features | ||||||
|  | 
 | ||||||
|  | TODO: List what your package can do. Maybe include images, gifs, or videos. | ||||||
|  | 
 | ||||||
|  | ## Getting started | ||||||
|  | 
 | ||||||
|  | TODO: List prerequisites and provide or point to information on how to | ||||||
|  | start using the package. | ||||||
|  | 
 | ||||||
|  | ## Usage | ||||||
|  | 
 | ||||||
|  | TODO: Include short and useful examples for package users. Add longer examples | ||||||
|  | to `/example` folder. | ||||||
|  | 
 | ||||||
|  | ```dart | ||||||
|  | const like = 'sample'; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Additional information | ||||||
|  | 
 | ||||||
|  | TODO: Tell users more about the package: where to find more information, how to | ||||||
|  | contribute to the package, how to file issues, what response they can expect | ||||||
|  | from the package authors, and more. | ||||||
| @ -0,0 +1 @@ | |||||||
|  | include: package:wyatt_analysis/analysis_options.flutter.yaml | ||||||
| @ -0,0 +1,255 @@ | |||||||
|  | // 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 'package:supabase_flutter/supabase_flutter.dart'; | ||||||
|  | import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart' as crud show Query; | ||||||
|  | import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart' hide Query; | ||||||
|  | 
 | ||||||
|  | typedef QueryBuilder = PostgrestTransformBuilder<List<Map<String, dynamic>>>; | ||||||
|  | typedef StreamBuilder = SupabaseStreamBuilder; | ||||||
|  | 
 | ||||||
|  | /// {@template crud_data_source_supabase_impl} | ||||||
|  | /// A concrete implementation of [CrudDataSource] that uses | ||||||
|  | /// [Supabase] as the data source. | ||||||
|  | /// {@endtemplate} | ||||||
|  | class CrudDataSourceSupabaseImpl extends CrudDataSource { | ||||||
|  |   /// {@macro crud_data_source_supabase_impl} | ||||||
|  |   CrudDataSourceSupabaseImpl( | ||||||
|  |     String table, { | ||||||
|  |     required super.id, | ||||||
|  |     this.getIdKey, | ||||||
|  |     SupabaseClient? supabase, | ||||||
|  |   }) : _supabase = supabase ?? Supabase.instance.client { | ||||||
|  |     _supabaseQueryBuilder = _supabase.from(table); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   final SupabaseClient _supabase; | ||||||
|  |   late SupabaseQueryBuilder _supabaseQueryBuilder; | ||||||
|  | 
 | ||||||
|  |   /// Get the id field name depending on the operation type. | ||||||
|  |   /// If null, 'id' will be used. | ||||||
|  |   final String? Function( | ||||||
|  |     OperationType operationType, | ||||||
|  |   )? getIdKey; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<void> create(Map<String, dynamic> object, {String? id}) { | ||||||
|  |     if (id != null) { | ||||||
|  |       return _supabaseQueryBuilder.upsert(object); | ||||||
|  |     } else { | ||||||
|  |       final String? id = this.id( | ||||||
|  |         OperationType.create, | ||||||
|  |         object, | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |       if (id != null) { | ||||||
|  |         return _supabaseQueryBuilder.upsert(object); | ||||||
|  |       } | ||||||
|  |       return _supabaseQueryBuilder.insert(object); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<void> delete(String id) { | ||||||
|  |     final String idKey = getIdKey?.call(OperationType.delete) ?? 'id'; | ||||||
|  |     return _supabaseQueryBuilder.delete().match({idKey: id}); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<void> deleteAll() async { | ||||||
|  |     final List<Map<String, dynamic>> snapshots = | ||||||
|  |         await _supabaseQueryBuilder.select(); | ||||||
|  |     for (final Map<String, dynamic> snapshot in snapshots) { | ||||||
|  |       final String idKey = getIdKey?.call(OperationType.delete) ?? 'id'; | ||||||
|  |       await _supabaseQueryBuilder.delete().match({idKey: snapshot[idKey]}); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<Map<String, dynamic>?> get(String id) async { | ||||||
|  |     final String idKey = getIdKey?.call(OperationType.read) ?? 'id'; | ||||||
|  |     final List<Map<String, dynamic>> snapshots = | ||||||
|  |         await _supabaseQueryBuilder.select().match({idKey: id}); | ||||||
|  |     return snapshots.firstOrNull; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<List<Map<String, dynamic>?>> getAll() async => | ||||||
|  |       _supabaseQueryBuilder.select(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<List<Map<String, dynamic>?>> search( | ||||||
|  |     List<crud.Query> conditions, | ||||||
|  |   ) async { | ||||||
|  |     final PostgrestFilterBuilder<List<Map<String, dynamic>>> query = | ||||||
|  |         _supabaseQueryBuilder.select(); | ||||||
|  | 
 | ||||||
|  |     final filter = conditions.whereType<WhereQuery<dynamic>>().firstOrNull; | ||||||
|  |     final modifiers = [ | ||||||
|  |       ...conditions.whereType<LimitQuery>(), | ||||||
|  |       ...conditions.whereType<OrderByQuery>(), | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     PostgrestTransformBuilder<List<Map<String, dynamic>>>? queryTransform; | ||||||
|  | 
 | ||||||
|  |     if (filter != null) { | ||||||
|  |       queryTransform = _queryFilterParser(filter, query); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (final condition in modifiers) { | ||||||
|  |       queryTransform = _queryModifierParser(condition, queryTransform ?? query); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return query; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Stream<List<Map<String, dynamic>?>> stream({ | ||||||
|  |     String? id, | ||||||
|  |     List<crud.Query>? conditions, | ||||||
|  |     bool includeMetadataChanges = false, | ||||||
|  |   }) { | ||||||
|  |     // TODO(hpcl): use conditions!! | ||||||
|  |     final stream = _supabaseQueryBuilder | ||||||
|  |         .stream(primaryKey: [getIdKey?.call(OperationType.read) ?? 'id']); | ||||||
|  | 
 | ||||||
|  |     if (id != null) { | ||||||
|  |       return stream.eq( | ||||||
|  |         getIdKey?.call(OperationType.read) ?? 'id', | ||||||
|  |         id, | ||||||
|  |       ); | ||||||
|  |     } else { | ||||||
|  |       return stream; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<void> update( | ||||||
|  |     String id, { | ||||||
|  |     Map<String, dynamic>? object, | ||||||
|  |   }) async { | ||||||
|  |     if (object != null) { | ||||||
|  |       final String idKey = getIdKey?.call(OperationType.update) ?? 'id'; | ||||||
|  |       return _supabaseQueryBuilder.update(object).match({idKey: id}); | ||||||
|  |     } else { | ||||||
|  |       throw Exception('You must provide data to update'); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<void> updateAll(Map<String, Object?>? data) async { | ||||||
|  |     if (data == null) { | ||||||
|  |       throw Exception('You must provide data to update'); | ||||||
|  |     } | ||||||
|  |     return _supabaseQueryBuilder.update(data); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   QueryBuilder _queryFilterParser( | ||||||
|  |     crud.Query condition, | ||||||
|  |     PostgrestFilterBuilder<List<Map<String, dynamic>>> query, | ||||||
|  |   ) { | ||||||
|  |     if (condition is WhereQuery) { | ||||||
|  |       switch (condition.type) { | ||||||
|  |         case WhereQueryType.isEqualTo: | ||||||
|  |           return query.eq(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.isNotEqualTo: | ||||||
|  |           return query.neq(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.isLessThan: | ||||||
|  |           return query.lt(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.isLessThanOrEqualTo: | ||||||
|  |           return query.lte(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.isGreaterThan: | ||||||
|  |           return query.gt(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.isGreaterThanOrEqualTo: | ||||||
|  |           return query.gte(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.arrayContains: | ||||||
|  |           return query.contains(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.whereIn: | ||||||
|  |           return query.inFilter( | ||||||
|  |             condition.field, | ||||||
|  |             condition.value as List<Object>, | ||||||
|  |           ); | ||||||
|  |         case WhereQueryType.whereNotIn: | ||||||
|  |           return query.not( | ||||||
|  |             condition.field, | ||||||
|  |             'in', | ||||||
|  |             condition.value as List<Object>, | ||||||
|  |           ); | ||||||
|  |         case WhereQueryType.isNull: | ||||||
|  |           if (condition.value as bool) { | ||||||
|  |             return query.isFilter(condition.field, null); | ||||||
|  |           } else { | ||||||
|  |             return query.not(condition.field, 'is', null); | ||||||
|  |           } | ||||||
|  |         case WhereQueryType.arrayContainsAny: | ||||||
|  |           throw UnsupportedError( | ||||||
|  |             '${condition.type} is not supported by Supabase', | ||||||
|  |           ); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return query; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   StreamBuilder _streamFilterParser( | ||||||
|  |     crud.Query condition, | ||||||
|  |     SupabaseStreamFilterBuilder query, | ||||||
|  |   ) { | ||||||
|  |     if (condition is WhereQuery) { | ||||||
|  |       switch (condition.type) { | ||||||
|  |         case WhereQueryType.isEqualTo: | ||||||
|  |           return query.eq(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.isNotEqualTo: | ||||||
|  |           return query.neq(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.isLessThan: | ||||||
|  |           return query.lt(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.isLessThanOrEqualTo: | ||||||
|  |           return query.lte(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.isGreaterThan: | ||||||
|  |           return query.gt(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.isGreaterThanOrEqualTo: | ||||||
|  |           return query.gte(condition.field, condition.value as Object); | ||||||
|  |         case WhereQueryType.whereIn: | ||||||
|  |           return query.inFilter( | ||||||
|  |             condition.field, | ||||||
|  |             condition.value as List<Object>, | ||||||
|  |           ); | ||||||
|  |         case WhereQueryType.arrayContains: | ||||||
|  |         case WhereQueryType.arrayContainsAny: | ||||||
|  |         case WhereQueryType.whereNotIn: | ||||||
|  |         case WhereQueryType.isNull: | ||||||
|  |           throw UnsupportedError( | ||||||
|  |             '${condition.type} is not supported in stream by Supabase', | ||||||
|  |           ); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return query; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   QueryBuilder _queryModifierParser( | ||||||
|  |     crud.Query condition, | ||||||
|  |     QueryBuilder query, | ||||||
|  |   ) { | ||||||
|  |     if (condition is LimitQuery) { | ||||||
|  |       return query.limit(condition.limit); | ||||||
|  |     } else if (condition is OrderByQuery) { | ||||||
|  |       return query.order( | ||||||
|  |         condition.field, | ||||||
|  |         ascending: condition.ascending, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |     return query; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,20 @@ | |||||||
|  | // 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/>. | ||||||
|  | 
 | ||||||
|  | /// Create/Read/Update/Delete BLoC implementation for Supabase. | ||||||
|  | library wyatt_crud_bloc_supabase; | ||||||
|  | 
 | ||||||
|  | export 'src/data/crud_data_source_supabase_impl.dart'; | ||||||
| @ -0,0 +1,35 @@ | |||||||
|  | name: wyatt_crud_bloc_supabase | ||||||
|  | description: Create/Read/Update/Delete implementation for Supabase | ||||||
|  | repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_crud_bloc | ||||||
|  | version: 0.2.0 | ||||||
|  | 
 | ||||||
|  | publish_to: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub | ||||||
|  | 
 | ||||||
|  | environment: | ||||||
|  |   sdk: ">=3.0.0 <4.0.0" | ||||||
|  | 
 | ||||||
|  | dependencies: | ||||||
|  |   flutter: { sdk: flutter } | ||||||
|  | 
 | ||||||
|  |   flutter_bloc: ^8.1.1 | ||||||
|  |   equatable: ^2.0.5 | ||||||
|  |   supabase_flutter: ^2.3.4 | ||||||
|  | 
 | ||||||
|  |   wyatt_architecture: | ||||||
|  |     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
|  |     version: ^0.2.0+1 | ||||||
|  | 
 | ||||||
|  |   wyatt_type_utils: | ||||||
|  |     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
|  |     version: ^0.0.5 | ||||||
|  |    | ||||||
|  |   wyatt_crud_bloc: | ||||||
|  |     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/ | ||||||
|  |     version: ^0.2.0 | ||||||
|  | 
 | ||||||
|  | dev_dependencies: | ||||||
|  |   flutter_test: { sdk: flutter } | ||||||
|  |   bloc_test: ^9.1.0 | ||||||
|  |   wyatt_analysis: | ||||||
|  |     hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub | ||||||
|  |     version: ^2.6.1 | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user