flamingo 1.1.1

  • Readme
  • Changelog
  • Example
  • Installing
  • 87

Flamingo #

Flamingo is a firebase firestore model framework library.

https://pub.dev/packages/flamingo

日本語ドキュメント

Example code #

See the example directory for a complete sample app using flamingo.

example

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  flamingo:
  flamingo_annotation: ^0.3.0

dev_dependencies:
  build_runner: ^1.10.0
  flamingo_generator: ^0.3.2

Setup #

Please check Setup of cloud_firestore.
https://pub.dev/packages/cloud_firestore

Usage #

Adding a configure code to main.dart.

Initialize #

import 'package:flamingo/flamingo.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  Flamingo.configure();
  ...
}

Also be able to set app to firebase instance.

final app = await FirebaseApp.configure(
  name: 'appName',
  options: const FirebaseOptions(
    googleAppID: '1:1234567890:ios:42424242424242',
    gcmSenderID: '1234567890',
  ),
);
final firestore = Firestore(app: app);
Flamingo.configure(
  firestore: firestore,
  storage: FirebaseStorage(app: app),
  root: firestore.collection('version').document('1'),
);

Create Model #

Create class that inherited Document. And add json mapping code into override functions.

Can be used flamingo_generator. Automatically create code for mapping JSON.

import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

part 'user.flamingo.dart';

class User extends Document<User> {
  User({
    String id,
    DocumentSnapshot snapshot,
    Map<String, dynamic> values,
  }) : super(id: id, snapshot: snapshot, values: values);

  @Field()
  String name;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);
}

Annotation list.

  • @Field()
  • @StorageField()
  • @ModelField()
  • @SubCollection()

Execute build runner to generate data mapping JSON.

flutter pub run build_runner build

It will be generated the following code.

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'user.dart';

// **************************************************************************
// FieldValueGenerator
// **************************************************************************

/// Field value key
enum UserKey {
  name,
}

extension UserKeyExtension on UserKey {
  String get value {
    switch (this) {
      case UserKey.name:
        return 'name';
      default:
        return toString();
    }
  }
}

/// For save data
Map<String, dynamic> _$toData(User doc) {
  final data = <String, dynamic>{};
  Helper.writeNotNull(data, 'name', doc.name);

  return data;
}

/// For load data
void _$fromData(User doc, Map<String, dynamic> data) {
  doc.name = Helper.valueFromKey<String>(data, 'name');
}

CRUD #

Create instance the following code.

final user = User();
print(user.id); // id: Automatically create document id;

final user = User(id: '0000');
print(user.id); // id: '0000'

Using DocumentAccessor or Batch or Transaction in order to CRUD.

final user = User()
      ..name = 'hoge';

DocumentAccessor documentAccessor = DocumentAccessor();

// save
await documentAccessor.save(user);

// update
await documentAccessor.update(user);

// delete
await documentAccessor.delete(user);

// Batch
final batch = Batch()
  ..save(user)
  ..update(user);
  ..delete(user);
await batch.commit();

If save a document, please check firestore console.

And can be used field value key and save data by specific key.

DocumentAccessor documentAccessor = DocumentAccessor();
await documentAccessor.saveRaw(
  <String, dynamic>{ UserKey.name.value: 'hogehoge' },
  user.reference,
);

Get a document.

// get
final user = User(id: '0000');  // need to 'id'.
final hoge = await documentAccessor.load<User>(user);

Get documents in collection.

final path = Document.path<User>();
final snapshot = await firestoreInstance.collection(path).getDocuments();

// from snapshot
final listA = snapshot.documents.map((item) => User(snapshot: item)).toList()
  ..forEach((user) {
    print(user.id); // user model.
  });

// from values.
final listB = snapshot.documents.map((item) => User(id: item.documentID, values: item.data)).toList()
  ..forEach((user) {
    print(user.id); // user model.
  });

Model of map object #

Example, Owner's document object is the following json.

