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.
Related
I have a string error which I can't seem to debug I think its related to how I'm trying to retrieve data when using Future.wait I get the above error. If I only build a single future and don't use Future.wait and retrieve data using snapshot.data!.data()!["prediction"] I don't get any errors.
Code below for my future.wait
Any help appreciated!
class CorrectMood extends StatefulWidget {
const CorrectMood({Key? key}) : super(key: key);
#override
_CorrectMoodState createState() => _CorrectMoodState();
}
class _CorrectMoodState extends State<CorrectMood> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: Future.wait([getData(), getLatestMood()]),
builder: (context, AsyncSnapshot<List> snapshot) {
snapshot.data![0]; //getLatestMood
snapshot.data![1]; //getData
if (snapshot.hasData) {
return Scaffold(
appBar: AppBar(
title: const Text('Display the Picture'),
backgroundColor: kPrimaryColor,
),
// The image is stored as a file on the device. Use the `Image.file`
// constructor with the given path to display the image.
body: Center(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(8.0, 20.0, 8.0, 8.0),
child: Column(
children: [
Center(
child:
Text(
"${snapshot.data![0]["firstName"]}"
// "${snapshot.data![0].prediction}"
//"${snapshot.data!.data()!["firstName"]} \n\n "
"We have predicted your mood as:\n\n "
//"${DatabaseService.getMood()}\n\n"
"Please select a reason associated to your mood",
style: const TextStyle(
color: Colors.black, fontSize: 15),
textAlign: TextAlign.center,
),
),
countDocuments(),
],
),
),
],
),
),
);
}else {
return CircularProgressIndicator();
}
},
);
}
}
Future<DocumentSnapshot<Map<String, dynamic>>> getData() async {
var currentUser = FirebaseAuth.instance.currentUser;
return await FirebaseFirestore.instance
.collection('USER_TABLE')
.doc(currentUser!.uid)
.get();
}
countDocuments() async {
var currentUser = FirebaseAuth.instance.currentUser;
QuerySnapshot _myDoc = await FirebaseFirestore.instance
.collection('userMoods')
.doc('useerID')
.collection(currentUser!.uid)
.get();
List<DocumentSnapshot> _myDocCount = _myDoc.docs;
return (_myDocCount.length);
}
Future<DocumentSnapshot<Map<String, dynamic>>> getLatestMood() async {
var currentUser = FirebaseAuth.instance.currentUser;
var latestMoodDoc = countDocuments();
return await FirebaseFirestore.instance
.collection('userMoods')
.doc('useerID') // make this the userID
.collection('UbcNaFtJwXWoId9J5RLuVBVPhpN2') // make this increment every time
.doc('2') //this can be system generated name don't care about it
.get();
}
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.
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());
}
},
);
}
i'm trying to add user in my contacts by writing his uid from firebase. I need to write users id in textfield and on pressing button i need to firebase check this uid, and if it's exists, my app needs to add it in contacts. Is there any solutions? p.s i'm making messenger app and it's "Add new contact" function. It would be nice if someone tells me how to create chat using their ID or create separate "chat id" which would be same to 2 users. btw i'm using realtime database
To check if the user exsits, you can do something like this:
final users = FirebaseFirestore.instance.collection('users');
final userDoc =
await users.doc('PUT THE UID TO SEARCH FOR HERE').get();
if (userDoc.exists) {
// do something
}
To make this reusable convert it to a function:
Future<bool> userExists(String uid) async {
final users = FirebaseFirestore.instance.collection('users');
final userDoc =
await users.doc(uid).get();
return userDoc.exists;
}
Now you can call the function with any uid:
bool _userExists = await userExists('UID');
Here is a full code example:
import 'package:flutter/material.dart';
void main() {
runApp(App());
}
class App extends StatefulWidget {
#override
_AppState createState() => new _AppState();
}
class _AppState extends State<App> {
// This key is used to control the SnackBars
final key = GlobalKey<ScaffoldMessengerState>();
final textCtrlr = TextEditingController();
bool isLoading = false;
#override
void dispose() {
super.dispose();
textCtrlr.dispose();
}
Future<bool> userExists(String uid) async {
final users = FirebaseFirestore.instance.collection('users');
final userDoc = await users.doc(uid).get();
return userDoc.exists;
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ScaffoldMessenger(
key: key, // Assign the key to the ScaffoldMessenger
child: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
child: TextFormField(
controller: textCtrlr,
),
width: 200.0,
),
),
isLoading
? const SizedBox(
child: CircularProgressIndicator(
strokeWidth: 2.0,
),
width: 20.0,
height: 20.0,
)
: ElevatedButton(
onPressed: () async {
final uid = textCtrlr.text;
setState(() => isLoading = false);
final bool _userExists = await userExists(uid);
setState(() => isLoading = false);
if (_userExists) {
// The user exists and can
// be added to contacts
key.currentState?.showSnackBar(
SnackBar(
content: Text(
'User added!',
),
backgroundColor: Colors.green,
behavior: SnackBarBehavior.floating,
),
);
return;
}
// The user doesn't exist
key.currentState?.showSnackBar(
SnackBar(
content: Text(
'The user doesn\'t exist',
),
backgroundColor: Theme.of(context).errorColor,
behavior: SnackBarBehavior.floating,
),
);
},
child: const Text('Search for user'),
),
],
),
),
),
),
);
}
}
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"];
)};