How to fetch data from cloud firestore in flutter? - database

I want to fetch contact details like phone number, email address, website url & also social media urls from firestore in flutter. I done coding to show contact details directly in-app but I need to get data from firestore because it will be good for me if suppose i need to change contact details in future.
My coding
import 'package:cloud_firestore/cloud_firestore.dart';
class AboutPage extends StatelessWidget {
const AboutPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: LightColor.white,
appBar: CustomAppBar(
isBackButton: true,
title: customTitleText(
'Contact us',
),
),
body: ListView(
physics: BouncingScrollPhysics(),
children: <Widget>[
HeaderWidget(
'Feel free to contact us',
secondHeader: true,
),
SettingRowWidget(
"Phone",
vPadding: 0,
showDivider: false,
onPressed: () {
Utility.launchURL(///i want to display this url from firestore///
"tel:+918889999888");
},
),
HeaderWidget('Social media'),
SettingRowWidget("Facebook", showDivider: true, onPressed: () {
Utility.launchURL( ///i want to display this url from firestore///
"https://facebook.com/ecways");
}),
HeaderWidget('Website'),
SettingRowWidget("Open website", showDivider: true, onPressed: () {
Utility.launchURL( ///i want to display this url from firestore///
"https://facebook.com/");
}),
],
),
);
}
}
I created firestore database with collection name "my_contact" and document name "details" and also i created field for phone, email, website and extra. Now i just want to know how to display that collection in my app with my coding.

First of all you have to change your firestore database as below
There should be array called contacts and inside that there should be 3 maps according to your data.
Then create a list in your screen class.
List contacts;
Then create a function to retrieve data from firestore.
Future<List> fetchAllContact() async {
List contactList = [];
DocumentSnapshot documentSnapshot =
await firestore.collection('my_contact').doc('details').get();
contactList = documentSnapshot.data()['contacts'];
return contactList;
}
Then call this function inside initState function.
#override
void initState() {
super.initState();
fetchAllContact().then((List list) {
setState(() {
contacts = list;
});
});
}
Finally replace your listView as a listViewBuilder.
Container(
child: ListView.builder(
padding: EdgeInsets.all(10),
itemCount: contacts.length,
itemBuilder: (context, index) {
return CustomTile(
mini: false,
onTap: () {},
title: Text(
contacts[index]['headerTitle'] != null
? contacts[index]['headerTitle']
: '',
style: TextStyle(
color: Colors.white,
fontFamily: "Arial",
fontSize: 19),
),
subtitle: Text(
contacts[index]['value'] != null
? contacts[index]['value']
: '',
style: TextStyle(
color: UniversalVariables.greyColor,
fontSize: 14,
),
),
leading: Container(
constraints:
BoxConstraints(maxHeight: 60, maxWidth: 60),
child: Stack(
children: <Widget>[
CircleAvatar(
maxRadius: 30,
backgroundColor: Colors.grey,
backgroundImage: NetworkImage(
"https://avatars.githubusercontent.com/u/49371842?v=4"),
),
Align(
alignment: Alignment.bottomRight,
child: Container(
height: 13,
width: 13,
decoration: BoxDecoration(
shape: BoxShape.circle,
color:
UniversalVariables.onlineDotColor,
border: Border.all(
color:
UniversalVariables.blackColor,
width: 2)),
),
)
],
),
),
);
}
),
)
This is how I did it. Thanks...

flutterfire now have a good walk through for that. Please refer to this section for fetching data from firestore https://firebase.flutter.dev/docs/firestore/usage/#collections--documents

Related

How do i show user data from firebase to my flutter app?

