Flutter - firestore-connections
Table of Contents
2 Connecting to firestore
First add the dependency
open the file pubspec.yaml
and add the dependency for cloud_firestore
dependencies:
flutter:
sdk: flutter
cloud_firestore: ^0.8.2
Make sure to run packages get
to pull the new dependencies
Connecting Android
Once you have your firebase project and firestore database created, you’ll need to add the keys for both Android and iOS. This section will just cover android
Create a new app in firebase and choose the android type.
Get the Android package name
from android/app/src/main/AndroidManifest.xml
-> manifest/package
Download the config file google-services.json
and move it to the android/app
directory
open android/app/build.gradle
, then add the following line as the last line in the file: apply plugin: 'com.google.gms.google-services'
Open android/build.gradle
, then inside the buildscript
tag, add a new dependency:
buildscript {
repositories {
// ...
}
dependencies {
// ...
classpath 'com.google.gms:google-services:3.2.1' // new
}
}
Using Firestore from your app
Replace the contents of main.dart
with the following
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
final dummySnapshot = [
{"name": "Filip", "votes": 15},
{"name": "Abraham", "votes": 14},
{"name": "Richard", "votes": 11},
{"name": "Ike", "votes": 10},
{"name": "Justin", "votes": 1},
];
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Baby Names',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() {
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Baby Name Votes')),
body: _buildBody(context),
);
}
Widget _buildBody(BuildContext context) {
// TODO: get actual snapshot from Cloud Firestore
return _buildList(context, dummySnapshot);
}
Widget _buildList(BuildContext context, List<Map> snapshot) {
return ListView(
padding: const EdgeInsets.only(top: 20.0),
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
);
}
Widget _buildListItem(BuildContext context, Map data) {
final record = Record.fromMap(data);
return Padding(
key: ValueKey(record.name),
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(5.0),
),
child: ListTile(
title: Text(record.name),
trailing: Text(record.votes.toString()),
onTap: () => print(record),
),
),
);
}
}
class Record {
final String name;
final int votes;
final DocumentReference reference;
Record.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['name'] != null),
assert(map['votes'] != null),
name = map['name'],
votes = map['votes'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
@override
String toString() => "Record<$name:$votes>";
}
Now replace the _buildBody
method with the following
Widget _buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('baby').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildList(context, snapshot.data.documents);
},
);
}
Change the _buildList
signature to this:
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
Change the _buildListItem
signature to this:
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
Update Firestore from your app
Find the line that says onTap: () => print(record)
and change it to this:
onTap: () => record.reference.updateData({'votes': record.votes + 1})
Firestore Snapshots
We just used the stream builder to access the records
QuerySnapshot <- Firestore.instance.collection(‘baby’).snapshots()
DocumentSnapshot <- Firestore.instance.collection(‘baby’).snapshots().data.documents
DocumentSnapshot <- Firestore.instance.collection(‘baby’).snapshots().data.documents.map( data )
^^ the .map( (data) => function(context, data) )
sends each document into the function
and provides all of the individual function
returns
DocumentReference <- Firestore.instance.collection(‘baby’).snapshots().data.documents.map( data.reference ) Map<String, dynamic> <- Firestore.instance.collection(‘baby’).snapshots().data.documents.map( data.data ) List (ListView) <- Firestore.instance.collection(‘baby’).snapshots().data.documents.map().toList()
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('baby').snapshots()
_buildList(context, snapshot.data.documents);
...
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
...
children: snapshot.map( (data) => _buildListItem(context, data) ).toList(),
...
_buildListItem(BuildContext context, DocumentSnapshot data) {
...
final record = Record.fromSnapshot(data);
onTap: () => record.reference.updateData({'votes': record.votes + 1})
...
class Record {
final DocumentReference reference;
...
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
Record.fromMap(Map<String, dynamic> map, {this.reference})
name = map['name'],
votes = map['votes'];