This Example we are implementing all CRUD operations.
What is Firestore Database?
Let's get Started.
Step 1: Create Flutter Application.
Step 2: Integrate Firebase database Refer My Previous post Integrate Firebase with Flutter.
Step 3: Add required dependencies
dependencies:
flutter:
sdk: flutter
cloud_firestore: ^0.13.4+2
font_awesome_flutter: ^8.8.1
image_picker: ^0.6.4
firebase_storage: ^3.1.5
|
Step 4:
Create Homepage to display all posts.
SocialPostFireStore.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'add_post.dart';
import 'constants.dart';
import 'details_post.dart';
class SocialPostFireStore extends StatelessWidget {
final db = Firestore.instance;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: app_color,
appBar: AppBar(title: Text("Social App"),backgroundColor: app_color,elevation: 0.0,),
floatingActionButton: FloatingActionButton(
mini: true,
backgroundColor: app_color,
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) {
return AddPost();
},));
},
child: Icon(Icons.add,color: Colors.white,),),
body: ListView(
padding: EdgeInsets.only(left: 5,right: 5,bottom: 20),
children: [
SizedBox(height: 5.0),
StreamBuilder(
stream: db.collection('Posts').orderBy("createdtm",descending: true).snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents.map((doc) {
print(doc.data);
return GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context) {
return PostDetails(data:doc.data['post']);
},));
},
child: Card(
shape:RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)
,)
),
color: Colors.white,
elevation: 1,
shadowColor: Colors.amberAccent,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 40.0,
height: 40.0,
decoration: new BoxDecoration(
shape: BoxShape.circle,
image: new DecorationImage(
fit: BoxFit.fill,
image: new NetworkImage(
"https://pbs.twimg.com/profile_images/916384996092448768/PF1TSFOE_400x400.jpg")),
),
margin: const EdgeInsets.symmetric(horizontal: 8.0),
),
(doc.data['post']==null)?Container():
Expanded(child: Text(doc.data['post']['title'],style: TextStyle(color: app_color,fontSize: 18,fontWeight: FontWeight.bold,letterSpacing:1),))
],
),
(doc.data['post']==null)?Container():
postInfo(doc.documentID,doc.data,context)
],
),
),
),
);
ListTile(
title: Text(doc.data['title'].toString()),
trailing: IconButton(
icon: Icon(Icons.cancel),
onPressed: () async {
await db
.collection('Posts')
.document(doc.documentID)
.delete();
},
),
);
}).toList(),
);
} else {
return SizedBox();
}
}),
],
),
);
}
postInfo(documentID,data,context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: Column(
children: [
Card(
elevation: 0.2,
margin: EdgeInsets.all(2),
child: Image.network(data['post']['img'],fit: BoxFit.fitWidth,height: 120,),
) ,
SizedBox(height: 10,),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(data['post']['desc'],maxLines:3,overflow: TextOverflow.ellipsis,style: TextStyle(
letterSpacing: 0.2,
color: Colors.indigoAccent,fontSize: 14
),),
),
SizedBox(height: 10,),
Divider(height: 2,color: app_color,thickness: 1,),
SizedBox(height: 10,),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.only(left:8.0),
child: Row(
children: [
Text(data['post']['like'].toString(),style: TextStyle(color: Colors.amber),),
IconButton(
icon: FaIcon(FontAwesomeIcons.solidHandPointUp,color: Colors.amber,),
onPressed: (){
data['post']['like']= data['post']['like']+1;
db.collection("Posts").document(documentID).updateData(data);
}),
],
),
),
Padding(
padding: const EdgeInsets.only(left:8.0),
child: Row(
children: [
Text(data['post']['dislike'].toString(),style: TextStyle(color: Colors.orange),),
IconButton(
icon: FaIcon(FontAwesomeIcons.solidHandPointDown,color: Colors.orange,),
onPressed: (){
data['post']['dislike']= data['post']['dislike']+1;
db.collection("Posts").document(documentID).updateData(data).catchError((ex){print(ex);});
}),
],
),
),
],
),
PopupMenuButton(itemBuilder: (context) {
return >[
new PopupMenuItem( value: 2, child: new Text('Delete')),
];
},icon: Icon(Icons.more_vert,color: Colors.red,),onSelected: (value) => {
db.collection("Posts").document(documentID).delete()
},),
],
),
decoration: new BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(10),bottomRight: Radius.circular(10)),
border: Border.all(color: app_color,width: 1)
),
)
],
),
);
}
}
|
Step 5: Create addPost file
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'constants.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as Path;
class AddPost extends StatefulWidget{
var scaffole_key= GlobalKey();
@override
State createState() {
// TODO: implement createState
return AddPostState();
}
}
class AddPostState extends State{
final db = Firestore.instance;
TextEditingController titleCtrl=TextEditingController();
TextEditingController descCtrl=TextEditingController();
String _uploadedFileURL;
File _image;
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
key: widget.scaffole_key,
appBar: AppBar(elevation: 0.0,backgroundColor: app_color,title: Text("Add Post"),),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: [
SizedBox(height: 10,),
TextFormField(
controller: titleCtrl,
decoration: new InputDecoration(
labelText: "Enter Post Title",
fillColor: Colors.white,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: app_color,width: 2),borderRadius: BorderRadius.only(bottomRight: Radius.circular(10),topLeft: Radius.circular(10))
),
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(5.0),
borderSide: new BorderSide(
),
),
//fillColor: Colors.green
),
validator: (val) {
if(val.length==0) {
return "Title cannot be empty";
}else{
return null;
}
},
keyboardType: TextInputType.emailAddress,
style: new TextStyle(
fontFamily: "Poppins",
),
),
SizedBox(height: 20,),
TextFormField(
minLines: 5,
maxLines: 8,
controller: descCtrl,
decoration: new InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: app_color,width: 2),borderRadius: BorderRadius.only(bottomRight: Radius.circular(10),topLeft: Radius.circular(10))
),
labelText: "Enter Post Description",
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(5.0),
borderSide: new BorderSide(
),
),
//fillColor: Colors.green
),
validator: (val) {
if(val.length==0) {
return "Description cannot be empty";
}else{
return null;
}
},
keyboardType: TextInputType.emailAddress,
style: new TextStyle(
fontFamily: "Poppins",
),
),
SizedBox(height: 10,),
Card(
elevation: 0.2,
margin: EdgeInsets.all(2),
) ,
SizedBox(height: 10,),
Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(bottomRight: Radius.circular(10),topLeft: Radius.circular(10)),
border: Border.all(color: Colors.amber,width: 1)
),
child: Column(
children: [
_image == null
? IconButton(
iconSize: 40,
icon: Icon(Icons.camera_alt),
onPressed: chooseFile,
color: Colors.amber,
)
: IconButton(
iconSize: 20,
icon: Icon(Icons.clear),
onPressed: (){
setState(() {
_image=null;
_uploadedFileURL="";
});
},
color: Colors.red,
),
Text('Selected Image'),
_image != null
? Image.asset(
_image.path,
height: 150,
)
: Container(height: 150),
],
),
),
SizedBox(height: 10,),
Divider(height: 2,color: app_color,thickness: 1,),
MaterialButton(
color: app_color,
textColor: Colors.white,
child: Text("Submit"),
onPressed: (){
if(titleCtrl.text.isEmpty)
{
widget.scaffole_key.currentState.showSnackBar(SnackBar(content: Text("Please enter Post title")));
return ;
}
Mapposthm=new Map();
Maphm=new Map();
hm.putIfAbsent("title", () => titleCtrl.text);
hm.putIfAbsent("desc", () => descCtrl.text);
hm.putIfAbsent("id", () => "");
hm.putIfAbsent("img", () => _uploadedFileURL);
hm.putIfAbsent("dislike", () => 0);
hm.putIfAbsent("like", () => 0);
posthm.putIfAbsent("post", () => hm);
posthm.putIfAbsent("createdtm", () => Timestamp.now());
db.collection("Posts").reference().add(posthm);
Navigator.pop(context);
})
],
),
),
);
}
Future chooseFile() async {
await ImagePicker.pickImage(source: ImageSource.gallery).then((image) {
setState(() {
_image=image;
});
uploadFile(_image);
});
}
Future uploadFile(_image) async {
StorageReference storageReference = FirebaseStorage.instance
.ref()
.child('posts/${Path.basename(_image.path)}}');
StorageUploadTask uploadTask = storageReference.putFile(_image);
await uploadTask.onComplete;
print('File Uploaded');
storageReference.getDownloadURL().then((fileURL) {
print("Uploaded file $fileURL");
setState(() {
_uploadedFileURL = fileURL;
});
});
}
Future delete(_image) async {
StorageReference storageReference = FirebaseStorage.instance
.ref()
.child('posts/${Path.basename(_image.path)}}');
storageReference.delete();
print('File Uploaded');
}
}
|
Step 6: Create Details page
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'constants.dart';
class PostDetails extends StatelessWidget{
PostDetails({this.data});
var data;
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(elevation: 0.0,backgroundColor: app_color,),
body: Padding(
padding: const EdgeInsets.all(12.0),
child: ListView(
children: [
Expanded(child: Text(data['title'],style: TextStyle(color: Colors.red,fontSize: 18,fontWeight: FontWeight.bold,letterSpacing:1),)),
SizedBox(height: 10,),
Card(
elevation: 0.2,
margin: EdgeInsets.all(2),
child: Image.network(data['img'],fit: BoxFit.fitWidth,),
),
SizedBox(height: 10,),
Container(
width: 200,
decoration: BoxDecoration(border: Border.all(color: Colors.amber),borderRadius: BorderRadius.all(Radius.circular(5))),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(left:8.0),
child: Row(
children: [
Text(data['like'].toString(),style: TextStyle(color: Colors.amber),),
IconButton(
icon: FaIcon(FontAwesomeIcons.solidHandPointUp,color: Colors.amber,),
)
],
),
),
Padding(
padding: const EdgeInsets.only(left:8.0),
child: Row(
children: [
Text(data['dislike'].toString(),style: TextStyle(color: Colors.orange),),
IconButton(
icon: FaIcon(FontAwesomeIcons.solidHandPointDown,color: Colors.orange,),
),
],
),
),
],
),
),
SizedBox(height: 10,),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(data['desc'],style: TextStyle(
letterSpacing: 0.2,
color: Colors.indigoAccent,fontSize: 14
),),
),
SizedBox(height: 10,),
Divider(height: 2,color: app_color,thickness: 1,),
],
),
),
);
}
}
|
Step 7: Update main dart file
import 'package:flutter/material.dart';
import 'delete_firestore.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Social App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SocialPostFireStore(),
);
}
}
|
Step 8: Run Application
Article Contributed By :
|
|
|
|
670 Views |