Compare commits

...

5 Commits

Author SHA1 Message Date
5ea5c510cb chore(release): publish packages
- wyatt_crud_bloc@0.0.2
 - wyatt_analysis@2.0.1
2022-04-20 23:12:12 +02:00
bb264b7362 docs: update readme with some instructions 2022-04-20 23:08:59 +02:00
17ae855ffb docs(crud): add example app 2022-04-20 23:08:37 +02:00
b38fea130f feat(crud) : new package for crud operations 2022-04-20 22:57:14 +02:00
e3776259df style(auth): update analysis options 2022-04-20 22:54:00 +02:00
58 changed files with 1973 additions and 21 deletions

View File

@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## 2022-04-20
### Changes
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`wyatt_crud_bloc` - `v0.0.2`](#wyatt_crud_bloc---v002)
- [`wyatt_analysis` - `v2.0.1`](#wyatt_analysis---v201)
---
#### `wyatt_crud_bloc` - `v0.0.2`
- Migrate crud_package in monorepo
- **DOCS**: add example app.
#### `wyatt_analysis` - `v2.0.1`
- **DOCS**: Update readme with new version.
## 2022-04-20
### Changes

View File

@ -63,22 +63,55 @@ dart pub global activate melos
Then bootstrap with `melos bs`.
---
### Create a new package
## Usage
Create a new package in `packages/` folder.
You can add any package of the `packages/` sub directory in your project.
```yaml
dependencies:
wyatt_analysis:
git:
url: ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-packages.git
ref: wyatt_analysis-v2.0.0
path: packages/wyatt_analysis
```shell
dart create -t package-simple wyatt_<name>
```
Here you can change `package name` and `package version`.
Remove any `example/` subfolder. Then create a new sample project.
```shell
flutter create --platforms android --project-name <name>_example example
```
Then bootstrap project with `melos bs` command.
### Convention
#### Naming
In the previous instructions `<name>` variable is important.
It have to be clear and intelligible.
You **MUST** use underscores.
You **MUST** use `wyatt` prefix for package.
You **MUST** name example with specific name.
For example, if name is CRUD BLOC
- name will be crud_bloc
- so the package will be: `wyatt_crud_bloc`
- and the example will be: `crud_bloc_example`
#### Commits
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
tl;dr : `type(scope): description` where type can be **feat, fix, docs, chores, ci, perf, refactor, style, test**, and scope is package name.
examples:
- `feat(auth): add AWS support.` = add a feature in authentication_bloc package.
- `docs: update readme.` = update **this** readme file.
- `fix(crud)!: fix bug in awesome() function.` = fix a bug, `!` is important and indicate `BREAKING CHANGES`.
Conventional commits are important for `melos version` command !
#### Badging
In the package `readme.md` file, please specify the supported SDK:
@ -97,6 +130,23 @@ or
---
## Usage
You can add any package of the `packages/` sub directory in your project.
```yaml
dependencies:
wyatt_analysis:
git:
url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages
ref: wyatt_analysis-v2.0.0
path: packages/wyatt_analysis
```
Here you can change `package name` and `package version`.
---
## Status
![Status: Experimental](https://img.shields.io/badge/Status-WIP-red?style=flat-square)

View File

@ -1,3 +1,7 @@
## 2.0.1
- **DOCS**: Update readme with new version.
## 2.0.0
> Note: This release has breaking changes.

View File

@ -1,7 +1,7 @@
name: wyatt_analysis
description: Lint rules for Dart and Flutter used internally at Wyatt and Wyatt Studio.
repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_analysis
version: 2.0.0
version: 2.0.1
environment:
sdk: '>=2.12.0 <3.0.0'

View File

@ -1,6 +1 @@
include: package:wyatt_analysis/analysis_options.flutter.1.1.1.yaml
linter:
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
include: package:wyatt_analysis/analysis_options.flutter.yaml

View File

@ -30,5 +30,5 @@ dev_dependencies:
wyatt_analysis:
git:
url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages
ref: wyatt_analysis-v2.0.0
ref: wyatt_analysis-v2.0.1
path: packages/wyatt_analysis

10
packages/wyatt_crud_bloc/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# Files and directories created by pub.
.dart_tool/
.packages
# Conventional directory for build outputs.
build/
# Omit committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock

View File

@ -0,0 +1,9 @@
## 0.0.2
- Migrate crud_package in monorepo
- **DOCS**: add example app.
## 1.0.0
- Initial version.

View 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.

View File

@ -0,0 +1 @@
include: package:wyatt_analysis/analysis_options.flutter.yaml

View File

@ -0,0 +1,48 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
/lib/firebase_options.dart

View 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: 5464c5bac742001448fe4fc0597be939379f88ea
channel: stable
project_type: app

View File

@ -0,0 +1,16 @@
# crud_bloc_example
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

View File

@ -0,0 +1,29 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View File

@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks

View File

@ -0,0 +1,71 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
// START: FlutterFire Configuration
apply plugin: 'com.google.gms.google-services'
// END: FlutterFire Configuration
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion flutter.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.crud_bloc_example"
minSdkVersion 21
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

View File

@ -0,0 +1,135 @@
{
"project_info": {
"project_number": "136771801992",
"firebase_url": "https://tchat-beta.firebaseio.com",
"project_id": "tchat-beta",
"storage_bucket": "tchat-beta.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:136771801992:android:4ff419f07afdad6097203d",
"android_client_info": {
"package_name": "com.example.authentication_bloc_example"
}
},
"oauth_client": [
{
"client_id": "136771801992-ncuib3rbu7p4ro4eo5su4vaudn2u4qrv.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAYS14uXupkS158Q5QAFP1864UrUN_yDSk"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "136771801992-ncuib3rbu7p4ro4eo5su4vaudn2u4qrv.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "136771801992-e585bm1n9b3lv89t4phrl9u0glsg52ua.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "com.example.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:136771801992:android:8482c9b90bc29de697203d",
"android_client_info": {
"package_name": "com.example.crud_bloc_example"
}
},
"oauth_client": [
{
"client_id": "136771801992-ncuib3rbu7p4ro4eo5su4vaudn2u4qrv.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAYS14uXupkS158Q5QAFP1864UrUN_yDSk"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "136771801992-ncuib3rbu7p4ro4eo5su4vaudn2u4qrv.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "136771801992-e585bm1n9b3lv89t4phrl9u0glsg52ua.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "com.example.example"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:136771801992:android:d20e0361057e815197203d",
"android_client_info": {
"package_name": "com.example.example"
}
},
"oauth_client": [
{
"client_id": "136771801992-n2pq8oqutvrqj58e05hbavvc7n1jdfjb.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.example.example",
"certificate_hash": "5d8790309e13b68c35e5d4d8437c35c6d15e6131"
}
},
{
"client_id": "136771801992-pj9s88ao7d99pnp4ace75nj1abtmoq7e.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.example.example",
"certificate_hash": "bc8faf31c0b0085dc358b2319684e10c93f42719"
}
},
{
"client_id": "136771801992-ncuib3rbu7p4ro4eo5su4vaudn2u4qrv.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAYS14uXupkS158Q5QAFP1864UrUN_yDSk"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "136771801992-ncuib3rbu7p4ro4eo5su4vaudn2u4qrv.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "136771801992-e585bm1n9b3lv89t4phrl9u0glsg52ua.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "com.example.example"
}
}
]
}
}
}
],
"configuration_version": "1"
}

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.crud_bloc_example">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,34 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.crud_bloc_example">
<application
android:label="crud_bloc_example"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

View File

@ -0,0 +1,6 @@
package com.example.crud_bloc_example
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.crud_bloc_example">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,34 @@
buildscript {
ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
// START: FlutterFire Configuration
classpath 'com.google.gms:google-services:4.3.10'
// END: FlutterFire Configuration
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

View File

@ -0,0 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

View File

@ -0,0 +1,11 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"

View File

@ -0,0 +1,168 @@
// 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 'dart:math';
import 'package:crud_bloc_example/models.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart';
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
final _userRepository = CrudRepositoryFirestore<UserFirestore>(
'users_crud',
UserFirestore.parser(),
);
final _userCubit = CrudCubit<UserFirestore>(_userRepository);
return RepositoryProvider<CrudRepositoryFirestore<UserFirestore>>(
create: (context) => _userRepository,
child: BlocProvider<CrudCubit<UserFirestore>>(
create: (context) => _userCubit,
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Demo Home Page'),
),
body: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 20),
const Text("Data:"),
CrudStreamBuilder<UserFirestore>(
onError: (context, state) => const SizedBox.shrink(),
onLoading: (context, state) => const Text("Loading..."),
onStream: (context, data) {
return ListView.builder(
shrinkWrap: true,
itemCount: data.length,
itemBuilder: (context, index) {
final user = data.elementAt(index);
return ListTile(
title: Text(user?.name ?? 'Error'),
subtitle: Text(user?.id ?? 'Error'),
onTap: () {
context.read<CrudCubit<UserFirestore>>().get(
(user?.id)!,
);
},
onLongPress: () {
context.read<CrudCubit<UserFirestore>>().delete(
(user?.id)!,
);
},
);
},
);
},
),
const SizedBox(height: 20),
BlocBuilder<CrudCubit<UserFirestore>, CrudState<UserFirestore>>(
builder: (context, state) {
return Center(
child: Text(
state.toString(),
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 20,
color: Colors.grey,
),
),
);
},
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
final r = Random().nextInt(1000);
context.read<CrudCubit<UserFirestore>>().create(
UserFirestore(
name: 'Wyatt $r',
email: '$r@wyattapp.io',
phone: '06$r'),
);
},
child: const Text("Create"),
),
ElevatedButton(
onPressed: () {
context.read<CrudCubit<UserFirestore>>().deleteAll();
},
child: const Text("DeleteAll"),
),
ElevatedButton(
onPressed: () {
context.read<CrudCubit<UserFirestore>>().getAll();
},
child: const Text("GetAll"),
),
ElevatedButton(
onPressed: () {
context
.read<CrudCubit<UserFirestore>>()
.query([LimitQueryFirestore(1)]);
},
child: const Text("Query"),
),
ElevatedButton(
onPressed: () {
context.read<CrudCubit<UserFirestore>>().streamOf();
},
child: const Text("StreamOf"),
),
ElevatedButton(
onPressed: () {
context
.read<CrudCubit<UserFirestore>>()
.updateAll({'updated': DateTime.now()});
},
child: const Text("UpdateAll"),
),
ElevatedButton(
onPressed: () {
context.read<CrudCubit<UserFirestore>>().reset();
},
child: const Text("Reset"),
),
const SizedBox(height: 20),
],
),
),
);
}
}

View File

@ -0,0 +1,29 @@
// 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/firebase_options.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}

View File

@ -0,0 +1,66 @@
// 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:cloud_firestore/cloud_firestore.dart';
import 'package:wyatt_crud_bloc/wyatt_crud_bloc.dart';
class UserFirestore extends Model<DocumentSnapshot, UserFirestore> {
@override
String? id;
String? name;
String? email;
String? phone;
UserFirestore({
required this.name,
required this.email,
required this.phone,
this.id,
});
UserFirestore._();
factory UserFirestore.parser() {
return UserFirestore._();
}
@override
UserFirestore? from(DocumentSnapshot? object) {
if (object == null) return null;
if (object.exists) {
return UserFirestore(
id: object.id,
name: (object.data() as Map<String, dynamic>?)!['name'] as String,
email: (object.data() as Map<String, dynamic>?)!['email'] as String,
phone: (object.data() as Map<String, dynamic>?)!['phone'] as String,
);
}
return null;
}
@override
Map<String, Object> toMap() {
return {
'name': name ?? '',
'email': email ?? '',
'phone': phone ?? '',
};
}
@override
String toString() =>
'UserFirestore(id: $id, name: $name, email: $email, phone: $phone)';
}

View File

@ -0,0 +1,94 @@
name: crud_bloc_example
description: A new Flutter project.
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
environment:
sdk: ">=2.16.2 <3.0.0"
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
cloud_firestore: ^3.1.12
firebase_core: ^1.14.1
flutter_bloc: ^8.0.1
wyatt_crud_bloc:
path: "../"
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^1.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages

View File

@ -0,0 +1,18 @@
// 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/>.
export 'crud_builder.dart';
export 'crud_stream_builder.dart';

View File

@ -0,0 +1,53 @@
// 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:flutter_bloc/flutter_bloc.dart';
import 'package:wyatt_crud_bloc/src/crud/cubit/crud_cubit.dart';
import 'package:wyatt_crud_bloc/src/models/model.dart';
class CrudBuilder<T extends Model<Object?, T>> extends StatelessWidget {
const CrudBuilder({
Key? key,
this.onIdle,
required this.onLoading,
required this.onError,
required this.onSuccess,
}) : super(key: key);
final Widget Function(BuildContext, CrudState<T>)? onIdle;
final Widget Function(BuildContext, CrudState<T>) onLoading;
final Widget Function(BuildContext, CrudState<T>) onError;
final Widget Function(BuildContext, CrudState<T>) onSuccess;
@override
Widget build(BuildContext context) {
return BlocBuilder<CrudCubit<T>, CrudState<T>>(
builder: (context, state) {
switch (state.status) {
case CrudStatus.idle:
return onIdle?.call(context, state) ?? onError.call(context, state);
case CrudStatus.loading:
return onLoading.call(context, state);
case CrudStatus.failure:
return onError.call(context, state);
case CrudStatus.success:
return onSuccess.call(context, state);
}
},
);
}
}

View File

@ -0,0 +1,55 @@
// 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:flutter_bloc/flutter_bloc.dart';
import 'package:wyatt_crud_bloc/src/crud/cubit/crud_cubit.dart';
import 'package:wyatt_crud_bloc/src/models/model.dart';
class CrudStreamBuilder<T extends Model<Object?, T>> extends StatelessWidget {
const CrudStreamBuilder({
Key? key,
required this.onLoading,
required this.onError,
required this.onStream,
}) : super(key: key);
final Widget Function(BuildContext, List<T?>) onStream;
final Widget Function(BuildContext, CrudState<T>) onLoading;
final Widget Function(BuildContext, CrudState<T>) onError;
@override
Widget build(BuildContext context) {
return BlocBuilder<CrudCubit<T>, CrudState<T>>(
builder: (context, state) {
if (state.stream != null) {
return StreamBuilder<List<T?>>(
stream: state.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return onStream(context, snapshot.data!);
} else {
return onLoading(context, state);
}
},
);
} else {
return onError(context, state);
}
},
);
}
}

View File

@ -0,0 +1,18 @@
// 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/>.
export 'builder/builder.dart';
export 'cubit/crud_cubit.dart';

View File

@ -0,0 +1,219 @@
// 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/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:wyatt_crud_bloc/src/models/model.dart';
import 'package:wyatt_crud_bloc/src/models/queries/queries_interface.dart';
import 'package:wyatt_crud_bloc/src/repositories/crud_repository_interface.dart';
part 'crud_state.dart';
class CrudCubit<T extends Model<Object?, T>> extends Cubit<CrudState<T>> {
final CrudRepositoryInterface<T> _crudRepository;
// ignore: prefer_const_constructors
CrudCubit(this._crudRepository) : super(CrudState());
// Here we can't use `const` because we need the generic type T
void reset() {
// ignore: prefer_const_constructors
emit(CrudState());
// Same here, because of `const` we can't use T generic type
}
Future<void> create(Model object, {String? id}) async {
emit(state.copyWith(status: CrudStatus.loading));
try {
await _crudRepository.create(object, id: id);
final data = state.data..addAll([object].cast<T>());
emit(
state.copyWith(
data: data,
status: CrudStatus.success,
),
);
} catch (e) {
// TODO(hpcl): implement Exception
emit(
state.copyWith(
status: CrudStatus.failure,
errorMessage: e.toString(),
),
);
}
}
Future<void> delete(String id) async {
emit(state.copyWith(status: CrudStatus.loading));
try {
await _crudRepository.delete(id);
final data = state.data
..removeWhere((element) => element!.id != null && element.id == id);
emit(
state.copyWith(
data: data,
status: CrudStatus.success,
),
);
} catch (e) {
emit(
state.copyWith(
status: CrudStatus.failure,
errorMessage: e.toString(),
),
);
}
}
Future<void> deleteAll() async {
emit(state.copyWith(status: CrudStatus.loading));
try {
await _crudRepository.deleteAll();
emit(
state.copyWith(
data: [],
status: CrudStatus.success,
),
);
} catch (e) {
emit(
state.copyWith(
status: CrudStatus.failure,
errorMessage: e.toString(),
),
);
}
}
Future<void> get(String id) async {
emit(state.copyWith(status: CrudStatus.loading));
try {
final data = await _crudRepository.get(id);
emit(
state.copyWith(
data: [data].cast<T>(),
status: CrudStatus.success,
),
);
} catch (e) {
emit(
state.copyWith(
status: CrudStatus.failure,
errorMessage: e.toString(),
),
);
}
}
Future<void> getAll() async {
emit(state.copyWith(status: CrudStatus.loading));
try {
final data = await _crudRepository.getAll();
emit(
state.copyWith(
data: data.cast<T>(),
status: CrudStatus.success,
),
);
} catch (e) {
emit(
state.copyWith(
status: CrudStatus.failure,
errorMessage: e.toString(),
),
);
}
}
Future<void> query(List<QueryInterface> conditions) async {
emit(state.copyWith(status: CrudStatus.loading));
try {
final data = await _crudRepository.query(conditions);
emit(
state.copyWith(
data: data.cast<T>(),
status: CrudStatus.success,
),
);
} catch (e) {
emit(
state.copyWith(
status: CrudStatus.failure,
errorMessage: e.toString(),
),
);
}
}
Future<void> streamOf({String? id}) async {
emit(state.copyWith(status: CrudStatus.loading));
try {
final Stream<List<T?>> data = _crudRepository.stream(id: id);
emit(
state.copyWith(
stream: data,
status: CrudStatus.success,
),
);
} catch (e) {
emit(
state.copyWith(
status: CrudStatus.failure,
errorMessage: e.toString(),
),
);
}
}
Future<void> update(
String id, {
Model? object,
Map<String, dynamic>? raw,
}) async {
emit(state.copyWith(status: CrudStatus.loading));
try {
await _crudRepository.update(
id,
object: object,
raw: raw,
);
emit(state.copyWith(status: CrudStatus.success));
} catch (e) {
emit(
state.copyWith(
status: CrudStatus.failure,
errorMessage: e.toString(),
),
);
}
}
Future<void> updateAll(Map<String, Object?> raw) async {
emit(state.copyWith(status: CrudStatus.loading));
try {
await _crudRepository.updateAll(raw);
emit(state.copyWith(status: CrudStatus.success));
} catch (e) {
emit(
state.copyWith(
status: CrudStatus.failure,
errorMessage: e.toString(),
),
);
}
}
}

View File

@ -0,0 +1,60 @@
// 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/>.
part of 'crud_cubit.dart';
enum CrudStatus {
idle,
loading,
success,
failure,
}
class CrudState<T> extends Equatable {
final CrudStatus status;
final List<T?> data;
final Stream<List<T?>>? stream;
final String? errorMessage;
const CrudState({
this.status = CrudStatus.idle,
this.data = const [],
this.stream,
this.errorMessage,
});
@override
List<Object?> get props => [status, data];
CrudState<T> copyWith({
CrudStatus? status,
List<T?>? data,
Stream<List<T?>>? stream,
String? errorMessage,
}) {
return CrudState<T>(
status: status ?? this.status,
data: data ?? this.data,
stream: stream ?? this.stream,
errorMessage: errorMessage ?? this.errorMessage,
);
}
@override
String toString() =>
// ignore: lines_longer_than_80_chars
'CrudState(status: $status, data: $data, stream: ${stream != null ? 'listening' : 'null'}, errorMessage: $errorMessage)';
}

View File

@ -0,0 +1,21 @@
// 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/>.
abstract class Model<O, T> {
String? get id;
Map<String, Object> toMap();
T? from(O? object);
}

View File

@ -0,0 +1,18 @@
// 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/>.
export 'model.dart';
export 'queries/queries.dart';

View File

@ -0,0 +1,18 @@
// 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/>.
export 'queries_firestore.dart';
export 'queries_interface.dart';

View File

@ -0,0 +1,88 @@
// 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:cloud_firestore/cloud_firestore.dart';
import 'package:wyatt_crud_bloc/src/models/queries/queries_interface.dart';
class QueryParserFirestore implements QueryParserInterface {
@override
Query parser(QueryInterface condition, Object query) {
query as Query;
if (condition is WhereQueryInterface) {
switch (condition.type) {
case WhereQueryType.isEqualTo:
return query.where(condition.field, isEqualTo: condition.value);
case WhereQueryType.isNotEqualTo:
return query.where(condition.field, isNotEqualTo: condition.value);
case WhereQueryType.isLessThan:
return query.where(condition.field, isLessThan: condition.value);
case WhereQueryType.isLessThanOrEqualTo:
return query.where(
condition.field,
isLessThanOrEqualTo: condition.value,
);
case WhereQueryType.isGreaterThan:
return query.where(condition.field, isGreaterThan: condition.value);
case WhereQueryType.isGreaterThanOrEqualTo:
return query.where(
condition.field,
isGreaterThanOrEqualTo: condition.value,
);
case WhereQueryType.arrayContains:
return query.where(condition.field, arrayContains: condition.value);
case WhereQueryType.arrayContainsAny:
return query.where(
condition.field,
arrayContainsAny: condition.value as List<Object>,
);
case WhereQueryType.whereIn:
return query.where(
condition.field,
whereIn: condition.value as List<Object>,
);
case WhereQueryType.whereNotIn:
return query.where(
condition.field,
whereNotIn: condition.value as List<Object>,
);
case WhereQueryType.isNull:
return query.where(condition.field, isNull: condition.value as bool);
}
} else if (condition is LimitQueryInterface) {
return query.limit(condition.limit);
} else if (condition is OrderByQueryInterface) {
return query.orderBy(
condition.field,
descending: !condition.ascending,
);
}
return query;
}
}
class WhereQueryFirestore extends WhereQueryInterface {
WhereQueryFirestore(WhereQueryType type, String field, Object value)
: super(type, field, value);
}
class LimitQueryFirestore extends LimitQueryInterface {
LimitQueryFirestore(int limit) : super(limit);
}
class OrderByQueryFirestore extends OrderByQueryInterface {
OrderByQueryFirestore(String field, {bool ascending = true})
: super(field, ascending: ascending);
}

View File

@ -0,0 +1,57 @@
// 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/>.
// ignore: one_member_abstracts
abstract class QueryParserInterface {
Object parser(QueryInterface condition, Object query);
}
abstract class QueryInterface {}
enum WhereQueryType {
isEqualTo,
isNotEqualTo,
isLessThan,
isLessThanOrEqualTo,
isGreaterThan,
isGreaterThanOrEqualTo,
arrayContains,
arrayContainsAny,
whereIn,
whereNotIn,
isNull,
}
abstract class WhereQueryInterface extends QueryInterface {
final WhereQueryType type;
final String field;
final Object value;
WhereQueryInterface(this.type, this.field, this.value);
}
abstract class LimitQueryInterface extends QueryInterface {
final int limit;
LimitQueryInterface(this.limit);
}
abstract class OrderByQueryInterface extends QueryInterface {
final String field;
final bool ascending;
OrderByQueryInterface(this.field, {this.ascending = true});
}

View File

@ -0,0 +1,102 @@
// 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:firebase_database/firebase_database.dart';
import 'package:wyatt_crud_bloc/src/models/model.dart';
import 'package:wyatt_crud_bloc/src/models/queries/queries_interface.dart';
import 'package:wyatt_crud_bloc/src/repositories/crud_repository_interface.dart';
class CrudRepositoryFirebaseDatabase<T> implements CrudRepositoryInterface<T> {
final FirebaseDatabase _firebaseDatabase;
final Model<Object, T> _parser;
late DatabaseReference _rootReference;
CrudRepositoryFirebaseDatabase(
String root,
Model<Object, T> parser, {
FirebaseDatabase? firebaseDatabase,
}) : _firebaseDatabase = firebaseDatabase ?? FirebaseDatabase.instance,
_parser = parser {
_rootReference = _firebaseDatabase.ref(root);
}
@override
Future<void> create(Model object, {String? id}) {
DatabaseReference _reference = _rootReference;
if (id != null) {
_reference = _reference.child(id);
}
return _reference.set(object.toMap());
}
@override
Future<void> delete(String id) {
final DatabaseReference _reference = _rootReference.child(id);
return _reference.remove();
}
@override
Future<void> deleteAll() {
return _rootReference.remove();
}
@override
Future<T?> get(String id) async {
final DatabaseEvent _event = await _rootReference.child(id).once();
return _parser.from(_event.snapshot.value);
}
@override
Future<List<T?>> getAll() async {
final DatabaseEvent _event = await _rootReference.once();
final List<T?> _objects = [];
_event.snapshot.children.map((e) => _objects.add(_parser.from(e.value)));
return _objects;
}
@override
Future<List<T?>> query(List<QueryInterface> conditions) {
// TODO(hpcl): implement query
throw UnimplementedError();
}
@override
Stream<List<T?>> stream({String? id, List<QueryInterface>? conditions}) {
DatabaseReference _reference = _rootReference;
if (id != null) {
_reference = _reference.child(id);
}
return _reference.onValue.map((e) {
final List<T?> _objects = [];
e.snapshot.children.map((e) => _objects.add(_parser.from(e.value)));
return _objects;
});
}
@override
Future<void> update(String id, {Model? object, Map<String, dynamic>? raw}) {
// TODO(hpcl): implement update
throw UnimplementedError();
}
@override
Future<void> updateAll(Map<String, Object?> raw) {
// TODO(hpcl): implement updateAll
throw UnimplementedError();
}
}

View File

@ -0,0 +1,146 @@
// 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:cloud_firestore/cloud_firestore.dart';
import 'package:wyatt_crud_bloc/src/models/model.dart';
import 'package:wyatt_crud_bloc/src/models/queries/queries_firestore.dart';
import 'package:wyatt_crud_bloc/src/models/queries/queries_interface.dart';
import 'package:wyatt_crud_bloc/src/repositories/crud_repository_interface.dart';
class CrudRepositoryFirestore<T> implements CrudRepositoryInterface<T> {
final FirebaseFirestore _firestore;
final Model<DocumentSnapshot, T> _parser;
late CollectionReference _collectionReference;
CrudRepositoryFirestore(
String collection,
Model<DocumentSnapshot, T> parser, {
FirebaseFirestore? firestore,
}) : _firestore = firestore ?? FirebaseFirestore.instance,
_parser = parser {
_collectionReference = _firestore.collection(collection);
}
@override
Future<void> create(Model object, {String? id}) {
if (id != null) {
return _collectionReference.doc(id).set(object.toMap());
} else {
return _collectionReference.add(object.toMap());
}
}
@override
Future<void> delete(String id) {
return _collectionReference.doc(id).delete();
}
@override
Future<void> deleteAll() async {
final _batch = _firestore.batch();
final QuerySnapshot snapshots = await _collectionReference.get();
for (final DocumentSnapshot snapshot in snapshots.docs) {
_batch.delete(snapshot.reference);
}
return _batch.commit();
}
@override
Future<T?> get(String id) async {
final DocumentSnapshot snapshot = await _collectionReference.doc(id).get();
return _parser.from(snapshot);
}
@override
Future<List<T?>> getAll() async {
final QuerySnapshot snapshots = await _collectionReference.get();
return snapshots.docs.map(_parser.from).toList();
}
@override
Future<List<T?>> query(List<QueryInterface> conditions) async {
Query query = _collectionReference;
for (final condition in conditions) {
query = QueryParserFirestore().parser(condition, query);
}
final QuerySnapshot snapshots = await query.get();
return snapshots.docs.map(_parser.from).toList();
}
@override
Stream<List<T?>> stream({
String? id,
List<QueryInterface>? conditions,
bool includeMetadataChanges = false,
}) {
if (id != null) {
return _collectionReference
.doc(id)
.snapshots(
includeMetadataChanges: includeMetadataChanges,
)
.map<List<T?>>(
(DocumentSnapshot snapshot) => [_parser.from(snapshot)],
);
} else {
if (conditions != null) {
Query query = _collectionReference;
for (final condition in conditions) {
query = QueryParserFirestore().parser(condition, query);
}
return query
.snapshots(
includeMetadataChanges: includeMetadataChanges,
)
.map((querySnapshot) {
return querySnapshot.docs.map(_parser.from).toList();
});
} else {
return _collectionReference
.snapshots(
includeMetadataChanges: includeMetadataChanges,
)
.map((querySnapshot) {
return querySnapshot.docs.map(_parser.from).toList();
});
}
}
}
@override
Future<void> update(String id, {Model? object, Map<String, Object?>? raw}) {
if (object != null) {
return _collectionReference.doc(id).update(object.toMap());
} else {
if (raw != null) {
return _collectionReference.doc(id).update(raw);
} else {
throw Exception('You must provide an object or a raw map');
}
}
}
@override
Future<void> updateAll(Map<String, Object?> raw) async {
final _batch = _firestore.batch();
final QuerySnapshot snapshots = await _collectionReference.get();
for (final DocumentSnapshot snapshot in snapshots.docs) {
_batch.update(snapshot.reference, raw);
}
return _batch.commit();
}
}

View File

@ -0,0 +1,30 @@
// 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_crud_bloc/src/models/model.dart';
import 'package:wyatt_crud_bloc/src/models/queries/queries_interface.dart';
abstract class CrudRepositoryInterface<T> {
Future<void> create(Model object, {String? id});
Future<void> delete(String id);
Future<void> deleteAll();
Future<T?> get(String id);
Future<List<T?>> getAll();
Future<List<T?>> query(List<QueryInterface> conditions);
Stream<List<T?>> stream({String? id, List<QueryInterface>? conditions});
Future<void> update(String id, {Model? object, Map<String, dynamic>? raw});
Future<void> updateAll(Map<String, Object?> raw);
}

View File

@ -0,0 +1,18 @@
// 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/>.
export 'crud_repository_firestore.dart';
export 'crud_repository_interface.dart';

View File

@ -0,0 +1,21 @@
// 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/>.
library wyatt_crud_bloc;
export 'src/crud/crud.dart';
export 'src/models/models.dart';
export 'src/repositories/repositories.dart';

View File

@ -0,0 +1,27 @@
name: wyatt_crud_bloc
description: Create/Read/Update/Delete BLoC for Flutter
repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_crud_bloc
version: 0.0.2
environment:
sdk: '>=2.16.2 <3.0.0'
flutter: ">=1.17.0"
dependencies:
flutter:
sdk: flutter
flutter_bloc: ^8.0.1
equatable: ^2.0.3
cloud_firestore: ^3.1.12
firebase_database: ^9.0.11
dev_dependencies:
flutter_test:
sdk: flutter
bloc_test: ^9.0.3
wyatt_analysis:
git:
url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages
ref: wyatt_analysis-v2.0.1
path: packages/wyatt_analysis

View File

@ -16,5 +16,5 @@ dev_dependencies:
wyatt_analysis:
git:
url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages
ref: wyatt_analysis-v2.0.0
ref: wyatt_analysis-v2.0.1
path: packages/wyatt_analysis