im new to flutter and i wanted to know how can i retrieve a user data from firebase to my profile page?
my firebase data contain a name, email, blood type, and a date of birth. and i would like to retrieve these data to my app's profile page.
this is my profile page code
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:line_awesome_flutter/line_awesome_flutter.dart';
import '../Reminder/ui/theme.dart';
class ProfilePage extends StatefulWidget {
const ProfilePage({super.key});
#override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
final user = FirebaseAuth.instance.currentUser!;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
//leading: IconButton(onPressed: (){}, icon: const Icon(Icons.arrow_back_ios_new),),
centerTitle: true,
title: Text(
'Profile',
style: headingStyle,
),
backgroundColor: Get.isDarkMode ? Colors.grey[700] : Colors.white,
),
body: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(10),
child: Column(
children: [
SizedBox(
width: 120,
height: 120,
child: Image(image: AssetImage("images/profile.png")),
),
const SizedBox(height: 50),
Form(
child: Column(
children: [
TextFormField(
decoration: InputDecoration(
prefixIconColor: Get.isDarkMode?Colors.black:Colors.white,
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100), borderSide: BorderSide(color: Get.isDarkMode?Colors.white:Colors.black,)),
labelText: "Email",
prefixIcon: Icon(LineAwesomeIcons.envelope_1, color: Get.isDarkMode?Colors.white:Colors.black),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(100))),
),
SizedBox(height: 10),
TextFormField(
decoration: InputDecoration(
prefixIconColor: Get.isDarkMode?Colors.black:Colors.white,
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100), borderSide: BorderSide(color: Get.isDarkMode?Colors.white:Colors.black,)),
labelText: "Full Name",
prefixIcon: Icon(LineAwesomeIcons.user, color: Get.isDarkMode?Colors.white:Colors.black),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(100))),
),
SizedBox(height: 10),
TextFormField(
decoration: InputDecoration(
prefixIconColor: Get.isDarkMode?Colors.black:Colors.white,
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100), borderSide: BorderSide(color: Get.isDarkMode?Colors.white:Colors.black,)),
labelText: "Date of Birth",
prefixIcon: Icon(LineAwesomeIcons.baby_carriage, color: Get.isDarkMode?Colors.white:Colors.black),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(100))),
),
SizedBox(height: 10),
TextFormField(
decoration: InputDecoration(
prefixIconColor: Get.isDarkMode?Colors.black:Colors.white,
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100), borderSide: BorderSide(color: Get.isDarkMode?Colors.white:Colors.black,)),
labelText: "Blood Type",
prefixIcon: Icon(Icons.bloodtype, color: Get.isDarkMode?Colors.white:Colors.black),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(100))),
),
SizedBox(height: 15,),
SizedBox(
width: 100,
child: MaterialButton(
onPressed: () {
FirebaseAuth.instance.signOut();
},
color: Colors.redAccent,
child: Text('SIGN OUT'),
),
),
],
),
)
],
),
),
),
);
}
}
Use either StreamBuilder or FutureBuilder and get the data from firebase and display it accordingly
1. StreamBuilder
When you want to listen to changes constantly, and want the data to get updated without hot reload/restart
2. FutureBuilder
When you want to get the document only once and have no requirement of listening constantly to the change of the document.
Using StreamBuilder
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore
.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid) // 👈 Your document id which is equal to currentuser
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
Map<String, dynamic> data =
snapshot.data!.data()! as Map<String, dynamic>;
return Text(data['fullName']); // 👈 your valid data here
},
),
),
);
}
Using FutureBuilder
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
future: FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid) // 👈 Your document id which is equal to currentuser
.get(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
Map<String, dynamic> data = snapshot.data!.data()!;
return Text(data['fullName']); //👈 Your valid data here
},
)),
);
}
You can use stram builder to retrieve data from the firebase and display it to the user on real time. It may have some issues with styling, since I wrote it without any IDE, but I hope you'll get the idea how to get your data from stream builder.
Example:
class ProfilePage extends StatefulWidget {
const ProfilePage({super.key});
#override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children:[
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('your_collection')
.snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: SizedBox(
height: 50,
width: 50,
child: CircularProgressIndicator(
color: Style.blueColorDark,
backgroundColor: Style.olive,
),
),
);
}else{
return ListView(
shrinkWrap: true,
children: snapshot.data!.docs.map((document) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16),
child: Card(
color: const Color.fromRGBO(
255, 255, 255, 1)
.withOpacity(0.6),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(15),
),
child: Column(
children: <Widget>[
Text(data['name']),
Text(data['email']),
Text(data['bloodType']),
Text(data['dob']),
],
),
),
);
}).toList(),
);
}
}
)
]
)
}
}

