Flutter future builder duplicating document item at every refresh - firebase

I am populating a list of orders from firestore database in flutter. but order screen is doubling the documents at every refresh. Kindly help.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class FullOrder extends StatelessWidget {
const FullOrder({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
// it enable scrolling on small device
return Center(
child: FutureBuilder(
future: FirebaseFirestore.instance.collection('orders').get(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done ||
snapshot.hasData) {
List<QueryDocumentSnapshot> docs = (snapshot.data! as QuerySnapshot).docs;
return ListView.builder(
shrinkWrap: true,
itemCount: docs.length,
itemBuilder: (context, index) {
var data = docs[index].data();
var dataOrders = data['orders'] as List<dynamic>;
var mappedDataOrders = dataOrders.map((o) => (o as Map<String, dynamic>)).toList();
return Card(
child: Container(
padding: const EdgeInsets.all(4),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Order Id: ${data['orderId']}'),
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Order Date: ${DateFormat('dd/MM/yyyy').format(data['createdAt'].toDate())}'),
Text('Order Time: ${DateFormat('hh:mm a').format(data['createdAt'].toDate())}'),
],),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Name: ${data['name']}', style: const TextStyle(fontWeight: FontWeight.bold),),
Text('Contact: ${data['phoneNumber'].toString()}', style: const TextStyle(fontWeight: FontWeight.bold),),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Delivery Slot', style: TextStyle(fontWeight: FontWeight.bold),),
Text('${data['deliverySlot']}'),
],
),
Column(
children: [
Text('Address: ${data['addressType']}', style: const TextStyle(fontWeight: FontWeight.bold),),
Text('${data['address']}'),
Text('${data['area']}'),
Text('${data['city']}')
],
)
],
),
...List.generate(
mappedDataOrders.length,
(index) {
var order = mappedDataOrders[index] as Map<String, dynamic>;
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(order['title']),
Text(order['unit'].toString()),
Text(order['quantity'].toString()),
Text(order['price'].toString()),
],
),
],
);
}
)
]
),
)
);
}
);
}
return const Center(
child: SizedBox(
width: 100,
height: 100,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.black),
strokeWidth: 5
)
)
);
}
),
);
}
}

When you convert the Database list to map instead of converting to toList() USE toSet(), this helps you out to filter out the duplicating item.
{
// use toSet() to filter the duplicated items.
var mappedDataOrders = dataOrders.map((o) => (o as Map<String, dynamic>)).toSet();
}

Use the .clear(); Because everytime you load youre map instead of restarting the counter id adds to it.
Where you create youre load mappedDataOrdes. You migth have it like this.
Future<List<Database>> searchDatabase() async{
final url= Uri.https(_baseUrl, 'Database.json');
final resp = await http.get(url);
final Map<String,dynamic> databaseMap= jsonDecode(resp.body);
////This is where you migth use the .clear() this will reset the counter for the index and eliminate duplicate
database.clear();
database.forEach((key, value) {
final tempDatabase= Database.fromMap(value);
tempDatabase.id=key;
database.add(tempDatabase);
});
return negocio;
}

Related

A value of type 'Null' can't be assigned to a parameter of type 'String' in a const constructor. Try using a subtype, or removing the keyword 'const'