{
  "name": "owner",
  "address": {
    "postCode": "0000",
    "country": "japan"
  },
  "medals": [
    {"name": "gold"},
    {"name": "silver"},
    {"name": "bronze"}
  ]
}

Owner that inherited Document has model of map object.

import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

import 'address.dart';
import 'medal.dart';

part 'owner.flamingo.dart';

class Owner extends Document<Owner> {
  Owner({
    String id,
    DocumentSnapshot snapshot,
    Map<String, dynamic> values,
  }) : super(id: id, snapshot: snapshot, values: values);

  @Field()
  String name;

  @ModelField()
  Address address;

  @ModelField()
  List<Medal> medals;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);
}

Create class that inherited Model.

import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

part 'address.flamingo.dart';

class Address extends Model {
  Address({
    this.postCode,
    this.country,
    Map<String, dynamic> values,
  }) : super(values: values);

  @Field()
  String postCode;

  @Field()
  String country;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);
}
import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

part 'medal.flamingo.dart';

class Medal extends Model {
  Medal({
    this.name,
    Map<String, dynamic> values,
  }) : super(values: values);

  @Field()
  String name;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);
}

Example of usage.

// save
final owner = Owner()
  ..name = 'owner'
  ..address = Address(
    postCode: '0000',
    country: 'japan',
  )
  ..medals = [
    Medal(name: 'gold',),
    Medal(name: 'silver',),
    Medal(name: 'bronze',),
  ];

await documentAccessor.save(owner);

// load
final _owner = await documentAccessor.load<Owner>(Owner(id: owner.id));
print('id: ${_owner.id}, name: ${_owner.name}');
print('address: ${_owner.id} ${_owner.address.postCode} ${_owner.address.country}');
print('medals: ${_owner.medals.map((d) => d.name)}');

Snapshot Listener #

Listen snapshot of document.

// Listen
final user = User(id: '0')
  ..name = 'hoge';

final dispose = user.reference.snapshots().listen((snap) {
  final user = User(snapshot: snap);
  print('${user.id}, ${user.name}');
});

// Save, update, delete
DocumentAccessor documentAccessor = DocumentAccessor();
await documentAccessor.save(user);

user.name = 'fuga';
await documentAccessor.update(user);

await documentAccessor.delete(user);

await dispose.cancel();

Listen snapshot of collection documents.

Need to import cloud_firestore.

import 'package:cloud_firestore/cloud_firestore.dart';
// Listen
final path = Document.path<User>();
final query = firestoreInstance.collection(path).limit(20);
final dispose = query.snapshots().listen((querySnapshot) {
  for (var change in querySnapshot.documentChanges) {
    if (change.type == DocumentChangeType.added ) {
      print('added ${change.document.documentID}');
    }
    if (change.type == DocumentChangeType.modified) {
      print('modified ${change.document.documentID}');
    }
    if (change.type == DocumentChangeType.removed) {
      print('removed ${change.document.documentID}');
    }
  }
  final _ = querySnapshot.documents.map((item) => User(snapshot: item)).toList()
    ..forEach((item) => print('${item.id}, ${item.name}'));
});

// Save, update, delete
final user = User(id: '0')
  ..name = 'hoge';

DocumentAccessor documentAccessor = DocumentAccessor();
await documentAccessor.save(user);

user.name = 'fuga';
await documentAccessor.update(user);

await documentAccessor.delete(user);

await dispose.cancel();

Sub Collection #

For example, ranking document has count collection.

Ranking model

import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

import 'count.dart';

part 'ranking.flamingo.dart';

class Ranking extends Document<Ranking> {
  Ranking(
      {String id,
      DocumentSnapshot snapshot,
      Map<String, dynamic> values,
      CollectionReference collectionRef})
      : super(
            id: id,
            snapshot: snapshot,
            values: values,
            collectionRef: collectionRef) {
    count = Collection(this, RankingKey.count.value);
  }

  @Field()
  String title;

  @SubCollection()
  Collection<Count> count;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);
}

Count model

import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

part 'count.flamingo.dart';

