Flutter : Autorun a function whenever a screen is opened - firebase

I want to run a function to check Firestore data everytime a screen is loaded.
Here is my code :
class PlaceTile extends StatefulWidget {
//String flag='inactive';
final Place place;
PlaceTile({ this.place });
#override
_PlaceTileState createState() => _PlaceTileState(place);
}
class _PlaceTileState extends State<PlaceTile> {
final Place place;
_PlaceTileState(this.place);
String flag = 'inactive';
void getUserById(String id) {
DatabaseService().placesCollection.document(id).get().then((DocumentSnapshot doc) {
print(doc.data);
});
}
checkUserStatus() async {
final FirebaseAuth auth = FirebaseAuth.instance;
final FirebaseUser user = await auth.currentUser();
String uid = user.uid;
UserDatabaseService().userCollection.getDocuments().then((QuerySnapshot snapshot) {
snapshot.documents.forEach((DocumentSnapshot doc) {
if(doc.documentID == uid)
{
if(doc.data['status']=='true')
{
setState(() {
flag = 'active';
});
}
else
{
setState(() {
flag = 'inactive';
});
}
}
});
});
return flag;
}
void showQueueDetailsPanel() {
showModalBottomSheet(context: context, builder: (context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 60.0),
child: QueueDetails(value: place.name),
);
});
}
String value;
#override
initState() {
super.initState();
checkUserStatus();
}
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 8.0),
child: Card(
margin: EdgeInsets.fromLTRB(20.0, 6.0, 20.0, 0.0),
child: ListTile(
isThreeLine: true,
leading: CircleAvatar(
radius: 25.0,
backgroundColor: Colors.white,
),
title: Text(place.name),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//Text("People "+place.totalPeople.toString()),
Text(""),
Text("Token "+place.tokenAvailable.toString()),
],
),
trailing: FlatButton.icon(
icon: Icon(Icons.add_box_rounded),
label: Text('Join'),
onPressed: checkUserStatus() =='inactive' ? showQueueDetailsPanel : null,
),
),
)
);
}
}
The code in its current state doesn't perform the way I expect. It s a fallacy actually. Once flag is set to active, the Join buttons get disabled and for them to get re-enabled they need to be pressed for condition to be checked. But that's not possible since the buttons can't be pressed as they are disabled.
I want to run checkUserStatus() everytime this page with PlaceTile is loaded. How can I achieve that? A code snippet would be helpful.

Add your function to initState:
#override
void initState() {
super.initState();
checkUserStatus();
}

Widget build(BuildContext context) {
return FutureBuilder(
future: futurePackageListModel,
builder: (BuildContext context,
AsyncSnapshot<List<Model>> snapshot) {
if (snapshot.hasData) {
return YourWidget();
} else if (snapshot.hasError) {
return ApiStatusFail();
} else {
return Center(child: CircularProgressIndicator());
}
},
);
}

Related

Refreshes the page when Slider values ​change - Flutter, BloC

