[Flutter Library] Flamingo is a firebase firestore model framework library. ๐Ÿค

Overview

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:

dev_dependencies:
  build_runner:
  flamingo_generator:

Setup

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

Usage

Adding a initializeApp code to main.dart.

Initialize

import 'package:flamingo/flamingo.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Flamingo.initializeApp();
  ...
}

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<Map<String, dynamic>>? 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:
        throw Exception('Invalid data key.');
    }
  }
}

/// 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');
}

[Option] build.yaml

If you set build.yaml in the root of the project, the automatic generation will be faster.

https://github.com/hukusuke1007/flamingo/blob/master/flamingo/example/build.yaml

targets:
  $default:
    builders:
      flamingo_generator|field_value_generator:
        generate_for:
          include:
            - lib/model/*.dart
            - lib/model/**/*.dart

CRUD

Create instance the following code.

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

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

Using DocumentAccessor or Batch or Transaction in order to CRUD.

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

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

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

Get a document.

final user = await documentAccessor.load<User>(User(id: 'userId'));

Get a document from cache.

final user = await documentAccessor.loadCache<User>(User(id: 'userId'));

Get a document from cache and server.

String name = 'Anonymous';

final user = await documentAccessor.load<User>(
  User(id: 'userId'),
  fromCache: (cache) {
    setState(() {
      // 1. update state from cache
      if (cache != null) {
        name = cache.name;
      }
    });
  },
);
setState(() {
  // 2. update state from serverAndCache
  if (user != null) {
    name = user.name;
  }
});

Get Collection Documents

CollectionPaging

Can be used get and paging features of documents by CollectionPaging.

Query of Collection.

final collectionPaging = CollectionPaging<User>(
  query: User().collectionRef.orderBy('createdAt', descending: true),
  limit: 20,
  decode: (snap) => User(snapshot: snap),
);

// Load 
List<User> items = await collectionPaging.load();

// LoadMore
final _items = await collectionPaging.loadMore();
items.addAll(_items);

Get a documents from cache and server.

List<User> items = [];

final _items = await collectionPaging.load(
  fromCache: (caches) {
    setState(() {
      // 1. update state from cache
      items = caches;
    });
  },
);

// 2. update state from serverAndCache
setState(() {
  items = _items;
});

Query of CollectionGroup.

final collectionPaging = CollectionPaging<User>(
  query: firestoreInstance
    .collectionGroup('user')
    .orderBy('createdAt', descending: true),
  limit: 20,
  decode: (snap) => User(snapshot: snap),
);

sample code

CollectionPagingListener

Can be used listener and paging features of documents by CollectionPagingListener.

final collectionPagingListener = CollectionPagingListener<User>(
  query: User().collectionRef.orderBy('updatedAt', descending: true),
  initialLimit: 20,
  pagingLimit: 20,
  decode: (snap) => User(snapshot: snap),
);

// Fetch to set listener.
collectionPagingListener.fetch();

final items = <User>[];

// Get documents via listener. data is ValueStream.
collectionPagingListener.data.listen((event) {
    setState(() {
      items = event;
    });
  });

// Get document changes status and cache status.
collectionPagingListener.docChanges.listen((event) {
    for (var item in event) {
      final change = item.docChange;
      print('id: ${item.doc.id}, changeType: ${change.type}, oldIndex: ${change.oldIndex}, newIndex: ${change.newIndex} cache: ${change.doc.metadata.isFromCache}');
    }
  });

// LoadMore. To load next page data.
collectionPagingListener.loadMore();


// Dispose.
await collectionPagingListener.dispose();

sample code

firestoreInstance

Can be get documents in collection.

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

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

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

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. And can be used also CollectionPagingListener.

// 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.docs.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();

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<Map<String, dynamic>>? 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)}');

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<Map<String, dynamic>>? snapshot,
      Map<String, dynamic>? values,
      CollectionReference<Map<String, dynamic>>? collectionRef})
      : super(
            id: id,
            snapshot: snapshot,
            values: values,
            collectionRef: collectionRef) {
    count = Collection(this, RankingKey.count.value);
  }

  @Field()
  String? title;

  @SubCollection()
  late 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<Map<String, dynamic>>? snapshot,
    Map<String, dynamic>? values,
    CollectionReference<Map<String, dynamic>>? 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).get();
