I'm very new to flutter and trying to learn it. I have been trying to work with firebase and trying to upload data to it for the storage purpose. I have been using Realtime Database in test mode just to learn it but unfortunately due to some issues it's not working for me now.
The code that I wrote is : -
This is my provider file for interacting with my firebase
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import './product.dart';
class Products with ChangeNotifier {
List<Product> _items = [
Product(
id: 'p1',
title: 'Red Shirt',
description: 'A red shirt - it is pretty red!',
price: 29.99,
imageUrl:
'https://cdn.pixabay.com/photo/2016/10/02/22/17/red-t-shirt-1710578_1280.jpg',
),
Product(
id: 'p2',
title: 'Trousers',
description: 'A nice pair of trousers.',
price: 59.99,
imageUrl:
'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Trousers%2C_dress_%28AM_1960.022-8%29.jpg/512px-Trousers%2C_dress_%28AM_1960.022-8%29.jpg',
),
Product(
id: 'p3',
title: 'Yellow Scarf',
description: 'Warm and cozy - exactly what you need for the winter.',
price: 19.99,
imageUrl:
'https://live.staticflickr.com/4043/4438260868_cc79b3369d_z.jpg',
),
Product(
id: 'p4',
title: 'A Pan',
description: 'Prepare any meal you want.',
price: 49.99,
imageUrl:
'https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Cast-Iron-Pan.jpg/1024px-Cast-Iron-Pan.jpg',
),
];
// var _showFavoritesOnly = false;
List<Product> get items {
// if (_showFavoritesOnly) {
// return _items.where((prodItem) => prodItem.isFavorite).toList();
// }
return [..._items];
}
List<Product> get favoriteItems {
return _items.where((prodItem) => prodItem.isFavorite).toList();
}
Product findById(String id) {
return _items.firstWhere((prod) => prod.id == id);
}
// void showFavoritesOnly() {
// _showFavoritesOnly = true;
// notifyListeners();
// }
// void showAll() {
// _showFavoritesOnly = false;
// notifyListeners();
// }
Future<void> addProduct(Product product) {
const url = 'https://random-app-effc2-default-rtdb.firebaseio.com/products.json';
return http
.post(
url,
body: json.encode({
'title': product.title,
'description': product.description,
'imageUrl': product.imageUrl,
'price': product.price,
'isFavorite': product.isFavorite,
}),
)
.then((response) {
final newProduct = Product(
title: product.title,
description: product.description,
price: product.price,
imageUrl: product.imageUrl,
id: json.decode(response.body)['name'],
);
_items.add(newProduct);
// _items.insert(0, newProduct); // at the start of the list
notifyListeners();
});
}
void updateProduct(String id, Product newProduct) {
final prodIndex = _items.indexWhere((prod) => prod.id == id);
if (prodIndex >= 0) {
_items[prodIndex] = newProduct;
notifyListeners();
} else {
print('...');
}
}
void deleteProduct(String id) {
_items.removeWhere((prod) => prod.id == id);
notifyListeners();
}
}
This is my widget code which is directly interacting with my firebase : -
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/product.dart';
import '../providers/products.dart';
class EditProductScreen extends StatefulWidget {
static const routeName = '/edit-product';
#override
_EditProductScreenState createState() => _EditProductScreenState();
}
class _EditProductScreenState extends State<EditProductScreen> {
final _priceFocusNode = FocusNode();
final _descriptionFocusNode = FocusNode();
final _imageUrlController = TextEditingController();
final _imageUrlFocusNode = FocusNode();
final _form = GlobalKey<FormState>();
var _editedProduct = Product(
id: null,
title: '',
price: 0,
description: '',
imageUrl: '',
);
var _initValues = {
'title': '',
'description': '',
'price': '',
'imageUrl': '',
};
var _isInit = true;
var _isLoading = false;
#override
void initState() {
_imageUrlFocusNode.addListener(_updateImageUrl);
super.initState();
}
#override
void didChangeDependencies() {
if (_isInit) {
final productId = ModalRoute.of(context).settings.arguments as String;
if (productId != null) {
_editedProduct =
Provider.of<Products>(context, listen: false).findById(productId);
_initValues = {
'title': _editedProduct.title,
'description': _editedProduct.description,
'price': _editedProduct.price.toString(),
// 'imageUrl': _editedProduct.imageUrl,
'imageUrl': '',
};
_imageUrlController.text = _editedProduct.imageUrl;
}
}
_isInit = false;
super.didChangeDependencies();
}
#override
void dispose() {
_imageUrlFocusNode.removeListener(_updateImageUrl);
_priceFocusNode.dispose();
_descriptionFocusNode.dispose();
_imageUrlController.dispose();
_imageUrlFocusNode.dispose();
super.dispose();
}
void _updateImageUrl() {
if (!_imageUrlFocusNode.hasFocus) {
if ((!_imageUrlController.text.startsWith('http') &&
!_imageUrlController.text.startsWith('https')) ||
(!_imageUrlController.text.endsWith('.png') &&
!_imageUrlController.text.endsWith('.jpg') &&
!_imageUrlController.text.endsWith('.jpeg'))) {
return;
}
setState(() {});
}
}
void _saveForm() {
final isValid = _form.currentState.validate();
if (!isValid) {
return;
}
_form.currentState.save();
setState(() {
_isLoading = true;
});
if (_editedProduct.id != null) {
Provider.of<Products>(context, listen: false)
.updateProduct(_editedProduct.id, _editedProduct);
setState(() {
_isLoading = false;
});
Navigator.of(context).pop();
} else {
Provider.of<Products>(context, listen: false)
.addProduct(_editedProduct)
.then((_) {
setState(() {
_isLoading = false;
});
Navigator.of(context).pop();
});
}
// Navigator.of(context).pop();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Edit Product'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.save),
onPressed: _saveForm,
),
],
),
body: _isLoading
? Center(
child: CircularProgressIndicator(),
)
: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _form,
child: ListView(
children: <Widget>[
TextFormField(
initialValue: _initValues['title'],
decoration: InputDecoration(labelText: 'Title'),
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(_priceFocusNode);
},
validator: (value) {
if (value.isEmpty) {
return 'Please provide a value.';
}
return null;
},
onSaved: (value) {
_editedProduct = Product(
title: value,
price: _editedProduct.price,
description: _editedProduct.description,
imageUrl: _editedProduct.imageUrl,
id: _editedProduct.id,
isFavorite: _editedProduct.isFavorite);
},
),
TextFormField(
initialValue: _initValues['price'],
decoration: InputDecoration(labelText: 'Price'),
textInputAction: TextInputAction.next,
keyboardType: TextInputType.number,
focusNode: _priceFocusNode,
onFieldSubmitted: (_) {
FocusScope.of(context)
.requestFocus(_descriptionFocusNode);
},
validator: (value) {
if (value.isEmpty) {
return 'Please enter a price.';
}
if (double.tryParse(value) == null) {
return 'Please enter a valid number.';
}
if (double.parse(value) <= 0) {
return 'Please enter a number greater than zero.';
}
return null;
},
onSaved: (value) {
_editedProduct = Product(
title: _editedProduct.title,
price: double.parse(value),
description: _editedProduct.description,
imageUrl: _editedProduct.imageUrl,
id: _editedProduct.id,
isFavorite: _editedProduct.isFavorite);
},
),
TextFormField(
initialValue: _initValues['description'],
decoration: InputDecoration(labelText: 'Description'),
maxLines: 3,
keyboardType: TextInputType.multiline,
focusNode: _descriptionFocusNode,
validator: (value) {
if (value.isEmpty) {
return 'Please enter a description.';
}
if (value.length < 10) {
return 'Should be at least 10 characters long.';
}
return null;
},
onSaved: (value) {
_editedProduct = Product(
title: _editedProduct.title,
price: _editedProduct.price,
description: value,
imageUrl: _editedProduct.imageUrl,
id: _editedProduct.id,
isFavorite: _editedProduct.isFavorite,
);
},
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
width: 100,
height: 100,
margin: EdgeInsets.only(
top: 8,
right: 10,
),
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey,
),
),
child: _imageUrlController.text.isEmpty
? Text('Enter a URL')
: FittedBox(
child: Image.network(
_imageUrlController.text,
fit: BoxFit.cover,
),
),
),
Expanded(
child: TextFormField(
decoration: InputDecoration(labelText: 'Image URL'),
keyboardType: TextInputType.url,
textInputAction: TextInputAction.done,
controller: _imageUrlController,
focusNode: _imageUrlFocusNode,
onFieldSubmitted: (_) {
_saveForm();
},
validator: (value) {
if (value.isEmpty) {
return 'Please enter an image URL.';
}
if (!value.startsWith('http') &&
!value.startsWith('https')) {
return 'Please enter a valid URL.';
}
if (!value.endsWith('.png') &&
!value.endsWith('.jpg') &&
!value.endsWith('.jpeg')) {
return 'Please enter a valid image URL.';
}
return null;
},
onSaved: (value) {
_editedProduct = Product(
title: _editedProduct.title,
price: _editedProduct.price,
description: _editedProduct.description,
imageUrl: value,
id: _editedProduct.id,
isFavorite: _editedProduct.isFavorite,
);
},
),
),
],
),
],
),
),
),
);
}
}
final url = Uri.parse('https://random-app-effc2-default-rtdb.firebaseio.com/products.json');
use this code instead of
const url = 'https://random-app-effc2-default-rtdb.firebaseio.com/products.json';
Related
I have made a online store app with flutter and backend on firebase , in sign up page whenever click on create account button it says same error, no matter if I put data on Text Fields or not, I am really confused about this!
the error is
given String is empty or null
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../widgets/custom_button.dart';
import '../widgets/custom_input.dart';
import 'const.dart';
import 'login.dart';
class SingUP extends StatefulWidget {
SingUP({Key? key}) : super(key: key);
#override
State<SingUP> createState() => _SingUPState();
}
class _SingUPState extends State<SingUP> {
Future<void> advanceAlertDialog(String message) {
return Get.defaultDialog(
title: 'Invalid Input',
content: Text(message),
actions: [
ElevatedButton(
onPressed: () => Get.back(),
child: Text('OK !'),
)
],
contentPadding: EdgeInsets.all(15.0),
);
}
Future<String?> signInMethod() async {
try {
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: takeEmail, password: takePassword);
return 'ok';
} on FirebaseAuthException catch (error) {
if (error.code == 'weak-password') {
return 'the password is too week';
} else if (error.code == 'email-already-in-use') {
return 'The account with this email is already exist !';
}
return error.message;
} catch (error) {
return error.toString();
}
}
void signIn() async {
setState(() {
isLoading = true;
});
String? result = await signInMethod();
if (result != 'ok') {
advanceAlertDialog(result!);
setState(() {
isLoading = false;
});
} else {
setState(() {
isLoading = false;
});
Get.to(LoginPage());
Get.snackbar('Successful', 'Account Created !',
backgroundColor: Colors.greenAccent, icon: Icon(Icons.check_circle));
}
}
bool isLoading = false;
String takeEmail = '';
String takePassword = '';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: EdgeInsets.only(top: 50),
child: Text(
'Create a New Account !',
style: Constans.headingTextStyle,
textAlign: TextAlign.center,
),
),
Column(
children: [
CustomInput(
hintText: 'Enter Your Email ...',
onChanged: (value) {
takeEmail = value;
},
checkPassword: false,
),
CustomInput(
hintText: 'Enter Your Password ...',
onChanged: (value) {
takeEmail = value;
},
checkPassword: true,
),
CustomButton(
text: 'Create Account',
loading: isLoading,
onTap: () {
signIn();
},
mode: false,
)
],
),
CustomButton(
text: 'Back to Login',
onTap: () => Get.back(),
mode: true,
loading: isLoading,
)
],
),
),
);
}
}
Emain and password widgets are the same takeEmail = value;, change the password onChange value to takePassword = value;, also where is exactly the error thrown?. I advice to add breakpoints to signInMethod() to see the input values of email: takeEmail, password: takePassword (both of this strings) and after the on FirebaseAuthException catch (error) { to see if the error is thrown from firebase or is in your code.
i am a flutter beginner and i am getting the "Flutter & Dart - The Complete Guide [2022 Edition]" course at Udemy (if you know the course i am at Section 10, Lesson 242 "Sending POST Requests". This is my first time using Firebase and a database and i stuck at this problem for quite some time now. We built a basic shop app at previous sections at course and now we are supposed to send a Post request to our Firebase realtime database when we add a new product to our app. We supposed to add some basic information to our database about product. When i try to add a new product, nothing happens, no data at my database and no new product at my app (adding product to app happens in same function right after sending Post request). There is no error at my terminal only one line below.
I/flutter (11699): ...
I was able to add products to app before adding http package and writing the post request codes from last lesson. These are my debug, database rules, and the function that sends post request.
void addProduct(Product product) {
final url = Uri.parse(
'https://flutter-update-ca55a-default-rtdb.firebaseio.com/products.json');
http.post(
url,
body: json.encode({
'title': product.title,
'description': product.description,
'imageUrl': product.imageUrl,
'price': product.price,
'isFavorite': product.isFavorite,
}),
);
final newProduct = Product(
id: DateTime.now().toString(),
title: product.title,
description: product.description,
price: product.price,
imageUrl: product.imageUrl);
_items.add(newProduct);
notifyListeners();
}
I tried course constructors example codes and it didn't work. Then i tried disabling my firewall, changing my database rules to as seen in my question, still same problem. I don't even know if my code is communicating with firebase or not.
Edit:
Sometimes i get the latest text at my Terminal as well, adding a screenshot below:
Click to see Terminal SS
Edit 2 : So i created an empty project to see if my computer is communicating with firebase at all and it worked, i added information to my database from a single screen app. I afraid i have a logical error in my Shop App (most likely at the screen i use addProduct function) so i am posting the code if you see the mistake please warn me. This is edit-product-screen, where i use addProduct function via provider.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/product.dart';
import '../providers/product_provider.dart';
class EditProductScreen extends StatefulWidget {
static const String routeName = '/edit-product-screen';
#override
State<EditProductScreen> createState() => _EditProductScreenState();
}
class _EditProductScreenState extends State<EditProductScreen> {
//final _priceFocusNode = FocusNode();
//final _descriptionFocusNode = FocusNode();
final _imageUrlController = TextEditingController();
//final _imageUrlFocusNode = FocusNode();
final _form = GlobalKey<FormState>();
var _editedProduct =
Product(id: '', title: '', description: '', price: 0, imageUrl: '');
var _isInit = true;
var _isloading = false;
var _initValues = {
'title': '',
'description': '',
'price': '',
'imageUrl': '',
};
#override
void initState() {
//_imageUrlFocusNode.addListener(_updateImageUrl);
super.initState();
}
#override
void didChangeDependencies() {
if (_isInit) {
final String? productId =
ModalRoute.of(context)!.settings.arguments as String?;
if (productId != null) {
_editedProduct = Provider.of<ProductProvider>(context, listen: false)
.findbyID(productId);
_initValues = {
'title': _editedProduct.title,
'description': _editedProduct.description,
'price': _editedProduct.price.toString(),
// 'imageUrl': _editedProduct.imageUrl,
'imageUrl': '',
};
_imageUrlController.text = _editedProduct.imageUrl;
}
}
_isInit = false;
super.didChangeDependencies();
}
// #override
// void dispose() {
// _imageUrlFocusNode.removeListener(_updateImageUrl);
// _priceFocusNode.dispose();
// _descriptionFocusNode.dispose();
// _imageUrlController.dispose();
// _imageUrlFocusNode.dispose();
// super.dispose();
// }
void _updateImageUrl() {
// if (!_imageUrlFocusNode.hasFocus) {
// if ((!_imageUrlController.text.startsWith('http') &&
// !_imageUrlController.text.startsWith('https')) ||
// (!_imageUrlController.text.endsWith('.png') &&
// !_imageUrlController.text.endsWith('.jpg') &&
// !_imageUrlController.text.endsWith('.jpeg'))) {
// return;
// }
setState(() {});
//}
}
void _saveForm() {
final isValid = _form.currentState!.validate();
if (!isValid) {
return;
}
_form.currentState!.save();
setState(() {
_isloading = true;
});
if (_editedProduct.id != null) {
//var olan bir product editleniyor
Provider.of<ProductProvider>(context, listen: false)
.updateProduct(_editedProduct.id, _editedProduct);
setState(() {
_isloading = false;
});
Navigator.of(context).pop();
} else {
//yeni bir product oluşturuluyor.
Provider.of<ProductProvider>(context, listen: false)
.addProduct(_editedProduct)
.catchError((error) {
return showDialog<Null>(
context: context,
builder: (ctx) => AlertDialog(
title: Text('An Error Occured'),
content: Text(error.toString()),
actions: [
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text('Okay'))
],
),
);
}).then((_) {
setState(() {
_isloading = false;
});
Navigator.of(context).pop();
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Edit Products'),
actions: [
IconButton(
onPressed: _saveForm,
icon: Icon(Icons.save),
),
],
),
body: _isloading
? Center(
child: CircularProgressIndicator(),
)
: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _form,
child: ListView(
children: [
TextFormField(
initialValue: _initValues['title'],
decoration: InputDecoration(labelText: 'Title'),
validator: (value) {
if (value!.isEmpty) {
return 'Please enter a title';
}
return null;
},
textInputAction: TextInputAction.next,
// onFieldSubmitted: (_) {
// FocusScope.of(context).requestFocus(_priceFocusNode);
// },
onSaved: (value) {
_editedProduct = Product(
title: value as String,
price: _editedProduct.price,
description: _editedProduct.description,
imageUrl: _editedProduct.imageUrl,
id: _editedProduct.id,
isFavorite: _editedProduct.isFavorite,
);
},
),
TextFormField(
initialValue: _initValues['price'],
decoration: InputDecoration(labelText: 'Price'),
textInputAction: TextInputAction.next,
keyboardType: TextInputType.number,
//focusNode: _priceFocusNode,
// onFieldSubmitted: (_) {
// FocusScope.of(context).requestFocus(_descriptionFocusNode);
// },
validator: (value) {
if (value!.isEmpty) {
return 'Please enter a price';
}
if (double.tryParse(value) == null) {
return 'Please enter a valid number';
}
if (double.parse(value) <= 0) {
return 'Plase enter a number greater than zero';
}
return null;
},
onSaved: (value) {
_editedProduct = Product(
title: _editedProduct.title,
price: double.parse(value as String),
description: _editedProduct.description,
imageUrl: _editedProduct.imageUrl,
id: _editedProduct.id,
isFavorite: _editedProduct.isFavorite,
);
},
),
TextFormField(
initialValue: _initValues['description'],
decoration: InputDecoration(labelText: 'Description'),
maxLines: 3,
validator: (value) {
if (value!.isEmpty) {
return 'Please enter a description';
}
if (value.length < 10) {
return 'Your description must be longer then 10 characters';
}
return null;
},
textInputAction: TextInputAction.next,
//focusNode: _descriptionFocusNode,
keyboardType: TextInputType.multiline,
onSaved: (value) {
_editedProduct = Product(
title: _editedProduct.title,
price: _editedProduct.price,
description: value as String,
imageUrl: _editedProduct.imageUrl,
id: _editedProduct.id,
isFavorite: _editedProduct.isFavorite,
);
},
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
width: 100,
height: 100,
margin: EdgeInsets.only(top: 8, right: 10),
decoration: BoxDecoration(
border: Border.all(width: 1, color: Colors.grey),
),
child: _imageUrlController.text.isEmpty
? Text('Enter a URL')
: FittedBox(
child: Image.network(
_imageUrlController.text,
fit: BoxFit.cover,
),
),
),
Expanded(
child: TextFormField(
decoration: InputDecoration(labelText: 'Image URL'),
validator: (value) {
if (value!.isEmpty) {
return 'Please enter a image url';
}
if (!value.startsWith('http') &&
!value.startsWith('https')) {
return 'Please enter a valid image url';
}
return null;
},
keyboardType: TextInputType.url,
textInputAction: TextInputAction.done,
controller: _imageUrlController,
//focusNode: _imageUrlFocusNode,
onFieldSubmitted: (_) {
_saveForm();
},
onSaved: (value) {
_editedProduct = Product(
title: _editedProduct.title,
price: _editedProduct.price,
description: _editedProduct.description,
imageUrl: value as String,
id: _editedProduct.id,
isFavorite: _editedProduct.isFavorite,
);
},
),
),
],
)
],
),
),
),
);
}
}
And this is the latest version of addProduct function
Future<void> addProduct(Product product) async {
final url = Uri.parse(
'https://flutter-update-ca55a-default-rtdb.firebaseio.com/products2.json');
try {
final response = await http.post(
url,
body: json.encode({
'title': product.title,
'description': product.description,
'imageUrl': product.imageUrl,
'price': product.price,
'isFavorite': product.isFavorite,
}),
);
print(json.decode(response.body));
final newProduct = Product(
id: DateTime.now().toString(),
title: product.title,
description: product.description,
price: product.price,
imageUrl: product.imageUrl);
_items.add(newProduct);
notifyListeners();
} catch (error) {
print(error);
throw error;
}
}
I'm thinking you're missing to implement await. Could you try to add await in the beginning http.post after trying to change your method Future then it going to work.
Future<Product> addProduct(Product product) async{
final url = Uri.parse(
'https://flutter-update-ca55a-default-rtdb.firebaseio.com/products.json');
await http.post(
url,
body: json.encode({
'title': product.title,
'description': product.description,
'imageUrl': product.imageUrl,
'price': product.price,
'isFavorite': product.isFavorite,
}),
);
And lastly, you should be use json to dart side for parsing and try to implement json encode to your model with factory methods. ( I've added my first post to your backend, please don't forget to change write rules for everyone)
If you want to learn more detail, please look at dart.pad
samples:
https://dartpad.dev/?id=c04e9842d98ac871988973df025c097e
Maybe this is late answer, but this problem has happened to me also,
if (_editedProduct.id != null) - in this line you are making a mistake, this should be: if (_editedProduct.id != '')
I hope it helps.
Actually i had the same problem, it is a not logical error as it might sound, I only created a new project with a new realtime data base with a different location than my vpn for instance my vpn was set to be US so i set realtime location on Belgium. I hope it works out for u as well.
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
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;
}
´´´
I am received the following error on my form, I am trying to submit a form page to a Firebase database. The error is "Another exception was thrown: NoSuchMethodError: The setter 'wastedate=' was called on null." I am thinking it must relate to the _saveWaste function as the print shows "saveWaste called" but not "form saved".
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:async';
import 'package:wasteagram/model/waste.dart';
import 'package:path/path.dart' as path;
import 'package:uuid/uuid.dart';
class CameraScreen extends StatefulWidget {
final bool isUpdating;
CameraScreen({#required this.isUpdating});
#override
_CameraScreenState createState() => _CameraScreenState();
}
class _CameraScreenState extends State<CameraScreen> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Waste _currentWaste;
Widget _buildDateField() {
return Form(
key: _formKey,
child: TextFormField(
decoration: InputDecoration(labelText: 'Date'),
keyboardType: TextInputType.text,
style: TextStyle(fontSize: 20),
validator: (String value) {
if(value.isEmpty){
return 'Date required';
}
if(value.length < 3 || value.length > 20) {
return 'Name must be more than 3 or less than 20';
}
return null;
},
onSaved: (String value) {
_currentWaste.wastedate = value;
},
),
);
}
Widget _buildWasteNumber() {
return Form(
child: TextFormField(
decoration: InputDecoration(labelText: 'Number'),
keyboardType: TextInputType.number,
style: TextStyle(fontSize: 20),
validator: (value) {
if(value.isEmpty){
return 'Number required';
}
return null;
},
onSaved: (String value) {
String wasteNum = _currentWaste.wastenumber.toString();
wasteNum = value;
},
),
);
}
_saveWaste(context) {
print("saveWaste Called");
if(!_formKey.currentState.validate()) {
return "FALSE";
}
_formKey.currentState.save();
print("form saved");
uploadItems(_currentWaste, widget.isUpdating, image);
print("date ${_currentWaste.wastedate}");
print("number ${_currentWaste.wastenumber.toString()}");
print("_imageFile ${image.toString()}");
}
File image;
void getImage() async {
image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState( () {});
}
#override
Widget build(BuildContext context) {
if (image == null) {
return Scaffold(
appBar: AppBar(
title: Text('Wasteagram')
),
body: Center(
child: RaisedButton(
child: Text('Select Photo'),
onPressed: () {
getImage();
},
),
),
);
} else {
return Scaffold(
appBar: AppBar(
title: Text('Wasteagram')
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.file(image),
SizedBox(height: 40),
RaisedButton(
child: Text('Select Photo'),
onPressed: () {
getImage();
}
),
_buildDateField(),
_buildWasteNumber(),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () => _saveWaste(context),
child: Icon(Icons.save),
foregroundColor: Colors.white,
),
);
}
}
}
uploadItems(Waste waste, bool isUpdating, File localFile) async {
if (localFile != null) {
print("uploading image");
var fileExtension = path.extension(localFile.path);
print(fileExtension);
var uuid = Uuid().v4();
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('/$uuid$fileExtension');
await firebaseStorageRef.putFile(localFile).onComplete.catchError(
(onError){
print(onError);
return false;
}
);
String url = await firebaseStorageRef.getDownloadURL();
print("download url: $url");
_uploadWaste(waste, isUpdating, imageUrl: url);
} else {
print("skipping image upload");
_uploadWaste(waste, isUpdating);
}
}
_uploadWaste(Waste waste, bool isUpdating, {String imageUrl}) async {
CollectionReference wasteRef = Firestore.instance.collection('todolist');
if(imageUrl != null) {
waste.image = imageUrl;
}
if(isUpdating) {
waste.updatedAt = Timestamp.now();
await wasteRef.document(waste.id).updateData(waste.toMap());
print("updated waste with id: ${waste.id}");
} else {
DocumentReference documentRef = await wasteRef.add(waste.toMap());
waste.id = documentRef.documentID;
print("uploaded waste successfully: ${waste.toString()}");
await documentRef.setData(waste.toMap(), merge: true);
}
}
You must init _currentWaste , it is null
Please change from
Waste _currentWaste;
To
Waste _currentWaste = Waste();