I'm new to Flutter, I started making a Slider through bloc and writing data to the fireStore, but I ran into a problem - when I change the value in the Slider, the page refreshes and freezes at the Loading stage, this is profile_screen. How can I fix the problem so that the page is not updated in real time, but only by clicking on the Save button?
profile_screen
double _currentSliderValue = 1;
#override
Widget build(BuildContext context) {
// final ProfileBloc infoBloc = context.read<ProfileBloc>();
ProfileCubit cubit = ProfileCubit.get(context);
return Scaffold(
body: Container(
child: Padding(
padding: const EdgeInsets.all(50),
child: BlocBuilder<ProfileCubit, ProfileState>(
builder: (context, state) {
if (state is ProfileInitial) {
return const Center(
child: Text('No Data'),
);
}
if (state is ProfileLoadingState) {
return CircularProgressIndicator();
}
if (state is ProfileLoadedState) {
return FutureBuilder<DocumentSnapshot>(
future: cubit.getInfo(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return _userNoInfo(cubit);
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return _userInfo(data, cubit);
}
return Text('Loading');
},
);
}
if (state is ProfileErrorState) {
return Center(
child: Text(state.error.toString()),
);
}
return Container();
})),
));
}
Widget _userInfo(data, ProfileCubit cubit) {
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Form(
key: _formKeyTwo,
child: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.2,
child: Slider(
value: _currentSliderValue,
max: 100,
divisions: 100,
label: _currentSliderValue.toString(),
onChanged: (value) {
setState(() {
_currentSliderValue = value;
});
}),
),
SizedBox(width: 100),
_cardData(),
],
),
const SizedBox(height: 50.0),
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.2,
child: ElevatedButton(
onPressed: () {
cubit.addAndUpdateInfo(
_bisNameContr.text,
_bisAddressContr.text,
_contactNameContr.text,
_contactEmailContr.text,
_phoneNumberContr.text,
_progNameContr.text,
_currentSliderValue.toString());
profile_cubit
class ProfileCubit extends Cubit<ProfileState> {
final Database _firestoreRepo;
ProfileCubit(this._firestoreRepo) : super(ProfileInitial()) {
getInfo();
}
static ProfileCubit get(context) => BlocProvider.of(context);
Future<DocumentSnapshot<Object?>> getInfo() {
try {
emit(ProfileLoadingState());
final Future<DocumentSnapshot<Object?>> infoData =
_firestoreRepo.getData();
emit(ProfileLoadedState(infoData));
return infoData;
} catch (e) {
emit(ProfileErrorState(e.toString()));
throw Exception(e);
}
}
Future<void> addAndUpdateInfo(
final String bisName,
final String bisAddress,
final String contactName,
final String contactEmail,
final String phoneNumber,
final String progName,
final String progYears,
) async {
await _firestoreRepo.addAndUpdateInfo(bisName, bisAddress, contactName,
contactEmail, phoneNumber, progName, progYears);
}
}
cubit_state
abstract class ProfileState extends Equatable {
const ProfileState();
#override
List<Object> get props => [];
}
class ProfileInitial extends ProfileState {}
class ProfileLoadingState extends ProfileState {}
class ProfileLoadedState extends ProfileState {
final Future<DocumentSnapshot<Object?>> dataInfo;
const ProfileLoadedState(this.dataInfo);
}
class ProfileErrorState extends ProfileState {
final String error;
const ProfileErrorState(this.error);
#override
List<Object> get props => [error];
}
If you don't want to build everytime, you can use buildWhen which is available inside BlocBuilder. if the value is true, it will rebuild everytime and if it's false, it will never rebuild. So you can keep a condition over there based on your requirements.

Getting ExpansionPanelList to work inside Streambuilder in flutter

I'm trying to arrange some data streamed from Firebase with an ExpansionPanellist. The panelList is placed inside a StreamBuilder, and above the StreamBuilder i have a SingleChildScrollView.
I am able to get the list showing with the headers, but i can't get the expand/collapse function to work, so I am not able to see the body-text.
screenshot of the list
The expanding/collapinsg function worked outside the Streambuilder, but I was not able to access the data from Firebase then.
Any help will be much appreciated! If this is the wrong way of doing this, I will also be grateful for any pointers to alternative ways of achieving this. (There won't be any data added to the server while looking at past climbs and graphs, so a streambuilder might not be necessary if there are easier/better ways).
-Kristian
class Graphs extends StatefulWidget {
static String id = 'graphs_screen';
#override
_GraphsState createState() => _GraphsState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(tabs: [
Tab(text: 'Graphs'),
Tab(text: 'Stats'),
Tab(text: 'Climbs'),
]),
),
body: TabBarView(
children: [
//Image.asset('assets/images/line_graph.png'),
Expanded(child: NumericComboLinePointChart.withSampleData()),
Container(
child: Text(''),
),
SingleChildScrollView(
child: DataStream(),
),
],
)),
),
);
}
}
class DataStream extends StatefulWidget {
#override
_DataStreamState createState() => _DataStreamState();
}
class _DataStreamState extends State<DataStream> {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('climbs')
.orderBy('Date', descending: true)
.snapshots(),
builder: (context, snapshot) {
List<ExpansionItem> expansionList = <ExpansionItem>[];
if (snapshot.hasData) {
final alldata = snapshot.data.docs;
for (var data in alldata) {
final dataFunction = data.data();
final grades = dataFunction['gradeScore'];
final climbDate = dataFunction['Date'];
final climbDateT = DateTime.fromMicrosecondsSinceEpoch(
climbDate.microsecondsSinceEpoch);
String climbDateString =
"${climbDateT.year.toString()}-${climbDateT.month.toString().padLeft(2, '0')}-${climbDateT.day.toString().padLeft(2, '0')} ${climbDateT.hour.toString()}-${climbDateT.minute.toString()}";
final climber = dataFunction['sender'];
final currentUSer = loggedInUser.email;
if (climber == loggedInUser.email) {
expansionList.add(ExpansionItem(
dateTimeHeader: climbDateString,
climbs: grades.toString()));
}
}
}
return ExpansionPanelList(
expansionCallback: (int index, bool isExpanded) {
setState(() {
print('tap registered');
expansionList[index].isExpanded = !isExpanded;
});
},
children: expansionList.map((ExpansionItem item) {
return ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return Container(
child: Text(item.dateTimeHeader),
);
},
body: Container(
child: Text(item.climbs),
),
isExpanded: item.isExpanded,
);
}).toList(),
);
});
}
}
class ExpansionItem {
ExpansionItem({this.isExpanded: false, this.dateTimeHeader, this.climbs});
bool isExpanded;
final String dateTimeHeader;
final String climbs;
}
I also ran into this issue and managed to develop a "work-around" (sorry in advance, it's a bit messy).
The reason your expansion tiles are not expanding is due to the nature of expansionCallback function. Once you press the expand button it also causes your StreamBuilder to rebuild. Therefore, since you're initializing "expansionList" within the StreamBuilder it will reset "isExpanded" back to false no matter how many times you press it. So your best option is to initialize the expansionList outside of the StreamBuilder and modify it from within. Check below for my solution but I welcome anyone to optimize it and/or share a better one.
class ExpansionItem {
String headerValue;
bool isExpanded;
SplitObject item;
ExpansionItem({this.item, this.headerValue, this.isExpanded = false});
}
class MyExample extends StatefulWidget{
#override
_MyExampleState createState() => _MyExampleState();
}
class _MyExampleState extends State<MyExample> {
//Pick a number as large as you see fit to always be more than necessary.
List<ExpansionItem> expansionItems = List<ExpansionItem>.generate('anyNumber', (int index)=> ExpansionItem(isExpanded: false,));
#override
Widget build(BuildContext context) {
return GestureDetector(
child: Scaffold(
appBar: AppBar(
title: Text('Split',style: Theme.of(context).textTheme.headline3,),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(8),
child: Container(
child: StreamBuilder(
builder: (context, streamData){
if(streamData.hasData){
List<SplitObject> items = streamData.data;
//Save data to Expansion list by iterating through it.
for (var i = 0; i < items.length; i++){
try {
expansionItems[i].item =items[i];
expansionItems[i].headerValue =items[i].itemName;
} catch (e) {
// Catch any range errors after trimming list.
if(e.toString().contains('RangeError')) {
expansionItems.add(ExpansionItem(
item: items[i], headerValue: items[i].itemName));
}
}
}
// Trim list
expansionItems = expansionItems.getRange(0, items.length).toList();
return _buildListPanel(expansionItems);
} else {
return ListTile(
title: Text('No items to split.'),
);
}
},
stream: DatabaseService().splitItemData,
),
),
),
)
);
}
Widget _buildListPanel(List<ExpansionItem> expansionItems){
// print(expansionItems[0].isExpanded);
return ExpansionPanelList(
expansionCallback: (int index, bool isExpanded){
setState(() {
expansionItems[index].isExpanded = !isExpanded;
// print(expansionItems[index].isExpanded);
});
},
children: expansionItems.map<ExpansionPanel>((ExpansionItem item){
return ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded){
print(item.isExpanded);
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(),
);
},
body: Container(),
isExpanded: item.isExpanded,
);
}).toList(),
);
}
}
You should create a class where your Expansion List will be, then your Stream builder must call it. Doing it this way Expansion Panel List callback will function just normal.
Look:
class _ExpansionPanelClass extends State<ExpansionPanelClass> {
#override
Widget build(BuildContext context) {
return ExpansionPanelList(
elevation: 3,
expansionCallback: (index, isExpanded) {
setState(() {
widget.product[index]['isExpanded'] = !isExpanded;
});
},
animationDuration: const Duration(milliseconds: 600),
children: widget.product
.map(
(item) => ExpansionPanel(
canTapOnHeader: true,
backgroundColor:
item['isExpanded'] == true ? Colors.cyan[100] : Colors.white,
headerBuilder: (_, isExpanded) => Container(
padding:
const EdgeInsets.symmetric(vertical: 15, horizontal: 30),
child: Text(
item['title'],
style: const TextStyle(fontSize: 20),
)),
body: Container(
padding:
const EdgeInsets.symmetric(vertical: 15, horizontal: 30),
child: Text(item['description']),
),
isExpanded: item['isExpanded'],
),
)
.toList(),
);
}
}
Then from your StreamBuilder:
StreamBuilder<QuerySnapshot>(
stream: dbProducts
.collection(ids[i])
.orderBy('order', descending: false)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Map<String, dynamic>> _items = [];
for (var document in snapshot.data!.docs) {
Map data = Map.from(document.data() as Map);
if (data['hide'] == false) {
Map<String, dynamic> map = {
'id': _items.length,
'title': data['name'],
'description': data['ingredients'],
'isExpanded': false
};
_items.add(map);
}
}
return ExpansionPanelClass(product: _items);
} else {
return const Center(
child: CircularProgressIndicator(
color: Colors.brown,
),
);
}
},
),
That's all.