class Count extends Document<Count> {
  Count({
    String id,
    DocumentSnapshot snapshot,
    Map<String, dynamic> values,
    CollectionReference collectionRef,
  }) : super(
            id: id,
            snapshot: snapshot,
            values: values,
            collectionRef: collectionRef);

  @Field()
  String userId;

  @Field()
  int count = 0;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);
}

Save and Get Sub Collection.

final ranking = Ranking(id: '20201007')
  ..title = 'userRanking';

// Save sub collection of ranking document
final countA = Count(collectionRef: ranking.count.ref)
  ..userId = '0'
  ..count = 10;
final countB = Count(collectionRef: ranking.count.ref)
  ..userId = '1'
  ..count = 100;
final batch = Batch()
  ..save(ranking)
  ..save(countA)
  ..save(countB);
await batch.commit();

// Get sub collection
final path = ranking.count.ref.path;
final snapshot = await firestoreInstance.collection(path).getDocuments();
final list = snapshot.documents.map((item) => Count(snapshot: item, collectionRef: ranking.count.ref)).toList()
  ..forEach((count) {
    print(count);
  });

Can be also used CollectionDataSource for getting documents.

import 'package:flamingo/collection_data_source.dart';

...

final ref = User().collectionRef;
final snapshot = await CollectionDataSource().loadDocuments(
    ref.path,
    limit: 20,
    order: 'createdAt',
    descending: true,
    whereList: [
      Where('age', isEqualTo: 20),
      Where('gender', isEqualTo: 'man'),
    ],
);
final users = snapshot.documents.map((item) => User(snapshot: item, collectionRef: ref)).toList();

File #

Can operation into Firebase Storage and upload and delete storage file. Using StorageFile and Storage class.

For examople, create post model that have StorageFile.

import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

part 'post.flamingo.dart';

class Post extends Document<Post> {
  Post({String id}) : super(id: id);

  @StorageField()
  StorageFile file;

  @StorageField()
  List<StorageFile> files;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);
}

Upload file to Firebase Storage.

final post = Post();
final storage = Storage();
final file = ... // load image.

// Fetch uploader stream
storage.fetch();

// Checking status
storage.uploader.listen((data){
  print('total: ${data.snapshot.totalByteCount} transferred: ${data.snapshot.bytesTransferred}');
});

// Upload file into firebase storage and save file metadata into firestore
final path = '${post.documentPath}/${PostKey.file.value}';
post.file = await storage.save(path, file, mimeType: mimeTypePng, metadata: {'newPost': 'true'}); // 'mimeType' is defined in master/master.dart
await documentAccessor.save(post);

// Dispose uploader stream
storage.dispose();

Delete storage file.

// delete file in firebase storage and delete file metadata in firestore
final path = '${post.documentPath}/${PostKey.file.value}';
await storage.delete(path, post.file);
await documentAccessor.update(post);

Alternatively, flamingo provide function to operate Cloud Storage and Firestore.

// Save storage and document of storage data.
final storageFile = await storage.saveWithDoc(
    post.reference,
    PostKey.file.value,
    file,
    mimeType: mimeTypePng,
    metadata: {
      'newPost': 'true'
    },
    additionalData: <String, dynamic>{
      'key0': 'key',
      'key1': 10,
      'key2': 0.123,
      'key3': true,
    },
);

// Delete storage and document of storage data.
await storage.deleteWithDoc(post.reference, PostKey.file.value, post.file, isNotNull: true);

Increment #

Example, CreditCard's document has point and score field. Their fields is Increment type.

import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

part 'credit_card.flamingo.dart';

class CreditCard extends Document<CreditCard> {
  CreditCard({
    String id,
    DocumentSnapshot snapshot,
    Map<String, dynamic> values,
  }) : super(id: id, snapshot: snapshot, values: values) {
    point = Increment(CreditCardKey.point.value);
    score = Increment(CreditCardKey.score.value);
  }

  @Field()
  Increment<int> point;