How to store data for each user in Flutter Firebase Realtime Database?

I am building a mobile application using Flutter.
For the to-do list feature, I connected it to the firebase real-time database so that when values are added to the application, those are automatically updated in the firebase database.
It was successfully done but what I want to implement is storing data separated by users.
It is like users have their own separated database in one firebase real-time database.
For example, if person A adds to-do list data, only A can view it and add more data of him when he signs in. And person B and C cannot view and access A's data but only their own data which they added. And they can add data that can be shown to only themselves when they sign in.
I searched and checked many documents but couldn't find one that helped me.
Could anyone help me implement this feature? I also want to make sure that whether I need to add some codes of it to the application if I change the database rule.
Below is the current firebase real-time database rule.
{
"rules": {
".read": true,
".write": true
}
}
And this is my todo list code.
class ToDo extends StatefulWidget {
#override
_ToDoState createState() => _ToDoState();
}
class _ToDoState extends State<ToDo> {
final fb = FirebaseDatabase.instance;
#override
Widget build(BuildContext context) {
final ref = fb.ref().child('todos');
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.indigo[900],
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => addnote(),
),
);
},
child: Icon(
Icons.add,
),
),
appBar: AppBar(
title: Text(
'Todos',
style: TextStyle(
fontSize: 30,
),
),
backgroundColor: Colors.white,
),
body: FirebaseAnimatedList(
query: ref,
shrinkWrap: true,
itemBuilder: (context, snapshot, animation, index) {
return GestureDetector(
onTap: () {},
child: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.white,
),
borderRadius: BorderRadius.circular(10),
),
tileColor: Colors.indigo[100],
trailing: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red[900],
),
onPressed: () {
ref.child(snapshot.key!).remove();
},
),
title: Text(
snapshot.value.toString(),
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
),
),
),
);
},
),
);
}
}
class addnote extends StatelessWidget {
TextEditingController title = TextEditingController();
final fb = FirebaseDatabase.instance;
#override
Widget build(BuildContext context) {
final ref = fb.ref().child('todos');
return Scaffold(
appBar: AppBar(
title: Text("Add Todos"),
backgroundColor: Colors.indigo[900],
),
body: Container(
child: Column(
children: [
SizedBox(
height: 10,
),
Container(
decoration: BoxDecoration(border: Border.all()),
child: TextField(
controller: title,
decoration: InputDecoration(
hintText: 'title',
),
),
),
SizedBox(
height: 10,
),
MaterialButton(
color: Colors.indigo[900],
onPressed: () {
ref
.push()
.set(
title.text,
)
.asStream();
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (_) => ToDo()));
},
child: Text(
"save",
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
],
),
),
);
}
}
Thank you
You could create a child nodes with users' UID as they as shown below:
todos/
├─ user1/
│ ├─ todoId1
├─ user2/
│ ├─ todoId2
This way you can restrict a user's access to their entries only with the following rules:
{
"rules": {
"todos": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
You'll have to change the DatabaseReference in your code to the UID node instead of just the todos so any new items pushed will be under that user:
// Use this ref to:
// 1. Fetch all TODOs
// 2. push() new TODO
final ref = fb.ref().child('todos').child(CURRENT_USER_ID);
Checkout the documentation to learn more about security rules.

I want to access the single document from firebase and use it show the data and update it

I was trying to get the single doc data from firebase and wanted to update
'''
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_neumorphic/flutter_neumorphic.dart';
import 'package:wallet_app/utils/custom_textfield.dart';
import '../module/firebase_data.dart';
import '../utils/utilts.dart';
class EditPage extends StatefulWidget {
const EditPage({
Key? key,
required this.docId,
}) : super(key: key);
final String docId;
#override
State<EditPage> createState() => _EditPageState();
}
class _EditPageState extends State<EditPage> {
late DocumentSnapshot data;
Future getData() async {
User? user = FirebaseAuth.instance.currentUser;
await FirebaseFirestore.instance
.collection('users')
.doc(user?.uid)
.collection('transactions')
.doc(widget.docId)
.get()
.then((value) => data = value);
}
#override
Widget build(BuildContext context) {
TextEditingController titleController =
TextEditingController(text: data['title']);
TextEditingController amountController =
TextEditingController(text: data['amount'].toString());
TextEditingController descriptionController =
TextEditingController(text: data['description']);
bool income = data['type'];
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
foregroundColor: Colors.grey.shade800,
elevation: 0,
centerTitle: true,
title: const Text(
'Edit Transaction',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
body: FutureBuilder(
future: getData(),
builder: (context, snapshot) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CustomTextfield(
hintText: 'Title', controller: titleController),
CustomTextfield(
hintText: 'Amount',
controller: amountController,
keyBoradType: TextInputType.number,
),
CustomTextfield(
hintText: 'Description',
controller: descriptionController,
miniLines: 4,
maxLines: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Expense',
style: TextStyle(
fontWeight: FontWeight.w500, fontSize: 18),
),
Switch(
activeColor: Colors.green.shade300,
inactiveTrackColor: Colors.red.shade300,
inactiveThumbColor: Colors.red.shade100,
value: income,
onChanged: (v) {
setState(() {
income = v;
});
}),
const Text(
'Income',
style: TextStyle(
fontWeight: FontWeight.w500, fontSize: 18),
),
],
),
NeumorphicButton(
margin: const EdgeInsets.only(top: 15),
style: NeumorphicStyle(
shape: NeumorphicShape.flat,
color: Colors.grey.shade800,
depth: 6,
),
onPressed: () async {
if (titleController.text.isEmpty &&
amountController.text.isEmpty) {
Utils.showError(message: 'Please fill all the fields');
return;
} else {
FireData()
.updateTransaction(
title: titleController.text,
description: descriptionController.text,
amount: double.parse(amountController.text),
type: income,
docId: widget.docId)
.then((value) => {
if (income == true)
{
Utils.showError(
message: 'Income Edited Successfully')
}
else
{
Utils.showError(
message:
'Expense Edited Successfully')
},
titleController.clear(),
descriptionController.clear(),
amountController.clear(),
income = false,
});
Navigator.pop(context);
}
},
child: const Text(
'Edit Transaction',
style: TextStyle(
fontSize: 20,
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
),
TextButton(onPressed: () => data, child: const Text('data'))
],
),
);
}),
);
}
}
'''
I want to update the data note I am using setState function to update the state of the slider but its not updating. I want to show the available data and then allow to update it.
I also tried to get the data from the previous page but I even got stuck in that if.
I can get the Data from previous page if there's any solution for that also we will try that method.

Flutter Images in a List (Flutter)

so I want to have a List/Array that contains images and where each image has his own title.
The image and the title should be shown in two different buttons and the title should change when I tap on the image.
I already could solve the first two points (to show in different places and that the title changes)
But I don't know how to add images to my List, could you help me?
In addition to that, the List should be randomized, but the title should always "stay" with his image.
I hope you understand what I want and thank you for your help.
class Sachen {
String title;
String image;
Sachen(this.title, this.image);
}
final List<Sachen> infoBank = [
Sachen("Chips", "images/snack1.png",),
Sachen("Erdnussflips", "images/snack2.png",),
];
int bankNumber = Random().nextInt(2) +1;
#override
Widget build(BuildContext context) {
return Center(
child: Column(
children: [
Card(
margin: EdgeInsets.fromLTRB(50, 35, 50, 0),
elevation: 8,
color: Color(0xFF4caf50),
child: SizedBox(
height: 80,
width: 150,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 18),
child: GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Rezept('Rezept'),
),
);
},
child: SizedBox(
height: 125,
width: 150,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 18),
child: Text(
infoBank[bankNumber].title,
style: GoogleFonts.rubik(
fontSize: 20,
color: Colors.white,
),
),
),
),
),
),
),
),
),
),
Row(
children: [
Expanded(
child: TextButton(
onPressed: () {
setState(() {
bankNumber++;
});
changeDiceNumber();
print('LeftDiceNumber = $DiceNumber');
},
child: Container(
margin: EdgeInsets.fromLTRB(10, 20, 10, 20),
decoration: BoxDecoration(
border: Border.all(
width: 2,
color: Colors.grey.shade700,
),
),
height: 350,
width: 350,
child: Image.asset('images/snack$DiceNumber.png',
fit: BoxFit.cover,
),
),
),
),
],
),
],
),
);
}
}
have you tried using Flutter's ListViewBuilder?
Like alread said ListView().builder will be a good usage.
Instead of building the widget you can just use ListTile or Card there you already have trailing, leading, and title for the positioning of your images.
Althou i would change the class Sachen with a final Icon or IconData to directly add it to your List. In The Constructor please use required for the parameters its for better reading and don't do mistakes
This is my first idea to use this
class Sachen {
final String title;
final String image;
Sachen({
required this.title,
required this.image,
});
}
final List<Sachen> liste = [
Sachen(title: "title", image: "name"),
Sachen(title: "title1", image: "name1"),
];
return ListView.builder(itemBuilder: (context, index) {
return ListTile(
leading: Image.asset(liste[index].image),
title: Text(liste[index].title),
onTap: (){
//Do On Tap
//remember to use SetState when you want to rebuild some changes
},
);
});
Other Idea maybe a little bit better:
class Sachen {
final String title;
final Image image;
Sachen({
required this.title,
required this.image,
});
}
final List<Sachen> liste = [
Sachen(title: "title", image: Image.asset("name")),
Sachen(title: "title1", image: Image.asset("name1")),
];
#override
Widget build(BuildContext context) {
return ListView.builder(itemBuilder: (context, index) {
return ListTile(
leading: liste[index].image,
title: Text(liste[index].title),
onTap: () {
//Do On Tap
//remember to use SetState when you want to rebuild some changes
},
);
});
}