firebase bool passes to null bug

Hello I am trying to change the data in firebase when I click the button from true to false and from false to true but when I click the value in the database goes to null.
Anyone know what’s wrong? Thank you.
class _MyHomePageState extends State<MyHomePage> {
bool selected;
#override
void initState() {
super.initState();
setInitialValue();
}
setInitialValue() async {
final value = await _incrementCounter();
setState(() {
selected = value?? true;
});
}
_loadCounter(bool value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('select', value);
}
Future<bool> _incrementCounter() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool boolValue = prefs.getBool('select');
return boolValue;
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text('ola'))),
MaterialButton(
color: Theme.of(context).primaryColor,
child: Text( 'Add', style: TextStyle(color: Colors.white), ),
onPressed: () {
Firestore.instance.collection('teste').document('eHJzjbq6c7MwrObrR9XY').updateData({'mover' : selected});
}
),
],
),
),
);
}
}
It seems that the value of the selected variable is not being set correctly, hence when you try to update the document you're sending a null value. Try to verify the value of selected to check if it has indeed a boolean value before writing it to firestore.

A build function returned null. Flutter Firebase

I tried many things but couldn't get any workable solution, please help.
Even wit the FutureBuilder it doesn't seem to work and without it, I get the result when I hot reload. I don't know how to change the code to make it work. Probably there is something small missing, but I couldn't figure yet what it is or how to solve it.
"""import 'package:flutter/material.dart';
import 'package:list/screens/add_new_item_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
final _firestore = Firestore.instance;
FirebaseUser loggedinUser;
Future<void> _fetchdata;
FirebaseAuth _auth = FirebaseAuth.instance;
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
void initState() {
super.initState();
_fetchdata = getCurrentUser();
}
Future<void> getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedinUser = user;
// print(loggedinUser.email);
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(
builder: (context) => Addnewitem()));
},
child: Icon(Icons.add),
),
appBar: AppBar(
leading: Container(),
title: Text("Shopping List"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
// messagesStream();
_auth.signOut();
Navigator.pop(context);
})
],
),
body: SafeArea(child:
MessagesStream(),
),
);
}
}
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
FutureBuilder(
future: _fetchdata,
builder: (context, myFuture){
if (myFuture.connectionState == ConnectionState.done && !myFuture.hasError && myFuture.hasData) {
if (myFuture.data != null) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('users')
.document(loggedinUser.uid)
.collection('items')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.hasError || snapshot.data == null || snapshot.connectionState == ConnectionState.waiting || loggedinUser.email == null) {
return (Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent)));
}
final items = snapshot.data.documents.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in items) {
final item = message.data['item'];
final quant = message.data['quant'];
final id = message.data['id'];
final boli = message.data['bool'];
// final currentUser = loggedinUser.email;
final messageBubble = MessageBubble(
text: item,
quant: quant,
documentReference: message.reference,
);
messageBubbles.add(messageBubble);
}
try {
return Expanded(
child: ListView(
// reverse: true,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
children: messageBubbles,
),
);
} catch (e) {
return Container();
}
});
}else {
return Container();
}
} else {
return CircularProgressIndicator();
}
});
}
}
class MessageBubble extends StatelessWidget {
MessageBubble({this.text, this.quant, this.documentReference});
final String text;
final String quant;
final DocumentReference documentReference;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
color: Colors.tealAccent,
child: FlatButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
text,
style: TextStyle(color: Colors.black, fontSize: 20),
),
Text(quant,
style: TextStyle(color: Colors.black, fontSize: 20))
],
),
onPressed: () {
documentReference.delete();
}),
)
],
),
),
);
}
}"""
Flutter doctor:
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.4)
[✓] Chrome - develop for the web
[✓] Android Studio (version 3.5)
[✓] VS Code (version 1.44.0)
[✓] Connected device (3 available)
• No issues found!
You need to add return keyword when using the build function since it returns a Widget:
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _fetchdata,
builder: (context, myFuture){
if (myFuture.connectionState == ConnectionState.done && !myFuture.hasError && myFuture.hasData) {
if (myFuture.data != null) {
return StreamBuilder<QuerySnapshot>(
For people having the same issue - here is my full code! Hope it helps
import 'package:flutter/material.dart';
import 'package:list/screens/add_new_item_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
final _firestore = Firestore.instance;
FirebaseUser loggedinUser;
Future<void> _fetchdata;
FirebaseAuth _auth = FirebaseAuth.instance;
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
void initState() {
super.initState();
_fetchdata = getCurrentUser();
}
Future<void> getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedinUser = user;
// print(loggedinUser.email);
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => Addnewitem()));
},
child: Icon(Icons.add),
),
appBar: AppBar(
leading: Container(),
title: Text("Shopping List"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
// messagesStream();
_auth.signOut();
Navigator.pop(context);
})
],
),
body: SafeArea(
child: MessagesStream(),
),
);
}
}
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _fetchdata,
builder: (context, myFuture) {
if (myFuture.connectionState == ConnectionState.done &&
!myFuture.hasError) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('users')
.document(loggedinUser.uid)
.collection('items')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData ||
snapshot.hasError ||
snapshot.data == null ||
snapshot.connectionState == ConnectionState.waiting ||
loggedinUser.email == null) {
return (Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent)));
}
final items = snapshot.data.documents.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in items) {
final item = message.data['item'];
final quant = message.data['quant'];
final id = message.data['id'];
final boli = message.data['bool'];
// final currentUser = loggedinUser.email;
final messageBubble = MessageBubble(
text: item,
quant: quant,
documentReference: message.reference,
);
messageBubbles.add(messageBubble);
}
try {
return Expanded(
child: ListView(
// reverse: true,
padding:
EdgeInsets.symmetric(horizontal: 10, vertical: 10),
children: messageBubbles,
),
);
} catch (e) {
return Container();
}
});
} else {
return CircularProgressIndicator();
}
});
}
}
class MessageBubble extends StatelessWidget {
MessageBubble({this.text, this.quant, this.documentReference});
final String text;
final String quant;
final DocumentReference documentReference;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
color: Colors.tealAccent,
child: FlatButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
text,
style: TextStyle(color: Colors.black, fontSize: 20),
),
Text(quant,
style: TextStyle(color: Colors.black, fontSize: 20))
],
),
onPressed: () {
documentReference.delete();
}),
)
],
),
),
);
}
}