  @Field()
  Increment<double> score;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);

  /// Call after create, update, delete.
  @override
  void onCompleted(ExecuteType executeType) {
    point = point.onRefresh();
    score = score.onRefresh();
  }
}

Increment and decrement of data.

// Increment
final card = CreditCard()
  ..point.incrementValue = 1
  ..score.incrementValue = 1.25;
await documentAccessor.save(card);
print('point ${card.point.value}, score: ${card.score.value}'); // point 1, score 1.25

final _card = await documentAccessor.load<CreditCard>(card);
print('point ${_card.point.value}, score: ${_card.score.value}'); // point 1, score 1.25


// Decrement
card
  ..point.incrementValue = -1
  ..score.incrementValue = -1.00;
await documentAccessor.update(card);
print('point ${card.point.value}, score: ${card.score.value}'); // point 0, score 0.25

final _card = await documentAccessor.load<CreditCard>(card);
print('point ${_card.point.value}, score: ${_card.score.value}'); // point 0, score 0.25


// Clear
card
  ..point.isClearValue = true
  ..score.isClearValue = true;
await documentAccessor.update(card);
print('point ${card.point.value}, score: ${card.score.value}'); // point 0, score 0.0

final _card = await documentAccessor.load<CreditCard>(card);
print('point ${_card.point.value}, score: ${_card.score.value}'); // point 0, score 0.0

Or can be use with increment method of DocumentAccessor.

final card = CreditCard();
final batch = Batch()
  ..save(card);
await batch.commit();

// Increment
card
  ..point = await documentAccessor.increment<int>(card.point, card.reference, value: 10)
  ..score = await documentAccessor.increment<double>(card.score, card.reference, value: 3.5);

// Decrement
card
  ..point = await documentAccessor.increment<int>(card.point, card.reference, value: -5)
  ..score = await documentAccessor.increment<double>(card.score, card.reference, value: -2.5);

// Clear
card
  ..point = await documentAccessor.increment<int>(card.point, card.reference, isClear: true)
  ..score = await documentAccessor.increment<double>(card.score, card.reference, isClear: true);

Attension:

Clear process only set 0 to document and update. It not try transaction process. Do not use except to first set doument

Distributed counter #

Using DistributedCounter and Counter.

For examople, create score model that have Counter.

import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

part 'score.flamingo.dart';

class Score extends Document<Score> {
  Score({
    String id,
  }) : super(id: id) {
    counter = Counter(this, ScoreKey.counter.value, numShards);
  }

  @Field()
  String userId;

  /// DistributedCounter
  @SubCollection()
  Counter counter;

  int numShards = 10;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);
}

Create and increment and load.

/// Create
final score = Score()
  ..userId = '0001';
await documentAccessor.save(score);

final distributedCounter = DistributedCounter();
await distributedCounter.create(score.counter);

/// Increment
for (var i = 0; i < 10; i++) {
  await distributedCounter.increment(score.counter, count: 1);
}

/// Load
final count = await distributedCounter.load(score.counter);
print('count $count ${score.counter.count}');

Transaction #

This api is simply wrap transaction function of Firestore.

RunTransaction.scope((transaction) async {
  final hoge = User()
    ..name = 'hoge';

  // save
  await transaction.set(hoge.reference, hoge.toData());

  // update
  final fuge = User(id: '0')
    ..name = 'fuge';
  await transaction.update(fuge.reference, fuge.toData());

  // delete
  await transaction.delete(User(id: '1').reference);
});

Objects for model #

Map objects

Create the following model class.

import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

part 'map_sample.flamingo.dart';

class MapSample extends Document<MapSample> {
  MapSample({
    String id,
    DocumentSnapshot snapshot,
    Map<String, dynamic> values,
  }) : super(id: id, snapshot: snapshot, values: values);

  @Field()
  Map<String, String> strMap;

  @Field()
  Map<String, int> intMap;

  @Field()
  Map<String, double> doubleMap;

  @Field()
  Map<String, bool> boolMap;

  @Field()
  List<Map<String, String>> listStrMap;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);
}

And save and load documents.