const homeScreenItems = [
FeedScreen(),
SearchScreen(),
AddPostScreen(),
Text('notification'),
ProfileScreen(uid: FirebaseAuth.instance.currentUser!.uid),
];
above code is my global variable page.
I want to pass uid I stored in Firestore to ProfileScreen() but I am getting the above titled error i.e A value of type 'Null' can't be assigned to a parameter of type 'String' in a const constructor. Try using a subtype, or removing the keyword 'const'.
I have declared uid as final in my ProfileScreen() but still I am getting the above error
//here is the code of ProfileScreen()
class ProfileScreen extends StatefulWidget {
final String uid;
const ProfileScreen({Key? key,required this.uid}) : super(key: key);
#override
_ProfileScreenState createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
var userData = {};
#override
void initState() {
getUserData();
super.initState();
}
getUserData() async {
try {
var snap = await FirebaseFirestore.instance
.collection('users')
.doc(widget.uid)
.get();
setState(() {
userData = snap.data()!;
});
} catch (e) {
showSnakBar(e.toString(), context);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: mobileBackgroundColor,
title: Text(userData['name']),
centerTitle: false,
),
body: ListView(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Row(
children: [
CircleAvatar(
radius: 40,
backgroundImage: NetworkImage(
'https://images.unsplash.com/photo-1647185255712-b5b8687b2a25?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1722&q=80',
),
),
Expanded(
flex: 1,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: [
buildStatColumn(20, 'posts'),
buildStatColumn(150, 'followers'),
buildStatColumn(10, 'following'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FollowButton(
backgroundColor: mobileBackgroundColor,
borderColor: Colors.grey,
text: 'Edit Profile',
textColor: primaryColor,
function: () {},
),
],
),
],
),
),
],
),
Container(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.only(top: 15),
child: Text(
'username',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
),
Container(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.only(top: 1),
child: Text('some bio'),
),
),
],
),
),
const Divider(),
],
),
);
}
Column buildStatColumn(int num, String lable) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
num.toString(),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Container(
margin: const EdgeInsets.only(top: 4),
child: Text(
lable,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
),
),
],
);
}
}
The issue here is that you're using const in homeScreenItems - this sets the variable constant during compile-time and can't be changed. It's usually used for fixed values like Text widgets with fixed String values.
Also, utilizing the bang (!) operator doesn't guarantee that the value won't be null. This only assures the compiler that the value is not null.
Depending on your use-case, you can remove the const from homeScreenItems and add ProfileScreen() once the user has signed-in and you're able to fetch FirebaseAuth.instance.currentUser.
List homeScreenItems = [
FeedScreen(),
SearchScreen(),
AddPostScreen(),
Text('notification'),
];
...
if(FirebaseAuth.instance.currentUser != null){
homeScreenItems.add(ProfileScreen(uid: FirebaseAuth.instance.currentUser!.uid));
}

Data is not being saved at Firebase nor is being retrieved from the firebase