final list = snapshot.docs.map((item) => Count(snapshot: item)).toList()
  ..forEach((count) {
    print(count);
  });

File

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

For example, 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.totalBytes} transferred: ${data.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
await storage.delete(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<Map<String, dynamic>>? snapshot,
    Map<String, dynamic>? values,
  }) : super(id: id, snapshot: snapshot, values: values);

  @Field()
  Increment<int> point = Increment<int>();

  @Field()
  Increment<double> score = Increment<double>();

  @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, fieldName: CreditCardKey.point.value, value: 10)
  ..score = await documentAccessor.increment<double>(card.score, card.reference, fieldName: CreditCardKey.score.value, value: 3.5);

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

// Clear
card
  ..point = await documentAccessor.increment<int>(card.point, card.reference, fieldName: CreditCardKey.point.value, isClear: true)
  ..score = await documentAccessor.increment<double>(card.score, card.reference, fieldName: CreditCardKey.score.value, 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 example, 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()
  late 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<Map<String, dynamic>>? 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<Map<String, dynamic>>? 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));

[WIP] Unit Test

โ€ปUnder construction

Install packages for unit test.

dev_dependencies:
  ...

  test: ^1.14.4
  cloud_firestore_mocks:
  firebase_storage_mocks:

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() async {
  final firestore = MockFirestoreInstance();
  final storage = MockFirebaseStorage();
  await Flamingo.initializeApp(
      firestore: firestore,
      storage: storage,
      root: firestore.document('test/v1'));
  ...
}

sample code

Reference