final sample1 = MapSample()
  ..strMap = {'userId1': 'tanaka', 'userId2': 'hanako', 'userId3': 'shohei',}
  ..intMap = {'userId1': 0, 'userId2': 1, 'userId3': 2,}
  ..doubleMap = {'userId1': 1.02, 'userId2': 0.14, 'userId3': 0.89,}
  ..boolMap = {'userId1': true, 'userId2': true, 'userId3': true,}
  ..listStrMap = [
    {'userId1': 'tanaka', 'userId2': 'hanako',},
    {'adminId1': 'shohei', 'adminId2': 'tanigawa',},
    {'managerId1': 'ueno', 'managerId2': 'yoshikawa',},
  ];
await documentAccessor.save(sample1);

final _sample1 = await documentAccessor.load<MapSample>(MapSample(id: sample1.id));

List

Create the following model class.

import 'package:flamingo/flamingo.dart';
import 'package:flamingo_annotation/flamingo_annotation.dart';

part 'list_sample.flamingo.dart';

class ListSample extends Document<ListSample> {
  ListSample({
    String id,
    DocumentSnapshot snapshot,
    Map<String, dynamic> values,
  }) : super(id: id, snapshot: snapshot, values: values);

  @Field()
  List<String> strList;

  @Field()
  List<int> intList;

  @Field()
  List<double> doubleList;

  @Field()
  List<bool> boolList;

  @StorageField(isWriteNotNull: false)
  List<StorageFile> filesA;

  @StorageField()
  List<StorageFile> filesB;

  @override
  Map<String, dynamic> toData() => _$toData(this);

  @override
  void fromData(Map<String, dynamic> data) => _$fromData(this, data);
}

And save and load documents.

/// Save
final sample1 = ListSample()
  ..strList = ['userId1', 'userId2', 'userId3',]
  ..intList = [0, 1, 2,]
  ..doubleList = [0.0, 0.1, 0.2,]
  ..boolList = [true, false, true,]
  ..filesA = [
    StorageFile(
        name: 'name1', url: 'https://sample1.jpg', mimeType: mimeTypePng),
    StorageFile(
        name: 'name2', url: 'https://sample2.jpg', mimeType: mimeTypePng),
    StorageFile(
        name: 'name3', url: 'https://sample3.jpg', mimeType: mimeTypePng),
  ]
  ..filesB = [
    StorageFile(
        name: 'name1', url: 'https://sample1.jpg', mimeType: mimeTypePng),
    StorageFile(
        name: 'name2', url: 'https://sample2.jpg', mimeType: mimeTypePng),
    StorageFile(
        name: 'name3', url: 'https://sample3.jpg', mimeType: mimeTypePng),
  ];
await documentAccessor.save(sample1);

/// Load
final _sample1 = await documentAccessor.load<ListSample>(ListSample(id: sample1.id));

Unit Test #

Install packages for unit test.

dev_dependencies:
  ...

  test: ^1.14.4
  cloud_firestore_mocks: ^0.4.4
  firebase_storage_mocks: ^0.1.0

Set Firestore and Cloud Storage mock instance.

import 'package:cloud_firestore_mocks/cloud_firestore_mocks.dart';
import 'package:firebase_storage_mocks/firebase_storage_mocks.dart';
import 'package:flamingo/flamingo.dart';
import 'package:test/test.dart';

void main() {
  final firestore = MockFirestoreInstance();
  final storage = MockFirebaseStorage();
  Flamingo.configure(
      firestore: firestore,
      storage: storage,
      root: firestore.document('test/v1'));
  ...
}

sample code

Dependency Injection #

Provide interface classes.

  • DocumentAccessorRepository
  • BatchRepository
  • CollectionRepository
  • StorageRepository
  • DistributedCounterRepository

Reference #

1.1.1 #

Added Unit Test description to README and added sample code.

1.1.0+1 #

Updated README.

1.1.0 #

Added interface classes. Added CollectionDataSource for getting collection documents.

1.0.0+1 #

Updated README.