There was no problem saving data into firebase until today. I think this is the same code i use most of the time to store the data in the firebase but strangely the collection " LoanFriends" is not being saved at the firebase. I may be missing some minute details.
The following code doesn't generate any error in the android studio but the data is not being saved.
The code is as follows:
import 'package:budgetapp/ExtractedWidgets/dialog_field.dart';
import 'package:budgetapp/constant.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class WalletScreen extends StatelessWidget {
static String id = 'wallet_screen';
TextEditingController _controllername = TextEditingController();
TextEditingController _controlleraddress =TextEditingController();
TextEditingController _controllerphoneno = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('My Wallet',style: kheadertext),
elevation: 0,
actions: [IconButton(onPressed: (){}, icon: Icon(Icons.notifications_sharp),),],
),
body: Column(
children: [
Container(
height: 200,
decoration: containerdecoration.copyWith( borderRadius: BorderRadius.circular(32.0),),
margin: EdgeInsets.all(15),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(left: 35),
child: Row(
children: [
Text('Balance',style: kmyTextstyle.copyWith(fontSize: 25),),
SizedBox(width: 200,),
Icon(FontAwesomeIcons.moneyBill,
color: Colors.white,),
],
),
),
),
Expanded(
child: Container(
padding: EdgeInsets.only(left: 35),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text('Rs. ', style: kmyTextstyle.copyWith(fontSize: 35),),
SizedBox(width: 5,),
Text("25000",style: kmyTextstyle.copyWith(fontSize: 35),),
],),
),
),
Expanded(
child: Container(
padding: EdgeInsets.only(left: 35),
child: Row(
children: [
Text('My wallet information',style: kmyTextstyle.copyWith(fontSize: 15),),
SizedBox(width: 150,),
Icon(FontAwesomeIcons.ccMastercard,
color: Colors.white,),
],
),
),
),
],
)
),
Text("Loan Mechanism",style: kheadertext.copyWith(fontSize: 20),),
SizedBox(height: 8,),
StreamBuilder<QuerySnapshot?>(
stream: FirebaseFirestore.instance.collection('LoanFriends').snapshots(),
builder: (context,snapshot){
if(!snapshot.hasData){
return CircularProgressIndicator();
}
else {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder:(context, index){
return Text(snapshot.data!.docs[index]['name']);
});
}
}
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: Color(0xFFcdc3ff),
onPressed: (){
showAlertDialog(context);
},
child: Icon(Icons.add),
),
);
}
void showAlertDialog(BuildContext context) {
showDialog(context: context, builder: (context){
return AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(32), ),
content: Container(
height: MediaQuery.of(context).size.height*0.4,
width: MediaQuery.of(context).size.width*0.5,
child: Column(
children: [
Dialogfield(hinttext: 'Enter name', controller: _controllername, textInputtype: TextInputType.name),
Dialogfield(hinttext: 'Enter address', controller: _controlleraddress, textInputtype: TextInputType.text),
Dialogfield(hinttext: 'Enter phonenumber', controller: _controllerphoneno, textInputtype: TextInputType.number),
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
Color(0xFFcdc3ff)),
),
onPressed: (){
Map<String, dynamic> mapdata = {'name': _controllername, 'address': _controlleraddress, 'phonenumber': _controllerphoneno
};
FirebaseFirestore.instance.collection('LoanFriends').add(mapdata);
_controllername.text ='';
_controlleraddress.text='';
_controllerphoneno.text ='';
Navigator.pop(context);
},
child: Text('Add User',style: kmyTextstyle.copyWith(fontSize: 15),),),
],
),
),
);
});
}
}
You need to access the text property of a controller. You cant refer to controller directly.
Change this line:
Map<String, dynamic> mapdata = {'name': _controllername, 'address': _controlleraddress, 'phonenumber': _controllerphoneno
into this line:
Map<String, dynamic> mapdata = {'name': _controllername.text, 'address': _controlleraddress.text, 'phonenumber': _controllerphoneno.text

Flutter Error: The getter 'iterator' was called on null - I'm using FutureBuilder

i'm trying to fetch data/images from firebase storage and then put them into ImageSlider using FutureBuilder, i've succeed to add into list but fail to pass into futurebuilder. Please if know what i should do to make it right, i will be happy for your contribution.
Note: after future builder then i put the images into provider, if you have any suggestion of what i may use instead of provider so that when the user want to review again the product images, user can view images without reloading the same product images.
import 'package:cached_network_image/cached_network_image.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:kariakoonline/constants.dart';
import 'package:kariakoonline/models/product_images.dart';
import 'package:kariakoonline/provider/productImages_provider.dart';
import 'package:kariakoonline/provider/product_provider.dart';
import 'package:provider/provider.dart';
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
class ProductImages extends StatefulWidget {
const ProductImages({
Key key,
#required this.product,
this.sellerId,
this.productId,
}) : super(key: key);
final String product;
final String sellerId;
final String productId;
#override
_ProductImagesState createState() => _ProductImagesState();
}
class _ProductImagesState extends State<ProductImages> {
int selectedImage = 0;
ProductImagesModel imgModel = ProductImagesModel();
List<ProductImagesModel> listPic = [];
#override
void initState() {
print(
'id:${widget.product} - productId: ${widget.productId} and Seller: ${widget.sellerId}');
// listProductImages();
super.initState();
}
Future<void> listProductImages() async {
List<ProductImagesModel> url = [];
List<String> images = [];
String imgUrl;
firebase_storage.ListResult result = await firebase_storage
.FirebaseStorage.instance
.ref('product_images/${widget.sellerId}/${widget.productId}')
.listAll();
if (result.items != null) {
for (firebase_storage.Reference ref in result.items) {
imgUrl = await firebase_storage.FirebaseStorage.instance
.ref(ref.fullPath)
.getDownloadURL();
if (imgUrl != null) {
images.add(imgUrl);
}
}
final imgUrlMode = imgModel.copy(id: widget.product, image: images);
url.add(imgUrlMode);
print('images: $images');
print('img url mode: ${imgUrlMode.image}');
print('url $url');
}
return url;
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: listProductImages(),
builder: (context, snapshot) {
final imgProvider = Provider.of<ProductImagesProvider>(context);
final providerImg = imgProvider.productImg;
imgProvider.setProductImg(snapshot.data);
print('My Data:');
print('My Data: ${snapshot.data}');
print('Provider Model IMG Length: ${imgProvider.productImg.length}');
if (snapshot.connectionState == ConnectionState.waiting) {
return Container(
height: MediaQuery.of(context).size.height / 2,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircularProgressIndicator(),
],
),
);
}
if (snapshot.hasError) {
return Container(
height: MediaQuery.of(context).size.height / 2,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('Something is wrong. Try again letter'),
],
),
);
}
if (snapshot.data == null) {
return Container(
height: MediaQuery.of(context).size.height / 2,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('Error Occoured. Try again letter'),
],
),
);
}
return Container(
child: Column(
children: <Widget>[
SizedBox(
width: double.infinity,
child: AspectRatio(
aspectRatio: 1,
child: CarouselSlider(
options: CarouselOptions(
disableCenter: true,
onScrolled: (index) {},
),
items: <Widget>[
...List.generate(
providerImg.length,
(index) => CachedNetworkImage(
imageUrl: providerImg[index].image[selectedImage],
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
placeholder: (context, url) => Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: CircularProgressIndicator(),
),
),
errorWidget: (context, url, error) => Stack(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Image.asset(
'assets/images/placeholder.jpg',
fit: BoxFit.cover,
),
),
Center(
child: CircularProgressIndicator(),
)
],
),
),
)
],
),
),
),
SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
...List.generate(
providerImg.length,
(index) => buildSmallPreview(index),
),
],
),
],
),
);
});
}
GestureDetector buildSmallPreview(int index) {
final productData = Provider.of<KariakooProducts>(context, listen: false);
final specDataById = productData.findProductId(widget.product);
return GestureDetector(
onTap: () {
setState(() {
selectedImage = index;
});
},
child: Container(
height: 40,
width: 40,
margin: EdgeInsets.symmetric(horizontal: 5),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: selectedImage == index ? kPrimaryColor : kSecondaryColor),
),
child: Image.network(
'',
fit: BoxFit.cover,
),
),
);
}
}
i found the solution.
Started by declaring
Future<List<ProductImagesModel>> listPic;
Then i initiated the listPic from the Future Function listProductImages()
#override
void initState() {
listPic = listProductImages();
super.initState();
}
Then i call listPic in FutureBuilder
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: listPic,
builder: (context, snapshot) {
......
......

Firebase Chat messages not ordering correctly

I have just completed this basic chat app based on a tutorial on YouTube. NO user name needed for using it. But my messages are not ordering correctly. It is sorting as auto generated ID on FireStore. There are total two field in Firebase "message" collection that I have created
"username" {this user name randomly generated by FireBase as user ID. example: 1Mrayhz7EKL7MklHXUxv}
"messagetext"
I don't understanding what should I do now
//Here's the code
class MyApp extends StatelessWidget {
final TextEditingController messaingTextBox = TextEditingController();
final CollectionReference cr =
FirebaseFirestore.instance.collection('messages');
#override
Widget build(BuildContext context) {
body:
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(
child: StreamBuilder(
stream: cr.snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) return CircularProgressIndicator();
return ListView.builder(
reverse: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(18.0),
child: Column(
children: [
Row(
children: [
Container(
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Text(
snapshot.data.documents[index]
.data()['username'],
),
),
),
SizedBox(
width: 10,
),
Container(
// width: 38.0,
width: MediaQuery.of(context).size.width / 1.6,
child: Padding(
padding: const EdgeInsets.all(9.0),
child: Column(
children: [
Text(
snapshot.data.documents[index]
.data()['messagetext'],
),
],
),
),
),
],
),
],
),
);
},
);
},
),
),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
cursorColor: HexColor("#003F51"),
style: TextStyle(color: Colors.black),
controller: messaingTextBox,
),
),
),
FloatingActionButton(
onPressed: () {
Message m = Message(
username: "unkown ",
messagetext: messaingTextBox.text.toString());
cr.add(m.mapMessages());
},
child: Icon(Icons.send),
),
],
),
],
);
}
}
class Message {
final String username;
final String messagetext;
Message({this.messagetext, this.username});
mapMessages() {
return {'messagetext': messagetext, 'username': username};
}
}
Please help me for solving this isue
You need to add third field to store time.
Then in the code try to add orderBy operator.
FirebaseFirestore.instance.collection('messages')
.orderBy('time_field', descending: true);
It's quite simple just add a timestamp with each message lets say createdAt, and the use
NOTE: The type of createdAt must be Date
FirebaseFirestore.instance.collection('messages').orderBy('createdAt', descending: true)