Comments
  • The data type of List being changed to null during update

    The data type of List being changed to null during update

    Description: The updated version allows me to deleted all the images from a list but changes the dataType to null due to which further query to add to list cannot be done. The dataType getting changed to null instead of array when all elements of a list are deleted

    code snippets :

    //in flamingo (UserDocument) writeStorageList(data, "subProfileImages", subProfileImages);

    //To fetch user Document final document = await DocumentAccessor() .load<UserDocument>(social.UserDocument(id: userId));

    Steps to reproduce:

    when updating document.subProfileImages = []

    In Firebase: when images are present: Screenshot 2020-03-31 at 19 45 22

    when the entire list is deleted(updated): Screenshot 2020-03-31 at 19 47 26

    subProfileImages becomes null due to which no further query can be made. @hukusuke1007

    opened by huma11farheen 8
  • Expected a value of type 'String', but got one of type 'Null'

    Expected a value of type 'String', but got one of type 'Null'

    Nice to meet you, my name is kyuji.

    We are evaluating flamingo, but if the field increases in the model, refer to the data before the increase. I get the error "Expected a value of type'String', but got one of type'Null'". It seems to occur when there is no corresponding Field in Helper.valueFromKey in _ $ fromData (this, data). Is it possible to set Null when there is no Field? Or is it used incorrectly?

    -- Japaneseใ€€-- flamingoใฎ่ฉ•ไพกใ‚’ใ—ใฆใŠใ‚Šใพใ™ใŒใ€modelใซFieldใŒๅข—ใˆใŸๅ ดๅˆใ€ๅข—ใˆใ‚‹ๅ‰ใฎใƒ‡ใƒผใ‚ฟใ‚’ๅ‚็…งใ™ใ‚‹ใจ ใ€ŒExpected a value of type 'String', but got one of type 'Null'ใ€ใฎใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใพใ™ใ€‚ _$fromData(this, data)ๅ†…ใฎใ€Helper.valueFromKeyใงใ€่ฉฒๅฝ“FieldใŒใชใ„ๆ™‚ใซ็™บ็”Ÿใ™ใ‚‹ใ‚ˆใ†ใงใ™ใ€‚ FieldใŒใชใ„ๅ ดๅˆใซใ€Nullใ‚’่จญๅฎšใ™ใ‚‹ไบ‹ใฏๅฏ่ƒฝใงใ—ใ‚‡ใ†ใ‹ใ€‚ ใใ‚Œใจใ‚‚ใ€ไฝฟ็”จๆ–นๆณ•ใŒ้–“้•ใฃใฆใ„ใพใ™ใงใ—ใ‚‡ใ†ใ‹ใ€‚

    ไปฅไธŠใ€ๅฎœใ—ใใŠ้ก˜ใ„่‡ดใ—ใพใ™ใ€‚

    bug 
    opened by kyujihub 5
  • Immutable data types

    Immutable data types

    Hi ! I've been struggling to find a good approach to modeling firebase data. I started with functional_data and then looked at this library but was discouraged by mutability and then I settled on freezed. However with the new null safety, I've been trying to solve one problem. Having everything be non-null. This includes the references, ids and so on of a document. One thing I've come to realize is that this would need two separate classes. Take for example a user. One class is the base implementation. Nothing to do with firebase. The second (generated) class would be the one after we've associated it with a firebase document. Its reference would never null.

    I came up with a close approximation of what it'd look like here:

    /// @Flamingo(options) will set the collection ref
    /// $User provides immutable `copyWith` implementation or lenses.
    @Flamingo(path: 'path/to/users', collectionRef: myCollectionRef)
    class User extends $User {
      const User({
        required this.name,
        required this.email,
      });
    
      final String name;
    
      final String email;
    
      UserDoc toDocument(DocumentSnapshot snapshot) => _$toDocument(snapshot);
    }
    
    /// This class will be auto generated and be kept inside the part file.
    /// $UserDoc will also create `copyWith` and/or lenses.
    class UserDoc extends $UserDoc with Document<UserDoc>, Snapshot {
      UserDoc({
        required this.name,
        required this.email,
        required this.reference,
        required this.metadata,
        required this.id,
        required this.exists,
      });
    
      final String name;
    
      final String email;
    
      final DocumentReference reference;
    
      final SnapshotMetadata metadata;
    
      final String id;
    
      final bool exists;
    
      factory UserDoc.fromSnapshot(DocumentSnapshot snapshot) =>
          _$fromSnapshot(snapshot);
    
      @override
      Map<String, dynamic> toData() => _$toData(this);
    }
    
    // In a separate file
    abstract class Document<T> {
      // Sort of the implementation as previously
    }
    
    // In a separate file
    abstract class Snapshot {
      DocumentReference get reference;
    
      SnapshotMetadata get metadata;
    
      String get id;
    
      bool get exists;
    }
    
    

    One thing I really like about this is that nothing is nullable. If something is we'd have a @nullable annotation or something otherwise we'll throw a parse error.

    To update a value for example we could:

    // You could either create a user and then attach it to a do
    // Or create a UserDoc from non empty a snapshot
    final user = User(name: 'kilo', email: '[email protected]');
    final userDoc = User.toDocument(CollectionRef.doc());
    
    await documentAccessor.save(userDoc.copyWith(name: 'Kilo'));
    

    If this is something you'd be interested in, I could try for a PR or be glad to keep discussing

    opened by Nolence 4
  • Enum support

    Enum support

    Hi!

    Is there currently no way to use enums?

    enum Role { admin, editor, user }
    
    class Profile extends Document<Profile> {
      // ...
      @Field()
      Role role;
    }
    
    [VERBOSE-2:ui_dart_state.cc(166)] Unhandled Exception: type 'String' is not a subtype of type 'Role' in type cast
    #0      _AppState.build.<anonymous closure> 
    package:approach_builder/main.dart:107
    #1      _streamStartListening.<anonymous closure>.<anonymous closure> 
    package:provider/src/async_provider.dart:30
    #2      _rootRunUnary  (dart:async/zone.dart:1198:47)
    #3      _CustomZone.runUnary  (dart:async/zone.dart:1100:19)
    #4      _CustomZone.runUnaryGuarded  (dart:async/zone.dart:1005:7)
    #5      _BufferingStreamSubscription._sendError.sendError  (dart:async/stream_impl.dart:378:15)
    #6      _BufferingStreamSubscription._sendError  (dart:async/stream_impl.dart:394:16)
    #7      _BufferingStreamSubscription._addError  (dart:async/stream_impl.dart:294:7)
    #8      _SyncBroadcastStreamController._sendError.<anonymous closure>  (dart:async/broadcast_stream_controller.dart:400:20)
    #9      _BroadcastStreamController._forEachListener  (dart:async/broadcast_stream_controller.dart:330:15)
    
    opened by Nolence 3
  • Reference to a child Document - how to retrieve data?

    Reference to a child Document - how to retrieve data?

    Thank you for providing this library. I'm a new user of it, and relatively new to firestore.

    Could you please confirm the best way to deal with references todocuments like in the image below ("ref" in "carts" (in the parent document) refers to another document in "shopper" (child document))

    image

    Should i use the child Document's id as the reference? If so, it seems ok to save the document with the reference it contains as a String with writeNotNull in the overriden toData method. But when loading the document containing the reference from firestore, what is the best way to trigger also the loading of the child document refered to by the parent document?

    Thanks in advance for your help

    opened by grangoni 3
  • Fix: Add empty List during updation

    Fix: Add empty List during updation

    Description: During updation, Empty List was not being accepted, Which makes the empty list always non-empty

    Changes made: Removed the condition for storageFiles.isNotEmpty

    opened by huma11farheen 3
  • Explanation about configuration on README.md

    Explanation about configuration on README.md

    The example shown in readme is not clear about how rootReference is going to be created.

    import 'package:flamingo/flamingo.dart';
    
    void main() {
      Flamingo.configure(rootName: 'version', version: 1);
      ...
    }
    

    My suggestion is to add this snippet or a text describing that rootName will be a collection and version a document:

    instance.rootReference =
            instance.firestore.collection('${rootName != null ? rootName : 'version'}')
                .document('${version != null ? version.toString() : '1'}');
    

    Also, would it be possible to not have this structure and just use Firestore's default "/" root?

    opened by Jagni 3
  • How can I set collection name for model

    How can I set collection name for model

    We'd like to customize the collection name which model class uses. For example we use file name user_model.dart with UserModel class inside. We'd like the collection to be named users.

    It would be handy to specify collection name using class annotation.

    opened by vladaman 2
  • Document.onCompleted() is called twice when documentAccessor.save()

    Document.onCompleted() is called twice when documentAccessor.save()

    I think Document.onCompleted() is called twice for each documents.

    https://github.com/hukusuke1007/flamingo/blob/7437db4dd66157499d65013230032d6cba7f08a6/flamingo/lib/src/batch.dart#L126 https://github.com/hukusuke1007/flamingo/blob/7437db4dd66157499d65013230032d6cba7f08a6/flamingo/lib/src/document_accessor.dart#L37

    Perhaps it should be called once for each documents after batch.commit() is completed?

    bug 
    opened by hajimetakase 2
  • How to get all document and not paging?

    How to get all document and not paging?

    collectionPaging = CollectionPaging<WallpagersDoc>(
          query: WallpagersDoc()
              .collectionRef
              .orderBy(documentUpdatedAtKey, descending: true),
          limit: 200,
          decode: (
            snap,
          ) =>
              WallpagersDoc(snapshot: snap),
        );
    

    how to get all document WallpagersDoc ?

    enhancement 
    opened by beheobong 2
  • Error when using Increment field: The getter 'fieldName' was called on null

    Error when using Increment field: The getter 'fieldName' was called on null

    Getting an error while using Increment field

    here is my model:

    
    import 'some/packages;
    
    
    part 'user.flamingo.dart';
    
    class AppUser extends Document<AppUser> {
      @Field()
      String name;
      @Field()
      String username;
      @Field()
      String firstName;
      @Field()
      String lastName;
      @Field()
      String email;
      @Field()
      String phoneNumber;
      @Field()
      String photoUrl;
    
      @Field()
      Increment<int> newMessagesCount;
      @SubCollection()
      Collection<Token> tokens;
    
      AppUser(
          {String id,
          DocumentSnapshot snapshot,
          Map<String, dynamic> values})
          : super(
                id: id,
                snapshot: snapshot,
                values: values,
          collectionRef: Flamingo.instance.rootReference.collection('users')) {
        tokens = Collection(this, AppUserKey.tokens.value);
        newMessagesCount = Increment(AppUserKey.newMessagesCount.value);
      }
    
    
      @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) {
        newMessagesCount = newMessagesCount.onRefresh();
      }
    }
    
    

    and here is some stacktraces:

    I/flutter (19763): โ•โ•โ•ก EXCEPTION CAUGHT BY WIDGETS LIBRARY โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    I/flutter (19763): The following NoSuchMethodError was thrown building StreamBuilder<DocumentSnapshot>(dirty, state:
    I/flutter (19763): _StreamBuilderBaseState<DocumentSnapshot, AsyncSnapshot<DocumentSnapshot>>#7e0eb):
    I/flutter (19763): The getter 'fieldName' was called on null.
    I/flutter (19763): Receiver: null
    I/flutter (19763): Tried calling: fieldName
    I/flutter (19763): 
    I/flutter (19763): The relevant error-causing widget was:
    I/flutter (19763):   StreamBuilder<DocumentSnapshot>
    I/flutter (19763):   file:///.../../file.dart:151:16
    I/flutter (19763): 
    I/flutter (19763): When the exception was thrown, this was the stack:
    I/flutter (19763): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
    I/flutter (19763): #1      _$fromData (package:app/models/user.flamingo.dart:75:65)
    I/flutter (19763): #2      AppUser.fromData (package:app/models/user.dart:60:47)
    I/flutter (19763): #3      Document.setSnapshot (package:flamingo/src/model/document.dart:125:7)
    I/flutter (19763): #4      new Document (package:flamingo/src/model/document.dart:48:9)
    I/flutter (19763): #5      new AppUser (package:app/models/user.dart:37:9)
    I/flutter (19763): #6      _ChatScreenState.build.<anonymous closure> (package:app/widgets/screens/main/chats/chat_screen.dart:157:29)
    I/flutter (19763): #7      StreamBuilder.build (package:flutter/src/widgets/async.dart:525:81)
    I/flutter (19763): #8      _StreamBuilderBaseState.build (package:flutter/src/widgets/async.dart:129:48)
    I/flutter (19763): #9      StatefulElement.build (package:flutter/src/widgets/framework.dart:4744:28)
    I/flutter (19763): #10     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4627:15)
    I/flutter (19763): #11     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
    I/flutter (19763): #12     Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
    I/flutter (19763): #13     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2730:33)
    I/flutter (19763): #14     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:913:20)
    I/flutter (19763): #15     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:302:5)
    I/flutter (19763): #16     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
    I/flutter (19763): #17     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1055:9)
    I/flutter (19763): #18     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:971:5)
    I/flutter (19763): #22     _invoke (dart:ui/hooks.dart:251:10)
    I/flutter (19763): #23     _drawFrame (dart:ui/hooks.dart:209:3)
    I/flutter (19763): (elided 3 frames from dart:async)
    I/flutter (19763): 
    I/flutter (19763): โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    I/flutter (19763): id: null, changeType: DocumentChangeType.added, oldIndex: -1, newIndex: 0 cache: true
    I/flutter (19763): id: null, changeType: DocumentChangeType.added, oldIndex: -1, newIndex: 1 cache: true
    I/flutter (19763): id: null, changeType: DocumentChangeType.added, oldIndex: -1, newIndex: 2 cache: true
    I/flutter (19763): โ•โ•โ•ก EXCEPTION CAUGHT BY WIDGETS LIBRARY โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    I/flutter (19763): The following NoSuchMethodError was thrown building StreamBuilder<DocumentSnapshot>(dirty, state:
    I/flutter (19763): _StreamBuilderBaseState<DocumentSnapshot, AsyncSnapshot<DocumentSnapshot>>#7e0eb):
    I/flutter (19763): The getter 'fieldName' was called on null.
    I/flutter (19763): Receiver: null
    I/flutter (19763): Tried calling: fieldName
    I/flutter (19763): 
    I/flutter (19763): The relevant error-causing widget was:
    I/flutter (19763):   StreamBuilder<DocumentSnapshot>
    I/flutter (19763):   file:///.../../file.dart:151:16
    I/flutter (19763): 
    I/flutter (19763): When the exception was thrown, this was the stack:
    I/flutter (19763): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
    I/flutter (19763): #1      _$fromData (package:app/models/user.flamingo.dart:75:65)
    I/flutter (19763): #2      AppUser.fromData (package:app/models/user.dart:60:47)
    I/flutter (19763): #3      Document.setSnapshot (package:flamingo/src/model/document.dart:125:7)
    I/flutter (19763): #4      new Document (package:flamingo/src/model/document.dart:48:9)
    I/flutter (19763): #5      new AppUser (package:app/models/user.dart:37:9)
    I/flutter (19763): #6      _ChatScreenState.build.<anonymous closure> (package:app/widgets/screens/main/chats/chat_screen.dart:157:29)
    I/flutter (19763): #7      StreamBuilder.build (package:flutter/src/widgets/async.dart:525:81)
    I/flutter (19763): #8      _StreamBuilderBaseState.build (package:flutter/src/widgets/async.dart:129:48)
    I/flutter (19763): #9      StatefulElement.build (package:flutter/src/widgets/framework.dart:4744:28)
    I/flutter (19763): #10     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4627:15)
    I/flutter (19763): #11     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
    I/flutter (19763): #12     Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
    I/flutter (19763): #13     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2730:33)
    I/flutter (19763): #14     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:913:20)
    I/flutter (19763): #15     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:302:5)
    I/flutter (19763): #16     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
    I/flutter (19763): #17     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1055:9)
    I/flutter (19763): #18     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:971:5)
    I/flutter (19763): #22     _invoke (dart:ui/hooks.dart:251:10)
    I/flutter (19763): #23     _drawFrame (dart:ui/hooks.dart:209:3)
    I/flutter (19763): (elided 3 frames from dart:async)
    I/flutter (19763): 
    I/flutter (19763): โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    
    bug 
    opened by tnaffh 2
  • How to limit query to just few fields?

    How to limit query to just few fields?

    We have a collection, let's say "Users" and we'd like any user to be able to query list of all user names but not other fields. In firestore we can set restriction rule to specific fields but running query just queries all fields.

    We get an error:

    Unhandled Exception: [cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.
    
    opened by vladaman 0
  • Saving existing model object updates createdAt field

    Saving existing model object updates createdAt field

    Every time we save model it also updates createdAt and updatedAt field. We'd expect the createdAt field would not be updated for future object updates.

    Code sample:

    final batch = Batch()
    ..save(existingObject);
    await batch.commit();
    

    We can use Batch()..update() but the behavior is different. It will update just updatedAt field but on the device it will set createdAt field to null. Is this expected behavior?

    final batch = Batch()
      ..update(existingObject);
      await batch.commit();
      debugPrint("New Val: ${existingObject.createdAt}"); // here createdAt is null
    

    We believe the issue is here, where createdAt will be set to null: https://github.com/hukusuke1007/flamingo/blob/af8836dfeddb4055a5e414bba3b1c63d18cc29be/flamingo/lib/src/model/document.dart#L144

    opened by vladaman 0
  • flutter_generator seem to ignore generate_for option

    flutter_generator seem to ignore generate_for option

    Even if we have following in pubspec.yaml

    flamingo_generator|field_value_generator:
            generate_for:
              include:
                - lib/models/*.dart
    

    the generator reports warnings about other files such as:

    [WARNING] flamingo_generator:field_value_generator on lib/screens/project_editor_screen.dart:
    project_editor_screen.flamingo.dart must be included as a part directive in the input library with:
        part 'project_editor_screen.flamingo.dart';
    

    This is reported when there is a previous error with some misspelled file name. Looks like the generator then goes over all files.

    opened by vladaman 0
  • Add Support for Fields which cannot be null

    Add Support for Fields which cannot be null

    We have following field which has no value in Firestore. If we fetch this model we get an error. We do not want to add bool? since we take this value as default if it's not present.

    // Field Definition
    @Field()
    bool requireSomeField = false;
    
    2021-07-28 11:09:24.547 25564-25650/eu.app E/flutter: [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: type 'Null' is not a subtype of type 'bool' in type cast
        #0      Helper.valueFromKey (package:flamingo/src/helper/helper.dart:214:18)
    
    enhancement 
    opened by vladaman 4
  • Document.onRelease() should be private?

    Document.onRelease() should be private?

    I think if Document.onRelease() is executed before the commit(), then the data could be corrupted(because it does incrementValue = null; https://github.com/hukusuke1007/flamingo/blob/7437db4dd66157499d65013230032d6cba7f08a6/flamingo/lib/src/model/increment.dart#L41 ). So maybe Document.onRelease() should be private?

    Also, I sometime wants to access to Document.value after the increment, so maybe there should be some field like Document.promisedValue which return the value after the commit() beforehand.

    int get promisedValue => { 
    if (incrementValue != null) {
            final _value =
                value != null ? value! + incrementValue! : incrementValue;
            result = Increment<T>(value: _value! as T);
          } else {
            result = Increment<T>(value: value);
          }
    return result.value
    }
    
    enhancement 
    opened by hajimetakase 0
Releases(2.18.0)
Owner
shohei
Never Inc. CEO & Engineer
shohei
Learn how to build a tensorflow model on Techable Machine and then run it on flutter app.

Ml With Flutter Learn how to build a tensorflow model on Techable Machine and then run it on flutter app. Youtube Tutorial Show Support Recommend Me O

Sanskar Tiwari 133 Jan 3, 2023
Flutter App Build for the machine Learning model which shows sentiments of instagram user by analysing their captions

InstaKnow Front-end By @ketanchoyal Back-end By @namas191297 Front-end Application Flutter application that allows user to analyze sentiments of other

Ketan Choyal 40 Oct 28, 2022
This is simple model replication i made in flutter

This is simple model replication i made in flutter

sushil gyawali 3 Sep 20, 2022
This is machine learning project where developed the model in teachable machine.

doc_help 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

Abu sayed chowdhury 1 Apr 26, 2022
A Widget that passes a Reactive Model to all of it's children

scoped_model A set of utilities that allow you to easily pass a data Model from a parent Widget down to its descendants. In addition, it also rebuilds

Brian Egan 779 Nov 30, 2022
A chat application that utilizes the smart reply ML model to suggest contextual conversation replies.

smart_reply A chat application that utilizes the smart reply ML model to suggest contextual conversation replies. Sample Notes Smart Replies are conte

Ahmed Aboelyazeed 1 May 15, 2022
Flutter web example with Firebase Authentication, Firestore Collection, BloC Pattern

flutter_auth_web Flutter Firebase auth. Getting Started This project is a starting point for a Flutter application. A few resources to get you started

null 1 Feb 26, 2022
Ifoodcare - Food Donation App in Flutter using Firebase Auth, Firestore

Food Donation App in Flutter using Firebase Auth, Firestore

Raunak Chatterjee 3 Nov 17, 2022
Functioning Doctor/Healthcare Catalog App created using Dart with Flutter. Stores and loads data from Firebase Firestore DB.

flutter_medical Functioning Doctor/Healthcare Catalog & Scheduling App created using Dart with Flutter. Stores and loads data from noSQL Firebase. Ins

John Uberbacher 209 Dec 19, 2022
A working Twitter clone written in Flutter using Firebase auth,realtime,firestore database and storage

A working Twitter clone written in Flutter using Firebase auth,realtime,firestore database and storage

The Github Mafia 17 Dec 24, 2022
Cross Platform app in Flutter with Firebase Auth and Firestore. Available for Mobile,Web,Desktop

NavokiNotes Navoki Notes, a note app app, will sync data to cloud and on all devices. We have application for Android, iOS, Web App, PWA, Windows, mac

shivam srivastava 93 Dec 27, 2022
Notey - A noteApp build using flutter with firebase cloud firestore

notey A project to create and store notes for later purposes. Notey is built usi

Al-amin O. 1 Aug 14, 2022
A working Twitter clone built in Flutter using Firebase auth,realtime,firestore database and storage.

Fwitter - Twitter clone in flutter A working Twitter clone built in Flutter using Firebase auth,realtime,firestore database and storage. Dependencies

Dominique Rwema Bagirishya 31 Oct 5, 2022
This project is based on ecommerce (medicine selling) application by flutter and firebase firestore

This project is based on ecommerce (medicine selling) application by flutter and firebase firestore. In this project you will get whole things like search, filter, order tracking etc. after order placed. I have created this by MVVM architecture with Razorpay payment and GetX State management.

Amir Rahi 3 Sep 7, 2022
The prime objective of this app is to store the real time information of the user using firebase cloud firestore and also can delete, remove and update the customer information

crud_firestore A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started i

Muhammad Zakariya 0 Mar 15, 2022
Implementing simple storage operations, CRUD (Create, Read, Update, Delete), using Firebase Firestore

CRUD Firebase Implementing simple storage operations, CRUD (Create, Read, Update

Luciano Martins 6 Oct 29, 2022
Firebase firestore currencies app, realtime database example.

Firebase firestore currencies app, realtime database example.

Mustafa KIZILTAY 1 Apr 27, 2022
This project uses transactions in Firebase(FirebaseAuth and FireStore) to send and receive virtual money across accounts

FinTech (WIP) This project uses transactions in Firebase(FirebaseAuth and FireStore) to send and receive virtual money across accounts. On account cre

Godson 4 Nov 15, 2022
Flying Fish is full-stack Dart framework - a semi-opinionated framework for building applications exclusively using Dart and Flutter

Flying Fish is full-stack Dart framework - a semi-opinionated framework for building applications exclusively using Dart and Flutter.

Flutter Fish 3 Dec 27, 2022