1.0.0 #

Added feature of automatically generate code.

0.5.3+1 #

Removed base.dart export.

0.5.3 #

Updated static document path function. Added override parameter to set key of "createdAt" and "updatedAt". Modified README.

0.5.2 #

Fixed environment.

0.5.1 #

Updated environment and README.

0.5.0 #

Added documentPath and collectionPath parameter in Document class.

0.4.0 #

Modified modelName and collectionRootReference.

0.3.0 #

Updated flamingo root and Batch interface.

0.2.6 #

Bug fix.

0.2.5 #

Fix: Save empty data of storage in writeStorage feature.

0.2.4 #

Fix: Add empty List during updation(Thanks huma11farheen-san).

0.2.3 #

Set default values for metadata and additionalData(Thanks kikuchy-san). Updated plugin and modify document.

0.2.2 #

Remove path_provider plugin adn updated plugin.

0.2.1 #

Update plugin.

0.2.0+1 #

Deleted unnecessary files.

0.2.0 #

Update plugin and bug fix for collection reference.

0.1.16 #

Bug fix.

0.1.15 #

Bug fix.

0.1.14 #

Bug fix.

0.1.13 #

Modified property access.

0.1.12 #

Modified mapping timestamp for algolia.

0.1.11 #

Remove dependency on json_annotation #2

0.1.10+1 #

Update example's pubspec.yaml.

0.1.10 #

Update environment version.

0.1.9 #

Rename function. saveStorageAndDoc => saveWithDoc, deleteStorageAndDoc => deleteWithDoc.

0.1.8 #

Add function of raw values for document. Add function to save and delete storage and document.

0.1.7 #

Update firestore plugin.

0.1.6 #

Update environment sdk.

0.1.5 #

Update dependence plugin.

0.1.4 #

Modified batch.

0.1.3 #

Bug fix.

0.1.2 #

Add function of raw values for batch. Add Increment model. Add override method of onCompleted.

0.1.1+2 #

Modified pubspec.yaml.

0.1.1+1 #

Updated document.

0.1.1 #

Rename transaction interface.

0.1.0+1 #

Updated document.

0.1.0 #

Format source code.

0.0.10 #

Add model class of map object. Updated and README.

0.0.9 #

Updated load of DocumentAccessor and README.

0.0.8 #

Added write function. Added path parameter of storage file. Updated firebase packages. Updated README.

0.0.7+1 #

Added additionalData parameter of storage file.

0.0.7 #

Added function for mapping list and modified mapping json of storage file.

0.0.6 #

Added function for mapping map objects and added metadata to storage file.

0.0.5 #

Update initialize spec.

0.0.4+1 #

Update document.

0.0.4 #

Update plugin of firebase.

0.0.3+2 #

Update CHANGELOG.md.

0.0.3+1 #

Update README.md.

0.0.3 #

Bug fix for Android.

0.0.2 #

Bug fix.

0.0.1 #