Show loading indicator /spinner when the page data isn't fully loaded from Firebase - Flutter

In my Flutter app, I am using ModalProgressHUD to show a spinner when I click on save buttons in my form screens and it stops spinner once data successfully writes to Firebase.
I have this screen that uses Listview.builder to display a list of all my expenses and I want to automatically show spinner as soon as the page displays, and to stop spinner once all the data from Firebase fully loads.
I need assistance in doing this. I've pasted excerpt of my code as shown below. Thanks in advance.
//class wide declaration
bool showSpinner = true;
Widget build(BuildContext context) {
ExpenseNotifier expenseNotifier = Provider.of<ExpenseNotifier>(context);
Future<void> _resfreshList() async {
expenseNotifier.getExpenses(expenseNotifier);
var expenseList = ExpenseNotifier.getExpenses(expenseNotifier);
if (expenseList != null) {
setState(() {
showSpinner = false;
});
}
return Scaffold(
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: RefreshIndicator(
onRefresh: _resfreshList,
child: Consumer<ExpenseNotifier>(
builder: (context, expense, child) {
return expense == null
? Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
PaddingClass(bodyImage: 'images/empty.png'),
SizedBox(
height: 20.0,
),
Text(
'You don\'t have any expenses',
style: kLabelTextStyle,
),
],
)
: ListView.separated(
itemBuilder: (context, int index) {
var myExpense = expense.expenseList[index];
return Card(
elevation: 8.0,
color: Colors.white70,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
RegularExpenseTextPadding(
regText:
'${_formattedDate(myExpense.updatedAt)}',
),
Container(
margin: EdgeInsets.all(20.0),
padding: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(5.0)),
border: Border.all(
color: kThemeStyleBorderHighlightColour),
),
child: Row(
children: <Widget>[
Expanded(
flex: 5,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
'${myExpense.amount}',
style: kRegularTextStyle,
),
SizedBox(
height: 20.0,
),
Text(
myExpense.description,
style: kRegularTextStyle,
),
],
),
),
Expanded(
flex: 1,
child: GestureDetector(
onTap: () {
expenseNotifier.currentExpense =
expenseNotifier
.expenseList[index];
Navigator.of(context).push(
MaterialPageRoute(builder:
(BuildContext context) {
return ExpenseDetailsScreen();
}));
},
child: Icon(
FontAwesomeIcons.caretDown,
color: kThemeIconColour,
),
),
),
],
),
),
],
),
);
},
separatorBuilder: (BuildContext context, int index) {
return SizedBox(
height: 20.0,
);
},
itemCount: expenseNotifier.expenseList.length,
);
},
),
),
),
);
}
this is an example from my app:
bool _isLoading = false; <- default false
bool _isInit = true; <- to mae it only load once
#override
void initState() {
if (_isInit) {
// activating spinner
_isLoading = true;
// your function here <------
_isInit = false;
super.initState();
}
Initstate gets called before the user can see any kind of thin in your app, so this is the perfect place to make your firebase data load. with this logic from above the loading spinner shows as long you are receiving the data. And your body looks like the following then:
#override
Widget build(BuildContext context) {
return _isLoading <- is loading condition true? shows spinner
? Center(child: CircularProgressIndicator()) <- loading spinner
// else shows your content of the app
: SafeArea(
child: Container()
....

Resources