null an the Display in Flutter but with the right Value in Future

I am pretty new in Flutter and i can not solve this problem.
i have a really simple application. it is just a login with google an a User is created in Firebase, that user have a counter and a button this button increased the counter (int _user.count++).
Then my problem: after the login in the next window, it is not visible the count variable until I click "plus" button. the variable is right and the query with fireStore work great I got the variable but if I do not click the button I got an the display in the place of the variable "null".
Thanks a lot for you Help and Time, I really hope that you can help me. maybe it is a tiny problem I have not found information about it but it is happen when some start to learn.
MyDAO: Hier the Method Future it is the responsable of make the Query to FireStore.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:gauth/user_model.dart';
import 'package:rxdart/rxdart.dart';
final UserDAO userDAO = UserDAO();
class UserDAO {
final Firestore _db = Firestore.instance;
PublishSubject loading;
Observable<Future<QuerySnapshot>> profile;
void updateData(UserModel user) async {
DocumentReference documentReference =
_db.collection("users").document(user.uid);
return documentReference.setData({
"uid": user.uid,
"userName": user.name,
"email": user.email,
"photoUrl": user.photoUrl,
"count": user.count,
"lastIn": DateTime.now()
}, merge: true);
}
Future<QuerySnapshot> readDateFutur(String email) async {
// loading.add(true);
QuerySnapshot querySnapshot = await (_db
.collection("users")
.where("email", isEqualTo: email)
.getDocuments());
// loading.add(false);
return querySnapshot;
}
}
hier in the method "void initState()" I hold the variable _user.couner, that works.
class PlusCounter extends StatefulWidget {
UserModel user;
PlusCounter(this.user);
#override
_PlusCounterState createState() => _PlusCounterState();
}
class _PlusCounterState extends State<PlusCounter> {
UserModel _user;
PublishSubject loading;
#override
void initState() {
// TODO: implement initState
super.initState();
setState(() {
_user = widget.user;
//loading.add(false);
userDAO.readDateFutur(_user.email).then((QuerySnapshot docs) {
if (docs.documents.isNotEmpty) {
print("::::::::::NOESTOY VACIO:::::::::::::::::::::");
print(docs.documents.last.data["count"]);
if (docs.documents.last.data["count"] != null) {
_user.count = docs.documents.last.data["count"];
} else {
_user.count = 0;
}
} else {
print(":::::::::::ESTOY VACIO:::::::::::::::::");
_user.count = 0;
}
});
});
}
void _plus() {
setState(() {
_user.count++;
});
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Text("Cuantas veces te has \n lavado las manos:"),
Text("${_user.count}"),
MaterialButton(
onPressed: () {
_plus();
},
child: Text("Plus"),
textColor: Colors.white,
color: Colors.blue,
),
MaterialButton(
onPressed: () => userDAO.updateData(_user),
child: Text("Guardar"),
textColor: Colors.white,
color: Colors.blue,
),
],
);
}
}
WelcomePage code is this one.
class userDataWelcome extends StatelessWidget {
UserModel _userModel;
userDataWelcome(this._userModel);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Welcome"),
),
body: Center(
child: Column(
children: <Widget>[
Center(
child: Container(
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(_userModel.photoUrl),
),
),
),
),
Text("${_userModel.name}"),
PlusCounter(_userModel),
MaterialButton(
onPressed: () => authService.SingOut(),
child: Text("Logout"),
textColor: Colors.white,
color: Colors.deepOrange,
)
],
),
),
);
}
}
Then I really do not why I need to click "plus" button before I can see the Value of _user.count, because I just see null in otherwise. just again I want to say Thanks for your help.
Try wrapping this line in initStat() _user.count = docs.documents.last.data["count"]; in setState((){}); like this
setState((){
_user.count = docs.documents.last.data["count"];
)};

Resources