Not Finding and Deleting a Firebase Document - firebase

I am trying to make a form so that whenever you enter information and press a button, it will delete an item from the firebase database. I got the addUser code working, but when I got to the deleteUser, it compiles fine but then whenever I submit a form it doesn't show that I deleted it. I know I am putting in the same data exactly, so I think the problem is either the async in my function title or the await in my itemsSnapshot, but I have no idea since deleting a document this way is super weird. What am I doing wrong? (I am not including the imports because I'm not sure if that is sensitive data)
class AdminScreen extends StatefulWidget {
const AdminScreen({Key? key}) : super(key: key);
#override
State<AdminScreen> createState() => _AdminScreenState();
}
class _AdminScreenState extends State<AdminScreen> {
CollectionReference items = FirebaseFirestore.instance.collection('items');
reloadUser() {
setState(() {});
}
//this section is for adding stuff to database
String name = "";
String type = "";
String location="";
String imageURL = "";
String claimed = "false";
bool addDataVisible = true;
//end of this section
TextEditingController nameController = TextEditingController();
TextEditingController typeController = TextEditingController();
TextEditingController locationController = TextEditingController();
TextEditingController imageURLController = TextEditingController();
String deleteName = "";
String deleteType = "";
String deleteLocation = "";
TextEditingController deleteNameController = TextEditingController();
TextEditingController deleteTypeController = TextEditingController();
TextEditingController deleteLocationController = TextEditingController();
Object addUser() {
// Call the user's CollectionReference to add a new user
if(name!="" && type!="" && location!="") {
return items
.add({
'name': name,
'type': type,
'location': location,
'image': imageURL,
'claimed': claimed
});
// .then((value) => print("User Added"))
// .catchError((error) => print("Failed to add user: $error"));
}else{
return "There was a null error";
}
}
String idDelete = "";
Future<Object> deleteUser() async{
var itemsSnapshot = await items.get();
// Call the user's CollectionReference to add a new user
if (name != "" && type != "" && location != "") {
for (var document in itemsSnapshot.docs) {
if (document[name] == deleteName &&
document[type] == deleteType &&
document[location] == deleteLocation) {
idDelete = document.id;
}
}
print(idDelete);
items.doc(idDelete).delete();
print("user deleted success");
return items;
} else {
return "There was a null error";
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Admin'),
),
body: SingleChildScrollView(
child: Column(children: [
FirebaseAuth.instance.currentUser == null ? LoginButton(
updateState: reloadUser,) : //Text('logged in'),
//render the new widgets
Visibility(
visible: addDataVisible,
child: Column(
children: [
TextField(
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Name of Item to Add',
),
controller: nameController,
onChanged: (text) {
setState(() {
name = text;
});
},
//for description
),
TextField(
controller: typeController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Type of Item to Add',
),
onChanged: (text) {
setState(() {
type = text;
});
},
//for location found
),
TextField(
controller: locationController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Location of Item to Add',
),
onChanged: (text) {
setState(() {
location = text;
});
},
//for location found
),
TextField(
controller: imageURLController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Image URL of Item (put it in the folder)',
),
onChanged: (text) {
setState(() {
imageURL = text;
});
},
//for location found
),
TextButton(
child: const Text('Click Here to Submit New Item to Database'),
onPressed: addUser,
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all<Color>(Colors.blue),
overlayColor: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return Colors.blue.withOpacity(0.04);
}
if (states.contains(MaterialState.focused) ||
states.contains(MaterialState.pressed)) {
return Colors.blue.withOpacity(0.12);
}
return null; // Defer to the widget's default.
},
),
),
),
//THIS SECTION IS FOR DELETING ITEMS
TextField(
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Name of Item to Delete',
),
controller: deleteNameController,
onChanged: (text) {
setState(() {
deleteName = text;
});
},
//for description
),
TextField(
controller: deleteTypeController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Type of Item to Delete',
),
onChanged: (text) {
setState(() {
deleteType = text;
});
},
//for location found
),
TextField(
controller: deleteLocationController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Location of Item to Delete',
),
onChanged: (text) {
setState(() {
deleteLocation = text;
});
},
//for location found
),
TextButton(
child: const Text('Click Here to Delete Item to Database'),
onPressed: deleteUser,
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all<Color>(Colors.blue),
overlayColor: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return Colors.blue.withOpacity(0.04);
}
if (states.contains(MaterialState.focused) ||
states.contains(MaterialState.pressed)) {
return Colors.blue.withOpacity(0.12);
}
return null; // Defer to the widget's default.
},
),
),
),
],
),
),
]),
),
);
}}

Related

set a username & profile picture firebase login and then get it for a profile later on