Is there a way to divide data coming from an API in flutter?

If I'm getting big amounts of data coming from an API and I want to divide them into parts based on the meaning of the words, what's the proper way to do it in flutter?
You can use the pagination package. With this, you can divide your data into pages and you can fetch the only related page data with offset. You can look at the sample code:
import 'package:example/user.dart';
import 'package:faker/faker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:pagination/pagination.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'PaginationView Demo',
theme: ThemeData(
primarySwatch: Colors.cyan,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'PaginationView Example',
style: TextStyle(
color: Colors.white,
),
),
),
body: PaginationList<User>(
shrinkWrap: true,
padding: EdgeInsets.only(
left: 5,
right: 5,
),
separatorWidget: Container(
height: 0.5,
color: Colors.black,
),
itemBuilder: (BuildContext context, User user) {
return ListTile(
title:
Text(user.prefix + " " + user.firstName + " " + user.lastName),
subtitle: Text(user.designation),
leading: IconButton(
icon: Icon(Icons.person_outline),
onPressed: () => null,
),
onTap: () => print(user.designation),
trailing: Icon(
Icons.call,
color: Colors.green,
),
);
},
pageFetch: pageFetch,
onError: (dynamic error) => Center(
child: Text('Something Went Wrong'),
),
initialData: <User>[
User(
faker.person.prefix(),
faker.person.firstName(),
faker.person.lastName(),
faker.company.position(),
),
User(
faker.person.prefix(),
faker.person.firstName(),
faker.person.lastName(),
faker.company.position(),
),
],
onEmpty: Center(
child: Text('Empty List'),
),
),
);
}
Future<List<User>> pageFetch(int offset) async {
final Faker faker = Faker();
final List<User> upcomingList = List.generate(
15,
(int index) => User(
faker.person.prefix(),
faker.person.firstName(),
faker.person.lastName(),
faker.company.position(),
),
);
await Future<List<User>>.delayed(
Duration(milliseconds: 1500),
);
return upcomingList;
}
}

Resources