First release.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flamingo/flamingo.dart';
import 'flamingo_test.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  Flamingo.configure();
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  final test = FlamingoTest();

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flamingo sample app'),
        ),
        body: SingleChildScrollView(
          child: _body(),
        ),
      ),
    );
  }

  Widget _body() {
    return Container(
      color: Colors.white,
      child: Align(
        alignment: Alignment.center,
        child: Column(
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('All',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.all();
                  },
                  child: Text('Start', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Document',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.save();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.amberAccent,
                  onPressed: () async {
                    await test.update();
                  },
                  child: Text('update', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.black12,
                  onPressed: () async {
                    await test.delete();
                  },
                  child: Text('Delete', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Document Raw',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.saveRaw();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.amberAccent,
                  onPressed: () async {
                    await test.updateRaw();
                  },
                  child: Text('update', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.black12,
                  onPressed: () async {
                    await test.deleteRaw();
                  },
                  child: Text('Delete', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Batch',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.batchSave();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.black12,
                  onPressed: () async {
                    await test.batchUpdateDelete();
                  },
                  child: Text('Delete', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Batch Raw',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.batchSaveRaw();
                  },
                  child: Text('Save Raw', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.black12,
                  onPressed: () async {
                    await test.batchUpdateDeleteRaw();
                  },
                  child: Text('Delete Raw', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Batch Collection',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.batchCollectionCRUD();
                  },
                  child: Text('CRUD', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Get',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.redAccent,
                  onPressed: () async {
                    await test.getAndUpdate();
                  },
                  child: Text('GetAndUpdate', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.green,
                  onPressed: () async {
                    await test.getCollection();
                  },
                  child: Text('Collection', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('SubCollection',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.green,
                  onPressed: () async {
                    await test.subCollection();
                  },
                  child: Text('SubCollection', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Storage',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.saveStorage();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.black12,
                  onPressed: () async {
                    await test.deleteStorage();
                  },
                  child: Text('Delete', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('StorageAndDoc',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.saveStorageAndDoc();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.black12,
                  onPressed: () async {
                    await test.deleteStorageAndDoc();
                  },
                  child: Text('Delete', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.saveAndDeleteStorageDocWithDocumentAccessor();
                  },
                  child: Text('Save empty list.', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('DistributedCounter',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.distributedCounter();
                  },
                  child: Text('CreateIncrementGet', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Transaction',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.transactionSave();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.amber,
                  onPressed: () async {
                    await test.transactionUpdate();
                  },
                  child: Text('Update', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.black12,
                  onPressed: () async {
                    await test.transactionDelete();
                  },
                  child: Text('Delete', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('MapSave',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.saveMap();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('ListSave',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.saveList();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('CheckModalSample',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.checkModelSample();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('ListenerSample',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.listenerSample();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Model',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.model();
                  },
                  child: Text('Save', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Increment',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.incrementTest1();
                  },
                  child: Text('Save 1', style: TextStyle(color: Colors.white),),
                ),
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.deepPurple,
                  onPressed: () async {
                    await test.incrementTest2();
                  },
                  child: Text('Save 2', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('ValueZeroTest',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.valueZeroTest();
                  },
                  child: Text('Save 1', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Extend document',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.extendCRUD();
                  },
                  child: Text('CRUD', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Test reference path',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.testReferencePath();
                  },
                  child: Text('CRUD', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Test custom field value key.',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.testCustomFieldValueKey();
                  },
                  child: Text('Execute', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.all(4),
              child: Text('Test error check',style: TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.left,),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.all(4),
                  color: Colors.lightBlue,
                  onPressed: () async {
                    await test.testErrorCheck();
                  },
                  child: Text('Execute', style: TextStyle(color: Colors.white),),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  flamingo: ^1.1.1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:flamingo/flamingo.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
74
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
87
Learn more about scoring.

We analyzed this package on Jun 4, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.2
  • pana: 0.13.8-dev
  • Flutter: 1.17.1

Health suggestions

Format lib/constants.dart.

Run flutter format to format lib/constants.dart.

Format lib/enum/execute_type.dart.

Run flutter format to format lib/enum/execute_type.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.7.0 <3.0.0
cloud_firestore ^0.13.6 0.13.6
firebase_core ^0.4.5 0.4.5
firebase_storage ^3.1.6 3.1.6
flutter 0.0.0
Transitive dependencies
charcode 1.1.3
cloud_firestore_platform_interface 1.1.2
cloud_firestore_web 0.1.1+2
collection 1.14.12
firebase 7.3.0
firebase_core_platform_interface 1.0.4
firebase_core_web 0.1.1+2
flutter_web_plugins 0.0.0
http 0.12.1
http_parser 3.1.4
js 0.6.1+1
matcher 0.12.6
meta 1.1.8
path 1.7.0
pedantic 1.9.0
plugin_platform_interface 1.0.2
quiver 2.1.3
sky_engine 0.0.99
source_span 1.7.0
stack_trace 1.9.3
string_scanner 1.0.5
term_glyph 1.1.0
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test
pedantic_mono ^1.9.1