ok, its late and I can't quite figure this out for some reason. I am coming from swift and newer to flutter. my code is below, I can't get my username to register in my json or anything else and I can't figure out how to pull it out later either, any help would be appreciated, I can pull out all the data but I haven't figured out how to assign the displayName or profile picture on a later screen
class WelcomeScreen extends StatefulWidget {
const WelcomeScreen({Key? key}) : super(key: key);
static const String id = 'welcome_screen';
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> with SingleTickerProviderStateMixin{
FirebaseAuth auth = FirebaseAuth.instance;
final _auth = FirebaseAuth.instance;
var _isLoading = false;
late AnimationController controller;
late Animation animation;
void _completeLogin() {
Navigator.pushReplacement<void, void>(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) => Home(),
),
);
}
void _submitAuthForm(
String email,
String username,
String password,
File imageFile,
bool isLogin,
BuildContext ctx,
) async {
UserCredential authResult;
try {
setState(() {
_isLoading = true;
});
if (isLogin) {
authResult = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
print('$username');
} else {
authResult = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
print('$username');
final ref = FirebaseStorage.instance
.ref()
.child('user_image')
.child(authResult.user!.uid + 'jpg');
await ref.putFile(imageFile);
final url = await ref.getDownloadURL();
await FirebaseFirestore.instance
.collection('users')
.doc(authResult.user!.uid)
.set({
'username': username,
'email': email,
'image_url': url,
});
}
} on FirebaseAuthException catch (error) {
var message = 'An error occurred, please check your credentials!';
if (error.message != null) {
message = error.message!;
}
ScaffoldMessenger.of(ctx).showSnackBar(SnackBar(content: Text(message)));
setState(() {
_isLoading = false;
});
}
}
#override
void initState() {
super.initState();
controller =
AnimationController (
duration: Duration(seconds: 1),
vsync: this,
);
animation = ColorTween(begin: Colors.transparent, end: Colors.white.withOpacity(0.5)).animate(controller);
controller.forward();
controller.addListener(() {
setState(() {
});
});
}
#override
Widget build(BuildContext context) {
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user == null) {
print('User is currently signed out!');
} else {
_completeLogin();
print('1');
}
});
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/bar1.jpg"),
fit: BoxFit.fill,
)
),
child: Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
body: Container(
child: Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Image.asset('assets/images/logo.png'),
AuthForm(
_submitAuthForm,
_isLoading,
),
],
),
),
),
),
),
);
}
}
and here is my auth form
FocusNode myFocusNode = FocusNode();
class AuthForm extends StatefulWidget {
const AuthForm(this.submitFn, this.isLoading, {Key? key}) : super(key: key);
final bool isLoading;
final void Function(
String email,
String userName,
String password,
File image,
bool isLogin,
BuildContext ctx,
) submitFn;
#override
_AuthFormState createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
String _userEmail = '';
String _userName = '';
String _userPassword = '';
File _userImageFile = File('');
void _pickedImage(File image) {
_userImageFile = image;
}
void _trySubmit() {
final isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
if (_userImageFile.path.isEmpty && !_isLogin) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Please pick an image'),
),
);
return;
}
if (isValid) {
_formKey.currentState!.save();
widget.submitFn(
_userEmail.trim(),
_userName.trim(),
_userPassword.trim(),
_userImageFile,
_isLogin,
context,
);
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Card(
margin: const EdgeInsets.symmetric(horizontal: 30, vertical: 20),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: AnimatedContainer(
duration: const Duration(milliseconds: 350),
curve: Curves.easeIn,
constraints: BoxConstraints(
minHeight: _isLogin ? 224 : 390,
maxHeight: _isLogin ? 268 : 456,
),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (!_isLogin)
UserImagePicker(_pickedImage),
TextFormField(
cursorColor: Colors.red,
key: const ValueKey('email'),
autocorrect: false,
textCapitalization: TextCapitalization.none,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email address',
),
validator: (val) {
if (EmailValidator.validate(val!) == false) {
return 'Please enter a valid email address.';
}
return null;
},
onSaved: (val) {
_userEmail = val!;
},
),
if (!_isLogin)
TextFormField(
cursorColor: Colors.red,
key: const ValueKey('username'),
decoration: const InputDecoration(
labelText: 'Username',
),
validator: (val) {
if (val!.isEmpty || val.length < 4) {
return 'Username must be at least 4 characters.';
}
return null;
},
onSaved: (val) {
_userName = val!;
},
),
TextFormField(
cursorColor: Colors.red,
key: const ValueKey('password'),
decoration: const InputDecoration(
labelText: 'Password',
),
obscureText: true,
validator: (val) {
if (val!.isEmpty || val.length < 6) {
return 'Check your password, it must be 6 character or longer.';
}
return null;
},
onSaved: (val) {
_userPassword = val!;
},
),
const SizedBox(height: 12),
widget.isLoading
? const CircularProgressIndicator()
: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
),
child: Text(_isLogin ? 'Log in' : 'Sign up'),
onPressed: _trySubmit,
),
TextButton(
child: Text(_isLogin
? 'Create new account'
: 'I already have an account'),
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
),
if (_isLogin)
TextButton(
child: Text(
'Forgot Password?'
),
onPressed: () {
Navigator.pushNamed(context, ForgotPassword.id);
},
),
],
),
),
),
),
),
),
);
}
}
answered it my self by writing to a category in firebase then used the below code to pull it out later
import 'package:flutter/material.dart';
// Import the firebase_core and cloud_firestore plugin
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class AddUser extends StatelessWidget {
final String fullName;
final String company;
final int age;
AddUser(this.fullName, this.company, this.age);
#override
Widget build(BuildContext context) {
// Create a CollectionReference called users that references the firestore collection
CollectionReference users = FirebaseFirestore.instance.collection('users');
Future<void> addUser() {
// Call the user's CollectionReference to add a new user
return users
.add({
'full_name': fullName, // John Doe
'company': company, // Stokes and Sons
'age': age // 42
})
.then((value) => print("User Added"))
.catchError((error) => print("Failed to add user: $error"));
}
return TextButton(
onPressed: addUser,
child: Text(
"Add User",
),
);
}
}
and this code to query it
class GetUserName extends StatelessWidget {
final String documentId;
GetUserName(this.documentId);
#override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection('users');
return FutureBuilder<DocumentSnapshot>(
future: users.doc(documentId).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
return Text("Full Name: ${data['full_name']} ${data['last_name']}");
}
return Text("loading");
},
);
}
}
You can pass them as a constructor
Example
class UserDetail extends StatelessWidget {
final File image;
final String display;
UserDetail({Key key, required this.image, required this.display}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(child:Row(
children: <Widget>[
Image.file(image: File(image))),
Text(display),
], ),);
}
}
You can read Passing data between screens in Flutter
For more info.

The non-nullable local variable 'result' must be assigned before it can be used

I cannot find the solution to this problem. I am creating a sign up screen connected to firebase but it is giving me this error, "The non-nullable local variable 'result' must be assigned before it can be used. Try giving it an initializer expression, or ensure that it's assigned on every execution path."
The error is here. On the first and third line under result.
FirebaseFirestore.instance.collection("User").doc(result.user!.uid).set({
"UserName": userName.text,
"UserId": result.user!.uid,
"UserEmail": email.text,
"UserAddress": address.text,
"UserGender": isMale == true ? "Male" : "Female",
"UserNumber": phoneNumber.text,
});
This is the whole code
`import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:e_commerce_application/screens/homepage.dart';
import 'package:e_commerce_application/screens/login.dart';
import 'package:e_commerce_application/widgets/changescreen.dart';
import 'package:e_commerce_application/widgets/mybutton.dart';
import 'package:e_commerce_application/widgets/mytextformField.dart';
import 'package:e_commerce_application/widgets/passwordtextformfield.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class SignUp extends StatefulWidget {
#override
_SignUpState createState() => _SignUpState();
}
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
String p =
r'^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regExp = new RegExp(p);
bool obserText = true;
final TextEditingController email = TextEditingController();
final TextEditingController userName = TextEditingController();
final TextEditingController phoneNumber = TextEditingController();
final TextEditingController password = TextEditingController();
final TextEditingController address = TextEditingController();
bool isMale = true;
bool isLoading = false;
class _SignUpState extends State<SignUp> {
void submit() async {
UserCredential result;
try {
setState(() {
isLoading = true;
});
result = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email.text, password: password.text);
print(result);
} on PlatformException catch (error) {
var message = "Please Check Your Internet Connection ";
if (error.message != null) {
message = error.message!;
}
_scaffoldKey.currentState!.showSnackBar(SnackBar(
content: Text(message.toString()),
duration: Duration(milliseconds: 600),
backgroundColor: Theme.of(context).primaryColor,
));
setState(() {
isLoading = false;
});
} catch (error) {
setState(() {
isLoading = false;
});
_scaffoldKey.currentState!.showSnackBar(SnackBar(
content: Text(error.toString()),
duration: Duration(milliseconds: 600),
backgroundColor: Theme.of(context).primaryColor,
));
print(error);
}
FirebaseFirestore.instance.collection("User").doc(result.user!.uid).set({
"UserName": userName.text,
"UserId": result.user!.uid,
"UserEmail": email.text,
"UserAddress": address.text,
"UserGender": isMale == true ? "Male" : "Female",
"UserNumber": phoneNumber.text,
});
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (ctx) => HomePage()));
setState(() {
isLoading = false;
});
}
void vaildation() async {
if (userName.text.isEmpty &&
email.text.isEmpty &&
password.text.isEmpty &&
phoneNumber.text.isEmpty &&
address.text.isEmpty) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("All Flied Are Empty"),
),
);
} else if (userName.text.length < 6) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Name Must Be 6 "),
),
);
} else if (email.text.isEmpty) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Email Is Empty"),
),
);
} else if (!regExp.hasMatch(email.text)) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Please Try Vaild Email"),
),
);
} else if (password.text.isEmpty) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Password Is Empty"),
),
);
} else if (password.text.length < 8) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Password Is Too Short"),
),
);
} else if (phoneNumber.text.length < 11 || phoneNumber.text.length > 11) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Phone Number Must Be 11 "),
),
);
} else if (address.text.isEmpty) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Address Is Empty "),
),
);
} else {
submit();
}
}
Widget _buildAllTextFormField() {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
MyTextFormField(
name: "UserName",
controller: userName,
),
SizedBox(
height: 10,
),
MyTextFormField(
name: "Email",
controller: email,
),
SizedBox(
height: 10,
),
PasswordTextFormField(
obserText: obserText,
controller: password,
name: "Password",
onTap: () {
FocusScope.of(context).unfocus();
setState(() {
obserText = !obserText;
});
},
),
SizedBox(
height: 10,
),
GestureDetector(
onTap: () {
setState(() {
isMale = !isMale;
});
},
child: Container(
height: 60,
padding: EdgeInsets.only(left: 10),
width: double.infinity,
decoration: BoxDecoration(border: Border.all(color: Colors.grey)),
child: Center(
child: Row(
children: [
Text(
isMale == true ? "Male" : "Female",
style: TextStyle(color: Colors.black87, fontSize: 18),
),
],
),
),
),
),
SizedBox(
height: 10,
),
MyTextFormField(
name: "Phone Number",
controller: phoneNumber,
),
SizedBox(
height: 10,
),
MyTextFormField(
name: "Address",
controller: address,
),
],
),
);
}
Widget _buildBottomPart() {
return Container(
margin: EdgeInsets.symmetric(horizontal: 10),
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_buildAllTextFormField(),
SizedBox(
height: 10,
),
isLoading == false
? MyButton(
name: "SignUp",
onPressed: () {
vaildation();
},
)
: Center(
child: CircularProgressIndicator(),
),
ChangeScreen(
name: "Login",
whichAccount: "I Have Already An Account!",
onTap: () {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (ctx) => Login(),
),
);
},
),
],
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: ListView(
children: [
Container(
height: 200,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Register",
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
),
),
],
),
),
Container(
height: 500,
child: _buildBottomPart(),
),
],
),
);
}
}
`
You are assigning result in your try catch, and accessing it after your try catch.
So if anything happens in your try block, result will never be assigned, and you cannot access whatever you want on it.
Solution would be to put your Firestore Call in your try catch block.
try {
setState(() {
isLoading = true;
});
result = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email.text, password: password.text);
print(result);
FirebaseFirestore.instance.collection("User").doc(result.user!.uid).set({
"UserName": userName.text,
"UserId": result.user!.uid,
"UserEmail": email.text,
"UserAddress": address.text,
"UserGender": isMale == true ? "Male" : "Female",
"UserNumber": phoneNumber.text,
});
Null safety in dart also cause this error in my code. The only solution is to assign a pre-define value to variable.
String imagePath = "path";
String imageName = '/image.jpeg';
I was getting this error in last line, in var imagePath.
class _newpostState extends State<newpost> {
//class newpost extends StatefulWidget {
//const newpost({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
String imagePath = "path";
String imageName = '/image.jpeg';
void pickImage() async {
final ImagePicker _picker = ImagePicker();
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
print(image!.name);
setState(() {
imagePath = image.path;
imageName = image.name;
});
}
final TextEditingController titlecontroller = TextEditingController();
final TextEditingController DcripController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
void submit() async {
//for post database
FirebaseAuth auth = FirebaseAuth.instance;
FirebaseFirestore firestore = FirebaseFirestore.instance;
//for storage
firebase_storage.FirebaseStorage storage =
firebase_storage.FirebaseStorage.instance;
try {
File file = File(imagePath);
await storage.ref(imageName).putFile(file);
It's so, frustrating to read "variable must be assigned before it can be used" because you already assigned the variable.
to solve this issue, provide a default value when you create the variable.
suppose the variable is a string.
String result; // instead of this
String result= ""; // use this

Manually entered data not being saved in Firebase document

I have a screen with several text fields and some are populated when it is created. This is done in the initState() function. When I enter data into the empty text fields and then save the data to a firebase document only the data that is manually entered after the screen has been created is saved to the document. Below is the code for the screen. Please help with this.
final _firebaseAuthUser = FirebaseAuth.instance.currentUser;
final agentsRef = FirebaseFirestore.instance.collection(('agents'));
final agencyRef = FirebaseFirestore.instance.collection(('agency'));
class AgentProfileScreen extends StatefulWidget {
static const String id = 'agent_profile_screen';
final Agents agents;
AgentProfileScreen([this.agents]);
#override
_AgentProfileScreenState createState() => _AgentProfileScreenState();
}
class _AgentProfileScreenState extends State<AgentProfileScreen> {
//final _auth = FirebaseAuth.instance;
final _db = FirebaseFirestore.instance;
final emailController = TextEditingController();
final passwordController = TextEditingController();
final fNameController = TextEditingController();
final lNameController = TextEditingController();
final address1Controller = TextEditingController();
final address2Controller = TextEditingController();
final cityController = TextEditingController();
final stateController = TextEditingController();
final zipController = TextEditingController();
final cellPhoneController = TextEditingController();
final officePhoneController = TextEditingController();
final agencyController = TextEditingController();
#override
void dispose() {
emailController.dispose();
passwordController.dispose();
fNameController.dispose();
lNameController.dispose();
address1Controller.dispose();
address2Controller.dispose();
cityController.dispose();
stateController.dispose();
zipController.dispose();
cellPhoneController.dispose();
officePhoneController.dispose();
agencyController.dispose();
super.dispose();
}
bool showSpinner = false;
String email;
String password;
String fName;
String lName;
String address1;
String address2;
String city;
String state;
String zip;
String cellPhone;
String officePhone;
String agency;
String _currentAgentState;
String _currentAgency;
getCurrentAgentProfile() async {
final DocumentSnapshot currentAgentProfile =
await agentsRef.doc(globals.currentUid).get();
//String currentAgencyId = currentAgentProfile.data()["agencyId"];
final DocumentSnapshot currentAgencyProfile =
await agencyRef.doc(globals.agencyId).get();
if (globals.newAgent == true) {
emailController.text = "";
fNameController.text = "";
lNameController.text = "";
address1Controller.text = currentAgencyProfile.data()['address1'];
address2Controller.text = currentAgencyProfile.data()['address2'];
cityController.text = currentAgencyProfile.data()['city'];
stateController.text = currentAgencyProfile.data()['state'];
globals.currentAgencyState = currentAgencyProfile.data()['state'];
zipController.text = currentAgencyProfile.data()['zipCode'].toString();
cellPhoneController.text = currentAgencyProfile.data()['cellPhone'];
officePhoneController.text = currentAgencyProfile.data()['officePhone'];
agencyController.text = currentAgencyProfile.data()['name'];
} else {
// existing record
// Updates Controllers
emailController.text = currentAgentProfile.data()["email"];
fNameController.text = currentAgentProfile.data()['fName'];
lNameController.text = currentAgentProfile.data()['lName'];
address1Controller.text = currentAgentProfile.data()['address1'];
address2Controller.text = currentAgentProfile.data()['address2'];
cityController.text = currentAgentProfile.data()['city'];
stateController.text = currentAgentProfile.data()['state'];
zipController.text = currentAgentProfile.data()['zipCode'].toString();
cellPhoneController.text = currentAgentProfile.data()['cellPhone'];
officePhoneController.text = currentAgentProfile.data()['officePhone'];
agencyController.text = currentAgentProfile.data()['agency'];
// Updates State
new Future.delayed(Duration.zero, () {
final agentProvider =
Provider.of<AgentProvider>(context, listen: false);
agentProvider.loadValues(widget.agents);
});
}
}
List<DropdownMenuItem<String>> _dropDownState;
List<DropdownMenuItem<String>> getDropDownState() {
List<DropdownMenuItem<String>> items = [];
for (String state in globals.states) {
items.add(new DropdownMenuItem(
value: state,
child: new Text(
state,
)));
}
return items;
}
void changedDropDownState(String selected_state) {
setState(() {
_currentAgentState = selected_state;
});
globals.selectedAgentState = selected_state;
}
void changedDropDownAgency(String selected_agency) {
setState(() {
_currentAgency = selected_agency;
});
globals.selectedAgency = selected_agency;
}
#override
void initState() {
getCurrentAgentProfile();
_currentAgentState = globals.currentAgentState;
_currentAgency = globals.agencyId;
_currentAgentState = globals.currentAgencyState;
super.initState();
_dropDownState = getDropDownState();
}
#override
Widget build(BuildContext context) {
// Get the stream of agents created in main.dart
final agentProvider = Provider.of<AgentProvider>(context);
final _firestoreService = FirestoreService();
String _chosenState = 'Select State';
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset('assets/images/Appbar_logo.png',
fit: BoxFit.cover, height: 56),
],
),
),
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
//mainAxisAlignment: MainAxisAlignment.center,
//crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'Agent Profile',
style: TextStyle(
fontSize: 30,
),
),
SizedBox(
height: 8.0,
),
// Email entry text field
TextField(
controller: fNameController,
keyboardType: TextInputType.text,
textAlign: TextAlign.center,
onChanged: (value) {
agentProvider.changefName(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'First Name', labelText: 'First Name'),
),
SizedBox(
height: 8.0,
),
TextField(
controller: lNameController,
keyboardType: TextInputType.text,
textAlign: TextAlign.center,
onChanged: (value) {
agentProvider.changelName(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Last Name', labelText: 'Last Name'),
),
SizedBox(
height: 8.0,
),
Container(
child: StreamBuilder(
stream: _db.collection('agency').snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return new DropdownButton<String>(
hint: new Text("Select Agency"),
value: _currentAgency,
onChanged: changedDropDownAgency,
items: snapshot.data.docs
.map<DropdownMenuItem<String>>((document) {
return new DropdownMenuItem<String>(
value: document.id,
child: new Text(document.data()['name']),
);
}).toList(),
);
}
;
}),
),
SizedBox(
height: 8.0,
),
TextField(
controller: address1Controller,
keyboardType: TextInputType.text,
textAlign: TextAlign.center,
onChanged: (value) {
agentProvider.changeaddress1(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Address 1', labelText: 'Address 1'),
),
SizedBox(
height: 8.0,
),
TextField(
controller: address2Controller,
textAlign: TextAlign.center,
onChanged: (value) {
agentProvider.changeaddress2(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Address 2', labelText: 'Address 2'),
),
SizedBox(
height: 8.0,
),
TextField(
controller: cityController,
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.center,
onChanged: (value) {
agentProvider.changecity(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'City', labelText: 'City'),
),
SizedBox(
height: 8.0,
),
DropdownButton(
value: _currentAgentState,
items: _dropDownState,
hint: Text('Choose State'),
onChanged: changedDropDownState,
),
SizedBox(
height: 8.0,
),
TextField(
controller: zipController,
keyboardType: TextInputType.phone,
textAlign: TextAlign.center,
onChanged: (value) {
agentProvider.changezipCode(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Zip Code', labelText: 'Zip Code'),
),
SizedBox(
height: 8.0,
),
TextField(
controller: cellPhoneController,
textAlign: TextAlign.center,
onChanged: (value) {
agentProvider.changecellPhone(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Cell Phone', labelText: 'Cell Phone'),
),
SizedBox(
height: 8.0,
),
TextField(
controller: officePhoneController,
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.center,
onChanged: (value) {
agentProvider.changeofficePhone(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Office Phone', labelText: 'Office Phone'),
),
SizedBox(
height: 8.0,
),
RoundedButton(
title: 'Save',
colour: Colors.blueAccent,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
agentProvider.saveAgent();
globals.newAgent = false;
globals.currentAgentState = _currentAgentState;
await _firestoreService.saveDeviceToken();
Navigator.pushNamed(context, Home_Screen.id);
setState(() {
showSpinner = false;
});
} catch (e) {
// todo: add better error handling
print(e);
}
},
),
SizedBox(
height: 8.0,
),
(widget != null)
? RoundedButton(
title: 'Delete',
colour: Colors.red,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
agentProvider.deleteAgent(globals.currentUid);
Navigator.pushNamed(
context, AgentDashboardScreen.id);
setState(() {
showSpinner = false;
});
} catch (e) {
// todo: add better error handling
print(e);
}
},
)
: Container()
],
),
),
),
),
);
}
}
Below is the provider code.
class AgentProvider with ChangeNotifier {
final firestoreService = FirestoreService();
final agencyRef = FirebaseFirestore.instance.collection(('agency'));
String _fName;
String _lName;
String _address1;
String _address2;
String _city;
String _state;
int _zipCode;
String _cellPhone;
String _officePhone;
String _agencyId;
String _agency;
//Getters
String get fName => _fName;
String get lName => _lName;
String get address1 => _address1;
String get address2 => _address2;
String get city => _city;
String get state => globals.selectedAgentState;
int get zipCode => _zipCode;
String get cellPhone => _cellPhone;
String get officePhone => _officePhone;
String get agencyId => globals.agencyId;
String get agency => _agency;
//Setters
changefName(String value) {
_fName = value;
notifyListeners();
}
changelName(String value) {
_lName = value;
notifyListeners();
}
changeaddress1(String value) {
_address1 = value;
notifyListeners();
}
changeaddress2(String value) {
_address2 = value;
notifyListeners();
}
changecity(String value) {
_city = value;
notifyListeners();
}
changestate(String value) {
_state = value;
notifyListeners();
}
// Convert String to int
changezipCode(String value) {
_zipCode = int.parse(value);
notifyListeners();
}
// Convert String to int
changecellPhone(String value) {
_cellPhone = value;
notifyListeners();
}
// Convert String to int
changeofficePhone(String value) {
_officePhone = value;
notifyListeners();
}
changeAgency(String value) {
_agency = value;
notifyListeners();
}
loadValues(Agents agents) {
_fName = agents.fName;
_lName = agents.lName;
_address1 = agents.address1;
_address2 = agents.address2;
_city = agents.city;
_state = globals.selectedAgentState;
_zipCode = agents.zipcode;
_cellPhone = agents.cellPhone;
_officePhone = agents.officePhone;
_agencyId = globals.agencyId;
_agency = agents.agency;
}
saveAgent() async {
final newAgent = new Map();
if (globals.newAgent == true) {
final DocumentSnapshot currentAgencyProfile =
await agencyRef.doc(globals.agencyId).get();
var newAgent = Agents(
agentId: globals.currentUid,
fName: _fName,
lName: _lName,
address1: currentAgencyProfile.data()['address1'],
address2: currentAgencyProfile.data()['address2'],
city: currentAgencyProfile.data()['city'],
state: globals.selectedAgentState,
zipcode: currentAgencyProfile.data()['zipCode'],
cellPhone: currentAgencyProfile.data()['cellPhone'],
officePhone: currentAgencyProfile.data()['officePhone'],
agencyId: globals.agencyId,
agency: agency);
firestoreService.saveAgent(newAgent);
} else {
var newAgent = Agents(
agentId: globals.currentUid,
fName: _fName,
lName: _lName,
address1: _address1,
address2: _address2,
city: _city,
state: globals.selectedAgentState,
zipcode: _zipCode,
cellPhone: _cellPhone,
officePhone: _officePhone,
agencyId: globals.agencyId,
agency: agency);
firestoreService.saveAgent(newAgent);
}
//firestoreService.saveAgent(newAgent);
_fName = "";
_lName = "";
_address1 = "";
_address2 = "";
_city = "";
_state = "";
_zipCode = null;
_cellPhone = "";
_officePhone = "";
_agencyId = "";
_agency = "";
}
Here is the saveAgent function. I really don't think this is the problem but here it is anyway.
Future<void> saveAgent(Agents agents) {
return _db.collection('agents').doc(globals.currentUid).set(agents.toMap());
}
initState is designed to be a synchronous function, and since your async function will take some time to execute, it will not work out as you expect. To call async function make use of FutureBuilder widget inside your build function.

Error: Missing or insufficient permissions firestore

I'm having troubles with creating users in my app, I get an error that says I don't have sufficient permissions even though I should have permission. My security rules are allowing users to be created so I don't really understand why I am getting this error. What's even more strange is that it works on my mates computer, he can create users (with the exact same userdetails). He is on a pc and I on a mac not sure if that matters?
The error I get is the following:
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: PlatformException(Error 7, FIRFirestoreErrorDomain, Missing or insufficient permissions.)
Our security rules are:
service cloud.firestore {
//match /databases/{database}/documents {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
}
match /Users/{userId} {
allow update: if request.auth.uid == userId;
}
match /Users/{document=**} {
allow create;
}
match /Recipes/{document=**} {
allow create: if request.auth != null;
allow update, delete: if request.resource.data.userId == request.auth.uid;
}
match /Recipes/{document=**}/newRatings {
allow create, update: if request.auth != null;
}
}
} ```
Our code for registering users is:
´´´ import 'package:cibus/pages/loginScreens/username_screen.dart';
import 'package:cibus/pages/loginScreens/verify_screen.dart';
import 'package:cibus/services/colors.dart';
import 'package:flutter/material.dart';
import 'package:cibus/services/login/auth.dart';
import 'package:cibus/services/constants.dart';
import 'package:cibus/pages/loginScreens/e-sign_in_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_user_stream/firebase_user_stream.dart';
import 'package:cibus/services/my_page_view.dart';
import 'package:provider/provider.dart';
import 'package:cibus/services/login/user.dart';
import 'package:cibus/services/database.dart';
import 'package:cibus/pages/loading_screen.dart';
const registerButtonColor = kTurquoise;
const formSizedBox = SizedBox(height: 20.0);
const EdgeInsets formPadding =
EdgeInsets.symmetric(vertical: 10.0, horizontal: 50.0);
const TextStyle textStyleErrorMessage =
TextStyle(color: Colors.red, fontSize: 14.0);
const TextStyle textStyleRegisterButton = TextStyle(color: Colors.white);
OutlineInputBorder textInputBorder = OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
);
class RegisterScreen extends StatefulWidget {
final Function toggleView;
RegisterScreen({this.toggleView});
#override
_RegisterScreenState createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
bool loading = false;
bool isVerified = false;
//final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
//text field state
String email = '';
String password = '';
String error = '';
String name = '';
String description = '';
String _currentUsername;
int age = 0;
int dropdownValue = null;
final TextEditingController _pass = TextEditingController();
final TextEditingController _confirmPass = TextEditingController();
#override
Widget build(BuildContext context) {
return loading
? LoadingScreen()
: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
appBar: AppBar(
backgroundColor: Theme.of(context).backgroundColor,
elevation: 0.0,
title: Text('Sign up to Cibus', style: TextStyle(color: kCoral)),
actions: <Widget>[
FlatButton.icon(
icon: Icon(Icons.person, color: kCoral),
label: Text('Sign in', style: TextStyle(color: kCoral)),
onPressed: () {
//widget.toggleView();
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) {
return EmailSignIn();
},
),
);
},
),
],
),
body: Padding(
padding: formPadding,
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(children: <Widget>[
formSizedBox,
TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Email',
),
validator: (val) =>
val.isEmpty ? 'Enter an email' : null,
onChanged: (val) {
setState(() => email = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Password',
),
obscureText: true,
controller: _pass,
validator: (String val) {
Pattern pattern =
r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!##\$&*~]).{8,}$';
RegExp regex = new RegExp(pattern);
print(val);
if (val.isEmpty) {
return 'Please enter password';
} else if (val.length < 8) {
return 'Minimum 8 characters required';
} else if (!val.contains(RegExp(r'[A-Z]'))) {
return 'One upper case letter required.';
} else if (!val.contains(RegExp(r'[a-z]'))) {
return 'One lower case letter required.';
} else if (!val.contains(RegExp(r'[0-9]'))) {
return 'One digit required.';
} else if (!val
.contains(RegExp(r'[!##$%^&*(),.?":{}|<>]'))) {
return 'One special character required.';
} /*
else {
if (!regex.hasMatch(val))
return 'Enter valid password: \n'
'Password must contain at least one upper case letter. \n'
'Password must contain at least one lower case letter. \n'
'Password must contain at least one digit. \n'
'Password must contain at least one special character.'; */
else
return null;
//}
},
onChanged: (val) {
setState(() => password = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: ' Re-enter Password',
),
obscureText: true,
controller: _confirmPass,
validator: (String val) {
if (val.isEmpty)
return 'Re-enter password field is empty';
if (val != _pass.text)
return 'passwords do not match';
return null;
},
onChanged: (val) {
setState(() => password = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Name',
),
validator: (val) =>
val.isEmpty ? 'Enter your name' : null,
onChanged: (val) {
setState(() => name = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Description',
),
minLines: 5,
maxLines: 10,
validator: (val) =>
val.isEmpty ? 'Enter your description' : null,
onChanged: (val) {
setState(() => description = val);
},
),
formSizedBox,
TextFormField(
maxLength: 20,
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Username',
),
validator: (val) {
if (val.length < 3)
return 'Username must be more than 2 characters';
/*else if (checkUsername == false)
return 'Username is allready taken';*/
return null;
},
onChanged: (val) {
setState(() {
_currentUsername = val;
print(_currentUsername);
});
}),
formSizedBox,
RaisedButton(
color: kCoral,
child: Text('Register', style: textStyleRegisterButton),
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
bool isUsernameFree = await DatabaseService()
.isUsernameTaken(username: _currentUsername);
print(' checkUsername: $isUsernameFree');
if (!isUsernameFree) {
dynamic result =
await _auth.registerWithEmailAndPassword(
email, password, name, description, age);
if (result == null) {
setState(() {
error = 'Email is already registered';
_verificationEmailDialog();
});
} else {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) {
return VerifyScreen();
},
),
);
}
} else {
setState(() {
error = 'Username is already taken';
});
_usernameDialog();
}
}
},
),
Text(
error,
style: textStyleErrorMessage,
),
])),
),
));
}
Future<void> _usernameDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Username is already taken'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(
'Unfortunately it seems like your username is allready taken. Please try another one'),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Aight bruh'),
onPressed: () {
setState(() {
loading = false;
});
Navigator.of(context)
.pop(); //TODO: When popping try to keep text in forms
},
),
],
);
},
);
}
Future<void> _verificationEmailDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Email is already in use'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(
'Unfortunately it seems like the email is already in use. Please try another one'),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Aight bruh'),
onPressed: () {
setState(() {
loading = false;
});
Navigator.of(context)
.pop(); //TODO: When popping try to keep text in forms
},
),
],
);
},
);
}
}
and here is the registerWithEmailAndPassword function:
Future registerWithEmailAndPassword(String email, String password,
String name, String description, int age) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
user.sendEmailVerification();
user.isEmailVerified;
print('Email verification sent?');
//create a new document for the user with the uid
await DatabaseService(uid: user.uid)
.updateUserData(name: name, description: description, age: age);
await DatabaseService(uid: user.uid).updateUserPicture(
pictureURL:
'https://firebasestorage.googleapis.com/v0/b/independent-project-7edde.appspot.com/o/blank_profile_picture.png?alt=media&token=49efb712-d543-40ca-8e33-8c0fdb029ea5');
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
It was a mistake on my part with the Security rules. I had that users could create users but they could only read if they were authenticated, so when I checked if username was taken the error occurred since I did not have the read permissions. I just added the read part on users and it works
match /Users/{document=**} {
allow create: if true;
allow read: if true;
}
´´´

Flutter ListView is not updating when the list items are changed

I started learning Flutter. I am developing a simple application using it. Now, I am developing a feature where my application will display the records from the SQLite database and where the user adds the new records into the SQLite database. But my ListView is displaying the blank screen.
I have a class called DatabaseHelper with the following code.
class DatabaseHelper {
static DatabaseHelper _databaseHelper;
Database _database;
String noteTable = 'note_table';
String colId = 'id';
String colTitle = 'title';
String colDescription = 'description';
String colPriority = 'priority';
String colDate = 'date';
DatabaseHelper._createInstance();
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper._createInstance();
}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'notes.db';
var notesDatabase = await openDatabase(path, version: 1, onCreate: _createDB);
return notesDatabase;
}
void _createDB(Database db, int newVersion) async {
await db.execute('CREATE TABLE $noteTable($colId INTEGER PRIMARY KEY AUTOINCREMENT, $colTitle TEXT, $colDescription TEXT, $colPriority INTEGER, $colDate TEXT)');
}
Future<List<Map<String, dynamic>>> getNoteMapList() async {
Database db = await this.database;
return await db.query(noteTable, orderBy: '$colPriority ASC');
}
Future<int> insertNote(Note note) async {
Database db = await this.database;
return await db.insert(noteTable, note.toMap());
}
Future<int> updateNote(Note note) async {
var db = await this.database;
return await db.update(noteTable, note.toMap(), where: '$colId = ?', whereArgs: [note.id]);
}
Future<int> deleteNote(int id) async {
var db = await this.database;
return await db.rawDelete('DELETE FROM $noteTable WHERE $colId = $id');
}
Future<int> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x = await db.rawQuery('SELECT COUNT(*) FROM $noteTable');
return Sqflite.firstIntValue(x);
}
}
Then I have a widget called NoteList with the following code where the list of items are displayed.
class NoteList extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _NoteListState();
}
}
class _NoteListState extends State<NoteList> {
List<Note> _notes = [];
int _count = 0;
DatabaseHelper _databaseHelper = DatabaseHelper();
_NoteListState() {
this._notes = getNotes();
this._count = _notes.length;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Notes"),),
body: Container(
child: getListView(context),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
navigateToNoteForm("Add Note");
},
),
);
}
Widget getListView(BuildContext context) {
return ListView.builder(
itemCount: _count,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: _notes[index].priority == 1? Colors.yellow: Colors.red,
child: Icon(_notes[index].priority == 1 ? Icons.arrow_right : Icons.add),
),
title: Text(_notes[index].title),
subtitle: Text(_notes[index].date),
trailing: Icon(Icons.delete),
onTap: () {
navigateToNoteForm("Edit Note", _notes[index]);
},
);
});
}
void navigateToNoteForm(String pageTitle, [Note note]) async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return NoteForm(pageTitle, note);
}));
if (result) {
setState(() {
debugPrint("Updating list");
_notes = getNotes();
_count = _notes.length;
});
}
}
List<Note> getNotes() {
List<Note> notes = List<Note>();
Future<List<Map<String, dynamic>>> notesFuture = _databaseHelper.getNoteMapList();
notesFuture.then((notesMap) {
debugPrint("Total notes found in the database ${notesMap.length}");
notesMap.forEach((map) {
notes.add(Note.fromMapObject(map));
});
});
return notes;
}
}
Then I also have another widget class called NoteForm with the following code.
class NoteForm extends StatefulWidget {
String _title = "";
Note _note = null;
NoteForm(String title, [Note note]) {
this._title = title;
this._note = note;
}
#override
State<StatefulWidget> createState() {
return _NoteFormState();
}
}
class _NoteFormState extends State<NoteForm> {
double _minimumPadding = 15.0;
var _priorities = [ 1, 2 ];
var _titleController = TextEditingController();
var _descriptionController = TextEditingController();
var _dateController = TextEditingController();
DatabaseHelper _databaseHelper = DatabaseHelper();
var _selectedPriority = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget._title),),
body: Builder(
builder: (scaffoldContext) => Form(
child: Column(
children: <Widget>[
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: TextFormField(
controller: _titleController,
decoration: InputDecoration(
labelText: "Title",
hintText: "Enter title"
),
),
),
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: TextFormField(
controller: _descriptionController,
decoration: InputDecoration(
labelText: "Description",
hintText: "Enter description"
),
),
)
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: TextFormField(
controller: _dateController,
decoration: InputDecoration(
labelText: "Date",
hintText: "Enter date"
),
),
),
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: DropdownButton<int>(
value: _selectedPriority,
items: _priorities.map((dropdownItem) {
return DropdownMenuItem<int>(
value: dropdownItem,
child: Text(dropdownItem == 1? "Low": "High"),
);
}).toList(),
onChanged: (int newSelectedValue) {
setState(() {
_selectedPriority = newSelectedValue;
});
},
),
),
),
Container(
child: Padding(
padding: EdgeInsets.all(_minimumPadding),
child: RaisedButton(
child: Text(
"Save"
),
onPressed: () {
_save(scaffoldContext);
},
),
),
)
],
),
),
)
);
}
void _save(BuildContext context) async {
Note note = Note();
note.title = _titleController.text;
note.description = _descriptionController.text;
note.date = _dateController.text;
note.priority = _selectedPriority;
if (widget._note != null && widget._note.id!=null) {
//update
_databaseHelper.updateNote(note);
this.showSnackBar(context, "Note has been updated.");
} else {
//create
_databaseHelper.insertNote(note);
this.showSnackBar(context, "Note has been added.");
}
closeForm(context);
}
void showSnackBar(BuildContext context, String message) {
var snackBar = SnackBar(
content: Text(message),
action: SnackBarAction(
label: "UNDO",
onPressed: () {
},
),
);
Scaffold.of(context).showSnackBar(snackBar);
}
void closeForm(BuildContext context) {
Navigator.pop(context, true);
}
}
When I run my application, it is just displaying the blank screen as follows.
As you can see I am logging out the number of records returned from the database using debugPrint method. It is saying that there are 6 records within the database. It is just not displaying the records. What is wrong with my code and how can I fix it?
As i mention in comment that was happening because of async task take some time to perform and if you do not keep it async then setState function execute before actual data load or set.
So Following changes solve your issue.
make getNotes async method And
getNotes().then((noteresponce){ setState((){ _notes=noteresponce; _count = _notes.length;} });

Resources